Skip to content

Instantly share code, notes, and snippets.

@hlorand
Last active August 10, 2024 12:59
Show Gist options
  • Save hlorand/e74cfddb641878b10e800237cc55913d to your computer and use it in GitHub Desktop.
Save hlorand/e74cfddb641878b10e800237cc55913d to your computer and use it in GitHub Desktop.
My m.youtube.com greasyfork scripts https://greasyfork.org/en/users/1193838-hlorand
// ==UserScript==
// @name m.YouTube.com auto fullscreen on rotate
// @namespace m-youtube-com-auto-fullcreen-on-rotate
// @version 1.1
// @description Switches the video to full-screen mode when you rotate your smart device
// @author hlorand.hu
// @match https://m.youtube.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net
// @grant none
// @license https://creativecommons.org/licenses/by-nc-sa/4.0/
// @downloadURL https://update.greasyfork.org/scripts/477524/mYouTubecom%20auto%20fullscreen%20on%20rotate.user.js
// @updateURL https://update.greasyfork.org/scripts/477524/mYouTubecom%20auto%20fullscreen%20on%20rotate.meta.js
// ==/UserScript==
// Screenshot: https://ibb.co/chtmD9F
(function() {
//'use strict';
var isFullscreen = false;
window.addEventListener("orientationchange", (event) => {
let player = document.getElementById("player-container-id");
let angle = event.target.screen.orientation.angle;
console.log(angle, isFullscreen);
// enter fullscreen
if( !isFullscreen && (angle > 60 && angle < 120 || angle > 240 && angle < 300) ){
player.requestFullscreen();
isFullscreen = true;
return;
}
// exit fullscreen
if( isFullscreen && (angle > 330 || angle < 30 || angle > 150 && angle < 210) ){
document.exitFullscreen();
isFullscreen = false;
return;
}
});
})();
// ==UserScript==
// @name YouTube.com more playback speeds (Mobile / Desktop)
// @namespace m-youtube-com-more-playback-speeds
// @version 1.11
// @description Adds 2.25x 2.5x 2.75x 3x speed buttons below the video. Works on mobile, tablet (m.youtube.com) and on desktop.
// @author hlorand.hu
// @match https://m.youtube.com/*
// @match https://youtube.com/*
// @match https://*.youtube.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net
// @grant none
// @license https://creativecommons.org/licenses/by-nc-sa/4.0/
// ==/UserScript==
// Screenshot: https://ibb.co/chtmD9F
(function() {
//'use strict';
function setspeed(speed){
// highlight
document.querySelectorAll(".speedbutton").forEach((btn)=>{
if( btn.textContent == speed){
btn.style.backgroundColor = "darkorange";
} else {
btn.style.backgroundColor = "blue";
}
});
let video = document.querySelector("video");
if(video && video.readyState >= 2) {
localStorage.setItem("yt_playbackspeed", speed);
video.playbackRate = speed;
video.mozPreservesPitch = video.webkitPreservesPitch = video.preservePitch = true;
}
}
function addbuttons(){
document.getElementById("speedbuttons").innerHTML = "";
const speeds = ["3.5","3.25","3.0","2.75","2.5","2.25","2.0","1.75","1.5","1.25","1.0"];
speeds.forEach((speed)=>{
let button = document.createElement('button');
button.textContent = speed;
button.className = "speedbutton";
button.style.margin = "4px";
button.style.padding = "4px";
button.style.backgroundColor = "blue";
button.style.position = "relative";
button.onclick = function() {
setspeed(this.textContent);
};
let target = document.getElementById("speedbuttons");
target.insertBefore(button, target.firstChild);
}); // end speeds foreach
} // end addbuttons
// Periodically check if the buttons are visible
// (sometimes YouTube redraws its interface).
setInterval(()=>{
// Creating a div that will contain buttons.
if( document.getElementById("speedbuttons") == undefined ){
// placement of buttons on desktop
let parent = document.getElementById('above-the-fold');
// placement of buttons on tablet
if( !parent ){
parent = document.querySelector('.watch-below-the-player');
}
// placement of buttons on mobile
if( !parent ){
parent = document.querySelector('.related-chips-slot-wrapper');
}
let wrapper = document.createElement('div');
wrapper.setAttribute("id","speedbuttons");
parent.insertBefore(wrapper, parent.firstChild);
addbuttons();
}
// Sometimes the buttons are not added, so I check and add them if necessary.
if( document.getElementById("speedbuttons").textContent.trim() === '' ){
addbuttons();
}
setspeed( localStorage.getItem("yt_playbackspeed") ?? 1 );
}, 1000);
})();
// ==UserScript==
// @name YouTube.com add PIP picture in picture pop-out button (Mobile / Desktop)
// @namespace m-youtube-com-pip-button
// @version 1.2
// @description Adds a pop out to PIP button below the video. Works on mobile, tablet (m.youtube.com) and on desktop.
// @author hlorand.hu
// @match https://m.youtube.com/*
// @match https://youtube.com/*
// @match https://*.youtube.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net
// @grant none
// @license https://creativecommons.org/licenses/by-nc-sa/4.0/
// ==/UserScript==
(function() {
//'use strict';
function addbutton(){
document.getElementById("pipbutton").innerHTML = "";
let button = document.createElement('button');
button.textContent = "PIP";
button.className = "pipbutton";
button.style.margin = "4px";
button.style.padding = "6px";
button.style.backgroundColor = "brown";
button.style.position = "relative";
button.onclick = function() {
let video = document.querySelector("video");
video.requestPictureInPicture();
};
let target = document.getElementById("pipbutton");
target.insertBefore(button, target.firstChild);
} // end addbuttons
// Periodically check if the buttons are visible
// (sometimes YouTube redraws its interface).
setInterval(()=>{
// Creating a div that will contain buttons.
if( document.getElementById("pipbutton") == undefined ){
// placement of buttons on desktop
let parent = document.getElementById('above-the-fold');
// placement of buttons on tablet
if( !parent ){
parent = document.querySelector('.watch-below-the-player');
}
// placement of buttons on mobile
if( !parent ){
parent = document.querySelector('.related-chips-slot-wrapper');
}
let wrapper = document.createElement('div');
wrapper.setAttribute("id","pipbutton");
parent.insertBefore(wrapper, parent.firstChild);
addbutton();
}
// Sometimes the buttons are not added, so I check and add them if necessary.
if( document.getElementById("qualitybuttons").textContent.trim() === '' ){
addbuttons();
}
}, 1000);
})();
// ==UserScript==
// @name YouTube.com quality change buttons (Mobile / Desktop)
// @namespace m-youtube-com-quality-change-buttons
// @version 1.13
// @description Adds quality change buttons below the video (144p, 240p, 360p, 480p, 720p, 1080p...) works on mobile (m.youtube.com) and on desktop.
// @author hlorand.hu
// @match https://m.youtube.com/watch*
// @match https://youtube.com/watch*
// @match https://*.youtube.com/watch*
// @icon https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net
// @grant none
// @license https://creativecommons.org/licenses/by-nc-sa/4.0/
// @run-at document-idle
// ==/UserScript==
// Screenshot: https://ibb.co/pyXQd4C
(function() {
//'use strict';
function addbuttons(){
document.getElementById("qualitybuttons").innerHTML = "";
var player = document.getElementById('movie_player');
// it is neccesary to start the video, to getAvailableQualityData
if( document.location.href.includes("m.youtube.com") ){
player.click(); // start video
player.click(); // pause video
}
const qualities = player.getAvailableQualityData();
qualities.forEach((q)=>{
let button = document.createElement('button');
button.setAttribute("quality", q.quality);
button.textContent = q.qualityLabel.replace("p50","p").replace("p60","p"); // remove fps from label
button.className = "qualitybutton";
button.style.margin = "4px";
button.style.padding = "4px";
button.style.position = "relative";
// get current quality
if( player.getPlaybackQualityLabel() == q.qualityLabel ){
button.style.backgroundColor = "darkorange";
} else{
button.style.backgroundColor = "green";
}
button.onclick = function() {
player.setPlaybackQualityRange( this.getAttribute("quality") );
// highlight the clicked button and desaturate the others
document.querySelectorAll(".qualitybutton").forEach((btn)=>{
btn.style.backgroundColor = "green";
});
this.style.backgroundColor = "darkorange";
};
let target = document.getElementById('qualitybuttons');
target.insertBefore(button, target.firstChild);
}); // end qualities foreach
} // end addbuttons
// Periodically check if the buttons are visible (sometimes YouTube redraws its interface).
setInterval(()=>{
// Creating a div that will contain buttons.
if( document.getElementById("qualitybuttons") == undefined ){
// placement of buttons on desktop
let parent = document.getElementById('above-the-fold');
// placement of buttons on tablet
if( !parent ){
parent = document.querySelector('.watch-below-the-player');
}
// placement of buttons on mobile
if( !parent ){
parent = document.querySelector('.related-chips-slot-wrapper');
}
let wrapper = document.createElement('div');
wrapper.setAttribute("id","qualitybuttons");
parent.insertBefore(wrapper, parent.firstChild);
addbuttons();
}
// Sometimes the buttons are not added, so I check and add them if necessary.
if( document.getElementById("qualitybuttons").textContent.trim() === '' ){
addbuttons();
}
}, 1000);
})();
// ==UserScript==
// @name YouTube.com seek buttons (Mobile / Desktop)
// @namespace m-youtube-com-seek-buttons
// @version 1.5
// @description Adds +-30sec +-1min +-5min buttons below the video. Works on mobile, tablet (m.youtube.com) and on desktop.
// @author hlorand.hu
// @match https://m.youtube.com/*
// @match https://youtube.com/*
// @match https://*.youtube.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net
// @grant none
// @license https://creativecommons.org/licenses/by-nc-sa/4.0/
// ==/UserScript==
// Screenshot: https://ibb.co/72YKQPn
(function() {
//'use strict';
function addbuttons(){
document.getElementById("seekbuttons").innerHTML = "";
const times = ["+300s", "+60s", "+30s", "-30s", "-60s", "-300s"];
times.forEach((time)=>{
let button = document.createElement('button');
button.textContent = time;
button.style.margin = "4px";
button.style.padding = "4px";
button.style.backgroundColor = "purple";
button.style.position = "relative";
button.onclick = function() {
let video = document.querySelector("video");
if(video && video.readyState >= 2) {
video.currentTime += parseInt(this.textContent.replace("s",""));
}
};
let target = document.getElementById("seekbuttons");
target.insertBefore(button, target.firstChild);
}); // end times foreach
} // end addbuttons
// Periodically check if the buttons are visible
// (sometimes YouTube redraws its interface).
setInterval(()=>{
// Creating a div that will contain buttons.
if( document.getElementById("seekbuttons") == undefined ){
// placement of buttons on desktop
let parent = document.getElementById('above-the-fold');
// placement of buttons on tablet
if( !parent ){
parent = document.querySelector('.watch-below-the-player');
}
// placement of buttons on mobile
if( !parent ){
parent = document.querySelector('.related-chips-slot-wrapper');
}
let wrapper = document.createElement('div');
wrapper.setAttribute("id","seekbuttons");
parent.insertBefore(wrapper, parent.firstChild);
addbuttons();
}
// Sometimes the buttons are not added, so I check and add them if necessary.
if( document.getElementById("seekbuttons").textContent.trim() === '' ){
addbuttons();
}
}, 1000);
})();
// ==UserScript==
// @name m.YouTube.com allow background play TEST SCRIPT
// @namespace m-youtube-com-allow-background-play
// @version 1.0
// @description Allows m.YouTube.com background play, especially useful for iPhone users
// @author hlorand.hu
// @match https://m.youtube.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net
// @grant none
// @license https://creativecommons.org/licenses/by-nc-sa/4.0/
// ==/UserScript==
// Original code: https://addons.mozilla.org/en-US/android/addon/video-background-play-fix/
(function() {
//'use strict';
const IS_YOUTUBE = window.location.hostname.search(/(?:^|.+\.)youtube\.com/) > -1 ||
window.location.hostname.search(/(?:^|.+\.)youtube-nocookie\.com/) > -1;
const IS_MOBILE_YOUTUBE = window.location.hostname == 'm.youtube.com';
const IS_DESKTOP_YOUTUBE = IS_YOUTUBE && !IS_MOBILE_YOUTUBE;
const IS_VIMEO = window.location.hostname.search(/(?:^|.+\.)vimeo\.com/) > -1;
const IS_ANDROID = window.navigator.userAgent.indexOf('Android') > -1;
// Page Visibility API
if (IS_ANDROID || !IS_DESKTOP_YOUTUBE) {
Object.defineProperties(document.wrappedJSObject,
{ 'hidden': {value: false}, 'visibilityState': {value: 'visible'} });
}
window.addEventListener(
'visibilitychange', evt => evt.stopImmediatePropagation(), true);
// Fullscreen API
if (IS_VIMEO) {
window.addEventListener(
'fullscreenchange', evt => evt.stopImmediatePropagation(), true);
}
// User activity tracking
if (IS_YOUTUBE) {
loop(pressKey, 60 * 1000, 10 * 1000); // every minute +/- 5 seconds
}
function pressKey() {
const keyCodes = [18];
let key = keyCodes[getRandomInt(0, keyCodes.length)];
sendKeyEvent("keydown", key);
sendKeyEvent("keyup", key);
}
function sendKeyEvent (aEvent, aKey) {
document.dispatchEvent(new KeyboardEvent(aEvent, {
bubbles: true,
cancelable: true,
keyCode: aKey,
which: aKey,
}));
}
function loop(aCallback, aDelay, aJitter) {
let jitter = getRandomInt(-aJitter/2, aJitter/2);
let delay = Math.max(aDelay + jitter, 0);
window.setTimeout(() => {
aCallback();
loop(aCallback, aDelay, aJitter);
}, delay);
}
function getRandomInt(aMin, aMax) {
let min = Math.ceil(aMin);
let max = Math.floor(aMax);
return Math.floor(Math.random() * (max - min)) + min;
}
})();
// ==UserScript==
// @name YouTube.com audio only mode buttons (Mobile / Desktop)
// @namespace youtube-download-buttons-video-audio
// @version 1.5
// @description Adds buttons below video to play media in audio only mode. Works on mobile (m.youtube.com) and on desktop.
// @author hlorand.hu
// @match https://m.youtube.com/*
// @match https://youtube.com/*
// @match https://*.youtube.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net
// @grant none
// @license https://creativecommons.org/licenses/by-nc-sa/4.0/
// @run-at document-idle
// @downloadURL https://update.greasyfork.org/scripts/494186/YouTubecom%20download%20buttons%20%28Mobile%20%20Desktop%29.user.js
// @updateURL https://update.greasyfork.org/scripts/494186/YouTubecom%20download%20buttons%20%28Mobile%20%20Desktop%29.meta.js
// ==/UserScript==
// Screenshot: https://ibb.co/F7NJZHT
(function() {
//'use strict';
// itag quality descriptors
// https://gist.github.com/sidneys/7095afe4da4ae58694d128b1034e01e2
function getQualityFromItag(itag) {
const q = {
'5':'FLV 240p',
'6':'FLV 270p',
'17':'3GP 144p',
'18':'MP4 360p',
'22':'MP4 720p',
'34':'FLV 360p',
'35':'FLV 480p',
'36':'3GP 180p',
'37':'MP4 1080p',
'38':'MP4 3072p',
'43':'WebM 360p',
'44':'WebM 480p',
'45':'WebM 720p',
'46':'WebM 1080p',
'82':'MP4 360p (3D)',
'83':'MP4 480p (3D)',
'84':'MP4 720p (3D)',
'85':'MP4 1080p (3D)',
'92':'HLS 240p (3D)',
'93':'HLS 360p (3D)',
'94':'HLS 480p (3D)',
'95':'HLS 720p (3D)',
'96':'HLS 1080p (3D)',
'100':'WebM 360p (3D)',
'101':'WebM 480p (3D)',
'102':'WebM 720p (3D)',
'132':'HLS 240p',
'133':'MP4 240p Video Only',
'134':'MP4 360p Video Only',
'135':'MP4 480p Video Only',
'136':'MP4 720p Video Only',
'137':'MP4 1080p Video Only',
'138':'MP4 2160p60 Video Only',
'139':'M4A Audio Only 48k',
'140':'M4A Audio Only 128k',
'141':'M4A Audio Only 256k',
'151':'HLS 72p',
'160':'MP4 144p Video Only',
'167':'WebM 360p Video Only',
'168':'WebM 480p Video Only',
'169':'WebM 1080p Video Only',
'171':'WebM Audio Only 128k',
'218':'WebM 480p Video Only',
'218':'WebM 144p Video Only',
'242':'WebM 240p Video Only',
'243':'WebM 360p Video Only',
'244':'WebM 480p Video Only',
'245':'WebM 480p Video Only',
'246':'WebM 480p Video Only',
'247':'WebM 720p Video Only',
'248':'WebM 1080p Video Only',
'249':'WebM Audio Only 50k',
'250':'WebM Audio Only 70k',
'251':'WebM Audio Only 160k',
'264':'MP4 1440p Video Only',
'266':'MP4 2160p60 Video Only',
'271':'WebM 1440p Video Only',
'272':'WebM 4320p Video Only',
'278':'WebM 144p Video Only',
'298':'MP4 720p60 Video Only',
'299':'MP4 1080p60 Video Only',
'302':'WebM 720p60 Video Only ',
'303':'WebM 1080p60 Video Only',
'308':'WebM 1440p60 Video Only',
'313':'WebM 2160p Video Only',
'315':'WebM 2160p60 Video Only',
'330':'WebM 144p60 Video Only (hdr)',
'331':'WebM 240p60 Video Only (hdr)',
'332':'WebM 360p60 Video Only (hdr)',
'333':'WebM 480p60 Video Only (hdr)',
'334':'WebM 720p60 Video Only (hdr)',
'335':'WebM 1080p60 Video Only (hdr)',
'336':'WebM 1440p60 Video Only (hdr)',
'337':'WebM 2160p60 Video Only (hdr)'
};
return q[itag] || "Unknown";
}
function addbuttons(){
document.getElementById("downloadbuttons").innerHTML = "";
// do not add buttons on homepage
if( !window.location.href.includes("watch") ) return;
// if config not available, reload page
if( window.location.href.includes("watch") && ( !ytplayer.config || !ytplayer.config.args ) ){
window.location.reload();
return;
}
// get video urls from youtube config
let medias = ytplayer.config.args.raw_player_response.streamingData.adaptiveFormats;
medias.push(...ytplayer.config.args.raw_player_response.streamingData.formats);
let urls = [];
for (let media of medias) {
// calculate filesizes
if( media.contentLength )
// audio
var _filesize = Math.round(media.contentLength / 1024 / 1024); // byte->MB
else
// video
var _filesize = Math.round(media.approxDurationMs/1000 * media.bitrate/1024/1024/8) // bits/s->MB
// collet the most important data to an object
let data = {
url : media.url.replace(/\\u0026/g, '&'),
qualityDescription : getQualityFromItag(media.itag),
qualityLabel : media.qualityLabel,
filesize : _filesize
};
// filter videos that has audio+video stream both included or audio only
if( data.qualityDescription.includes("Audio Only") || data.qualityDescription.includes("MP4") && !data.qualityDescription.includes("Only") )
urls.push( data );
}
// filter out duplicates
urls = Array.from(new Set(urls.map(a => a.url))).map(url => {
return urls.find(a => a.url === url);
});
// create and add buttons
urls.forEach((url)=>{
let button = document.createElement('button');
button.setAttribute("url", url.url);
button.textContent = url.qualityDescription.replace(" Only","").replace("WebM","").replace("M4A","") + (isNaN(url.filesize) ? "" : " "+url.filesize+"M");
button.className = "downloadbutton";
button.style.margin = "4px";
button.style.padding = "4px";
button.style.position = "relative";
button.style.backgroundColor = "chocolate";
button.onclick = function() {
document.write(`<html>
<body>
<video controls><source src=`+this.getAttribute("url")+`></video><br><br>
<style>button{margin-bottom:5px;font-size:large;}video{width:100%;max-height:100vh;}</style>
<button onclick="document.querySelector('video').playbackRate = 3">3</button><br>
<button onclick="document.querySelector('video').playbackRate = 2.75">2.75</button><br>
<button onclick="document.querySelector('video').playbackRate = 2.5">2.5</button><br>
<button onclick="document.querySelector('video').playbackRate = 2.25">2.25</button><br>
<button onclick="document.querySelector('video').playbackRate = 2">2</button><br>
<button onclick="document.querySelector('video').playbackRate = 1.75">1.75</button><br>
<button onclick="document.querySelector('video').playbackRate = 1.5">1.5</button><br>
<button onclick="document.querySelector('video').playbackRate = 1">1</button><br>
</body>
</html>`);
};
let target = document.getElementById('downloadbuttons');
target.insertBefore(button, target.firstChild);
}); // end foreach
} // end addbuttons
// Periodically check if the buttons are visible (sometimes YouTube redraws its interface).
setInterval(()=>{
// Creating a div that will contain buttons.
if( document.getElementById("downloadbuttons") == undefined ){
// placement of buttons on desktop
let parent = document.getElementById('above-the-fold');
// placement of buttons on tablet
if( !parent ){
parent = document.querySelector('.watch-below-the-player');
}
// placement of buttons on mobile
if( !parent ){
parent = document.querySelector('.related-chips-slot-wrapper');
}
if( parent ){
let wrapper = document.createElement('div');
wrapper.setAttribute("id","downloadbuttons");
parent.insertBefore(wrapper, parent.firstChild);
addbuttons();
}
}
// Sometimes the buttons are not added, so I check and add them if necessary.
if( document.getElementById("downloadbuttons") && document.getElementById("downloadbuttons").textContent.trim() === '' ){
addbuttons();
}
}, 1000);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment