mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-11 10:31:47 +00:00
Merge pull request #749 from foonathan/master
Support MPRIS loop and volume change
This commit is contained in:
@ -11,6 +11,7 @@ module.exports = (_options) => {
|
|||||||
document.addEventListener('apiLoaded', e => {
|
document.addEventListener('apiLoaded', e => {
|
||||||
api = e.detail;
|
api = e.detail;
|
||||||
ipcRenderer.on('changeVolume', (_, toIncrease) => changeVolume(toIncrease));
|
ipcRenderer.on('changeVolume', (_, toIncrease) => changeVolume(toIncrease));
|
||||||
|
ipcRenderer.on('setVolume', (_, value) => setVolume(value));
|
||||||
firstRun();
|
firstRun();
|
||||||
}, { once: true, passive: true })
|
}, { once: true, passive: true })
|
||||||
};
|
};
|
||||||
@ -163,26 +164,29 @@ function setupSliderObserver() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** if (toIncrease = false) then volume decrease */
|
function setVolume(value) {
|
||||||
function changeVolume(toIncrease) {
|
api.setVolume(value);
|
||||||
// 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));
|
|
||||||
|
|
||||||
// Save the new volume
|
// Save the new volume
|
||||||
saveVolume(api.getVolume());
|
saveVolume(value);
|
||||||
|
|
||||||
// change slider position (important)
|
// change slider position (important)
|
||||||
updateVolumeSlider();
|
updateVolumeSlider();
|
||||||
|
|
||||||
// Change tooltips to new value
|
// Change tooltips to new value
|
||||||
setTooltip(options.savedVolume);
|
setTooltip(value);
|
||||||
// Show volume slider
|
// Show volume slider
|
||||||
showVolumeSlider();
|
showVolumeSlider();
|
||||||
// Show volume HUD
|
// 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() {
|
function updateVolumeSlider() {
|
||||||
|
|||||||
@ -2,6 +2,7 @@ const mpris = require("mpris-service");
|
|||||||
const { ipcMain } = require("electron");
|
const { ipcMain } = require("electron");
|
||||||
const registerCallback = require("../../providers/song-info");
|
const registerCallback = require("../../providers/song-info");
|
||||||
const getSongControls = require("../../providers/song-controls");
|
const getSongControls = require("../../providers/song-controls");
|
||||||
|
const config = require("../../config");
|
||||||
|
|
||||||
function setupMPRIS() {
|
function setupMPRIS() {
|
||||||
const player = mpris({
|
const player = mpris({
|
||||||
@ -19,7 +20,7 @@ function setupMPRIS() {
|
|||||||
|
|
||||||
function registerMPRIS(win) {
|
function registerMPRIS(win) {
|
||||||
const songControls = getSongControls(win);
|
const songControls = getSongControls(win);
|
||||||
const { playPause, next, previous } = songControls;
|
const { playPause, next, previous, volumeMinus10, volumePlus10 } = songControls;
|
||||||
try {
|
try {
|
||||||
const secToMicro = n => Math.round(Number(n) * 1e6);
|
const secToMicro = n => Math.round(Number(n) * 1e6);
|
||||||
const microToSec = n => Math.round(Number(n) / 1e6);
|
const microToSec = n => Math.round(Number(n) / 1e6);
|
||||||
@ -34,6 +35,35 @@ function registerMPRIS(win) {
|
|||||||
let currentSeconds = 0;
|
let currentSeconds = 0;
|
||||||
ipcMain.on('timeChanged', (_, t) => currentSeconds = t);
|
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.getPosition = () => secToMicro(currentSeconds)
|
||||||
|
|
||||||
player.on("raise", () => {
|
player.on("raise", () => {
|
||||||
@ -53,21 +83,45 @@ function registerMPRIS(win) {
|
|||||||
playPause()
|
playPause()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
player.on("playpause", () => {
|
||||||
|
player.playbackStatus = player.playbackStatus === 'Playing' ? "Paused" : "Playing";
|
||||||
|
playPause();
|
||||||
|
});
|
||||||
|
|
||||||
player.on("playpause", playPause);
|
|
||||||
player.on("next", next);
|
player.on("next", next);
|
||||||
player.on("previous", previous);
|
player.on("previous", previous);
|
||||||
|
|
||||||
player.on('seek', seekBy);
|
player.on('seek', seekBy);
|
||||||
player.on('position', seekTo);
|
player.on('position', seekTo);
|
||||||
|
|
||||||
registerCallback(songInfo => {
|
ipcMain.on('volumeChanged', (_, value) => {
|
||||||
if (player) {
|
player.volume = value;
|
||||||
const data = {
|
});
|
||||||
'mpris:length': secToMicro(songInfo.songDuration),
|
player.on('volume', (newVolume) => {
|
||||||
'mpris:artUrl': songInfo.imageSrc,
|
if (config.plugins.isEnabled('precise-volume')) {
|
||||||
'xesam:title': songInfo.title,
|
// With precise volume we can set the volume to the exact value.
|
||||||
'xesam:artist': [songInfo.artist],
|
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': '/'
|
'mpris:trackid': '/'
|
||||||
};
|
};
|
||||||
if (songInfo.album) data['xesam:album'] = songInfo.album;
|
if (songInfo.album) data['xesam:album'] = songInfo.album;
|
||||||
|
|||||||
@ -20,7 +20,10 @@ module.exports = (win) => {
|
|||||||
go1sBack: () => pressKey(win, "h", ["shift"]),
|
go1sBack: () => pressKey(win, "h", ["shift"]),
|
||||||
go1sForward: () => pressKey(win, "l", ["shift"]),
|
go1sForward: () => pressKey(win, "l", ["shift"]),
|
||||||
shuffle: () => pressKey(win, "s"),
|
shuffle: () => pressKey(win, "s"),
|
||||||
switchRepeat: () => pressKey(win, "r"),
|
switchRepeat: (n = 1) => {
|
||||||
|
for (let i = 0; i < n; i++)
|
||||||
|
pressKey(win, "r");
|
||||||
|
},
|
||||||
// General
|
// General
|
||||||
volumeMinus10: () => pressKey(win, "-"),
|
volumeMinus10: () => pressKey(win, "-"),
|
||||||
volumePlus10: () => pressKey(win, "="),
|
volumePlus10: () => pressKey(win, "="),
|
||||||
|
|||||||
@ -22,6 +22,8 @@ module.exports = () => {
|
|||||||
if (config.plugins.isEnabled('tuna-obs') ||
|
if (config.plugins.isEnabled('tuna-obs') ||
|
||||||
(is.linux() && config.plugins.isEnabled('shortcuts'))) {
|
(is.linux() && config.plugins.isEnabled('shortcuts'))) {
|
||||||
setupTimeChangeListener();
|
setupTimeChangeListener();
|
||||||
|
setupRepeatChangeListener();
|
||||||
|
setupVolumeChangeListener(apiEvent.detail);
|
||||||
}
|
}
|
||||||
const video = $('video');
|
const video = $('video');
|
||||||
// name = "dataloaded" and abit later "dataupdated"
|
// name = "dataloaded" and abit later "dataupdated"
|
||||||
@ -63,3 +65,21 @@ function setupTimeChangeListener() {
|
|||||||
});
|
});
|
||||||
progressObserver.observe($('#progress-bar'), { attributeFilter: ["value"] })
|
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());
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user