summaryrefslogtreecommitdiff
path: root/services/players.ts
diff options
context:
space:
mode:
Diffstat (limited to 'services/players.ts')
-rw-r--r--services/players.ts154
1 files changed, 0 insertions, 154 deletions
diff --git a/services/players.ts b/services/players.ts
deleted file mode 100644
index b81d4b5..0000000
--- a/services/players.ts
+++ /dev/null
@@ -1,154 +0,0 @@
-import { GLib, GObject, property, readFile, register, writeFileAsync } from "astal";
-import AstalMpris from "gi://AstalMpris";
-import { isRealPlayer } from "../utils/mpris";
-
-@register({ GTypeName: "Players" })
-export default class Players extends GObject.Object {
- static instance: Players;
- static get_default() {
- if (!this.instance) this.instance = new Players();
-
- return this.instance;
- }
-
- readonly #path = `${CACHE}/players.txt`;
- readonly #players: AstalMpris.Player[] = [];
- readonly #subs = new Map<
- JSX.Element,
- { signals: string[]; callback: () => void; ids: number[]; player: AstalMpris.Player | null }
- >();
-
- @property(AstalMpris.Player)
- get lastPlayer(): AstalMpris.Player | null {
- return this.#players.length > 0 && this.#players[0].identity !== null ? this.#players[0] : null;
- }
-
- /**
- * List of real players.
- */
- @property(Object)
- get list() {
- return this.#players;
- }
-
- hookLastPlayer(widget: JSX.Element, signal: string, callback: () => void): this;
- hookLastPlayer(widget: JSX.Element, signals: string[], callback: () => void): this;
- hookLastPlayer(widget: JSX.Element, signals: string | string[], callback: () => void) {
- if (!Array.isArray(signals)) signals = [signals];
- // Add subscription
- if (this.lastPlayer)
- this.#subs.set(widget, {
- signals,
- callback,
- ids: signals.map(s => this.lastPlayer!.connect(s, callback)),
- player: this.lastPlayer,
- });
- else this.#subs.set(widget, { signals, callback, ids: [], player: null });
-
- // Remove subscription on widget destroyed
- widget.connect("destroy", () => {
- const sub = this.#subs.get(widget);
- if (sub?.player) sub.ids.forEach(id => sub.player!.disconnect(id));
- this.#subs.delete(widget);
- });
-
- // Initial run of callback
- callback();
-
- // For chaining
- return this;
- }
-
- makeCurrent(player: AstalMpris.Player) {
- const index = this.#players.indexOf(player);
- // Ignore if already current
- if (index === 0) return;
- // Remove if present
- else if (index > 0) this.#players.splice(index, 1);
- // Connect signals if not already in list (i.e. new player)
- else this.#connectPlayerSignals(player);
-
- // Add to front
- this.#players.unshift(player);
- this.#updatePlayer();
-
- // Save to file
- this.#save();
- }
-
- #updatePlayer() {
- this.notify("last-player");
-
- for (const sub of this.#subs.values()) {
- sub.callback();
- if (sub.player) sub.ids.forEach(id => sub.player!.disconnect(id));
- sub.ids = this.lastPlayer ? sub.signals.map(s => this.lastPlayer!.connect(s, sub.callback)) : [];
- sub.player = this.lastPlayer;
- }
- }
-
- #save() {
- writeFileAsync(this.#path, this.#players.map(p => p.busName).join("\n")).catch(console.error);
- }
-
- #connectPlayerSignals(player: AstalMpris.Player) {
- // Change order on attribute change
- for (const signal of [
- "notify::playback-status",
- "notify::shuffle-status",
- "notify::loop-status",
- "notify::volume",
- "notify::rate",
- ])
- player.connect(signal, () => this.makeCurrent(player));
- }
-
- constructor() {
- super();
-
- const mpris = AstalMpris.get_default();
-
- // Load players
- if (GLib.file_test(this.#path, GLib.FileTest.EXISTS)) {
- this.#players = readFile(this.#path)
- .split("\n")
- .map(p => mpris.players.find(p2 => p2.busName === p))
- .filter(isRealPlayer) as AstalMpris.Player[];
- // Add new players from in between sessions
- for (const player of mpris.players)
- if (!this.#players.includes(player) && isRealPlayer(player)) this.#players.push(player);
- } else {
- const sortOrder = [
- AstalMpris.PlaybackStatus.PLAYING,
- AstalMpris.PlaybackStatus.PAUSED,
- AstalMpris.PlaybackStatus.STOPPED,
- ];
- this.#players = mpris.players
- .filter(isRealPlayer)
- .sort((a, b) => sortOrder.indexOf(a.playbackStatus) - sortOrder.indexOf(b.playbackStatus));
- }
- this.#updatePlayer();
- this.#save();
- // Connect signals to loaded players
- for (const player of this.#players) this.#connectPlayerSignals(player);
-
- // Add and connect signals when added
- mpris.connect("player-added", (_, player) => {
- if (isRealPlayer(player)) {
- this.makeCurrent(player);
- this.notify("list");
- }
- });
-
- // Remove when closed
- mpris.connect("player-closed", (_, player) => {
- const index = this.#players.indexOf(player);
- if (index >= 0) {
- this.#players.splice(index, 1);
- this.notify("list");
- if (index === 0) this.#updatePlayer();
- this.#save();
- }
- });
- }
-}