# `media`

The active media player, over MPRIS: every `org.mpris.MediaPlayer2.*`
on the session bus, the one playing (the latest to start) chosen, else
the latest to pause, unless one was picked with `p.select()`, which
holds until that player leaves or another starts playing; `players`
lists them all. Its position is carried forward from the
player's last report at its rate, never asked for again (no polling),
and only while a visible reader shows it.

| Field | Type | |
| --- | --- | --- |
| `playing` | `bool` | Something is playing. |
| `title` | `text?` | The track's title. |
| `artist` | `text?` | The track's artist. |
| `album` | `text?` | The track's album. |
| `art` | `text?` | The album art: `image media.art { fit: cover }`. Local art (a `file://` URL or a path) as the player sent it; remote (`https://`, `http://`) art fetched and shown as a file once it is in. Null when the player sent none, while remote art loads, or when it failed, so `media.art ?? "audio-x-generic"` falls back. |
| `position` | `float rw` | Fraction of the track played, 0 to 1. Writable: a scrubber's `slider { value: <-> media.position }` seeks the player (MPRIS `SetPosition`, or `Seek` when the track has no id). A player that cannot seek, or a track of unknown length, keeps its place. |
| `elapsed` | `duration` | Time played. |
| `length` | `duration?` | The track's length, when known. |
| `player` | `text?` | The active player's name, such as `Firefox` or `mpv`; null when no player runs. |
| `can_next` | `bool` | The active player can skip to the next track (MPRIS `CanGoNext`): `opacity: media.can_next ? 1 : 0.4`. False when no player runs or it takes no control (`CanControl` false). |
| `can_previous` | `bool` | The active player can go back to the previous track (`CanGoPrevious`, as `can_next`). |
| `can_seek` | `bool` | Writing `position` seeks: the active player can seek (`CanSeek`, as `can_next`) and the track's length is known. |
| `players` | `[Player]` | Every player running, keyed by its bus name (`for p in media.players key p.id { … }`): a switcher, a card per player. The one `media.*` follows is `active`; `p.select()` picks another. Read only while a visible reader reads it; its playing players' times tick once a second then. |

| Method | |
| --- | --- |
| `action play_pause()` | Plays or pauses. |
| `action next()` | Skips to the next track. |
| `action previous()` | Goes back to the previous track. |
