import { createBinding, createState, With } from "ags"; import { execAsync } from "ags/process"; import { Gtk } from "ags/gtk4"; import { getSymbolicIcon } from "../../scripts/apps"; import { Separator } from "../Separator"; import { Windows } from "../../windows"; import { Clipboard } from "../../scripts/clipboard"; import GObject from "ags/gobject"; import AstalMpris from "gi://AstalMpris"; import Pango from "gi://Pango?version=1.0"; export const dummyPlayer = AstalMpris.Player.new("colorshellDummy"); export let [player, setPlayer] = createState(dummyPlayer); export const Media = () => { const connections: Map|number> = new Map(); if(AstalMpris.get_default().players[0]) setPlayer(AstalMpris.get_default().players[0]); connections.set(AstalMpris.get_default(), [ AstalMpris.get_default().connect("player-added", (_, player) => player.available && setPlayer(player)), AstalMpris.get_default().connect("player-closed", (_, closedPlayer) => { const players = AstalMpris.get_default().players.filter(pl => pl?.available); if(players.length > 0) { setPlayer(players[0]); return; } else setPlayer(dummyPlayer); }) ]); return pl.available)} $={(self) => { const gestureClick = Gtk.GestureClick.new(), controllerMotion = Gtk.EventControllerMotion.new(), controllerScroll = Gtk.EventControllerScroll.new( Gtk.EventControllerScrollFlags.VERTICAL); self.add_controller(gestureClick); self.add_controller(controllerMotion); self.add_controller(controllerScroll); connections.set(gestureClick, gestureClick.connect("released", () => Windows.getDefault().toggle("center-window"))); connections.set(controllerScroll, controllerScroll.connect("scroll", (_, _dx, dy) => { if(AstalMpris.get_default().players.length === 1 && player.get()?.busName === AstalMpris.get_default().players[0].busName) return true; const players = AstalMpris.get_default().players; for(let i = 0; i < players.length; i++) { const pl = players[i]; if(pl.busName !== player.get().busName) continue; if(dy > 0 && players[i-1]) { setPlayer(players[i-1]); break; } if(dy < 0 && players[i+1]) { setPlayer(players[i+1]); break; } } return true; }) ); connections.set(controllerMotion, [ controllerMotion.connect("enter", () => { const revealer = self.get_last_child() as Gtk.Revealer; revealer.set_reveal_child(true); }), controllerMotion.connect("leave", () => { const revealer = self.get_last_child() as Gtk.Revealer; revealer.set_reveal_child(false); }) ]); connections.set(self, self.connect("destroy", () => connections.forEach((ids, obj) => Array.isArray(ids) ? ids.forEach(id => obj.disconnect(id)) : obj.disconnect(ids)) )); }}> pl.available)}> pl.available)}> {(available: boolean) => available && { const splitName = busName.split('.').filter(str => str !== "" && !str.toLowerCase().includes('instance')); return getSymbolicIcon(splitName[splitName.length - 1]) ? getSymbolicIcon(splitName[splitName.length - 1])! : "folder-music-symbolic"; })} /> title ?? "No Title")} maxWidthChars={20} ellipsize={Pango.EllipsizeMode.END} /> artist ?? "No Artist")} maxWidthChars={18} ellipsize={Pango.EllipsizeMode.END} /> } pl.available)}> {(available: boolean) => available && { execAsync(`playerctl --player=${ player.get().busName.replace(/^org\.mpris\.MediaPlayer2\./i, "") } metadata xesam:url`).then(link => { Clipboard.getDefault().copyAsync(link); }).catch((e: Error) => { console.error(`Media: couldn't copy media link. Stderr: \n${e.message}\n${e.stack}`); }); }} /> player.get().canGoPrevious && player.get().previous()} /> status === AstalMpris.PlaybackStatus.PAUSED ? "media-playback-start-symbolic" : "media-playback-pause-symbolic")} tooltipText={ createBinding(player.get(), "playbackStatus").as(status => status === AstalMpris.PlaybackStatus.PAUSED ? "Play" : "Pause") } onClicked={player.get().play_pause} /> player.get().canGoNext && player.get().next()} /> } }