diff --git a/plugins/precise-volume/front.js b/plugins/precise-volume/front.js index 0bf3e36df2..38a2a60bc1 100644 --- a/plugins/precise-volume/front.js +++ b/plugins/precise-volume/front.js @@ -11,6 +11,7 @@ module.exports = (_options) => { document.addEventListener('apiLoaded', e => { api = e.detail; ipcRenderer.on('changeVolume', (_, toIncrease) => changeVolume(toIncrease)); + ipcRenderer.on('setVolume', (_, value) => setVolume(value)); firstRun(); }, { once: true, passive: true }) }; @@ -163,26 +164,29 @@ function setupSliderObserver() { }); } -/** if (toIncrease = false) then volume decrease */ -function changeVolume(toIncrease) { - // Apply volume change if valid - const steps = Number(options.steps || 1); - api.setVolume(toIncrease ? - Math.min(api.getVolume() + steps, 100) : - Math.max(api.getVolume() - steps, 0)); - +function setVolume(value) { + api.setVolume(value); // Save the new volume - saveVolume(api.getVolume()); + saveVolume(value); // change slider position (important) updateVolumeSlider(); // Change tooltips to new value - setTooltip(options.savedVolume); + setTooltip(value); // Show volume slider showVolumeSlider(); // Show volume HUD - showVolumeHud(options.savedVolume); + showVolumeHud(value); +} + +/** if (toIncrease = false) then volume decrease */ +function changeVolume(toIncrease) { + // Apply volume change if valid + const steps = Number(options.steps || 1); + setVolume(toIncrease ? + Math.min(api.getVolume() + steps, 100) : + Math.max(api.getVolume() - steps, 0)); } function updateVolumeSlider() { diff --git a/plugins/shortcuts/mpris.js b/plugins/shortcuts/mpris.js index 973feb514f..bf427b5896 100644 --- a/plugins/shortcuts/mpris.js +++ b/plugins/shortcuts/mpris.js @@ -2,6 +2,7 @@ const mpris = require("mpris-service"); const { ipcMain } = require("electron"); const registerCallback = require("../../providers/song-info"); const getSongControls = require("../../providers/song-controls"); +const config = require("../../config"); function setupMPRIS() { const player = mpris({ @@ -19,7 +20,7 @@ function setupMPRIS() { function registerMPRIS(win) { const songControls = getSongControls(win); - const { playPause, next, previous } = songControls; + const { playPause, next, previous, volumeMinus10, volumePlus10 } = songControls; try { const secToMicro = n => Math.round(Number(n) * 1e6); const microToSec = n => Math.round(Number(n) / 1e6); @@ -34,6 +35,35 @@ function registerMPRIS(win) { let currentSeconds = 0; ipcMain.on('timeChanged', (_, t) => currentSeconds = t); + let currentLoopStatus = undefined; + let manuallySwitchingStatus = false; + ipcMain.on("repeatChanged", (_, mode) => { + if (manuallySwitchingStatus) + return; + + if (mode === "Repeat off") + currentLoopStatus = "None"; + else if (mode === "Repeat one") + currentLoopStatus = "Track"; + else if (mode === "Repeat all") + currentLoopStatus = "Playlist"; + + player.loopStatus = currentLoopStatus; + }); + player.on("loopStatus", (status) => { + // switchRepeat cycles between states in that order + const switches = ["None", "Playlist", "Track"]; + const currentIndex = switches.indexOf(currentLoopStatus); + const targetIndex = switches.indexOf(status); + + // Get a delta in the range [0,2] + const delta = (targetIndex - currentIndex + 3) % 3; + + manuallySwitchingStatus = true; + songControls.switchRepeat(delta); + manuallySwitchingStatus = false; + }) + player.getPosition = () => secToMicro(currentSeconds) player.on("raise", () => { @@ -53,21 +83,45 @@ function registerMPRIS(win) { playPause() } }); + player.on("playpause", () => { + player.playbackStatus = player.playbackStatus === 'Playing' ? "Paused" : "Playing"; + playPause(); + }); - player.on("playpause", playPause); player.on("next", next); player.on("previous", previous); player.on('seek', seekBy); player.on('position', seekTo); - registerCallback(songInfo => { - if (player) { - const data = { - 'mpris:length': secToMicro(songInfo.songDuration), - 'mpris:artUrl': songInfo.imageSrc, - 'xesam:title': songInfo.title, - 'xesam:artist': [songInfo.artist], + ipcMain.on('volumeChanged', (_, value) => { + player.volume = value; + }); + player.on('volume', (newVolume) => { + if (config.plugins.isEnabled('precise-volume')) { + // With precise volume we can set the volume to the exact value. + win.webContents.send('setVolume', newVolume) + } else { + // With keyboard shortcuts we can only change the volume in increments of 10, so round it. + const deltaVolume = Math.round((newVolume - player.volume) / 10); + + if (deltaVolume > 0) { + for (let i = 0; i < deltaVolume; i++) + volumePlus10(); + } else { + for (let i = 0; i < -deltaVolume; i++) + volumeMinus10(); + } + } + }); + + registerCallback(songInfo => { + if (player) { + const data = { + 'mpris:length': secToMicro(songInfo.songDuration), + 'mpris:artUrl': songInfo.imageSrc, + 'xesam:title': songInfo.title, + 'xesam:artist': [songInfo.artist], 'mpris:trackid': '/' }; if (songInfo.album) data['xesam:album'] = songInfo.album; diff --git a/providers/song-controls.js b/providers/song-controls.js index 91c6d140a9..a23190ebf4 100644 --- a/providers/song-controls.js +++ b/providers/song-controls.js @@ -20,7 +20,10 @@ module.exports = (win) => { go1sBack: () => pressKey(win, "h", ["shift"]), go1sForward: () => pressKey(win, "l", ["shift"]), shuffle: () => pressKey(win, "s"), - switchRepeat: () => pressKey(win, "r"), + switchRepeat: (n = 1) => { + for (let i = 0; i < n; i++) + pressKey(win, "r"); + }, // General volumeMinus10: () => pressKey(win, "-"), volumePlus10: () => pressKey(win, "="), diff --git a/providers/song-info-front.js b/providers/song-info-front.js index e8bb8bcfc1..03cf2957d1 100644 --- a/providers/song-info-front.js +++ b/providers/song-info-front.js @@ -22,6 +22,8 @@ module.exports = () => { if (config.plugins.isEnabled('tuna-obs') || (is.linux() && config.plugins.isEnabled('shortcuts'))) { setupTimeChangeListener(); + setupRepeatChangeListener(); + setupVolumeChangeListener(apiEvent.detail); } const video = $('video'); // name = "dataloaded" and abit later "dataupdated" @@ -63,3 +65,21 @@ function setupTimeChangeListener() { }); progressObserver.observe($('#progress-bar'), { attributeFilter: ["value"] }) } + +function setupRepeatChangeListener() { + const repeatObserver = new MutationObserver(mutations => { + ipcRenderer.send('repeatChanged', mutations[0].target.title); + }); + repeatObserver.observe($('#right-controls .repeat'), { attributeFilter: ["title"] }); + + // Emit the initial value as well; as it's persistent between launches. + ipcRenderer.send('repeatChanged', $('#right-controls .repeat').title); +} + +function setupVolumeChangeListener(api) { + $('video').addEventListener('volumechange', (_) => { + ipcRenderer.send('volumeChanged', api.getVolume()); + }); + // Emit the initial value as well; as it's persistent between launches. + ipcRenderer.send('volumeChanged', api.getVolume()); +}