1

I do not mean YouTube playlists or the next auto-play track. I mean a long YouTube mix of music that is all within the same video, i.e. one like this.

It is a hassle to have to scroll down and click the time next to the track name, I'd like a way to have a next/previous track for mixes like this (provided the time for each track is given in the description).

How can I do this?

0

While it's not natively possible on YouTube, you can do so using a usercript.

I've created a userscript that adds a previous and next song in the mix functionality to YouTube (along with hotkeys u and i to go back and forward). You need something like TamperMonkey installed for your browser and can download it from GreasyFork if you'd prefer.

Here's the code:

// ==UserScript==
// @name         YouTube mix next/previous buttons
// @namespace    https://zachsaucier.com/
// @version      0.5
// @description  Adds next/previous buttons to seek between tracks in a YouTube mix without having to scroll down.
// @author       Zach Saucier
// @include      /^https://www.youtube.com/watch
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    function goToNextTrack() {
        var currTimeString = document.querySelector(".ytp-time-current").innerText,
            currTime = parseTimeString(currTimeString);

        for(var i = 0; i < timeLinks.length; i++) {
            var linkTimeString = timeLinks[i].innerText,
                linkTime = parseTimeString(linkTimeString);

            if(isLaterTime(currTime, linkTime)) {
                timeLinks[i].click();
                return;
            }
        }

        timeLinks[0].click();
    }

    function goToPreviousTrack() {
        var currTimeString = document.querySelector(".ytp-time-current").innerText,
            currTime = parseTimeString(currTimeString);

        for(var i = timeLinks.length - 1; i >= 0; i--) {
            var linkTimeString = timeLinks[i].innerText,
                linkTime = parseTimeString(linkTimeString);

            if(isLaterTime(linkTime, currTime)) {
                timeLinks[i].click();
                return;
            }
        }

        timeLinks[timeLinks.length - 1].click();
    }

    function parseTimeString(timeString) {
        var timeArr = timeString.match(/\d+/g);

        var h = 0,
            m = 0,
            s = 0;

        if(timeArr.length === 3) {
            h = parseInt(timeArr[0]);
            m = parseInt(timeArr[1]);
            s = parseInt(timeArr[2]);
        } else if(timeArr.length == 2) {
            m = parseInt(timeArr[0]);
            s = parseInt(timeArr[1]);
        }

        return [h, m, s];
    }

    function isLaterTime(firstTime, secondTime) {
        if(firstTime[0] < secondTime[0]
           || (firstTime[0] === secondTime[0] && firstTime[1] < secondTime[1])
           || (firstTime[0] === secondTime[0] && firstTime[1] === secondTime[1] && firstTime[2] < secondTime[2])
          )
            return true;

        else
            return false;
    }

    var description, 
        timeLinks;

    var url = window.location.href;
    var videoid = url.match(/(?:https?:\/{2})?(?:w{3}\.)?youtu(?:be)?\.(?:com|be)(?:\/watch\?v=|\/)([^\s&]+)/);

    function checkReady() {
        description = document.getElementById("description");

        if(description) { 
            timeLinks = description.querySelectorAll("a[href *= '/watch?v=" + videoid[1] + "'");

            // If true, it's (probably) a mix with tracklisting provided
            if(timeLinks.length > 0) {
                // Create the buttons
                var nextButton = document.createElement("button"),
                    prevButton = document.createElement("button"),
                    br = document.createElement("br");

                nextButton.innerText = "Next track";
                prevButton.innerText = "Previous track";
                nextButton.onclick = goToNextTrack;
                prevButton.onclick = goToPreviousTrack;

                nextButton.style = "cursor: pointer; background-color:#444244; color: white; padding: 4px 12px; border: none; margin-right: 5px; margin-bottom: 5px;";
                prevButton.style = "cursor: pointer; background-color:#444244; color: white; padding: 4px 12px; border: none; margin-right: 5px; margin-bottom: 5px;";

                nextButton.title = "Hotkey: u";
                prevButton.title = "Hotkey: i";

                description.insertBefore(br, description.childNodes[0]);
                description.insertBefore(nextButton, description.childNodes[0]);
                description.insertBefore(prevButton, description.childNodes[0]);

                // Create the key listeners
                document.addEventListener("keyup", function(e) {
                    if(e.keyCode === 73
                    && e.srcElement.tagName !== "INPUT"
                    && e.srcElement.tagName !== "TEXTAREA") { // i pressed
                        goToNextTrack();
                    } else if(e.keyCode === 85
                    && e.srcElement.tagName !== "INPUT"
                    && e.srcElement.tagName !== "TEXTAREA") { // u pressed
                        goToPreviousTrack();
                    }
                });
            }
        }
        else {
            setTimeout(checkReady, 100);
        }
    }
    setTimeout(checkReady, 100);

})();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.