JohnyP36 / YT-Nonstop

Extension to let YouTube run nonstop with autoplay, autoconfirm and automatic pressing the loopbutton.
GNU General Public License v2.0
14 stars 1 forks source link

Don't make `autonav` dependent on `interval` #15

Closed JohnyP36 closed 1 year ago

JohnyP36 commented 1 year ago

Prerequisites

I tried to reproduce the issue when...

Describe the issue

At the moment you have to wait 5 seconds before the autoplay button and the loop button change in YouTube if you changed the settings in the extension popup. Could this be solved, but without reducing the interval time (as this will burden the browser)?

Screenshot(s)

No response

Browser & Extension version

Firefox 109 & 2.0.4.4

Operating System & Version

Windows 10, 22H2

Notes

maybe this could be a solution ```js function injectScript(YTNonstop, tag) { var node = document.getElementsByTagName(tag)[0]; var init = document.createElement("script"); var run = document.createElement("script"); init.setAttribute("type","text/javascript"); run.setAttribute("type","text/javascript"); init.append(`YTNonstop = ${YTNonstop}()`); node.appendChild(init); run.append("Nonstop = YTNonstop = new YTNonstop();"); node.appendChild(run); init.remove() } let YTNonstop = function YTNonstop(options) { const MutationObserver = window.MutationObserver || window.WebKitMutationObserver; const Nonstop = { _autoSkip: null, _autoLoop: null, getIsAutoSkip: function(){return Nonstop._autoSkip}, getIsAutoLoop: function(){return Nonstop._autoLoop}, setAutoSkip: function(value){return Nonstop._autoSkip = value}, setAutoLoop: function(value){return Nonstop._autoLoop = value}, }; /** * .getPlayerState(): * -1 – unstarted * 0 – ended * 1 – playing * 2 – paused * 3 – buffering * 5 – video cued */ const get_YT={ player: () => document.getElementById("movie_player") || document.getElementById("player"), loop: { button: () => playlistLoop()[0], // status: function() { // return get_YT.loop.button() ? JSON.parse(get_YT.loop.button().getAttribute("aria-pressed")) : undefined // } } }; function playlistLoop() { if (window.location.hostname === 'www.youtube.com') { return[...document.querySelectorAll('div[id="playlist-action-menu"] ytd-playlist-loop-button-renderer button[aria-label]')] } else if (window.location.hostname === 'music.youtube.com') { return[...document.querySelectorAll('ytmusic-player-bar > #right-controls > div[class^="right-controls-buttons"] > [class^="repeat"][role="button"]')] } else { return } } //if video ended ---> skip to next video const AutoPlay = () => { if(Nonstop.getIsAutoSkip() == true && get_YT.player().getPlayerState() === 0) { get_YT.player().setAutonav(true); const Index = get_YT.player().getPlaylistIndex(); const Playlist = get_YT.player().getPlaylist(); // const Loop = document.querySelector('#playlist-action-menu ytd-playlist-loop-button-renderer #button[aria-label] > yt-icon path[d="M20,14h2v5L5.84,19.02l1.77,1.77l-1.41,1.41L1.99,18l4.21-4.21l1.41,1.41l-1.82,1.82L20,17V14z M4,7l14.21-0.02l-1.82,1.82 l1.41,1.41L22.01,6l-4.21-4.21l-1.41,1.41l1.77,1.77L2,5v6h2V7z"]'); const Shuffle = document.querySelector('#playlist-action-menu ytd-toggle-button-renderer #button[aria-label][aria-pressed="true"]') || document.querySelector('#playlist-action-menu ytd-toggle-button-renderer button[aria-label][aria-pressed="true"]'); /** * 1. If the video is not in a playlist ---> skip to the next video * 2. If the loop function is turned on in the extension popup & shuffle is turned on in YouTube ---> play a random video in the playlist * 3. If only the loop function is turned on in the extension popup and the last video of the playlist is playing ---> go to the 1st video * 4. If only the shuffle is turned on in YouTube ---> don't autoplay to a video outside the playlist if currently playing the last video * 5. If the loop function is turned off in the extension popup ---> autoplay to the next video if the last video in the playlist is playing * If all above is not true AND/OR autoplay is turned off in the extension ---> don't autoplay to next video */ if (Playlist === null || Playlist === undefined) { return get_YT.player().nextVideo() } if ( (Nonstop.getIsAutoLoop() && Shuffle) || Shuffle) { // const getRandomNum = () => { // const rn = Math.abs(Math.floor(Math.random() * Playlist.length)); // if (rn == Index) return getRandomNum(); // return rn; // }; // get_YT.player().playVideoAt(getRandomNum()); return; } else if (Nonstop.getIsAutoLoop()) { const PlayAt = Playlist.length - 1 == Index ? 0 : Index + 1; //go to the first video on the list if currently playing the last video on the list get_YT.player().playVideoAt(PlayAt); return; // } else // if (Shuffle) { // return get_YT.player().setAutonav(false); } else { Playlist.length -1 == Index ? get_YT.player().nextVideo() : get_YT.player().playVideoAt(Index + 1) } } else { get_YT.player().setAutonav(false) } }; //if paused ---> unpause // const Play = p => { // if(get_YT.player().getPlayerState() === 2) { // p.click(); // get_YT.player().playVideo(); // log('Clicked to unpause video'); // } // }; function Run() { const Play_Pause = { getButton:window.document.getElementsByClassName("ytp-play-button ytp-button")[0] || window.document.getElementById("play-pause-button"), config: { attributes:true, childList:true, subtree:true }, callback: (MutationList, Observer) => { //check if mutationList has the 'attributes' type if(MutationList.some(el => el.type === "attributes")) { //get "you there?" popup const p = window.document.getElementById("confirm-button") || window.document.getElementsByClassName('ytmusic-you-there-renderer')[2] || undefined; if(p) { // Play(p); // log('Popup gets closed and video will start playing again'); } else { AutoPlay(); } } } }; const autoplay_button = { getButton: window.document.querySelector('#movie_player .ytp-progress-bar') || window.document.querySelector('#movie_player .ytmusic-player-bar#progress-bar'), config: { attributes: true }, callback: (mutationsList, observer) => { loadSettings.setAutonav(); } } const lp_button = { getButton: window.document.querySelector('#movie_player .ytp-progress-bar') || window.document.querySelector('#movie_player .ytmusic-player-bar#progress-bar'), config: { attributes: true }, callback: (mutationsList, observer) => { loadSettings.setLoop(); } } const Settings = { setInterval: setInterval(() => { if (window.location.href.indexOf("/watch") == -1) return; //set play button observer const pb_Observer = new MutationObserver(Play_Pause.callback); pb_Observer.observe(Play_Pause.getButton, Play_Pause.config); //set autonav button const autoplay_button_observer = new MutationObserver(autoplay_button.callback); autoplay_button_observer.observe(autoplay_button.getButton, autoplay_button.config); //set loop button const lp_button_observer = new MutationObserver(lp_button.callback); lp_button_observer.observe(lp_button.getButton, lp_button.config); clearInterval(Settings.setInterval) }, 1000), setAutonav: function() { const on = document.querySelector('.ytp-autonav-toggle-button-container > .ytp-autonav-toggle-button[aria-checked="true"]') || document.querySelector('#automix[role="button"][aria-pressed="true"]') const off = document.querySelector('.ytp-autonav-toggle-button-container > .ytp-autonav-toggle-button[aria-checked="false"]') || document.querySelector('#automix[role="button"][aria-pressed="false"]') if (Nonstop.getIsAutoSkip() == true && off) { off.click(); } else if (Nonstop.getIsAutoSkip() == false && on) { on.click(); } else { return; } }, setLoop: function() { const on = document.querySelector('#playlist-action-menu ytd-playlist-loop-button-renderer #button[aria-label] > yt-icon path[d^="M20,"]') || document.querySelector('#playlist-action-menu ytd-playlist-loop-button-renderer button[aria-label] yt-icon path[d^="M20,"]') || document.querySelector('ytmusic-player-bar > #right-controls > div[class^="right-controls-buttons"] > [class^="repeat"][title*="Alle"] path[d^="M3"]') || document.querySelector('ytmusic-player-bar > #right-controls > div[class^="right-controls-buttons"] > [class^="repeat"][title*="all"] path[d^="M3"]') || document.querySelector('ytmusic-player-bar > #right-controls > div[class^="right-controls-buttons"] > [class^="repeat"][title*="Tout"] path[d^="M3"]') const off = document.querySelector('#playlist-action-menu ytd-playlist-loop-button-renderer #button[aria-label] > yt-icon path[d^="M21,"]') || document.querySelector('#playlist-action-menu ytd-playlist-loop-button-renderer button[aria-label] yt-icon path[d^="M21,"]') || document.querySelector('ytmusic-player-bar > #right-controls > div[class^="right-controls-buttons"] > [class^="repeat"][title*="uit"] path[d^="M3"]') || document.querySelector('ytmusic-player-bar > #right-controls > div[class^="right-controls-buttons"] > [class^="repeat"][title*="off"] path[d^="M3"]') || document.querySelector('ytmusic-player-bar > #right-controls > div[class^="right-controls-buttons"] > [class^="repeat"][title*="aus"] path[d^="M3"]') || document.querySelector('ytmusic-player-bar > #right-controls > div[class^="right-controls-buttons"] > [class^="repeat"][title*="désactivée"] path[d^="M3"]') const o1f = document.querySelector('#playlist-action-menu ytd-playlist-loop-button-renderer #button[aria-label] > yt-icon path[d^="M13,"]') || document.querySelector('#playlist-action-menu ytd-playlist-loop-button-renderer button[aria-label] yt-icon path[d^="M13,"]') || document.querySelector('ytmusic-player-bar > #right-controls > div[class^="right-controls-buttons"] > [class^="repeat"] path[d^="M4"]') if (get_YT.loop.button() && Nonstop.getIsAutoLoop() == true && off) { get_YT.loop.button().click(); } else if (get_YT.loop.button() && Nonstop.getIsAutoLoop() == false && on) { get_YT.loop.button().click(); } else if (get_YT.loop.button() && Nonstop.getIsAutoLoop() == false && o1f) { get_YT.loop.button().click(); //this makes it impossible to loop a video if you turned 'loop playlist' off in the extension popup; you can only loop a video if 'loop playlist' is turned on } else { return } } }; return Nonstop } //exposing functions function _getSkip() {return Nonstop.getIsAutoSkip()} function _getLoop() {return Nonstop.getIsAutoLoop()} function _get_YT() {return get_YT} function YTNonstop(){ this.isAutoSkip = _getSkip; this.isAutoLoop = _getLoop; this.get_yt = _get_YT; Run() } //private functions const eventHandler = (key, value) => { switch(key) { case"autoSkip": Nonstop.setAutoSkip(value); break; case"autoLoop": Nonstop.setAutoLoop(value); // if(value !== get_YT.loop.status()) // get_YT.loop.button() && get_YT.loop.button().click(); break } }; addEventListener("message", (function(data) { for(key in data.data) { eventHandler(key, data.data[key]) } })); return YTNonstop }; injectScript(YTNonstop,"html"); //if you remove this line, the whole script will stop working ```

A major drawback is that now the extension will only respond if a video is playing. So, if you pause a video and change the settings nothing will happen until you will play the video again.

JohnyP36 commented 1 year ago

A drawback of this is that if you set autonav in the popup to true (so it will stop autoplay) but after that you changed the autoplay in YouTube to true. It will not check if autoplay is still off.

JohnyP36 commented 1 year ago

Also see this script for manifest v2 or this script for v3.

github-actions[bot] commented 1 year ago

This will not be worked on, but I appreciate your contribution.