Youtube outro skip

Sick of 20 second outros on your favourite playlists? With this script simply set the outro length in seconds, apply and enjoy!

2019-11-15 يوللانغان نەشرى. ئەڭ يېڭى نەشرىنى كۆرۈش.

// ==UserScript==
// @name         Youtube outro skip
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Sick of 20 second outros on your favourite playlists? With this script simply set the outro length in seconds, apply and enjoy!
// @author       JustDaile
// @match        https://www.youtube.com/*
// @grant        GM_setValue
// @grant        GM_getValue
// @require      http://code.jquery.com/jquery-latest.js
// ==/UserScript==

(function(fn) {
    'use strict';
    $(document).ready(fn);
    //
    // detect page change hashchange not working
    // so check every 3 seconds if current URL matches URL we started with.
    // handle appropriately.
    //
    var l = document.URL;
    setInterval(function(){
        if (l != document.URL){
            l = document.URL;
            fn();
        }
        console.log("interval :" + l + " " + document.URL)
    }, 3000)
})(function(){
        //
        // make sure we have no events binded, in the case fn() was called by interval on URL change
        // this will ensure that we can create clean controls for the current playlist without accidentally
        // having events persisting in the background.
        //
        $(".video-stream").unbind();
        $("#set-outro").unbind();
        //
        var urlString = document.URL + '&';
        //
        // if we are not on a youtube playlist remove controls
        if (! urlString.includes("list") ){
            $(".outro-controls").remove();
            return;
        }
        var playlistId = urlString.match (/[\?\&]list=([^\&\#]+)[\&\#]/i) [1];
        var loadedOutroSetInSeconds = GM_getValue(playlistId);
        //
        // basic outro controls design prepended to the primary container.
        // if property length doesn't exist we can assume controls don't either.
        // prepend controls to #primary container
        //
        if (! $(".outro-controls").length ) {
            $("#primary").prepend(
                $("<div class='outro-controls'>").append(
                    $("<h3>Youtube Skip Outro Controller V1.1</h3>")
                ).append(
                    $("<input type='number' id='outro-length' placeholder='outro length in seconds'/>")
                ).append(
                    $("<button id='set-outro'>apply</button>")
                ).append(
                    $("<div>outro set: <span id='outro-set'>0</span> seconds</div>").css({
                        "padding": "2px",
                    })
                ).css({
                    "margin": "2px",
                    "textAlign": "right",
                })
            );
        }
        //
        // handle apply outro in seconds
        //
        $("#set-outro").on("click", function(e){
           var seconds = $("#outro-length").val().toString();
           if(seconds && seconds != "" && parseInt(seconds) != NaN){
               GM_setValue(playlistId, seconds);
               location.reload();
           }
        })
        //
        // hook video timeupdate, wait for outro and hit next button when time reached
        //
        if(loadedOutroSetInSeconds){
           var skipOutroSeconds = parseInt(loadedOutroSetInSeconds) | 0;
           $(".video-stream").on("timeupdate", function(e){
               var currentTime = this.currentTime;
               var duration = this.duration;
               if(currentTime >= duration - skipOutroSeconds){
                   $(".ytp-next-button")[0].click();
               }
            });
            $("#outro-set").text(loadedOutroSetInSeconds);
        }
    });