Skip to content

Instantly share code, notes, and snippets.

@ngothanhthien
Created October 3, 2023 03:46
Show Gist options
  • Save ngothanhthien/d4702ce5ac38a2df7547e250917cdfa1 to your computer and use it in GitHub Desktop.
Save ngothanhthien/d4702ce5ac38a2df7547e250917cdfa1 to your computer and use it in GitHub Desktop.
Tamper monkey youtube looper
// ==UserScript==
// @name YouTube Video Looper with UI
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Loop a YouTube video from X to Y seconds with UI
// @author You
// @match https://www.youtube.com/watch?v=*
// @grant none
// ==/UserScript==
(function() {
'use strict';
let loopStart = '00:00:00';
let loopEnd = '00:00:00';
let isLoop = false;
// Create UI
const createUI = () => {
const controlBar = document.querySelector('.ytp-right-controls');
if (controlBar) {
const loopContainer = document.createElement('div');
loopContainer.style.display = 'flex';
loopContainer.style.alignItems = 'center';
loopContainer.style.marginLeft = '16px';
loopContainer.style.position = 'absolute';
loopContainer.style.top = '4px';
loopContainer.style.left = '31%';
const videoId = getVideoId();
const savedLoopStart = localStorage.getItem(videoId + '_loopStart');
const savedLoopEnd = localStorage.getItem(videoId + '_loopEnd');
if (savedLoopStart !== null && savedLoopEnd !== null) {
loopStart = secondsToFormattedTime(savedLoopStart);
loopEnd = secondsToFormattedTime(savedLoopEnd);
}
loopContainer.innerHTML = `
<label style="margin-right: 4px;">Loop from:</label>
<input type="text" id="loopStart" min="0" style="width: 50px;" value="${loopStart}">
<label style="margin: 0 4px;">to</label>
<input type="text" id="loopEnd" min="0" style="width: 50px;" value="${loopEnd}">
<button id="setLoop">Set Loop</button>
<button id="stopLoop">Stop</button>
`;
controlBar.appendChild(loopContainer);
document.getElementById('setLoop').addEventListener('click', setLoopTimes);
document.getElementById('stopLoop').addEventListener('click', stopLoop);
document.getElementById('loopStart').addEventListener('keydown', function(event) {
event.stopPropagation();
});
document.getElementById('loopEnd').addEventListener('keydown', function(event) {
event.stopPropagation();
});
}
};
const setLoopTimes = () => {
isLoop = true
const loopStartInput = document.getElementById('loopStart').value;
const loopEndInput = document.getElementById('loopEnd').value;
loopStart = parseTimeToSeconds(loopStartInput);
loopEnd = parseTimeToSeconds(loopEndInput);
// Save to localStorage
const videoId = getVideoId();
localStorage.setItem(videoId + '_loopStart', loopStart);
localStorage.setItem(videoId + '_loopEnd', loopEnd);
const video = document.querySelector('video');
if (video) {
video.play()
}
};
const stopLoop = () => {
isLoop = false
}
// Function to set the video time and loop
const setVideoTime = () => {
const video = document.querySelector('video');
if (video) {
video.addEventListener('timeupdate', function() {
if (isLoop && (video.currentTime >= loopEnd || video.currentTime < loopStart)) {
video.currentTime = loopStart;
video.play();
}
});
}
};
// Check for video element every second and set time once found
const checkVideo = setInterval(() => {
if (document.querySelector('video')) {
clearInterval(checkVideo);
setVideoTime();
}
}, 1000);
// Check for control bar every second and create UI once found
const checkControlBar = setInterval(() => {
if (document.querySelector('.ytp-right-controls')) {
clearInterval(checkControlBar);
createUI();
}
}, 1000);
const parseTimeToSeconds = (timeString) => {
const parts = timeString.split(':').map(Number);
let seconds = 0;
if (parts.length === 3) {
// HH:MM:SS format
seconds += parts[0] * 3600; // hours
seconds += parts[1] * 60;// minutes
seconds += parts[2];// seconds
} else if (parts.length === 2) {
// MM:SS format
seconds += parts[0] * 60;// minutes
seconds += parts[1];// seconds
} else {
// Invalid format
return 0;
}
return seconds;
};
const secondsToFormattedTime = (seconds) => {
const hrs = Math.floor(seconds / 3600);
const mins = Math.floor((seconds % 3600) / 60);
const secs = Math.floor(seconds % 60);
return `${hrs}:${(mins < 10 ? '0' : '') + mins}:${(secs < 10 ? '0' : '') + secs}`;
};
const getVideoId = () => {
const url = new URL(window.location.href);
return url.searchParams.get('v');
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment