Fixed Media Widget not showing media
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
border: 2px solid alpha(@color4, 0.5);
|
border: 2px solid alpha(@color4, 0.5);
|
||||||
padding: 8px 15px;
|
padding: 8px 15px;
|
||||||
|
min-width: 300px;
|
||||||
font-family: "JetBrainsMono Nerd Font", sans-serif;
|
font-family: "JetBrainsMono Nerd Font", sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,3 +55,27 @@
|
|||||||
.media-btn:hover {
|
.media-btn:hover {
|
||||||
color: @color4;
|
color: @color4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.media-progress {
|
||||||
|
min-height: 4px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-progress trough {
|
||||||
|
min-height: 4px;
|
||||||
|
background-color: alpha(@foreground, 0.2);
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-progress highlight {
|
||||||
|
background-color: @accent;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-progress slider {
|
||||||
|
background-color: transparent;
|
||||||
|
min-width: 0px;
|
||||||
|
min-height: 0px;
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|||||||
+38
-16
@@ -6,21 +6,25 @@ import { createPoll } from "ags/time"
|
|||||||
export default function Media(gdkmonitor: Gdk.Monitor) {
|
export default function Media(gdkmonitor: Gdk.Monitor) {
|
||||||
const { TOP, LEFT } = Astal.WindowAnchor
|
const { TOP, LEFT } = Astal.WindowAnchor
|
||||||
|
|
||||||
// Poll playerctl for complete metadata and status in one go
|
const pollCmd = "playerctl metadata -f '{{title}}|||{{artist}}|||{{mpris:artUrl}}|||{{status}}|||{{mpris:length}}|||{{position}}' 2>/dev/null || echo 'No Media||||||Stopped|||0|||0'";
|
||||||
|
|
||||||
const mediaState = createPoll({
|
const mediaState = createPoll({
|
||||||
title: "No Media",
|
title: "No Media",
|
||||||
artist: "",
|
artist: "",
|
||||||
artUrl: "",
|
artUrl: "",
|
||||||
status: "Stopped"
|
status: "Stopped",
|
||||||
}, 1000, "playerctl metadata -f '{{title}}|||{{artist}}|||{{mpris:artUrl}}|||{{status}}' 2>/dev/null || echo 'No Media||||||Stopped'", (stdout) => {
|
length: 0,
|
||||||
|
position: 0
|
||||||
|
}, 1000, pollCmd, (stdout) => {
|
||||||
const parts = stdout.split("|||");
|
const parts = stdout.split("|||");
|
||||||
const title = parts[0]?.trim() || "No Media";
|
const title = parts[0]?.trim() || "No Media";
|
||||||
const artist = parts[1]?.trim() || "";
|
const artist = parts[1]?.trim() || "";
|
||||||
// GTK supports raw paths better than file:// URIs in background-image CSS
|
|
||||||
const rawUrl = parts[2]?.trim() || "";
|
const rawUrl = parts[2]?.trim() || "";
|
||||||
const artUrl = rawUrl.replace(/^file:\/\//, '');
|
const artUrl = rawUrl.replace(/^file:\/\//, '');
|
||||||
const status = parts[3]?.trim() || "Stopped";
|
const status = parts[3]?.trim() || "Stopped";
|
||||||
return { title, artist, artUrl, status };
|
const length = Number(parts[4]) || 0;
|
||||||
|
const position = Number(parts[5]) || 0;
|
||||||
|
return { title, artist, artUrl, status, length, position };
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -33,46 +37,64 @@ export default function Media(gdkmonitor: Gdk.Monitor) {
|
|||||||
margin={20}
|
margin={20}
|
||||||
application={app}
|
application={app}
|
||||||
>
|
>
|
||||||
<box class="media-container" spacing={15}>
|
<box class="media-container" css="min-width: 350px;" spacing={15}>
|
||||||
<box
|
<box
|
||||||
class="media-cover"
|
class="media-cover"
|
||||||
css={mediaState.as(s => s.artUrl ? `background-image: url('${s.artUrl}');` : 'background-color: alpha(@color0, 0.5);')}
|
css={mediaState.as(s => s.artUrl ? `background-image: url('${s.artUrl}'); min-width: 80px; min-height: 80px;` : 'min-width: 80px; min-height: 80px; background-color: alpha(@color0, 0.5);')}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<box vertical class="media-info-box" valign={Gtk.Align.CENTER}>
|
<box vertical class="media-info-box" valign={Gtk.Align.CENTER} hexpand>
|
||||||
<label
|
<label
|
||||||
class="media-title"
|
class="media-title"
|
||||||
label={mediaState.as(s => s.title)}
|
label={mediaState.as(s => s.title)}
|
||||||
halign={Gtk.Align.START}
|
halign={Gtk.Align.FILL}
|
||||||
|
xalign={0}
|
||||||
truncate
|
truncate
|
||||||
maxWidthChars={20}
|
maxWidthChars={35}
|
||||||
|
css="font-size: 15px;"
|
||||||
/>
|
/>
|
||||||
<label
|
<label
|
||||||
class="media-artist"
|
class="media-artist"
|
||||||
label={mediaState.as(s => s.artist)}
|
label={mediaState.as(s => s.artist)}
|
||||||
halign={Gtk.Align.START}
|
halign={Gtk.Align.FILL}
|
||||||
|
xalign={0}
|
||||||
truncate
|
truncate
|
||||||
maxWidthChars={25}
|
maxWidthChars={40}
|
||||||
|
css="font-size: 13px;"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<box class="media-controls" spacing={10} halign={Gtk.Align.START} marginTop={5}>
|
<slider
|
||||||
|
class="media-progress"
|
||||||
|
drawValue={false}
|
||||||
|
hexpand
|
||||||
|
min={0}
|
||||||
|
max={1}
|
||||||
|
value={mediaState.as(s => {
|
||||||
|
const len = s.length / 1000000;
|
||||||
|
return len > 0 ? Math.min(s.position / len, 1) : 0;
|
||||||
|
})}
|
||||||
|
marginTop={10}
|
||||||
|
marginBottom={10}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<box class="media-controls" spacing={15} halign={Gtk.Align.CENTER}>
|
||||||
<button
|
<button
|
||||||
class="media-btn"
|
class="media-btn"
|
||||||
onClicked={() => execAsync("playerctl previous").catch(print)}
|
onClicked={() => execAsync("playerctl previous").catch(print)}
|
||||||
>
|
>
|
||||||
<label label="" />
|
<label label="" css="font-size: 18px;" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="media-btn"
|
class="media-btn"
|
||||||
onClicked={() => execAsync("playerctl play-pause").catch(print)}
|
onClicked={() => execAsync("playerctl play-pause").catch(print)}
|
||||||
>
|
>
|
||||||
<label label={mediaState.as(s => s.status === "Playing" ? "" : "")} />
|
<label label={mediaState.as(s => s.status === "Playing" ? "" : "")} css="font-size: 22px;" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="media-btn"
|
class="media-btn"
|
||||||
onClicked={() => execAsync("playerctl next").catch(print)}
|
onClicked={() => execAsync("playerctl next").catch(print)}
|
||||||
>
|
>
|
||||||
<label label="" />
|
<label label="" css="font-size: 18px;" />
|
||||||
</button>
|
</button>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
|
|||||||
Reference in New Issue
Block a user