Le Show Enhancements

Enhancements for Le Show

// ==UserScript==
// @name         Le Show Enhancements
// @author       Than
// @version      0.03
// @description  Enhancements for Le Show
// @match        https://harryshearer.com*
// @include      https://harryshearer.com*
// @connect      harryshearer.com
// @grant        GM.xmlHttpRequest
// @grant        unsafeWindow
// @grant        GM_addStyle
// @grant        GM_setClipboard
// @run-at       document-end
// @namespace https://greasyfork.org/users/288098
// ==/UserScript==

//0.3 - Added skip forward and skip back. And hopefully fixed a bug where my phone keeps the volume too quiet after skipping a song.
//0.2 - published script

(function() {
    'use strict';
    /*--------------------------------------------------------------------------------------------------------------------
    ------------------------------------------- General functions --------------------------------------------------
    --------------------------------------------------------------------------------------------------------------------*/

    // not currently using anything here

    /*--------------------------------------------------------------------------------------------------------------------
    ------------------------------------------- Init functions --------------------------------------------------
    --------------------------------------------------------------------------------------------------------------------*/
    init(); // kick things off
    function init(){
        enhanceIndividualShowPage(); // fixes audio stuff on individual le show pages. Skips songs, prevents looping.
    }
    function enhanceIndividualShowPage(){
        if (!document.URL.includes("/le-shows/")){return} // if it's not an individual show page, return
        var audio = document.querySelector("audio"); // grab the audio tag from the page
        var goodTimestampArray = getTimestampArr(); // make an array of "good" timestamps - a list full of seconds where harry is talking and not playing music
        //  console.log(goodTimestampArray);
        audio.addEventListener("timeupdate",progressUpdated); // as the progress bar
        var currentTime; // global variable to store the current progress of the episode
        var gracePeriod = false; // if set to true, the script won't skip the song (assuming it's the grace period, last 30 seconds of the song.
        addSkipButtons();
        function addSkipButtons(){ // adds buttons to skip forward & back ten seconds
            var skipDiv = document.createElement("div");
            skipDiv.innerHTML = `<button id="rewind">⏪</button><button id="fast_forward">⏩</button>`; // creating our skip buttons
            var container = document.querySelector(".jp-type-playlist"); // choosing which container they'll go in
            var insertBeforeThis = container.querySelector("h3"); // we'll put our buttons above the "Music & Segments" H3 element
            container.insertBefore(skipDiv, insertBeforeThis); // insert the buttons
            skipDiv.addEventListener("click",skipClickHandler); // add their click logic
            function skipClickHandler(e){
                if (e.target == e.currentTarget){return} // ignores any clicks on the skipDiv itself
                var clicked = e.target; // what did the user click?
               // console.log(clicked);
                if (clicked.id === "rewind" || clicked.parentNode.id === "rewind"){ // user clicked the rewind button
                    audio.currentTime = audio.currentTime - 10; // skip back 10 seconds
                }
                else if (clicked.id === "fast_forward" || clicked.parentNode.id === "fast_forward"){ // user clicked the fast forward button
                    audio.currentTime = audio.currentTime + 20; // skip forward 20 seconds
                }
            }
        }
        async function fadeAudioOut(skipTo) {
            gracePeriod = true;
            var audio = document.querySelector("audio");
            var fadeOut = setInterval(volDown, 200);
            function volDown() {
                if (audio.volume <= 0.1) {
                    console.log("cancelling fade out")
                    clearInterval(fadeOut);
                    audio.currentTime = skipTo;
                    fadeAudioIn();
                } else {
                    console.log("ducking audio")
                    audio.volume = audio.volume - 0.03;
                }
            }
        }
        async function fadeAudioIn() {
            var audio = document.querySelector("audio");
            var fadeIn = setInterval(volUp, 400);
            function volUp() {
                if (audio.volume >= 0.8) {
                    console.log("finished fading in");
                    audio.volume = 1; // set volume to max
                    clearInterval(fadeIn);
                    // gracePeriod = false;
                } else {
                    console.log("upping audio")
                    audio.volume = audio.volume + 0.1;
                }
            }
        }
        async function progressUpdated(){
            var timestamp = Math.floor(audio.currentTime); // grab the current progress of the episode
            if (currentTime > 3300 && timestamp == 0){audio.pause()} // If the previous second was at the end of the episode, and the current second is at the beginning, pause so it doesn't loop
            if (currentTime == timestamp){return} // this whole function runs every time the event handler updates, which is 4 times per second. We don't want to iterate through the goodTimestampArray 4 times per second, so we do it once per second
            currentTime = timestamp; // now it's ok to update the time
            //   console.log(timestamp);
            if (goodTimestampArray.includes(timestamp)){
                gracePeriod = false;
                return} // if the current second is in the "good" timestamp array, never mind we're all good
            if (gracePeriod){return} // we're in the grace period part of the song. Return.
            for (var i=0,j = goodTimestampArray.length;i<j;i++){ // otherwise, loop through the array
                if (goodTimestampArray[i] > timestamp){ // look for the first array value which is bigger than the current time
                    fadeAudioOut(goodTimestampArray[i] - 30);
                    //   audio.currentTime = goodTimestampArray[i]-30; // skip to that value
                    break; // no need to loop any more
                }
            }
        }
        function getTimestampArr(){ // make an array of "good" timestamps, where harry is talking and not playing music
            var timestampDomElements = document.querySelector(".jp-playlist").querySelectorAll(".time"); // all timestamps for the episode
            var musicTimestampDomElements = document.querySelector(".other-list").querySelectorAll(".time"); // just the music timestamps
            var musicStartTimeArray = []; // this will be populated with the timestamps of the music we want to skip
            for (var i=0,j = musicTimestampDomElements.length-1;i<j;i++){ // -1 so as to allow the instrumental at the end of the broadcast to play. For each music timestamp
                if (musicTimestampDomElements[i].nextElementSibling.textContent.includes("Harry Shearer")){continue} // if it's Harry's own song, don't skip it
                var musicStartTime = convertTimeToSeconds(musicTimestampDomElements[i].textContent); // convert the time to seconds
                musicStartTimeArray.push(musicStartTime); // push the timestamp into our array of music to skip
            }
            //   console.log(musicStartTimeArray);
            var goodTimeArray = []; // this will be populated with a list of seconds which don't contain music
            for (var k=0,l = timestampDomElements.length;k<l;k++){ // for each timestamp dom element
                var startTime = convertTimeToSeconds(timestampDomElements[k].textContent); // convert the timestamp to seconds
                var endTime; // populate this with the end time, which depends on a couple of factors
                if (timestampDomElements[k+1]){ // if there's a next timestamp in the dom
                    endTime = convertTimeToSeconds(timestampDomElements[k+1].textContent); // make that the end time
                }
                else { // otherwise
                    endTime = 3900; // no more timestamps, it's the end of the podcast. Hard coded 3900 cos that's the absolute max duration of the show
                }
                if (musicStartTimeArray.includes(startTime)){ // if the start time of this element is the same as a music start time
                    continue; // don't add this chunk of seconds to the array
                }
                addGoodTimestampsToArr(goodTimeArray,startTime,endTime); // add this timestamp & all the seconds up to & including its endtime to the goodTimeArray
                //addGoodTimestampsToArray(array,startTime,endTime);
            }
            return goodTimeArray; // send this array back
        }
        function convertTimeToSeconds(timestamp){ // simple function to convert a timestamp to seconds (taken from the website's own code!)
            var timeSplit = timestamp.split(":");
            var timeInSeconds = (parseFloat(timeSplit[0]) * 60) + parseFloat(timeSplit[1]);
            return timeInSeconds;
        }
        function addGoodTimestampsToArr(array,startTime,endTime){ // feed this function the array you wan to update, the start time & the end time
            for (var i = parseInt(startTime); i <= parseInt(endTime); i++) { // for every number from start time to end time
                array.push(i); // push those numbers to the array
            }
        }
    }

    // not currently setting styles, but we might!
    var globalStyle = `
#rewind,#fast_forward{
  width: 60px;
  height: 50px;
  padding: 5px;
  margin: 5px;
  font-size: 30px;
  background-color: #fda732;
}
`
    GM_addStyle(globalStyle)
    // Your code here...
})();