NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Clean Loopy and Instant Autoplay For Youtube (Improved) // @namespace VolkanK_CL_YT // @description Displays a link below YouTube videos to enable/disable auto replay. Instant Autoplay for Youtube. Play next video instantly. // @include *://*.youtube.com/* // @match *://*.youtube.com/* // @credits QuaraMan (embed code) .Paradise (List Loop Support) RowenStipe (GreasyFork mirror) // @version 4.5.3 // @author Volkan K. // @run-at document-end // @grant unsafeWindow // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @grant GM_log // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js // @license MIT // ==/UserScript== this.$ = this.jQuery = jQuery.noConflict(true); unsafeWindow.my_jQuery=jQuery.noConflict(true); if (typeof GM_getValue == "undefined") { // We will use static values if we can't use Greasemonkey API var ytInstant = true; //alert("DEBUG1"); // for debug }else { if (GM_getValue('yt_instant.autoplay', "abc") == "abc") GM_setValue('yt_instant.autoplay', true); var ytInstant = GM_getValue('yt_instant.autoplay', true); //alert("DEBUG2"); // for debug //alert(ytInstant); // for debug. } if (typeof GM_registerMenuCommand != "undefined") { GM_registerMenuCommand("Enable YT Instant Autoplay", function(){ var r=confirm("Do you want to enable YT Instant Autoplay?\nNOTE:Change of this setting requres reload of YT tabs\n (current setting:"+GM_getValue('yt_instant.autoplay', true)+") (default setting:true)"); if (r == true) { GM_setValue('yt_instant.autoplay', true); GM_log('Enabled YT Instant Autoplay'); } else { GM_setValue('yt_instant.autoplay', false); GM_log('Disabled YT Instant Autoplay'); } }); } //alert(ytInstant); // for debug. myScript = function(ytInstant) { //alert(ytInstant); // for debug. var ytLoop = false; var ytPlayList; var ytPLIndex; var script_name="USER-SCRIPT CLEAN-LOOPY"; var debug_internal=true; function debugLog(message){ if (debug_internal) { console.log(script_name+" : "+message); } } loopy = document.createElement("div"); loopy.setAttribute("id","loopyButton"); loopy.setAttribute("class","ytp-menuitem"); loopy.setAttribute("role","menuitemcheckbox"); loopy.setAttribute("aria-checked","false"); loopy.setAttribute("tabindex","0"); loopy.setAttribute("onClick", "LoopyOnOff();"); loopy.innerHTML = '<div class="ytp-menuitem-label">Loop</div>' +'<div id="loopyContent" class="ytp-menuitem-content">' +' <div class="ytp-menuitem-toggle-checkbox"></div>' +'</div>'; var is_frame=false; var ytPlayer; function checkNested(obj /*, level1, level2, ... levelN*/) { var args = Array.prototype.slice.call(arguments), obj = args.shift(); for (var i = 0; i < args.length; i++) { if (!obj.hasOwnProperty(args[i])) { return false; } obj = obj[args[i]]; } return true; } function start() { if (typeof ytplayer === "object" && checkNested(ytplayer, "config", "attrs", "id") && document.getElementById(ytplayer.config.attrs.id)) { ytPlayer = document.getElementById(ytplayer.config.attrs.id); //debugLog("90"); } else if (document.getElementById("movie_player")) { ytPlayer = document.getElementById("movie_player"); } else if (document.getElementById("movie_player_neo")) { ytPlayer = document.getElementById("movie_player_neo"); } else if (document.getElementsByClassName("html5-video-player")) { ytPlayer = document.getElementsByClassName("html5-video-player")[0]; } else if (document.getElementById("ytplayer").contentDocument.getElementsByClassName("html5-video-player")) { is_frame=true; ytPlayer = document.getElementById("ytplayer").contentDocument.getElementsByClassName("html5-video-player")[0]; } //alert (ytPlayer); // for debug if ( typeof ytPlayer.stopVideo === 'function' ) { initLoopy(); }else { ytPlayer.addEventListener("onReady", "initLoopy"); } } setInterval(start,1000); function initLoopy() { if (!document.getElementById("loopyButton")) { //alert ("loopy button not found"); // for debug settings_button = document.querySelector("div.ytp-right-controls > button.ytp-button.ytp-settings-button"); if (settings_button === null) { debugLog("ERROR: couldnt find settings button!"); return; } settings_menu_c = document.querySelector("div.ytp-settings-menu > div.ytp-panel > div.ytp-panel-menu > div"); if (settings_menu_c === null) { settings_button.click(); // to open settings menu, so it populates HTML setTimeout(function (settings_button){settings_button.click();},1,settings_button); // to close it after job done. } settings_menu = document.querySelector("div.ytp-settings-menu > div.ytp-panel > div.ytp-panel-menu"); if (settings_menu === null) { debugLog("ERROR: couldnt find settings menu!"); return ; } for (var i = 0; i < settings_menu.childNodes.length; i++) { if (settings_menu.childNodes[i].innerText.includes("Speed") && settings_menu.childNodes[i].getAttribute("aria-haspopup")=="true"){ settings_menu.insertBefore(loopy, settings_menu.childNodes[i]); fix_height_fit_children("div.ytp-settings-menu > div.ytp-panel > div.ytp-panel-menu",2) break; } } } if (is_frame == true) { ytPlayer.addEventListener("onStateChange", "window.parent.onPlayerStateChange"); //alert("DEBUG1"); // debugging. } else { ytPlayer.addEventListener("onStateChange", "onPlayerStateChange"); //alert("DEBUG2"); // debugging. } mic_add_EL(); mic_prepare(); document.querySelector('div.html5-video-player').addEventListener("contextmenu",mic_add_EL,false); } mic_prepare = function (){ var m_i_c = document.querySelector('div.ytp-contextmenu div.ytp-menuitem[role="menuitemcheckbox"]'); if (m_i_c!==null){ // menuitemcheckbox (loop) is here. exit. return ; } // trigger contextmenu var element = ytPlayer; if (window.CustomEvent) { element.dispatchEvent(new CustomEvent('contextmenu')); } else if (document.createEvent) { var ev = document.createEvent('HTMLEvents'); ev.initEvent('contextmenu', true, false); element.dispatchEvent(ev); } else { // Internet Explorer element.fireEvent('oncontextmenu'); } // close it setTimeout(function(){document.body.click()},1); } mic_add_EL = function() { // menuitemcheckbox addEventListener var m_i_c = document.querySelector('div.ytp-contextmenu div.ytp-menuitem[role="menuitemcheckbox"]'); if (m_i_c!==null){ m_i_c.addEventListener("click", sync_the_loop, false); } } sync_the_loop = function() { var m_i_c = document.querySelector('div.ytp-contextmenu div.ytp-menuitem[role="menuitemcheckbox"]'); if (m_i_c===null){ return; } if ((m_i_c.getAttribute("aria-checked")=="true" && ytLoop===false) || (m_i_c.getAttribute("aria-checked")=="false" && ytLoop===true)){ LoopyOnOff(); } } fix_height_fit_children = function(selector,up_level){ if (typeof selector !== "string"){ return; } new_height=0; parent=my_jQuery(selector); children=parent.children(); children.each(function(){ new_height+=my_jQuery(this).outerHeight(); }); if (parent.height()<new_height){ parent.height(new_height); } debugLog(selector+" height = "+parent.height()+" ; children height = "+new_height); if (typeof up_level==="number"){ for (var i = 0; i < up_level; i++) { current_parent=parent.parents().eq(i); if (current_parent.height()<new_height){ current_parent.height(new_height); } debugLog(current_parent.prop("tagName")+'.'+current_parent.attr('class').split(' ').join('.')+" height = "+current_parent.height()); } } } onPlayerStateChange = function(newState) { //alert("DEBUG3"); // debugging. if (newState == "0"){ if (ytLoop) { //alert("DEBUG 185"); // debugging. window.setTimeout(function() { ytPlayer.playVideo(); }, 60); } else if (ytInstant) { if ((document.getElementById("autoplay-checkbox") && document.getElementById("autoplay-checkbox").checked) || (document.getElementById("toggle") && document.getElementById("toggle").checked)) { //alert("DEBUG5"); // debugging. window.setTimeout(function() { if ( document.querySelector("button.ytp-upnext-cancel-button")!==null) { document.querySelector("button.ytp-upnext-cancel-button").click(); } if ( document.querySelector("ytd-compact-autoplay-renderer a#thumbnail")!==null ) { document.querySelector("ytd-compact-autoplay-renderer a#thumbnail").click(); } else { ytPlayer.nextVideo(); } }, 60); } } } } LoopyOnOff = function() { if (ytLoop) { document.getElementById("loopyButton").setAttribute("aria-checked", "false"); ytLoop = false; loop_item=document.querySelector('div.ytp-contextmenu div.ytp-menuitem[role="menuitemcheckbox"][aria-checked="true"]'); if (loop_item!==null){ loop_item.click(); } else { document.getElementsByTagName("video")[0].removeAttribute("loop"); } } else { document.getElementById("loopyButton").setAttribute("aria-checked", "true"); ytLoop = true; /*if((apbut = document.querySelectorAll('.playlist-nav-controls .yt-uix-button-player-controls.toggle-autoplay')) && (apbut = apbut[0]) && apbut.classList.contains('yt-uix-button-toggled')){ apbut.click(); // Turn off Playlist Autoplay so we can loop the current video. }*/ loop_item=document.querySelector('div.ytp-contextmenu div.ytp-menuitem[role="menuitemcheckbox"][aria-checked="false"]'); if (loop_item!==null){ loop_item.click(); } else { document.getElementsByTagName("video")[0].createAttribute("loop"); } } mic_add_EL(); } function getCookie(name) { var results = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)'); if (results) { return unescape(results[2]); } else { return null; } } function setCookie(name, value) { document.cookie = name + "=" + escape(value); } if (typeof GM_addStyle == "undefined") { GM_addStyle = function(text) { var head = document.getElementsByTagName("head")[0]; var style = document.createElement("style"); style.setAttribute("type", "text/css"); style.textContent = text; head.appendChild(style); } } GM_addStyle(" \ loopyButton:hover {\ border: 0px none;} \ img.LoopyOff{\ background: url(\"//image.ibb.co/j0Mnhm/jlhKt.png\") -0px -0px no-repeat transparent !important;\ height: 18px;\ width: 30px;}\ img.LoopyOn{\ background: url(\"//image.ibb.co/j0Mnhm/jlhKt.png\") -0px -18px no-repeat transparent !important;\ height: 18px;\ width: 30px;}" ); }; var uw; // unwraps the element so we can use its methods freely function unwrap(elem) { if (elem) { if ( typeof XPCNativeWrapper === 'function' && typeof XPCNativeWrapper.unwrap === 'function' ) { return XPCNativeWrapper.unwrap(elem); } else if (elem.wrappedJSObject) { return elem.wrappedJSObject; } } return elem; } // get the raw window object of the YouTube page uw = typeof unsafeWindow !== 'undefined' ? unsafeWindow : unwrap(window); // disable Red Bar aka SPF if (uw._spf_state && uw._spf_state.config) { uw._spf_state.config['navigate-limit'] = 0; uw._spf_state.config['reload-identifier'] =null; } if ( /^\/?watch/i.test(window.location.pathname) ) { document.body.appendChild(document.createElement("script")).innerHTML = "("+myScript+")("+ytInstant+")"; }