Echo360 Super Speed

Adds faster speed options (4x, 3x) to Echo360 player and allows the user to add their own speed options.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==UserScript==
// @name        Echo360 Super Speed
// @namespace   https://www.petertanner.dev/
// @description Adds faster speed options (4x, 3x) to Echo360 player and allows the user to add their own speed options.
// @include     *://echo360.net.au/*
// @include     *://echo360.org.uk/*
// @include     *://echo360.org/*
// @include     *://echo360.ca/*
// @include     *://echo360.org.au/*
// @version     1.2
// @author      Peter Tanner
// @namespace   https://github.com/peter-tanner/Echo360-Super-Speed-Userscript/
// @supportURL  https://github.com/peter-tanner/Echo360-Super-Speed-Userscript/issues
// @license     GPL-3.0
// @website     https://www.petertanner.dev/
// @run-at      document-start
// ==/UserScript==

/* USER CUSTOMIZATION BEGIN */
// NOTE: Add (or remove) speeds to this array to your liking.
// Note that there is a browser set limit of 16x, and speeds above 4x are muted.
// https://searchfox.org/mozilla-central/rev/f1c881ba5603410dacbe52874053af38bd825c3b/dom/html/HTMLMediascript_Element.cpp#179-183
const selected_speeds = [4, 3, 2, 1.75, 1.5, 1.25, 1, 0.75];
// const selected_speeds = [2, 1.75, 1.5, 1.25, 1, 0.75, 0.5, 0.25]; // Default Echo360 speeds.

// NOTE: Change this to modify how much the speed changes when you use the < or
// > hotkey to change speed
const speed_hotkey_increment = 0.25;
/* USER CUSTOMIZATION END */

// The code in compatible string representation since we are putting strings in
// script tags instead of executing them here.
const speed_code_txt =
  "[" +
  selected_speeds
    .map((speed) => `{label:"${speed}x",value:${speed}}`)
    .join(",") +
  "]";

const max_speed = Math.max(...selected_speeds);
const min_speed = Math.min(...selected_speeds);

// The page contains a script tag which is called after the player bundle
// `echoPlayerV2FullApp.react-bundle.js` is downloaded. This tag is generated
// with the page and contains information about the video (such as the title,
// institution and thumbnail paths) and calls the player with this information.
// This contextual information is stored in the variable to be called after the
// player is modified.
var player_calling_context =
  "console.error('Echo360 super speed failed to load :(')";

new MutationObserver(async (mutations, observer) => {
  let script_elem = mutations
    .flatMap((e) => [...e.addedNodes])
    .filter((e) => e.tagName === "SCRIPT")
    .find((e) => e.src.match(/echoPlayerV2FullApp\.react-bundle\.js/));

  if (script_elem) {
    // Do not load the unmodified player code
    observer.disconnect();
    script_elem.remove();

    // Download the player code for modification...
    await fetch(script_elem.src)
      .then((e) => e.text())
      .then((player_code) => {
        player_code = player_code.replace(
          // Overwrite all previous speeds in case the user wants to remove the
          // default speeds
          '[{label:"2x",value:2},{label:"1.75x",value:1.75},{label:"1.5x",value:1.5},{label:"1.25x",value:1.25},{label:"1x",value:1},{label:"0.75x",value:.75},{label:"0.5x",value:.5},{label:"0.25x",value:.25}]',

          // Replace with our custom speeds
          speed_code_txt
        );

        player_code = player_code.replace(
          // This code handles hotkeys for changing speed, adjust bounds to match new speeds.
          '{key:">",handler:function(){b<2&&I(b+.25)}},{key:"<",handler:function(){b>.25&&I(b-.25)}}',
          `{key:">",handler:function(){b<${max_speed}&&I(b+${speed_hotkey_increment})}},{key:"<",handler:function(){b>${min_speed}&&I(b-${speed_hotkey_increment})}}`
        );

        // Add the player calling context code since this event listener does
        // not block, resulting in the original player calling code being called
        // (with a harmless error, since the player code has not loaded by the
        // time it is called)
        player_code +=
          ";" +
          player_calling_context +
          "; console.log('Echo360 super speed has successfully been loaded :3')";

        // Create a new script tag containing the modified player & add to head
        const new_script = document.createElement("script");
        new_script.type = "text/javascript";
        new_script.textContent = player_code;
        document.getElementsByTagName("head")[0].append(new_script);
      });
  }
}).observe(document, {
  childList: true,
  subtree: true,
});

window.addEventListener(
  "load",
  () => {
    const script_elems = document.getElementsByTagName("script");
    player_calling_context = script_elems[script_elems.length - 1].innerText;
  },
  false
);