Merge pull request #275 from Araxeus/precise-volume-HUD

precise-volume plugin fixes & updates
This commit is contained in:
th-ch
2021-10-24 11:40:54 +02:00
committed by GitHub
4 changed files with 143 additions and 87 deletions

View File

@ -1,23 +1,9 @@
const { isEnabled } = require("../../config/plugins");
/* /*
This is used to determine if plugin is actually active This is used to determine if plugin is actually active
(not if its only enabled in options) (not if its only enabled in options)
*/ */
let enabled = false; let enabled = false;
module.exports = (win) => { module.exports = () => enabled = true;
enabled = true;
// youtube-music register some of the target listeners after DOMContentLoaded module.exports.enabled = () => enabled;
// did-finish-load is called after all elements finished loading, including said listeners
// Thats the reason the timing is controlled from main
win.webContents.once("did-finish-load", () => {
win.webContents.send("restoreAddEventListener");
win.webContents.send("setupVideoPlayerVolumeMousewheel", !isEnabled("hide-video-player"));
});
};
module.exports.enabled = () => {
return enabled;
};

View File

@ -3,25 +3,73 @@ const { ipcRenderer, remote } = require("electron");
const { setOptions } = require("../../config/plugins"); const { setOptions } = require("../../config/plugins");
function $(selector) { return document.querySelector(selector); } function $(selector) { return document.querySelector(selector); }
let api;
module.exports = (options) => { module.exports = (options) => {
document.addEventListener('apiLoaded', e => {
api = e.detail;
firstRun(options);
})
};
/** Restore saved volume and setup tooltip */
function firstRun(options) {
if (typeof options.savedVolume === "number") {
// Set saved volume as tooltip
setTooltip(options.savedVolume);
if (api.getVolume() !== options.savedVolume) {
api.setVolume(options.savedVolume);
}
}
setupPlaybar(options); setupPlaybar(options);
setupSliderObserver(options);
setupLocalArrowShortcuts(options); setupLocalArrowShortcuts(options);
setupGlobalShortcuts(options); setupGlobalShortcuts(options);
firstRun(options); const noVid = $("#main-panel")?.computedStyleMap().get("display").value === "none";
injectVolumeHud(noVid);
if (!noVid) {
setupVideoPlayerOnwheel(options);
}
}
// This way the ipc listener gets cleared either way function injectVolumeHud(noVid) {
ipcRenderer.once("setupVideoPlayerVolumeMousewheel", (_event, toEnable) => { if (noVid) {
if (toEnable) const position = "top: 18px; right: 60px; z-index: 999; position: absolute;";
setupVideoPlayerOnwheel(options); const mainStyle = "font-size: xx-large; padding: 10px; transition: opacity 1s";
});
}; $(".center-content.ytmusic-nav-bar").insertAdjacentHTML("beforeend",
`<span id="volumeHud" style="${position + mainStyle}"></span>`)
} else {
const position = `top: 10px; left: 10px; z-index: 999; position: absolute;`;
const mainStyle = "font-size: xxx-large; padding: 10px; transition: opacity 0.6s; webkit-text-stroke: 1px black; font-weight: 600;";
$("#song-video").insertAdjacentHTML('afterend',
`<span id="volumeHud" style="${position + mainStyle}"></span>`)
}
}
let hudFadeTimeout;
function showVolumeHud(volume) {
let volumeHud = $("#volumeHud");
if (!volumeHud) return;
volumeHud.textContent = volume + '%';
volumeHud.style.opacity = 1;
if (hudFadeTimeout) {
clearTimeout(hudFadeTimeout);
}
hudFadeTimeout = setTimeout(() => {
volumeHud.style.opacity = 0;
hudFadeTimeout = null;
}, 2000);
}
/** Add onwheel event to video player */ /** Add onwheel event to video player */
function setupVideoPlayerOnwheel(options) { function setupVideoPlayerOnwheel(options) {
@ -32,35 +80,20 @@ function setupVideoPlayerOnwheel(options) {
}); });
} }
function toPercent(volume) {
return Math.round(Number.parseFloat(volume) * 100);
}
function saveVolume(volume, options) { function saveVolume(volume, options) {
options.savedVolume = volume; options.savedVolume = volume;
setOptions("precise-volume", options); writeOptions(options);
} }
/** Restore saved volume and setup tooltip */ //without this function it would rewrite config 20 time when volume change by 20
function firstRun(options) { let writeTimeout;
const videoStream = $(".video-stream"); function writeOptions(options) {
const slider = $("#volume-slider"); if (writeTimeout) clearTimeout(writeTimeout);
// Those elements load abit after DOMContentLoaded
if (videoStream && slider) { writeTimeout = setTimeout(() => {
// Set saved volume IF it pass checks setOptions("precise-volume", options);
if (options.savedVolume writeTimeout = null;
&& options.savedVolume >= 0 && options.savedVolume <= 100 }, 1500)
&& Math.abs(slider.value - options.savedVolume) < 5
// If plugin was disabled and volume changed then diff>4
) {
videoStream.volume = options.savedVolume / 100;
slider.value = options.savedVolume;
}
// Set current volume as tooltip
setTooltip(toPercent(videoStream.volume));
} else {
setTimeout(firstRun, 500, options); // Try again in 500 milliseconds
}
} }
/** Add onwheel event to play bar and also track if play bar is hovered*/ /** Add onwheel event to play bar and also track if play bar is hovered*/
@ -81,32 +114,63 @@ function setupPlaybar(options) {
playerbar.addEventListener("mouseleave", () => { playerbar.addEventListener("mouseleave", () => {
playerbar.classList.remove("on-hover"); playerbar.classList.remove("on-hover");
}); });
setupSliderObserver(options);
}
/** Save volume + Update the volume tooltip when volume-slider is manually changed */
function setupSliderObserver(options) {
const sliderObserver = new MutationObserver(mutations => {
for (const mutation of mutations) {
// This checks that volume-slider was manually set
if (mutation.oldValue !== mutation.target.value &&
(typeof options.savedVolume !== "number" || Math.abs(options.savedVolume - mutation.target.value) > 4)) {
// Diff>4 means it was manually set
setTooltip(mutation.target.value);
saveVolume(mutation.target.value, options);
}
}
});
// Observing only changes in 'value' of volume-slider
sliderObserver.observe($("#volume-slider"), {
attributeFilter: ["value"],
attributeOldValue: true
});
} }
/** if (toIncrease = false) then volume decrease */ /** if (toIncrease = false) then volume decrease */
function changeVolume(toIncrease, options) { function changeVolume(toIncrease, options) {
// Need to change both the actual volume and the slider
const videoStream = $(".video-stream");
const slider = $("#volume-slider");
// Apply volume change if valid // Apply volume change if valid
const steps = (options.steps || 1) / 100; const steps = (options.steps || 1);
videoStream.volume = toIncrease ? api.setVolume(toIncrease ?
Math.min(videoStream.volume + steps, 1) : Math.min(api.getVolume() + steps, 100) :
Math.max(videoStream.volume - steps, 0); Math.max(api.getVolume() - steps, 0));
// Save the new volume // Save the new volume
saveVolume(toPercent(videoStream.volume), options); saveVolume(api.getVolume(), options);
// Slider value automatically rounds to multiples of 5
slider.value = options.savedVolume; // change slider position (important)
updateVolumeSlider(options);
// Change tooltips to new value // Change tooltips to new value
setTooltip(options.savedVolume); setTooltip(options.savedVolume);
// Show volume slider on volume change // Show volume slider
showVolumeSlider(slider); showVolumeSlider();
// Show volume HUD
showVolumeHud(options.savedVolume);
}
function updateVolumeSlider(options) {
// Slider value automatically rounds to multiples of 5
$("#volume-slider").value = options.savedVolume > 0 && options.savedVolume < 5 ?
5 : options.savedVolume;
} }
let volumeHoverTimeoutID; let volumeHoverTimeoutID;
function showVolumeSlider(slider) { function showVolumeSlider() {
const slider = $("#volume-slider");
// This class display the volume slider if not in minimized mode // This class display the volume slider if not in minimized mode
slider.classList.add("on-hover"); slider.classList.add("on-hover");
// Reset timeout if previous one hasn't completed // Reset timeout if previous one hasn't completed
@ -122,27 +186,6 @@ function showVolumeSlider(slider) {
}, 3000); }, 3000);
} }
/** Save volume + Update the volume tooltip when volume-slider is manually changed */
function setupSliderObserver(options) {
const sliderObserver = new MutationObserver(mutations => {
for (const mutation of mutations) {
// This checks that volume-slider was manually set
if (mutation.oldValue !== mutation.target.value &&
(!options.savedVolume || Math.abs(options.savedVolume - mutation.target.value) > 4)) {
// Diff>4 means it was manually set
setTooltip(mutation.target.value);
saveVolume(mutation.target.value, options);
}
}
});
// Observing only changes in 'value' of volume-slider
sliderObserver.observe($("#volume-slider"), {
attributeFilter: ["value"],
attributeOldValue: true
});
}
// Set new volume as tooltip for volume slider and icon + expanding slider (appears when window size is small) // Set new volume as tooltip for volume slider and icon + expanding slider (appears when window size is small)
const tooltipTargets = [ const tooltipTargets = [
"#volume-slider", "#volume-slider",

View File

@ -24,10 +24,10 @@ function overrideAddEventListener() {
module.exports = () => { module.exports = () => {
overrideAddEventListener(); overrideAddEventListener();
// Restore original function after did-finish-load to avoid keeping Element.prototype altered // Restore original function after finished loading to avoid keeping Element.prototype altered
ipcRenderer.once("restoreAddEventListener", () => { // Called from main to make sure page is completly loaded window.addEventListener('load', () => {
Element.prototype.addEventListener = Element.prototype._addEventListener; Element.prototype.addEventListener = Element.prototype._addEventListener;
Element.prototype._addEventListener = undefined; Element.prototype._addEventListener = undefined;
ignored = undefined; ignored = undefined;
}); }, { once: true });
}; };

View File

@ -10,6 +10,8 @@ const setupSongInfo = require("./providers/song-info-front");
const plugins = config.plugins.getEnabled(); const plugins = config.plugins.getEnabled();
let api;
plugins.forEach(([plugin, options]) => { plugins.forEach(([plugin, options]) => {
const preloadPath = path.join(__dirname, "plugins", plugin, "preload.js"); const preloadPath = path.join(__dirname, "plugins", plugin, "preload.js");
fileExists(preloadPath, () => { fileExists(preloadPath, () => {
@ -38,6 +40,9 @@ document.addEventListener("DOMContentLoaded", () => {
}); });
}); });
// wait for complete load of youtube api
listenForApiLoad();
// inject song-info provider // inject song-info provider
setupSongInfo(); setupSongInfo();
@ -51,3 +56,25 @@ document.addEventListener("DOMContentLoaded", () => {
global.reload = () => global.reload = () =>
remote.getCurrentWindow().webContents.loadURL(config.get("url")); remote.getCurrentWindow().webContents.loadURL(config.get("url"));
}); });
function listenForApiLoad() {
api = document.querySelector('#movie_player');
if (api) {
onApiLoaded();
return;
}
const observer = new MutationObserver(() => {
api = document.querySelector('#movie_player');
if (api) {
observer.disconnect();
onApiLoaded();
}
})
observer.observe(document.documentElement, { childList: true, subtree: true });
}
function onApiLoaded() {
document.dispatchEvent(new CustomEvent('apiLoaded', { detail: api }));
}