Le Show Enhancements

Enhancements for Le Show

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==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...
})();