Created
October 3, 2023 03:46
-
-
Save ngothanhthien/d4702ce5ac38a2df7547e250917cdfa1 to your computer and use it in GitHub Desktop.
Tamper monkey youtube looper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==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