Skip to content

Instantly share code, notes, and snippets.

@neon-dev
Last active November 16, 2023 11:45
Show Gist options
  • Save neon-dev/f641eb74a91a01d0e4c7434ffe0fb5ef to your computer and use it in GitHub Desktop.
Save neon-dev/f641eb74a91a01d0e4c7434ffe0fb5ef to your computer and use it in GitHub Desktop.
Userscript that remembers and applies video playback speeds on YouTube per channel
// ==UserScript==
// @name YouTube Channel Playback Speed
// @namespace https://gist.github.com/neon-dev
// @version 0.1
// @description Remembers playback speeds by channel. Change the speed on one video and it automatically applies to all videos of the same channel.
// @author Neon
// @match https://www.youtube.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @updateURL https://gist.github.com/neon-dev/f641eb74a91a01d0e4c7434ffe0fb5ef/raw
// @downloadURL https://gist.github.com/neon-dev/f641eb74a91a01d0e4c7434ffe0fb5ef/raw
// @grant GM.info
// @grant GM.setValue
// @grant GM.getValue
// @grant GM.deleteValue
// ==/UserScript==
(function() {
'use strict';
let video, navigated;
document.addEventListener('yt-navigate-finish', (event) => {
navigated = true;
video?.removeEventListener('ratechange', speedChangeListener);
});
document.body.addEventListener('yt-page-data-updated', (event) => {
if (navigated) {
navigated = false;
const channelHandle = getChannelHandle();
const videoContainer = document.getElementById('movie_player');
const isLiveStream = videoContainer?.querySelector('.ytp-live') || false;
video = videoContainer?.querySelector('video');
if (channelHandle && video && !isLiveStream) {
applySavedSpeed(channelHandle, video);
setTimeout(() => video.addEventListener('ratechange', speedChangeListener), 250); // slight delay since youtube applies the speed from the previous video
}
}
});
function speedChangeListener(event) {
const channelHandle = getChannelHandle();
if (channelHandle) {
saveOrDeleteSpeed(channelHandle, event.target.playbackRate);
} else {
log('Could not find channel handle, current speed cannot be saved');
}
};
async function saveOrDeleteSpeed(channelHandle, speed) {
if (speed == 1) {
GM.deleteValue(channelHandle);
log(`Deleted playback speed for ${channelHandle}`);
} else if (speed != await GM.getValue(channelHandle)) {
GM.setValue(channelHandle, speed);
log(`Saved playback speed ${speed}x for ${channelHandle}`);
};
}
async function applySavedSpeed(channelHandle, video) {
const channelSpeed = await GM.getValue(channelHandle);
if (channelSpeed) {
video.playbackRate = channelSpeed;
log(`Restored saved speed ${channelSpeed}x for ${channelHandle}`);
}
}
function getChannelHandle() {
const channelUrl = document.querySelector('#owner a')?.href;
return channelUrl ? channelUrl.substring(channelUrl.lastIndexOf('/') + 1) : null;
}
function log() {
console.debug(`[${GM.info.script.name}]`, ...arguments);
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment