forked from Shinonome/dots-hyprland
106 lines
4.3 KiB
JavaScript
106 lines
4.3 KiB
JavaScript
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
|
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
|
import Mpris from 'resource:///com/github/Aylur/ags/service/mpris.js';
|
|
const { execAsync, exec } = Utils;
|
|
import { AnimatedCircProg } from "../../lib/animatedcircularprogress.js";
|
|
import { showMusicControls } from '../../variables.js';
|
|
|
|
function trimTrackTitle(title) {
|
|
if(!title) return '';
|
|
const cleanRegexes = [
|
|
/【[^】]*】/, // Touhou n weeb stuff
|
|
/\[FREE DOWNLOAD\]/, // F-777
|
|
];
|
|
cleanRegexes.forEach((expr) => title.replace(expr, ''));
|
|
return title;
|
|
}
|
|
|
|
const TrackProgress = () => {
|
|
const _updateProgress = (circprog) => {
|
|
const mpris = Mpris.getPlayer('');
|
|
if (!mpris) return;
|
|
// Set circular progress value
|
|
circprog.css = `font-size: ${Math.max(mpris.position / mpris.length * 100, 0)}px;`
|
|
}
|
|
return AnimatedCircProg({
|
|
className: 'bar-music-circprog',
|
|
vpack: 'center', hpack: 'center',
|
|
extraSetup: (self) => self
|
|
.hook(Mpris, _updateProgress)
|
|
.poll(3000, _updateProgress)
|
|
,
|
|
})
|
|
}
|
|
|
|
const moveToRelativeWorkspace = async (self, num) => {
|
|
try {
|
|
const Hyprland = (await import('resource:///com/github/Aylur/ags/service/hyprland.js')).default;
|
|
Hyprland.sendMessage(`dispatch workspace ${num > 0 ? '+' : ''}${num}`);
|
|
} catch {
|
|
console.log(`TODO: Sway workspace ${num > 0 ? '+' : ''}${num}`);
|
|
}
|
|
}
|
|
|
|
export const ModuleMusic = () => {
|
|
// TODO: use cairo to make button bounce smaller on click, if that's possible
|
|
const playingState = Widget.Box({ // Wrap a box cuz overlay can't have margins itself
|
|
homogeneous: true,
|
|
children: [Widget.Overlay({
|
|
child: Widget.Box({
|
|
vpack: 'center',
|
|
className: 'bar-music-playstate',
|
|
homogeneous: true,
|
|
children: [Widget.Label({
|
|
vpack: 'center',
|
|
className: 'bar-music-playstate-txt',
|
|
justification: 'center',
|
|
setup: (self) => self.hook(Mpris, label => {
|
|
const mpris = Mpris.getPlayer('');
|
|
label.label = `${mpris !== null && mpris.playBackStatus == 'Playing' ? 'pause' : 'play_arrow'}`;
|
|
}),
|
|
})],
|
|
setup: (self) => self.hook(Mpris, label => {
|
|
const mpris = Mpris.getPlayer('');
|
|
if (!mpris) return;
|
|
label.toggleClassName('bar-music-playstate-playing', mpris !== null && mpris.playBackStatus == 'Playing');
|
|
label.toggleClassName('bar-music-playstate', mpris !== null || mpris.playBackStatus == 'Paused');
|
|
}),
|
|
}),
|
|
overlays: [
|
|
TrackProgress(),
|
|
]
|
|
})]
|
|
});
|
|
const trackTitle = Widget.Scrollable({
|
|
hexpand: true,
|
|
child: Widget.Label({
|
|
className: 'txt-smallie txt-onSurfaceVariant',
|
|
setup: (self) => self.hook(Mpris, label => {
|
|
const mpris = Mpris.getPlayer('');
|
|
if (mpris)
|
|
label.label = `${trimTrackTitle(mpris.trackTitle)} • ${mpris.trackArtists.join(', ')}`;
|
|
else
|
|
label.label = 'No media';
|
|
}),
|
|
})
|
|
})
|
|
return Widget.EventBox({
|
|
onScrollUp: (self) => moveToRelativeWorkspace(self, -1),
|
|
onScrollDown: (self) => moveToRelativeWorkspace(self, +1),
|
|
onPrimaryClickRelease: () => showMusicControls.setValue(!showMusicControls.value),
|
|
onSecondaryClickRelease: () => execAsync(['bash', '-c', 'playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` &']),
|
|
onMiddleClickRelease: () => execAsync('playerctl play-pause').catch(print),
|
|
child: Widget.Box({
|
|
className: 'bar-group-margin bar-sides',
|
|
children: [
|
|
Widget.Box({
|
|
className: 'bar-group bar-group-standalone bar-group-pad-music spacing-h-10',
|
|
children: [
|
|
playingState,
|
|
trackTitle,
|
|
]
|
|
})
|
|
]
|
|
})
|
|
});
|
|
} |