Merge pull request #462 from Araxeus/fix-playback-speed-plugin

fix playback speed plugin
This commit is contained in:
th-ch
2021-11-01 22:10:02 +01:00
committed by GitHub
3 changed files with 87 additions and 93 deletions

View File

@ -1,83 +1,95 @@
const {
getSongMenu,
watchDOMElement,
} = require("../../providers/dom-elements");
const { getSongMenu } = require("../../providers/dom-elements");
const { ElementFromFile, templatePath } = require("../utils");
function $(selector) { return document.querySelector(selector); }
const slider = ElementFromFile(templatePath(__dirname, "slider.html"));
const MIN_PLAYBACK_SPEED = 0.25;
const MAX_PLAYBACK_SPEED = 2;
const roundToTwo = (n) => Math.round(n * 1e2) / 1e2;
let videoElement;
let playbackSpeedPercentage = 50; // = Playback speed of 1
const MIN_PLAYBACK_SPEED = 0.07;
const MAX_PLAYBACK_SPEED = 16;
const computePlayBackSpeed = () => {
if (playbackSpeedPercentage <= 50) {
// Slow down video by setting a playback speed between MIN_PLAYBACK_SPEED and 1
return (
MIN_PLAYBACK_SPEED +
((1 - MIN_PLAYBACK_SPEED) / 50) * playbackSpeedPercentage
);
}
let playbackSpeed = 1;
// Accelerate video by setting a playback speed between 1 and MAX_PLAYBACK_SPEED
return 1 + ((MAX_PLAYBACK_SPEED - 1) / 50) * (playbackSpeedPercentage - 50);
};
const computePlayBackSpeed = (playbackSpeedPercentage) => playbackSpeedPercentage || MIN_PLAYBACK_SPEED;
const updatePlayBackSpeed = () => {
const playbackSpeed = Math.round(computePlayBackSpeed() * 100) / 100;
$('video').playbackRate = playbackSpeed;
if (!videoElement || videoElement.playbackRate === playbackSpeed) {
return;
}
videoElement.playbackRate = playbackSpeed;
const playbackSpeedElement = document.querySelector("#playback-speed-value");
const playbackSpeedElement = $("#playback-speed-value");
if (playbackSpeedElement) {
playbackSpeedElement.innerHTML = playbackSpeed;
}
};
module.exports = () => {
watchDOMElement(
"video",
(document) => document.querySelector("video"),
(element) => {
videoElement = element;
updatePlayBackSpeed();
}
);
let menu;
let observingSlider = false;
watchDOMElement(
"menu",
(document) => getSongMenu(document),
(menuElement) => {
if (!menuElement.contains(slider)) {
menuElement.prepend(slider);
const observePopupContainer = () => {
const observer = new MutationObserver(() => {
if (!menu) {
menu = getSongMenu();
}
if (menu && !menu.contains(slider)) {
menu.prepend(slider);
if (!observingSlider) {
setupSliderListener();
observingSlider = true;
}
const playbackSpeedElement = document.querySelector(
"#playback-speed-slider #sliderKnob .slider-knob-inner"
);
const playbackSpeedObserver = new MutationObserver((mutations) => {
mutations.forEach(function (mutation) {
if (mutation.type == "attributes") {
const value = playbackSpeedElement.getAttribute("value");
playbackSpeedPercentage = parseInt(value, 10);
if (isNaN(playbackSpeedPercentage)) {
playbackSpeedPercentage = 50;
}
updatePlayBackSpeed();
return;
}
});
});
playbackSpeedObserver.observe(playbackSpeedElement, {
attributes: true,
});
}
);
});
observer.observe($('ytmusic-popup-container'), {
childList: true,
subtree: true,
});
};
const observeVideo = () => {
$('video').addEventListener('ratechange', forcePlaybackRate)
$('video').addEventListener('loadeddata', forcePlaybackRate)
}
const setupWheelListener = () => {
slider.addEventListener('wheel', e => {
e.preventDefault();
if (isNaN(playbackSpeed)) {
playbackSpeed = 1;
}
// e.deltaY < 0 means wheel-up
playbackSpeed = roundToTwo(e.deltaY < 0 ?
Math.min(playbackSpeed + 0.01, MAX_PLAYBACK_SPEED) :
Math.max(playbackSpeed - 0.01, MIN_PLAYBACK_SPEED)
);
updatePlayBackSpeed();
// update slider position
$('#playback-speed-slider').value = playbackSpeed;
})
}
function setupSliderListener() {
$('#playback-speed-slider').addEventListener('immediate-value-changed', () => {
playbackSpeed = computePlayBackSpeed($('#playback-speed-slider #sliderBar').value);
if (isNaN(playbackSpeed)) {
playbackSpeed = 1;
}
updatePlayBackSpeed();
})
}
function forcePlaybackRate(e) {
if (e.target.playbackRate !== playbackSpeed) {
e.target.playbackRate = playbackSpeed
}
}
module.exports = () => {
document.addEventListener('apiLoaded', e => {
observePopupContainer();
observeVideo();
setupWheelListener();
}, { once: true, passive: true })
};

View File

@ -13,19 +13,20 @@
<tp-yt-paper-slider
id="playback-speed-slider"
class="volume-slider style-scope ytmusic-player-bar on-hover"
max="100"
style="display: inherit !important"
max="2"
min="0"
step="5"
step="0.125"
dir="ltr"
title="Playback speed"
aria-label="Playback speed"
role="slider"
tabindex="0"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="50"
aria-valuemax="2"
aria-valuenow="1"
aria-disabled="false"
value="50"
value="1"
><!--css-build:shady-->
<div id="sliderContainer" class="style-scope tp-yt-paper-slider">
<div class="bar-container style-scope tp-yt-paper-slider">
@ -34,10 +35,10 @@
aria-hidden="true"
class="style-scope tp-yt-paper-slider"
role="progressbar"
value="50"
aria-valuenow="50"
value="1"
aria-valuenow="1"
aria-valuemin="0"
aria-valuemax="100"
aria-valuemax="2"
aria-disabled="false"
style="touch-action: none"
><!--css-build:shady-->
@ -70,7 +71,7 @@
>
<div
class="slider-knob-inner style-scope tp-yt-paper-slider"
value="50"
value="1"
></div>
</div>
</div>

View File

@ -1,23 +1,4 @@
let domElements = {};
const watchDOMElement = (name, selectorFn, cb) => {
const observer = new MutationObserver((mutations, observer) => {
if (!domElements[name]) {
domElements[name] = selectorFn(document);
}
if (domElements[name]) {
cb(domElements[name]);
}
});
observer.observe(document, {
childList: true,
subtree: true,
});
};
const getSongMenu = () =>
document.querySelector("ytmusic-menu-popup-renderer tp-yt-paper-listbox");
module.exports = { getSongMenu, watchDOMElement };
module.exports = { getSongMenu };