💥 fix(media, big-media): only show button to copy media link if it's provided by the player

makes use of a connection to notify::metadata to get when the link is updated, instead of binding directly to AstalMpris.Player::metadata and getting the 'xesam:url' property, since JS does not support the hashmap thing
This commit is contained in:
retrozinndev
2025-07-29 14:18:58 -03:00
parent a67da99839
commit ba5694271d
2 changed files with 24 additions and 22 deletions
+17 -10
View File
@@ -1,5 +1,4 @@
import { createBinding, createState, onCleanup, With } from "ags"; import { Accessor, createBinding, createConnection, createState, onCleanup, With } from "ags";
import { execAsync } from "ags/process";
import { Gtk } from "ags/gtk4"; import { Gtk } from "ags/gtk4";
import { Separator } from "../Separator"; import { Separator } from "../Separator";
import { Windows } from "../../windows"; import { Windows } from "../../windows";
@@ -8,7 +7,7 @@ import { Clipboard } from "../../scripts/clipboard";
import GObject from "ags/gobject"; import GObject from "ags/gobject";
import AstalMpris from "gi://AstalMpris"; import AstalMpris from "gi://AstalMpris";
import Pango from "gi://Pango?version=1.0"; import Pango from "gi://Pango?version=1.0";
import { getPlayerIconFromBusName } from "../../scripts/utils"; import { decoder, getPlayerIconFromBusName, variableToBoolean } from "../../scripts/utils";
export const dummyPlayer = AstalMpris.Player.new("colorshellDummy"); export const dummyPlayer = AstalMpris.Player.new("colorshellDummy");
@@ -127,14 +126,10 @@ export const Media = () => {
<With value={player(pl => pl.available)}> <With value={player(pl => pl.available)}>
{(available: boolean) => available && <Gtk.Box class={"media-controls button-row"}> {(available: boolean) => available && <Gtk.Box class={"media-controls button-row"}>
<Gtk.Button class={"link"} iconName={"edit-paste-symbolic"} <Gtk.Button class={"link"} iconName={"edit-paste-symbolic"}
visible={variableToBoolean(getMediaUrl(player.get()))}
tooltipText={"Copy link to Clipboard"} onClicked={() => { tooltipText={"Copy link to Clipboard"} onClicked={() => {
execAsync(`playerctl --player=${ const url = getMediaUrl(player.get()).get();
player.get().busName.replace(/^org\.mpris\.MediaPlayer2\./i, "") url && Clipboard.getDefault().copyAsync(url);
} 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}`);
});
}} }}
/> />
<Gtk.Button class={"previous"} iconName={"media-skip-backward-symbolic"} <Gtk.Button class={"previous"} iconName={"media-skip-backward-symbolic"}
@@ -159,3 +154,15 @@ export const Media = () => {
</Gtk.Revealer> </Gtk.Revealer>
</Gtk.Box> </Gtk.Box>
} }
export function getMediaUrl(player: AstalMpris.Player): Accessor<string|undefined> {
return createConnection(player.get_meta("xesam:url"),
[player, "notify::metadata", () => player.get_meta("xesam:url")]
).as(url => {
const byteString = url?.get_data_as_bytes();
return byteString ?
decoder.decode(byteString.toArray())
: undefined;
})
}
+7 -12
View File
@@ -1,10 +1,9 @@
import { timeout } from "ags/time"; import { timeout } from "ags/time";
import { execAsync } from "ags/process";
import { Astal, Gtk } from "ags/gtk4"; import { Astal, Gtk } from "ags/gtk4";
import { Clipboard } from "../../scripts/clipboard"; import { Clipboard } from "../../scripts/clipboard";
import { player, setPlayer } from "../bar/Media"; import { getMediaUrl, player, setPlayer } from "../bar/Media";
import { Accessor, createBinding, createConnection, For, With } from "ags"; import { Accessor, createBinding, createConnection, For, With } from "ags";
import { getPlayerIconFromBusName, pathToURI } from "../../scripts/utils"; import { getPlayerIconFromBusName, pathToURI, variableToBoolean } from "../../scripts/utils";
import AstalMpris from "gi://AstalMpris"; import AstalMpris from "gi://AstalMpris";
import AstalIO from "gi://AstalIO"; import AstalIO from "gi://AstalIO";
@@ -96,14 +95,10 @@ export const BigMedia = () => {
<Gtk.Box class={"controls button-row"} $type="center"> <Gtk.Box class={"controls button-row"} $type="center">
<Gtk.Button class={"link"} iconName={"edit-paste-symbolic"} <Gtk.Button class={"link"} iconName={"edit-paste-symbolic"}
tooltipText={"Copy link to clipboard"} tooltipText={"Copy link to clipboard"}
visible={variableToBoolean(getMediaUrl(player))}
onClicked={() => { onClicked={() => {
execAsync(`playerctl --player=${ const url = getMediaUrl(player).get();
player.busName.replace(/^org\.mpris\.MediaPlayer2\./i, "") url && Clipboard.getDefault().copyAsync(url);
} 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}`);
});
}} }}
/> />
<Gtk.Button class={"shuffle"} visible={createBinding(player, "shuffleStatus").as(status => <Gtk.Button class={"shuffle"} visible={createBinding(player, "shuffleStatus").as(status =>
@@ -185,10 +180,10 @@ export function PlayerSelectButton({ player, reveal, halign = Gtk.Align.CENTER,
{(pl: AstalMpris.Player) => {(pl: AstalMpris.Player) =>
<Gtk.Button class={"player"} onClicked={() => setPlayer(pl)}> <Gtk.Button class={"player"} onClicked={() => setPlayer(pl)}>
<Gtk.Box> <Gtk.Box>
<Gtk.Image iconName={createBinding(player, "busName").as( <Gtk.Image iconName={createBinding(pl, "busName").as(
getPlayerIconFromBusName getPlayerIconFromBusName
)} /> )} />
<Gtk.Label label={createBinding(player, "identity")} <Gtk.Label label={createBinding(pl, "identity")}
hexpand={false} class={"identity"} singleLineMode hexpand={false} class={"identity"} singleLineMode
maxWidthChars={8} maxWidthChars={8}
/> />