import Gtk from "gi://Gtk?version=3.0" import GLib from "gi://GLib" import Pango from "gi://Pango" import AstalMpris from "gi://AstalMpris" import { Variable, bind } from "astal" const mpris = AstalMpris.get_default() const PREV = "media-skip-backward-symbolic" const PLAY = "media-playback-start-symbolic" const PAUSE = "media-playback-pause-symbolic" const NEXT = "media-skip-forward-symbolic" const NO_ART = "audio-x-generic-symbolic" function fmtTime(seconds: number) { if (!seconds || seconds < 0) return "0:00" const min = Math.floor(seconds / 60) const sec = Math.floor(seconds % 60) return `${min}:${sec < 10 ? "0" : ""}${sec}` } function playerIcon(entry: string) { const name = entry ? `${entry.toLowerCase()}-symbolic` : "" const theme = Gtk.IconTheme.get_default()! return name !== "" && theme.has_icon(name) ? name : NO_ART } function PlayerCard(player: AstalMpris.Player) { // position only changes on the bus when seeking, so poll every second; // the ticker stops itself when the player disconnects so we never // touch a disposed GObject const position = Variable(-1) GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1000, () => { if (!mpris.players.includes(player)) return GLib.SOURCE_REMOVE position.set(player.available ? player.position : -1) return GLib.SOURCE_CONTINUE }) return ( c !== "" ? `background-image: url('${encodeURI(`file://${c}`)}')` : "", )} > {/* kept allocated (opacity, not visible) so the padded box stays 48px and the icon sits dead center with no art */} (c !== "" ? 0 : 1))} />