Skip to content

Commit f0bb328

Browse files
authored
Merge pull request #749 from foonathan/master
Support MPRIS loop and volume change
2 parents 5b004ac + 0f96da9 commit f0bb328

File tree

4 files changed

+102
-21
lines changed

4 files changed

+102
-21
lines changed

plugins/precise-volume/front.js

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ module.exports = (_options) => {
1111
document.addEventListener('apiLoaded', e => {
1212
api = e.detail;
1313
ipcRenderer.on('changeVolume', (_, toIncrease) => changeVolume(toIncrease));
14+
ipcRenderer.on('setVolume', (_, value) => setVolume(value));
1415
firstRun();
1516
}, { once: true, passive: true })
1617
};
@@ -163,26 +164,29 @@ function setupSliderObserver() {
163164
});
164165
}
165166

166-
/** if (toIncrease = false) then volume decrease */
167-
function changeVolume(toIncrease) {
168-
// Apply volume change if valid
169-
const steps = Number(options.steps || 1);
170-
api.setVolume(toIncrease ?
171-
Math.min(api.getVolume() + steps, 100) :
172-
Math.max(api.getVolume() - steps, 0));
173-
167+
function setVolume(value) {
168+
api.setVolume(value);
174169
// Save the new volume
175-
saveVolume(api.getVolume());
170+
saveVolume(value);
176171

177172
// change slider position (important)
178173
updateVolumeSlider();
179174

180175
// Change tooltips to new value
181-
setTooltip(options.savedVolume);
176+
setTooltip(value);
182177
// Show volume slider
183178
showVolumeSlider();
184179
// Show volume HUD
185-
showVolumeHud(options.savedVolume);
180+
showVolumeHud(value);
181+
}
182+
183+
/** if (toIncrease = false) then volume decrease */
184+
function changeVolume(toIncrease) {
185+
// Apply volume change if valid
186+
const steps = Number(options.steps || 1);
187+
setVolume(toIncrease ?
188+
Math.min(api.getVolume() + steps, 100) :
189+
Math.max(api.getVolume() - steps, 0));
186190
}
187191

188192
function updateVolumeSlider() {

plugins/shortcuts/mpris.js

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const mpris = require("mpris-service");
22
const { ipcMain } = require("electron");
33
const registerCallback = require("../../providers/song-info");
44
const getSongControls = require("../../providers/song-controls");
5+
const config = require("../../config");
56

67
function setupMPRIS() {
78
const player = mpris({
@@ -19,7 +20,7 @@ function setupMPRIS() {
1920

2021
function registerMPRIS(win) {
2122
const songControls = getSongControls(win);
22-
const { playPause, next, previous } = songControls;
23+
const { playPause, next, previous, volumeMinus10, volumePlus10 } = songControls;
2324
try {
2425
const secToMicro = n => Math.round(Number(n) * 1e6);
2526
const microToSec = n => Math.round(Number(n) / 1e6);
@@ -34,6 +35,35 @@ function registerMPRIS(win) {
3435
let currentSeconds = 0;
3536
ipcMain.on('timeChanged', (_, t) => currentSeconds = t);
3637

38+
let currentLoopStatus = undefined;
39+
let manuallySwitchingStatus = false;
40+
ipcMain.on("repeatChanged", (_, mode) => {
41+
if (manuallySwitchingStatus)
42+
return;
43+
44+
if (mode === "Repeat off")
45+
currentLoopStatus = "None";
46+
else if (mode === "Repeat one")
47+
currentLoopStatus = "Track";
48+
else if (mode === "Repeat all")
49+
currentLoopStatus = "Playlist";
50+
51+
player.loopStatus = currentLoopStatus;
52+
});
53+
player.on("loopStatus", (status) => {
54+
// switchRepeat cycles between states in that order
55+
const switches = ["None", "Playlist", "Track"];
56+
const currentIndex = switches.indexOf(currentLoopStatus);
57+
const targetIndex = switches.indexOf(status);
58+
59+
// Get a delta in the range [0,2]
60+
const delta = (targetIndex - currentIndex + 3) % 3;
61+
62+
manuallySwitchingStatus = true;
63+
songControls.switchRepeat(delta);
64+
manuallySwitchingStatus = false;
65+
})
66+
3767
player.getPosition = () => secToMicro(currentSeconds)
3868

3969
player.on("raise", () => {
@@ -53,21 +83,45 @@ function registerMPRIS(win) {
5383
playPause()
5484
}
5585
});
86+
player.on("playpause", () => {
87+
player.playbackStatus = player.playbackStatus === 'Playing' ? "Paused" : "Playing";
88+
playPause();
89+
});
5690

57-
player.on("playpause", playPause);
5891
player.on("next", next);
5992
player.on("previous", previous);
6093

6194
player.on('seek', seekBy);
6295
player.on('position', seekTo);
6396

64-
registerCallback(songInfo => {
65-
if (player) {
66-
const data = {
67-
'mpris:length': secToMicro(songInfo.songDuration),
68-
'mpris:artUrl': songInfo.imageSrc,
69-
'xesam:title': songInfo.title,
70-
'xesam:artist': [songInfo.artist],
97+
ipcMain.on('volumeChanged', (_, value) => {
98+
player.volume = value;
99+
});
100+
player.on('volume', (newVolume) => {
101+
if (config.plugins.isEnabled('precise-volume')) {
102+
// With precise volume we can set the volume to the exact value.
103+
win.webContents.send('setVolume', newVolume)
104+
} else {
105+
// With keyboard shortcuts we can only change the volume in increments of 10, so round it.
106+
const deltaVolume = Math.round((newVolume - player.volume) / 10);
107+
108+
if (deltaVolume > 0) {
109+
for (let i = 0; i < deltaVolume; i++)
110+
volumePlus10();
111+
} else {
112+
for (let i = 0; i < -deltaVolume; i++)
113+
volumeMinus10();
114+
}
115+
}
116+
});
117+
118+
registerCallback(songInfo => {
119+
if (player) {
120+
const data = {
121+
'mpris:length': secToMicro(songInfo.songDuration),
122+
'mpris:artUrl': songInfo.imageSrc,
123+
'xesam:title': songInfo.title,
124+
'xesam:artist': [songInfo.artist],
71125
'mpris:trackid': '/'
72126
};
73127
if (songInfo.album) data['xesam:album'] = songInfo.album;

providers/song-controls.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ module.exports = (win) => {
2020
go1sBack: () => pressKey(win, "h", ["shift"]),
2121
go1sForward: () => pressKey(win, "l", ["shift"]),
2222
shuffle: () => pressKey(win, "s"),
23-
switchRepeat: () => pressKey(win, "r"),
23+
switchRepeat: (n = 1) => {
24+
for (let i = 0; i < n; i++)
25+
pressKey(win, "r");
26+
},
2427
// General
2528
volumeMinus10: () => pressKey(win, "-"),
2629
volumePlus10: () => pressKey(win, "="),

providers/song-info-front.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ module.exports = () => {
2222
if (config.plugins.isEnabled('tuna-obs') ||
2323
(is.linux() && config.plugins.isEnabled('shortcuts'))) {
2424
setupTimeChangeListener();
25+
setupRepeatChangeListener();
26+
setupVolumeChangeListener(apiEvent.detail);
2527
}
2628
const video = $('video');
2729
// name = "dataloaded" and abit later "dataupdated"
@@ -63,3 +65,21 @@ function setupTimeChangeListener() {
6365
});
6466
progressObserver.observe($('#progress-bar'), { attributeFilter: ["value"] })
6567
}
68+
69+
function setupRepeatChangeListener() {
70+
const repeatObserver = new MutationObserver(mutations => {
71+
ipcRenderer.send('repeatChanged', mutations[0].target.title);
72+
});
73+
repeatObserver.observe($('#right-controls .repeat'), { attributeFilter: ["title"] });
74+
75+
// Emit the initial value as well; as it's persistent between launches.
76+
ipcRenderer.send('repeatChanged', $('#right-controls .repeat').title);
77+
}
78+
79+
function setupVolumeChangeListener(api) {
80+
$('video').addEventListener('volumechange', (_) => {
81+
ipcRenderer.send('volumeChanged', api.getVolume());
82+
});
83+
// Emit the initial value as well; as it's persistent between launches.
84+
ipcRenderer.send('volumeChanged', api.getVolume());
85+
}

0 commit comments

Comments
 (0)