Jupiter's Tools for YouTube

Speed control, precise aspect ratio control, nice 'n' accurate looper, volume booster, and more.

// ==UserScript==
// @name         Jupiter's Tools for YouTube
// @namespace    Violentmonkey Scripts
// @license      CC BY-SA
// @version      1.0.2
// @description  Speed control, precise aspect ratio control, nice 'n' accurate looper, volume booster, and more.
// @description  2025-04-17 7:00 PM
// @author       Jupiter Liar
// @match        *://www.youtube.com/*
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function () {
    "use strict";

    let logging = false;

    function log(...args) {
        if (logging) {
            console.log(...args);
        }
    }

    log("YouTube Video Manipulator started...");

    const head = document.head || document.getElementsByTagName("head")[0];

    let video;

    let timeLoopDebug = false;
    let compressorTipDivTesting = false;
    let extraDebugButtons = false;

    let lastChecked = 0;
    let lockRate = null; // Variable to store the locked playback rate
    let playLock = false;
    let pauseLock = false;
    let rawAspectRatio;
    let aspectRatio;
    let savedAspectRatio;
    let aspectRatioSpecified = false;
    let nativeRatio;
    let zoom = 1;
    let isZoomed = false;
    let hideOverlaysVar = false;
    let flipRotateStyle;
    let videoZoomStyle;
    let overrideObjectFitStyle;
    let frameAspectStyle;
    let frameIsRescaled = false;
    let noScaleAndTop = false;
    let zoomInput;
    let buttonRefs = {};
    let playbackRateLocked = false;
    let playbackRateForeverLocked = false;
    let speedLockCheckbox;
    let foreverLockCheckbox;
    let squareCorners = false;
    let squareCornersStyle;
    let noAspect = true;
    let customBlink;
    let startLoopingBlink;
    let resizeDefaultCheckbox;
    let resizeByDefault;
    let topRow;
    let actions;
    let chapters;
    let chapterMoving;
    let chapterPosition;
    let looping = false;
    let loopMode = "forever";
    let lastCustom;
    let lastCustomRepeated = false;
    let lastCustomReset = false;
    let tipAspectStyle;

    let container;
    let containerWidth;
    let containerHeight;
    let containerRatio;

    frameAspectStyle = document.createElement("style");
    frameAspectStyle.id = "frame-aspect-style";
    head.appendChild(frameAspectStyle);

    const innerItemAfterStyles = document.createElement("style");
    innerItemAfterStyles.id = "inner-item-after-styles";
    head.appendChild(innerItemAfterStyles);

    tipAspectStyle = document.createElement("style");
    tipAspectStyle.id = "tip-aspect-style";
    head.appendChild(tipAspectStyle);

    let overlayHiderStyle;
    let controlPanelOuter;
    let controlPanel;
    let additionalStyles = document.createElement("style");

    let videoControlsMasterHolder;
    let videoControlsShowHideMenu;
    let lockControlsOuterDiv;
    let playbackRateOuter;
    let videoSeekControlsOuterDiv;
    let cosmeticCheckboxesOuterDiv;
    let videoLoopControlsOuterDiv;
    let compressorControlsParentDiv;
    let aboutDiv;

    let chapterMoveAttempts = 0;
    let chapterMoveAttemptsMax = 15;

    // Declare an AudioContext &c.
    let audioContext = null;
    let preGain;
    let thresholdGain;
    let compressor;
    let finalGain;
    let source = null;
    let boostLockState = false;

    let establishChaptersAttempts;
    let maxEstablishChaptersAttempts;
    let establishChaptersAttemptsInterval;
    let establishChapters;
    let moveChapters;

    const generalStyles = `
      :root {
          --video-manipulator-button-active: hsl(0, 100%, 85%);
          --video-manipulator-button-just-pressed: hsl(0, 100%, 75%);
      }

      ytd-watch-metadata #top-row #actions {
          margin-left: 8px;
      }

      ytd-watch-metadata #top-row ytd-menu-renderer {
          margin-right: 1em;
      }

      #video-controls-master-holder {
          display: flex;
          flex-direction: row;
          flex-wrap: wrap;
          gap: 10px 24px;
      }

      .video-manipulator-outer-div [invisible] {
          opacity: 0;
      }

      .video-manipulator-outer-div, .video-manipulator-outer-div * {
          color: inherit;
          --button-outline-op: .25;
      }

      .video-manipulator-outer-div {
          font-size: 14px;
      }

      .video-manipulator-outer-div * {
          font-size: inherit;
      }

      .video-manipulator-outer-div [hidden] {
          display: none;
      }

      .video-manipulator-outer-div button, .video-manipulator-outer-div input {
          cursor: pointer;
      }

      .video-manipulator-inner-item {
          display: flex;
          flex-wrap: wrap;
          gap: .5em;
          /* margin: auto; */
          align-items: center;
          position: relative;
      }

      .video-manipulator-inner-item:after {
          content: '';
          pointer-events: none;
          position: absolute;
          width: 100%;
          height: 100%;
          padding: 4px;
          left: -4px;
          top: -4px;
          border-radius: 8px;
      }

      .video-manipulator-inner-item:hover:after {
          box-shadow: 0px 0px 0px 2px hsla(240, 100%, 50%, var(--button-outline-op));
      }

      .video-manipulator-sub-item {
          display: flex;
          flex-wrap: wrap;
          gap: .5em;
          align-items: center;
      }

      .video-manipulator-outer-div:hover button, button.video-manipulator-inner-item:hover {
          /* box-shadow: 0px 0px 0px 2px inset hsla(240, 100%, 50%, var(--button-outline-op)); */
      }

      .video-manipulator-outer-div {
          /* margin-top: 12px; */
          display: flex;
          /* margin-right: 1.5em; */
          z-index: 1;
      }

      .video-manipulator-outer-div label, .video-manipulator-outer-div input[type="checkbox"],
      .video-manipulator-outer-div .video-manipulator-divider {
          /* font-size: 1.4rem; */
      }

      #playback-rate-input {
          margin-right: .5em;
      }

      .video-manipulator-outer-div input[type="checkbox"] {
          margin: 0 .25em;
      }

      .video-manipulator-inner-item button, button.video-manipulator-inner-item {
          border-radius: 1em;
          border: unset;
          padding: 0.25em 0.75em;
      }

      .video-manipulator-inner-item button:not(:hover), button.video-manipulator-inner-item:not(:hover) {
          box-shadow: inset 0px 0px 0px 1px hsla(0, 0%, 50%, 0.065);
      }

      .video-manipulator-inner-item button:hover, button.video-manipulator-inner-item:hover {
          box-shadow: 0px 0px 0px 1px inset hsla(0, 0%, 50%, .75);
      }

      #video-display-controls #aspect-custom-input, #video-display-controls #zoom-input {
          width: 4em;
          text-align: center;
      }

      #video-display-controls span {
          /* font-size: 1.5rem; */
          margin-left: .5em;
      }

      #playback-rate-controls input[type="number"] {
          width: 4em;
          text-align: center;
          padding: 0;
          /* border-radius: 1em; */
      }

      .video-manipulator-inner-item label ~ label,
      .video-manipulator-inner-item ~ .video-manipulator-inner-item label {
          margin-left: .25em;
      }

      #playback-rate-controls label {
          padding-left: 0;
      }

      .video-manipulator-outer-div button.active {
          background-color: var(--video-manipulator-button-active);
      }

      @keyframes blink {
          0% {
              background-color: var(--video-manipulator-button-color);
          }
          50% {
              background-color: var(--video-manipulator-button-just-pressed);
          }
          100% {
              background-color: var(--video-manipulator-button-color);
          }
      }

      .video-manipulator-outer-div button.blinking {
          animation: blink 1s infinite;
      }

      .video-manipulator-outer-div button.just-pressed,
      .video-manipulator-outer-div button.active.just-pressed {
          background-color: var(--video-manipulator-button-just-pressed);
      }

      #lock-controls .lock-button .lock-span {
          filter: drop-shadow(0px 0px .4px black)
          drop-shadow(0px 0px 0px black)
          drop-shadow(0px 0px 0px black)
          drop-shadow(0px 0px 0px black)
          drop-shadow(0px 0px 0.25px black)
          drop-shadow(0px 0px 0px black);
      }

      ytd-watch-metadata #top-row {
          display: flex;
          flex-wrap: wrap;
      }

      #compressor-controls-parent-div {
          z-index: 901;
          /* position: fixed; */

          /* font-size: 16px; */

          display: flex;
          flex-direction: column;
          gap: 0 .5em;
          /* display: none; */
          width: 100%;
      }

      .compressor-control-div {
          display: flex;
          align-items: center;
      }

      .compressor-control-div label {
          width: 5.5em;
      }

      .compressor-control-div input {
          margin: 0 .5em;
          text-align: right;
          width: 3.5em;
          cursor: pointer;
      }

      .compressor-control-div .conversion-div {
          margin: 0 0.5em;
          font-size: 0.8em;
      }

      #compressor-controls-group-div,
      #compressor-control-tip-div,
      #compressor-control-tip-div-background {
          padding: 0.75em 1em;
          border-radius: 1em;
      }

      #compressor-control-tip-div {
          background: none;
          border: 3px solid transparent;
      }

      #compressor-controls-group-div,
      #compressor-control-tip-div-background {
          background: var(--yt-spec-base-background);
          border: 3px solid var(--video-manipulator-button-color, gray);
      }

      #compressor-control-tip-div-background {
            position: absolute;
      }

      #compressor-control-tip-div {
          max-width: 21.5em;
          position: absolute;
      }

      #compressor-control-tip-parent {

      }

      #compressor-controls-group-div {
          width: fit-content;
      }

      #compressor-simple-controls-div {
          display: flex;
          gap: .25em;
      }

      #compressor-simple-controls-div #simpleBoost-control-div {
          /* margin-right: 8px; */
      }

      #compressor-advanced-controls-div {
          position: absolute;
      }

      #compressor-advanced-controls-container-div {

      }

      #compressor-controls-group-div, #compressor-control-tip-parent {
          margin-top: 0.25em;
      }

      .empty-spanner {
          width: 100%;
          height: 0;
      }

      .empty-spanner.line {
          margin: 10px 0;
          border-bottom: 1px solid var(--yt-spec-10-percent-layer);
      }

      #compressor-controls-parent-div:not(.active) > *:not(#compressor-simple-controls-div),
      #compressor-controls-parent-div:not(.active) #compressor-simple-controls-div > *:not(#compressor-boost-button),
      #compressor-advanced-controls-container-div:not(.active) {
          display: none;
      }

      #show-full-compressor-controls .down-expand-arrow {
          transition: scale 0.5s;
      }

      #show-full-compressor-controls.active .down-expand-arrow {
          scale: 1 -1;
      }

      #compressor-reset-button {
          position: absolute;
          bottom: 1.25em;
          right: 1.25em;
      }

      #boost-lock-div {
          display: flex;
          align-items: center;
          gap: 0.25em;
      }

      .video-manipulator-divider {
          width: 1px;
          height: 1em;
          background: var(--yt-spec-text-primary);
      }

      #video-seek-controls input[type="number"], #video-seek-controls input[type="text"],
      #video-loop-controls input[type="number"], #video-loop-controls input[type="text"] {
          width: 6.75em;
          text-align: center;
      }

      #video-loop-controls-outer-div {
          /* z-index: 9012; */
          z-index: 2;
      }

      #video-seek-controls .video-manipulator-divider,
      #video-loop-controls .video-manipulator-divider,
      #video-display-controls .video-manipulator-divider {
          margin: 0 .25em;
      }

      #video-display-controls .video-manipulator-divider {

      }

      .video-manipulator-sub-item span {
          /* font-size: 1.4em; */
      }

      #video-loop-controls #loop-times-input, #video-loop-controls #measure-rate-input {
          width: 3em;
          margin: 0 .25em;
      }

      .video-manipulator-inner-item .radio-div {
          display: flex;
          align-items: center;
      }

      .video-manipulator-inner-item .radio-div input[type="radio"] {
          margin-top: 0;
      }

      #looping-buttons-outer-div {
          flex-direction: column;
          position: relative;
      }

      #loop-error-holder-outer {
          position: absolute;
          bottom: 0;
          width: 100%;
          height: 0;
          left: 0;
          pointer-events: none;
          /* font-size: 1.4em; */
          transition: opacity 0.5s;
          z-index: 9020;
      }

      #loop-error-holder-inner {
          margin-top: 0.5em;
          position: absolute;
          width: fit-content;
          display: block;
      }

      #loop-error-pre-span {
          background: var(--yt-spec-base-background);
          border: 3px solid var(--video-manipulator-button-color, gray);
          position: absolute;
          padding: 0.25em .5em;
          border-radius: 1em;
          z-index: 1;
          top: -2px;
          left: -2px;
      }

      #loop-error-span {
          /* border: 3px solid transparent; */
          position: relative;
          display: inline;
          top: .25em;
          left: .5em;
          border-radius: 1em;
          z-index: 1;
      }

      #video-controls-show-hide-menu {
          margin-top: 12px;
      }

      #video-controls-show-hide-menu.video-manipulator-outer-div button.inactive:not(.just-pressed) {
          filter: contrast(0);
          box-shadow: inset 0px 0px 0px 1px hsla(0, 0%, 50%, .5);
      }

      #video-controls-show-hide-menu-inner.video-manipulator-inner-item button {
          border-radius: 0.75em;
          border-radius: 0em;
          font-size: .95em;
          padding: 0.2em 1.5em;
          /* border: 1px solid hsla(0, 0%, 0%, .20); */
      }

      #video-controls-show-hide-menu-inner.video-manipulator-inner-item {
          gap: 0.25em;
      }

      #linktree-button {
          all: unset;
          background: #41df5d;
          height: 24px;
          width: 24px;
          border-radius: 20%;
          cursor: pointer;
      }

      #linktree-button svg {
          aspect-ratio: 1;
          padding: 15%;
      }

      #jl-about-div {
          font-size: 14px;
          display: flex;
          align-items: center;
      }

      #jl-about-span {
          margin-right: .5em;
      }

      #jl-about-span a {
          text-decoration: none;
          color: green;
          font-weight: bold;
          letter-spacing: .25px;
      }

      #compressor-control-tip-paragraph {
          display: inline;
      }

      #video-controls-manual {
          font-size: 14px;
      }

      #video-controls-manual h2 {

      }

      #video-controls-manual p {
          margin: 0.5em 1.5em;
      }
      `;

    // Default sections to hide, global variable
    let sectionsToHide = [
        "video-seek-controls-outer-div",
        "video-loop-controls-outer-div",
        "cosmetic-checkboxes-outer-div",
        "compressor-controls-parent-div",
        "video-controls-manual",
        "jl-about-div"
    ];

    // Global stylesheet constant
    let sectionsToHideStyle;

    // Load the saved sections from localStorage
    function loadSectionsState() {
        const storedState = localStorage.getItem("videoSectionsState");
        if (storedState) {
            sectionsToHide = JSON.parse(storedState);
        }
    }

    // Save the sections state to localStorage
    function saveSectionsState() {
        localStorage.setItem("videoSectionsState", JSON.stringify(sectionsToHide));
    }

    // Build the stylesheet based on sectionsToHide
    function buildSectionHiderStylesheet() {
        // Directly use sectionsToHide to create the CSS rules
        const hiddenSections = sectionsToHide
            .map((id) => `#${id}`) // Format the IDs as CSS selectors
            .join(", ");

        // Apply the styles to hide those sections
        sectionsToHideStyle.textContent = `${hiddenSections} { display: none; }`;
    }

    loadSectionsState();

    function createDivider() {
        const divider = document.createElement("div");
        divider.classList.add("video-manipulator-divider");
        return divider;
    }

    function createVideoControlsMasterHolder() {
        videoControlsMasterHolder = document.createElement("div");
        videoControlsMasterHolder.id = "video-controls-master-holder";
        topRow.appendChild(videoControlsMasterHolder);
    }

    function insertAboutDiv() {
        aboutDiv = document.createElement("div");
        aboutDiv.id = "jl-about-div";
        aboutDiv.classList.add("video-manipulator-outer-div");

        const aboutText =
            "This script was created by Jupiter Liar, and is licensed CC-BY-SA. " + "More projects can be found at my ";

        const linkTreeLink = document.createElement("a");
        linkTreeLink.href = "https://linktr.ee/jupiterliar";
        linkTreeLink.textContent = "Linktree";

        const aboutSpan = document.createElement("span");
        aboutSpan.id = "jl-about-span";
        // aboutSpan.textContent = aboutText;

        const aboutTextNode = document.createTextNode(aboutText);
        const periodTextNode = document.createTextNode(".");

        const linktreeButton = document.createElement("button");
        linktreeButton.id = "linktree-button";
        linktreeButton.innerHTML = `
      <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
           viewBox="0 0 80 97.7" style="enable-background:new 0 0 80 97.7;" xml:space="preserve">
     <path d="M0.2,33.1h24.2L7.1,16.7l9.5-9.6L33,23.8V0h14.2v23.8L63.6,7.1l9.5,9.6L55.8,33H80v13.5H55.7l17.3,16.7l-9.5,9.4L40,49.1
        L16.5,72.7L7,63.2l17.3-16.7H0V33.1H0.2z M33.1,65.8h14.2v32H33.1V65.8z">
     </path>
    </svg>
      `;

        linktreeButton.addEventListener("click", () => {
            window.open("https://linktr.ee/jupiterliar", "_blank");
        });

        aboutSpan.appendChild(aboutTextNode);
        aboutSpan.appendChild(linkTreeLink);
        aboutSpan.appendChild(periodTextNode);

        aboutDiv.appendChild(aboutSpan);
        aboutDiv.appendChild(linktreeButton);

        videoControlsMasterHolder.appendChild(aboutDiv);
    }

    function insertVideoControlsShowHideMenu() {
        // Create the video controls show/hide menu
        videoControlsShowHideMenu = document.createElement("div");
        videoControlsShowHideMenu.id = "video-controls-show-hide-menu";
        videoControlsShowHideMenu.classList.add("video-manipulator-outer-div");

        // Append the menu to the body or another container
        topRow.appendChild(videoControlsShowHideMenu);
    }

    // Function to populate the Show/Hide menu
    function populateVideoControlsShowHideMenu() {
        const videoControlsShowHideMenuInner = document.createElement("div");
        videoControlsShowHideMenuInner.id = "video-controls-show-hide-menu-inner";
        videoControlsShowHideMenuInner.classList.add("video-manipulator-inner-item");

        const controlTexts = [
            "Speed Control",
            "Play/Pause Lock",
            "Aspect, Zoom, Flip, & Frame",
            "Jump to Time / Get Current Time",
            "Nice 'n' Accurate Looper",
            "Corners, Overlays, & Chapters",
            "Volume Boost",
            "Manual",
            "About"
        ];

        let dividerNumber = 0;

        // Create buttons for each section
        const sectionIds = [
            "playback-rate-controls-outer",
            "lock-controls-outer",
            "video-display-controls-outer",
            "video-seek-controls-outer-div",
            "video-loop-controls-outer-div",
            "cosmetic-checkboxes-outer-div",
            "compressor-controls-parent-div",
            "video-controls-manual",
            "jl-about-div"
        ];

        sectionIds.forEach((sectionId, index) => {
            const button = document.createElement("button");
            button.textContent = controlTexts[index];

            button.id = sectionId + "-hider-button";
            buttonRefs[button.id] = button;

            // Check if the section is hidden and mark the button as inactive
            if (sectionsToHide.includes(sectionId)) {
                button.classList.add("inactive");
            }

            // Add event listener to toggle visibility of the corresponding section
            button.addEventListener("click", () => {
                if (sectionsToHide.includes(sectionId)) {
                    sectionsToHide = sectionsToHide.filter((id) => id !== sectionId); // Remove from hide list
                    button.classList.remove("inactive"); // Remove inactive class
                } else {
                    sectionsToHide.push(sectionId); // Add to hide list
                    button.classList.add("inactive"); // Add inactive class
                }

                saveSectionsState(); // Save the updated state to localStorage
                buildSectionHiderStylesheet(); // Update the stylesheet
            });

            // Append the button to the menu
            videoControlsShowHideMenuInner.appendChild(button);

            // Divider for visual separation (every 4th button)
            const divider = createDivider();
            dividerNumber += 1;
            divider.id = "divider-number-" + dividerNumber;
            videoControlsShowHideMenuInner.appendChild(divider);
        });

        // Append the final divider style to hide the last divider if needed
        const hideFinalDividerStyle = document.createElement("style");
        hideFinalDividerStyle.textContent = `
        #divider-number-${dividerNumber} {
            display: none;
        }
    `;
        videoControlsShowHideMenuInner.appendChild(hideFinalDividerStyle);
        videoControlsShowHideMenu.appendChild(videoControlsShowHideMenuInner);
    }

    // Default values for the compressor settings, including preGain and finalGain
    const compressorValuesDefault = {
        threshold: 0,
        knee: 3,
        ratio: 20,
        attack: 0, // Fast attack
        release: 0.25,
        preGain: 1, // Default preGain
        finalGain: 1 // Default finalGain
    };

    function findVideo() {
        video = document.querySelector("video");
    }

    let gnrInProgress = false;
    let gnrInQ = false;

    function getNativeRatio() {
        if (gnrInProgress) {
            log("gnrInProgress: " + gnrInProgress);
            gnrInQ = true;
            return;
        } else {
            gnrInProgress = true;
            setTimeout(() => {
                gnrInProgress = false;
            }, 250);
        }
        log("Getting native ratio...");
        findVideo();
        if (!video) {
            setTimeout(() => {
                getNativeRatio();
            }, 1000);
            return;
        }
        try {
            nativeRatio = parseFloat(video.videoWidth / video.videoHeight);
            log("nativeRatio: " + nativeRatio);
        } catch {
            setTimeout(() => {
                getNativeRatio();
            }, 1000);
            return;
        }

        if (gnrInQ) {
            gnrInQ = false;
            setTimeout(() => {
                // gnrInProgress = false;
                getNativeRatio();
            }, 250);
        }
    }

    function findContainerRatio() {
        container = video.closest("#player, #full-bleed-container");
        log("Closest element was:", container);

        containerWidth = container.offsetWidth;
        containerHeight = container.offsetHeight;
        containerRatio = containerWidth / container.offsetHeight;
        // log('Container ratio:', containerRatio);
        log(
            "Container width: " +
                containerWidth +
                "\nContainer height: " +
                containerHeight +
                "\nContainer ratio: " +
                containerRatio
        );
    }

    function parseAspectRatio() {
        log("Parsing aspect ratio:", rawAspectRatio);
        if (!savedAspectRatio) {
            getNativeRatio();
            savedAspectRatio = nativeRatio;
        }
        if (rawAspectRatio === undefined || rawAspectRatio === null) {
            log("Nothing to parse.");
            aspectRatio = savedAspectRatio;
            return;
        }
        if (typeof rawAspectRatio === "string") {
            aspectRatio = rawAspectRatio.includes("/")
                ? parseFloat(rawAspectRatio.split("/")[0]) / parseFloat(rawAspectRatio.split("/")[1])
                : parseFloat(rawAspectRatio);
            log("New aspect ratio:", aspectRatio);
        } else {
            aspectRatio = parseFloat(rawAspectRatio);
        }

        if (isNaN(aspectRatio) || aspectRatio === null || aspectRatio === undefined) {
            console.error("Invalid aspect ratio:", aspectRatio);
            aspectRatio = savedAspectRatio;
            log("Aspect ratio reverted to:", aspectRatio);
            return true;
        }

        log("Parsed aspect ratio: " + aspectRatio);
        savedAspectRatio = aspectRatio;
    }

    // Load the compressor values from localStorage or use the defaults
    let compressorValues = {
        ...compressorValuesDefault
    };

    function loadCompressorValues() {
        // Check if values exist in localStorage
        const savedValues = JSON.parse(localStorage.getItem("compressorValues"));
        log("Saved compressor values: " + savedValues);
        if (savedValues) {
            // Merge saved values with defaults to keep missing ones defaulted
            compressorValues = {
                ...compressorValuesDefault,
                ...savedValues
            };
        } else {
            // If no saved values, use the defaults
            compressorValues = {
                ...compressorValuesDefault
            };
        }
    }

    loadCompressorValues();

    function saveCompressorValues() {
        try {
            // Get the previously saved values from localStorage, or initialize an empty object
            const savedValues = JSON.parse(localStorage.getItem("compressorValues")) || {};

            // Create an object to hold the updated values
            const updatedValues = { ...compressorValues };

            // Compare current values with saved ones and store only the updated ones
            for (const key in compressorValues) {
                if (compressorValues[key] !== savedValues[key]) {
                    updatedValues[key] = compressorValues[key];
                } else {
                    // If no change, ensure the key is still saved
                    if (!savedValues.hasOwnProperty(key)) {
                        updatedValues[key] = compressorValues[key];
                    }
                }
            }

            // If any values were updated, save them to localStorage
            if (Object.keys(updatedValues).length > 0) {
                localStorage.setItem("compressorValues", JSON.stringify(updatedValues));
            }
        } catch (error) {
            console.error("Error saving compressor values to localStorage", error);
        }
    }

    // Example to update compressor values and save
    function updateCompressorSetting(key, value) {
        log("Updating compressor setting: " + key + ", " + value);
        if (compressorValues.hasOwnProperty(key)) {
            log("Saving setting...");
            compressorValues[key] = value;
            saveCompressorValues(); // Save the updated value
        }
    }

    function deleteSavedCompressorValues() {
        try {
            // Remove the compressorValues from localStorage
            localStorage.removeItem("compressorValues");
            log("Compressor values deleted from localStorage.");
        } catch (error) {
            console.error("Error deleting compressor values from localStorage", error);
        }
    }

    // Placeholder function to modify the compressor values
    function modifyCompression(property, value) {
        // log(`Modifying ${property} to ${value}`);
        // Actual logic for modifying the compressor settings goes here
    }

    // Function to create a compressor control
    function createCompressorControl(config, reset) {
        let input;
        let conversionSpan;
        const conversionType = config.conversion;

        // Handle the input population and modification
        let value = compressorValues[config.property ? config.property : config.id] || 0; // Fetch current value

        //     // Apply conversions and modifiers when populating
        //     if (config.conversion) {
        //         value = convertValue(value, config.conversion);
        //     }

        //     if (config.calculationMod) {
        //         value = applyCalculationMod(value, config.calculationMod);
        //     }

        if (config.divideBy1000) {
            value *= 1000; // Multiply by 1000 when populating
        }

        // Function to handle the conversions (dB -> times or dB -> percent)
        function convertValue(value, conversionType) {
            // log('Converting', (config.property ? config.property : config.id),
            // 'with value', value, 'and type', conversionType + '.');
            let calcVal = value;
            const scaleFactor = 1;

            if (conversionType === "times") {
                calcVal = Math.pow(2, value / 6); // dB to multiplier (times)
            } else if (conversionType === "percent") {
                calcVal = Math.pow(2, value / 6) * 100; // dB to percentage representation
            }

            log(config);

            if (config.calculationMod || config.hasOwnProperty("calculationMod")) {
                log("A calculation modification is present.");
                calcVal = applyCalculationMod(calcVal, config.calculationMod); // Apply modifier
            }

            return calcVal; // No conversion if not specified
        }

        function convertToDB(value) {
            return 6 * Math.log2(value);
            // return value; // No conversion if not specified
        }

        // Function to handle calculation modifiers dynamically
        function applyCalculationMod(value, mod) {
            log("Modifying calculations with inputs", value, "and", mod + ".");
            // Assume calculationMod contains simple expressions like '- 100' or any other formula
            const [operator, num] = mod.split(" ");
            if (operator === "-" && num) {
                return value - parseFloat(num);
            }
            log("Modified value equals", value + ".");
            return value; // If no valid modifier is found, return value unchanged
        }

        function getConvertedValue(newValue) {
            if (config.conversion) {
                newValue = convertValue(newValue, config.conversion); // Convert value based on config
            }

            if (config.divideBy1000) {
                newValue = newValue / 1000; // Divide by 1000 when sending back the value
                // modifyCompression((config.property ? config.property : config.id), newValue);
                // // Update the compressor with the modified value
            } else {
                // modifyCompression((config.property ? config.property : config.id), value);
            }

            return newValue;
        }

        function adjustStepSize() {
            log("Handling varying step sizes...");
            const value = parseFloat(input.value);
            let step = config.stepSize;
            let nextValue = value;
            log("Step equals " + step + ".");
            for (let range of JSON.parse(config.stepRanges)) {
                log("Step ranges parsed as" + JSON.stringify(JSON.parse(config.stepRanges)) + ".");
                if (value >= range.range[0] && value < range.range[1]) {
                    step = range.step;
                    log("Step should be " + step + ".");
                    // Adjust the value based on the current step
                    nextValue = Math.round(value / step) * step; // Round to the nearest step increment
                    break;
                }
            }
            // Set the next value programmatically
            // input.value = nextValue;

            input.step = step; // Dynamically adjust the step size for the input
        }

        if (!reset) {
            const controlDiv = document.createElement("div");
            controlDiv.classList.add("compressor-control-div");
            controlDiv.id = `${config.id}-control-div`;

            const label = document.createElement("label");
            label.setAttribute("for", `${config.id}-input`);
            label.textContent = config.label;

            input = document.createElement("input");
            input.type = "number";
            input.id = `${config.id}-input`;
            // input.value = compressorValues[config.id] || 0;
            input.min = config.minValue || 0;
            input.max = config.maxValue || 100;
            input.step = config.stepSize;

            const postLabel = document.createElement("span");
            postLabel.textContent = ` ${config.postLabel}`;

            const conversionDiv = document.createElement("div");
            conversionDiv.classList.add("conversion-div");

            const secondPostLabel = document.createElement("span");
            secondPostLabel.textContent = ` ${config.secondPostLabel || ""}`;

            const openParenthesisSpan = document.createElement("span");
            openParenthesisSpan.textContent = "(";

            conversionSpan = document.createElement("span");
            conversionSpan.classList.add("conversion-span");

            // Populate the input box with the modified value
            if (conversionType === "times") {
                input.value = convertToDB(value);
            } else {
                input.value = value;
            }

            // Handle variable step size logic for ratio, attack, release
            if (config.stepSize === "variable") {
                log("Setting up varying step sizes...");
                adjustStepSize();
                input.addEventListener("input", function () {
                    adjustStepSize();
                });
            }

            // Handle the input change event dynamically
            input.addEventListener("input", function () {
                let newValue = parseFloat(input.value);
                log("New value: " + newValue);
                const minLimit = config.minLim;

                if (minLimit && newValue < minLimit) {
                    newValue = minLimit;
                    input.value = minLimit;
                }

                let retainValue = newValue;

                //                 if (config.divideBy1000) {
                //                     retainValue = retainValue / 1000; // Multiply by 1000 when populating
                //                 }

                conversionSpan.textContent = getConvertedValue(newValue).toFixed(2);

                if (config.link) {
                    const linkedElement = document.getElementById(`${config.link}-input`);
                    linkedElement.value = newValue;
                    const linkedConversion = document.querySelector(
                        `#${config.link}-control-div .conversion-div .conversion-span`
                    );
                    if (linkedConversion) {
                        log("Linked conversion found.");
                        linkedConversion.textContent = getConvertedValue(newValue).toFixed(2);
                    } else {
                        log("No linked conversion found.");
                    }
                }

                let passValue = getConvertedValue(newValue);

                if (config.id === "threshold") {
                    log("Converting threshold...");
                    passValue = Math.pow(2, newValue / 6);
                }

                log("Pass value: " + passValue);

                changeCompressorValue(config.property ? config.property : config.id, passValue, newValue);
                // changeCompressorValue((config.property ? config.property : config.id), passValue, newValue);

                setTimeout(function () {
                    changeCompressorValue(config.property ? config.property : config.id, passValue, newValue);
                    // changeCompressorValue((config.property ? config.property : config.id), passValue, newValue);
                    updateCompressorSetting(config.id, config.saveRaw ? retainValue : passValue);
                }, 0);
            });

            // Tip logic for showing the relevant tip on hover
            controlDiv.addEventListener("mouseover", function () {
                // const tipDiv = document.getElementById("compressor-control-tip-div");
                compressorControlTipParagraph.innerHTML = config.tip;

                compressorControlTipDiv.style.display = "block";
                compressorControlTipDivBG.style.display = "block";

                // Get the bounding rectangle of the paragraph
                const paragraphRect = compressorControlTipParagraph.getBoundingClientRect();

                // Set the width and height of the div background to match the paragraph size
                compressorControlTipDivBG.style.width = `${paragraphRect.width}px`;
                compressorControlTipDivBG.style.height = `${paragraphRect.height}px`;

                log(
                    `Updated size of background div: Width = ${paragraphRect.width}px, ` +
                        `Height = ${paragraphRect.height}px`
                );
            });

            controlDiv.addEventListener("mouseout", function () {
                // const tipDiv = document.getElementById("compressor-control-tip-div");
                if (compressorTipDivTesting) {
                    return;
                }
                compressorControlTipParagraph.innerHTML = "";
                compressorControlTipDiv.style.display = "none";
                compressorControlTipDivBG.style.display = "none";
            });

            if (config.label) {
                controlDiv.appendChild(label);
            }
            controlDiv.appendChild(input);
            controlDiv.appendChild(postLabel);
            if (config.conversion) {
                conversionDiv.appendChild(openParenthesisSpan);
                conversionDiv.appendChild(conversionSpan);
                conversionDiv.appendChild(secondPostLabel);
                controlDiv.appendChild(conversionDiv);
                if (conversionType === "times") {
                    conversionSpan.textContent = value.toFixed(2);
                } else {
                    conversionSpan.textContent = getConvertedValue(value).toFixed(2);
                }
            }
            return controlDiv;
        } else {
            const controlDiv = document.getElementById(`${config.id}-control-div`);
            input = document.getElementById(`${config.id}-input`);

            // Populate the input box with the modified value
            if (conversionType === "times") {
                input.value = convertToDB(value);
            } else {
                input.value = value;
            }

            conversionSpan = controlDiv.querySelector(".conversion-span");
            if (conversionSpan) {
                if (conversionType === "times") {
                    conversionSpan.textContent = value.toFixed(2);
                } else {
                    conversionSpan.textContent = getConvertedValue(value).toFixed(2);
                }
            }

            // Handle variable step size logic for ratio, attack, release
            if (config.stepSize === "variable") {
                log("Setting up varying step sizes...");
                adjustStepSize();
                input.addEventListener("input", function () {
                    adjustStepSize();
                });
            }

            deleteSavedCompressorValues();
        }
    }

    let compressorControlTipDiv;
    let compressorControlTipParagraph;
    let compressorControlTipDivBG;

    // Function to insert all the compressor controls
    function insertCompressorControls() {
        // const emptySpanner = insertEmptySpanner();
        // videoControlsMasterHolder.appendChild(emptySpanner);

        compressorControlsParentDiv = document.createElement("div");
        compressorControlsParentDiv.id = "compressor-controls-parent-div";
        compressorControlsParentDiv.classList.add("video-manipulator-outer-div");

        const compressorSimpleControlsDiv = document.createElement("div");
        compressorSimpleControlsDiv.id = "compressor-simple-controls-div";
        compressorSimpleControlsDiv.classList.add("video-manipulator-inner-item");

        const compressorBoostButton = document.createElement("button");
        compressorBoostButton.id = "compressor-boost-button";
        compressorBoostButton.classList.add("video-manipulator-sub-item");
        compressorBoostButton.textContent = "Boost Volume";
        buttonRefs[compressorBoostButton.id] = compressorBoostButton;

        compressorSimpleControlsDiv.appendChild(compressorBoostButton);

        const simpleControlsConfig = [
            {
                id: "simpleBoost",
                property: "preGain",
                link: "preGain",
                postLabel: "dB",
                conversion: "times",
                secondPostLabel: "x original volume)",
                stepSize: 0.5,
                minValue: -96,
                maxValue: 96,
                tip: `Measured in dB. A conversion is offered for those who can't think in dB.`
            }
        ];

        // Loop through each control configuration and add it to the parent div
        simpleControlsConfig.forEach((config) => {
            const controlDiv = createCompressorControl(config);
            compressorSimpleControlsDiv.appendChild(controlDiv);
        });

        const boostLockDiv = document.createElement("div");
        boostLockDiv.id = "boost-lock-div";

        const boostLockCheckbox = document.createElement("input");
        boostLockCheckbox.id = "boost-lock-checkbox";
        boostLockCheckbox.type = "checkbox";

        const boostLockLabel = document.createElement("label");
        boostLockLabel.textContent = "Boost all videos";
        boostLockLabel.htmlFor = "boost-lock-checkbox";

        boostLockDiv.appendChild(boostLockLabel);
        boostLockDiv.appendChild(boostLockCheckbox);

        // Retrieve the stored value from localStorage and update the checkbox state if it's set
        boostLockState = JSON.parse(localStorage.getItem("boostLockState") || "false");
        if (boostLockState) {
            boostLockCheckbox.checked = true;
        }

        // Add an event listener to save the checkbox state to localStorage when clicked
        boostLockCheckbox.addEventListener("change", function () {
            localStorage.setItem("boostLockState", boostLockCheckbox.checked);
        });

        compressorSimpleControlsDiv.appendChild(boostLockDiv);

        const showFullCompressorControlsButton = document.createElement("button");
        showFullCompressorControlsButton.id = "show-full-compressor-controls";
        showFullCompressorControlsButton.classList.add("video-manipulator-sub-item");
        buttonRefs[showFullCompressorControlsButton.id] = showFullCompressorControlsButton;

        // Create the outer span
        const spanDownArrow = document.createElement("span");
        spanDownArrow.classList.add("down-expand-arrow");
        spanDownArrow.textContent = "▼";

        // Create the text "Expert"
        const textNode = document.createTextNode("Expert");

        // Create the second span
        const spanUpArrow = document.createElement("span");
        spanUpArrow.classList.add("down-expand-arrow");
        spanUpArrow.textContent = "▼";

        // Append all the elements to the button
        showFullCompressorControlsButton.appendChild(spanDownArrow);
        showFullCompressorControlsButton.appendChild(textNode);
        showFullCompressorControlsButton.appendChild(spanUpArrow);

        compressorSimpleControlsDiv.appendChild(showFullCompressorControlsButton);

        compressorControlsParentDiv.appendChild(compressorSimpleControlsDiv);

        const compressorControlsGroupDiv = document.createElement("div");
        compressorControlsGroupDiv.id = "compressor-controls-group-div";

        compressorControlTipDiv = document.createElement("div");
        compressorControlTipDiv.id = "compressor-control-tip-div";
        compressorControlTipDiv.style.display = "none";

        compressorControlTipParagraph = document.createElement("p");
        compressorControlTipParagraph.id = "compressor-control-tip-paragraph";

        compressorControlTipDivBG = document.createElement("div");
        compressorControlTipDivBG.id = "compressor-control-tip-div-background";
        compressorControlTipDivBG.style.display = "none";

        const compressorControlTipParent = document.createElement("div");
        compressorControlTipParent.id = "compressor-control-tip-parent";

        const controlsConfig = [
            {
                id: "preGain",
                label: "Input Boost",
                link: "simpleBoost",
                postLabel: "dB",
                conversion: "times",
                secondPostLabel: "x original volume)",
                stepSize: 0.5,
                minValue: -96,
                maxValue: 96,
                tip: `Measured in dB. A conversion is offered for those who can't think in dB.`
            },
            {
                id: "threshold",
                label: "Threshold",
                postLabel: "dB",
                conversion: "percent",
                secondPostLabel: "% of max volume)",
                stepSize: 0.5,
                maxValue: 0,
                minValue: -100,
                saveRaw: true,
                tip: `Measured in dB. 0 is the ceiling — as loud as the sound can go. Lower values come below the ceiling.<br>
                If you put this too high, the compressor really won't do much. Going above the ceiling is not recommended.<br>
            A conversion is offered for those who can't think in dB.`
            },
            {
                id: "knee",
                label: "Knee",
                postLabel: "dB",
                conversion: "percent",
                secondPostLabel: "% over the threshold)",
                calculationMod: `- 100`,
                stepSize: 1,
                minValue: 0,
                maxValue: 40,
                saveRaw: true,
                tip: `Bigger values are subtler, but if it gets too big, the compressor won't compress much.<br>
            Knee comes before threshold is reached with this compressor.<br>
            A conversion is offered for those who can't think in dB.`
            },
            {
                id: "ratio",
                label: "Ratio",
                postLabel: " : 1",
                stepSize: "variable",
                stepRanges: `
                [
                    { "range": [0, 4], "step": 0.5 },
                    { "range": [4, 8], "step": 1 },
                    { "range": [8, 12], "step": 2 },
                    { "range": [12, 24], "step": 4 }
                ]
            `,
                minValue: 0,
                maxValue: 20,
                minLim: 1,
                tip: `The higher the value, the harder it compresses. A value of 1 does nothing at all. 20 is as high as it can go.`
            },
            {
                id: "attack",
                label: "Attack",
                postLabel: "ms",
                stepSize: "variable",
                stepRanges: `
                [
                    { "range": [0, 1], "step": 0.1 },
                    { "range": [1, 5], "step": 0.5 },
                    { "range": [5, 10], "step": 1 },
                    { "range": [10, 50], "step": 5 },
                    { "range": [50, 100], "step": 10 },
                    { "range": [100, 500], "step": 50 },
                    { "range": [500, 2000], "step": 100 }
                ]
            `,
                minValue: 0,
                maxValue: 1000,
                divideBy1000: true,
                tip: `The lower the value, the faster it lowers the volume. 1000 is as slow as it goes.`
            },
            {
                id: "release",
                label: "Release",
                postLabel: "ms",
                stepSize: "variable",
                stepRanges: `
                [
                    { "range": [0, 100], "step": 10 },
                    { "range": [100, 250], "step": 25 },
                    { "range": [250, 500], "step": 50 },
                    { "range": [500, 2000], "step": 100 }
                ]
            `,
                minValue: 0,
                maxValue: 1000,
                divideBy1000: true,
                tip: `Find a sweet spot. Values below 100 may sound crummy.`
            }
        ];

        // Loop through each control configuration and add it to the parent div
        controlsConfig.forEach((config) => {
            const controlDiv = createCompressorControl(config);
            compressorControlsGroupDiv.appendChild(controlDiv);
        });

        const compressorResetButton = document.createElement("button");
        compressorResetButton.id = "compressor-reset-button";
        compressorResetButton.textContent = "Reset";
        buttonRefs[compressorResetButton.id] = compressorResetButton;

        compressorControlsGroupDiv.appendChild(compressorResetButton);

        compressorResetButton.addEventListener("click", () => {
            compressorValues = {
                ...compressorValuesDefault
            };

            simpleControlsConfig.forEach((config) => {
                const controlDiv = createCompressorControl(config, true);
            });

            controlsConfig.forEach((config) => {
                const controlDiv = createCompressorControl(config, true);
            });

            setCompressorValues();
        });

        const compressorAdvancedControlsDiv = document.createElement("div");
        compressorAdvancedControlsDiv.id = "compressor-advanced-controls-div";

        const compressorAdvancedControlsContainerDiv = document.createElement("div");
        compressorAdvancedControlsContainerDiv.id = "compressor-advanced-controls-container-div";

        compressorAdvancedControlsDiv.appendChild(compressorControlsGroupDiv);
        compressorControlTipDiv.appendChild(compressorControlTipParagraph);
        compressorControlTipParent.appendChild(compressorControlTipDivBG);
        compressorControlTipParent.appendChild(compressorControlTipDiv);
        compressorAdvancedControlsDiv.appendChild(compressorControlTipParent);

        // Declare the observer
        let closeFullCompressorControlsObserver;

        // Function to connect the observer
        function connectCloseFullCompressorControlsObserver() {
            closeFullCompressorControlsObserver = (event) => {
                // Check if the click is outside of the button or the controls container
                if (
                    !showFullCompressorControlsButton.contains(event.target) &&
                    !compressorAdvancedControlsContainerDiv.contains(event.target)
                ) {
                    // Remove the 'active' class to close the controls
                    showFullCompressorControlsButton.classList.remove("active");
                    compressorAdvancedControlsContainerDiv.classList.remove("active");
                    // Disconnect the observer once it's no longer needed
                    document.removeEventListener("click", closeFullCompressorControlsObserver);
                }
            };

            // Add event listener to the document for clicks
            document.addEventListener("click", closeFullCompressorControlsObserver);
        }

        showFullCompressorControlsButton.addEventListener("click", () => {
            if (showFullCompressorControlsButton.classList.contains("active")) {
                showFullCompressorControlsButton.classList.remove("active");
                compressorAdvancedControlsContainerDiv.classList.remove("active");
            } else {
                showFullCompressorControlsButton.classList.add("active");
                compressorAdvancedControlsContainerDiv.classList.add("active");
                connectCloseFullCompressorControlsObserver();
            }
        });

        compressorBoostButton.addEventListener("click", () => {
            if (compressorBoostButton.classList.contains("active")) {
                compressorBoostButton.classList.remove("active");
                compressorControlsParentDiv.classList.remove("active");
                boostLockState = false;
                localStorage.setItem("boostLockState", boostLockState);
                boostLockCheckbox.checked = boostLockState;
                disconnectCompressor();
            } else {
                compressorBoostButton.classList.add("active");
                compressorControlsParentDiv.classList.add("active");
                initiateCompressor();
            }
            recalculateForElement(compressorSimpleControlsDiv);
        });

        if (boostLockState) {
            compressorBoostButton.classList.add("active");
            compressorControlsParentDiv.classList.add("active");
            initiateCompressor();
        }

        compressorAdvancedControlsContainerDiv.appendChild(compressorAdvancedControlsDiv);

        compressorControlsParentDiv.appendChild(compressorAdvancedControlsContainerDiv);

        // Append the controls to the body or another container element

        videoControlsMasterHolder.appendChild(compressorControlsParentDiv);
    }

    function hideOverlays() {
        log("Hiding overlays...");
        overlayHiderStyle.textContent = `
    .ytp-chrome-top-buttons, .ytp-ce-element, .ytp-paid-content-overlay, .videowall-endscreen, .ytp-suggested-action, .annotation {
      display: none  !important;
    }
    `;
        hideOverlaysVar = true;

        localStorage.setItem("hideOverlaysState", "true");
    }

    function showOverlays() {
        log("Showing overlays...");
        overlayHiderStyle.textContent = `
    .ytp-chrome-top-buttons, .ytp-ce-element, .ytp-paid-content-overlay, .videowall-endscreen, .ytp-suggested-action, .annotation {
      /* display: none  !important; */
    }
    `;
        hideOverlaysVar = false;

        localStorage.setItem("hideOverlaysState", "false");
    }

    function insertOverlayHider() {
        overlayHiderStyle = document.createElement("style");
        overlayHiderStyle.id = "overlay-hider-style";

        head.appendChild(overlayHiderStyle);

        const storedState = JSON.parse(localStorage.getItem("hideOverlaysState")) || false;

        if (storedState === true) {
            hideOverlays();
        } else {
            showOverlays();
        }
    }

    insertOverlayHider();

    // Function to create and insert stylesheets
    function insertStylesheets() {
        insertCustomStyles();

        flipRotateStyle = document.createElement("style");
        flipRotateStyle.id = "flip-rotate-style";
        head.appendChild(flipRotateStyle);

        videoZoomStyle = document.createElement("style");
        videoZoomStyle.id = "video-zoom-style";
        head.appendChild(videoZoomStyle);

        overrideObjectFitStyle = document.createElement("style");
        overrideObjectFitStyle.id = "override-object-fit-style";
        head.appendChild(overrideObjectFitStyle);

        additionalStyles.id = "video-display-controls-style";
        additionalStyles.textContent += generalStyles;
        head.appendChild(additionalStyles);

        sectionsToHideStyle = document.createElement("style");
        sectionsToHideStyle.id = "sections-to-hide-style";
        document.head.appendChild(sectionsToHideStyle);
        buildSectionHiderStylesheet();
    }

    // Function to create and insert the control panel
    function insertControlPanel() {
        log("The insertControlPanel function is running.");
        // const existingControls = document.querySelector("#video-display-controls-outer");
        // if (existingControls) {
        //     return;
        // }

        const buttons = [
            {
                id: "aspect-4-3",
                class: "aspect",
                text: "4/3",
                titleText: "Converts the aspect ratio to 4 by 3.",
                onClick: () => handleAspectRatio("4/3", "aspect-4-3")
            },
            {
                id: "aspect-16-9",
                class: "aspect",
                text: "16/9",
                titleText: "Converts the aspect ratio to 16 by 9.",
                onClick: () => handleAspectRatio("16/9", "aspect-16-9")
            },
            {
                id: "aspect-2pt35",
                class: "aspect",
                text: "2.35",
                titleText: "Converts the aspect ratio to 2.35 to 1.",
                onClick: () => handleAspectRatio("2.35", "aspect-2pt35")
            },
            {
                id: "aspect-custom",
                class: "aspect",
                text: "Custom",
                titleText:
                    "Rescale the video to the custom aspect ration in the input box. Must be pressed to apply each time.",
                onClick: () => handleCustomAspect("aspect-custom")
            },
            {
                id: "zoom",
                class: "zoom",
                text: "Zoom",
                titleText: "Zooms the video by a specified amount.",
                onClick: () => handleZoom("zoom")
            },
            {
                id: "mirror",
                class: "orientation",
                text: "Mirror",
                titleText: "Mirrors the video horizontally.",
                onClick: () => handleMirror("mirror")
            },
            {
                id: "flip",
                class: "orientation",
                text: "Flip",
                titleText: "Flips the video vertically.",
                onClick: () => handleFlip("flip")
            },
            {
                id: "rotate-180",
                class: "orientation",
                text: "180°",
                titleText: "Rotates the video 180°.",
                onClick: () => handleRotate180("rotate-180")
            },
            {
                id: "resize-frame",
                class: "frame-resize",
                text: "Resize Frame",
                titleText: "Resize the video container to match the selected aspect ratio. May still have some bugs.",
                onClick: () => handleFrameResize("resize-frame")
            },
            {
                id: "reset",
                class: "reset",
                text: "Reset",
                titleText:
                    "Resets all flips, mirrors, rotations, aspect ratios, and zooms. " +
                    "Leaves the input boxes as they are so values can be easily recalled.",
                onClick: () => handleReset("reset")
            }
        ];

        // Conditionally add debug buttons
        if (extraDebugButtons) {
            buttons.push(
                {
                    id: "scale-and-top",
                    class: "scale-and-top",
                    text: "Scale and Top",
                    titleText: "A debugging button that immediately runs the scaleAndTop function.",
                    onClick: () => scaleAndTop()
                },
                {
                    id: "scale-and-top-direct",
                    class: "scale-and-top-direct",
                    text: "Scale and Top (direct)",
                    titleText: "A debugging button that immediately runs the scaleAndTop function, direct set to true.",
                    onClick: () => scaleAndTop(true)
                },
                {
                    id: "recalculate-after-pseudo-elements",
                    class: "recalculate-after-pseudo-elements",
                    text: "Recalculate After Pseudo Elements",
                    titleText: "Recalculates size for the after pseudo elements.",
                    onClick: () => recalculateAllAfterPseudoElements()
                },
                {
                    id: "test-difference",
                    class: "test-difference",
                    text: "Test Difference",
                    titleText: "A debugging button that runs testDimensionDif.",
                    onClick: () => testDimensionDif()
                }
            );
        }

        controlPanelOuter = document.createElement("div");
        controlPanelOuter.id = "video-display-controls-outer";
        controlPanelOuter.classList.add("video-manipulator-outer-div");

        controlPanel = document.createElement("div");
        controlPanel.id = "video-display-controls";
        controlPanel.classList.add("video-manipulator-inner-item");

        buttons.forEach((button) => {
            const btn = document.createElement("button");
            btn.id = button.id;
            btn.classList.add(button.class);
            btn.textContent = button.text;
            btn.addEventListener("click", button.onClick);
            if (button.titleText) {
                btn.title = button.titleText;
            }

            log("Creating button " + btn.id + "...");

            // Save the button reference to the buttonRefs object
            buttonRefs[button.id] = btn;

            controlPanel.appendChild(btn);

            if (button.id === "aspect-custom") {
                const customContainer = document.createElement("div");
                customContainer.id = "custom-container";
                customContainer.classList.add("video-manipulator-sub-item");

                const customInput = document.createElement("input");
                customInput.type = "text";
                customInput.id = "aspect-custom-input";
                customInput.title =
                    "This value is not reset when the reset button is pressed, to make the value easy to apply again.";
                customInput.placeholder = "e.g., 4/3";

                customContainer.appendChild(btn);
                customContainer.appendChild(customInput);
                controlPanel.appendChild(customContainer);

                const divider = createDivider();
                controlPanel.appendChild(divider);

                // Add event listener to detect changes in input value
                customInput.addEventListener("input", () => {
                    // Add blinking class to button
                    buttonRefs["aspect-custom"].classList.add("blinking");

                    // Optionally, you can remove the class after a certain duration to stop blinking
                    clearTimeout(customBlink);
                    customBlink = setTimeout(() => {
                        buttonRefs["aspect-custom"].classList.remove("blinking");
                    }, 5000); // Adjust duration based on your preference
                });
            }

            if (button.id === "resize-frame") {
                const resizeAutomaticallyText = "Resize the frame automatically when each new video loads.";

                resizeDefaultCheckbox = document.createElement("input");
                resizeDefaultCheckbox.type = "checkbox";
                resizeDefaultCheckbox.id = "resize-by-default-checkbox";
                resizeDefaultCheckbox.title = resizeAutomaticallyText;

                const resizeDefaultLabel = document.createElement("label");
                resizeDefaultLabel.textContent = "Auto Resize";
                resizeDefaultLabel.htmlFor = "resize-by-default-checkbox";
                resizeDefaultLabel.title = resizeAutomaticallyText;

                const resizeContainer = document.createElement("div");
                resizeContainer.classList.add("video-manipulator-sub-item");
                resizeContainer.id = "resize-container";

                resizeContainer.appendChild(btn);
                resizeContainer.appendChild(resizeDefaultLabel);
                resizeContainer.appendChild(resizeDefaultCheckbox);

                controlPanel.appendChild(resizeContainer);

                const divider = createDivider();
                controlPanel.appendChild(divider);

                resizeByDefault = JSON.parse(localStorage.getItem("resizeByDefault")) || false;

                if (resizeByDefault) {
                    setTimeout(() => {
                        // buttonRefs["resize-frame"].classList.add("active");
                        resizeDefaultCheckbox.checked = true;
                        frameIsRescaled = true;
                        handleFrameResize("resize-frame");
                    }, 0);
                }

                // Add event listener to save checkbox state to localStorage
                resizeDefaultCheckbox.addEventListener("change", () => {
                    resizeByDefault = resizeDefaultCheckbox.checked;
                    localStorage.setItem("resizeByDefault", JSON.stringify(resizeByDefault));
                });
            }

            if (button.id === "zoom") {
                const zoomContainer = document.createElement("div");
                zoomContainer.id = "zoom-container";
                zoomContainer.classList.add("video-manipulator-sub-item");

                // Add zoom control
                zoomInput = document.createElement("input");
                zoomInput.type = "number";
                zoomInput.step = 0.01; // Increment step for numeric input
                zoomInput.value = 1; // Default value
                zoomInput.id = "zoom-input"; // Assign an ID for styling or JavaScript access
                zoomInput.title = "Click the Zoom button every time you wish to resize.";

                zoomContainer.appendChild(btn);
                zoomContainer.appendChild(zoomInput);
                controlPanel.appendChild(zoomContainer);

                const divider = createDivider();
                controlPanel.appendChild(divider);

                // Add event listener for zoomInput changes
                zoomInput.addEventListener("input", () => {
                    handleZoom("zoom"); // Call your function with the zoom value
                });
            }

            if (button.id === "rotate-180") {
                const divider = createDivider();
                controlPanel.appendChild(divider);
            }
        });

        controlPanelOuter.appendChild(controlPanel);

        log("controlPanelOuter:", controlPanelOuter);

        videoControlsMasterHolder.appendChild(controlPanelOuter);

        log("Control panel inserted.");
        // Call the function to insert custom styles before inserting the control panel
    }

    function insertEmptySpanner(line) {
        const emptySpanner = document.createElement("div");
        emptySpanner.classList.add("empty-spanner");
        if (line) {
            emptySpanner.classList.add("line");
        }
        return emptySpanner;
    }

    // Function to create and insert the playback rate control panel
    function insertPlaybackRateControls() {
        const existingControls = document.querySelector("#playback-rate-controls-outer");
        if (existingControls) {
            return;
        }

        playbackRateOuter = document.createElement("div");
        playbackRateOuter.id = "playback-rate-controls-outer";
        playbackRateOuter.classList.add("video-manipulator-outer-div");

        const playbackRateControls = document.createElement("div");
        playbackRateControls.id = "playback-rate-controls";
        playbackRateControls.classList.add("video-manipulator-inner-item");

        const label = document.createElement("label");
        label.textContent = "Speed:";

        const input = document.createElement("input");
        input.type = "number";
        input.step = "0.05";
        input.min = "0";
        input.id = "playback-rate-input";
        input.value = "1.00"; // Default value until actual playbackRate is detected
        input.addEventListener("input", handleRateChange);
        input.addEventListener("focus", handleRateChange);

        const playLockTitleText =
            "Prevents speed from being changed, whether by YouTube, an extension, or another script.";

        const checkbox = document.createElement("input");
        checkbox.type = "checkbox";
        checkbox.id = "lock-rate-checkbox";
        checkbox.addEventListener("change", handleLockToggle);
        checkbox.title = playLockTitleText;

        speedLockCheckbox = checkbox;

        const checkboxLabel = document.createElement("label");
        checkboxLabel.htmlFor = "lock-rate-checkbox";
        checkboxLabel.textContent = "Lock now";
        checkboxLabel.title = playLockTitleText;

        const divider = createDivider();

        const foreverLockTitleText = "Automatically sets the speed of videos when they load.";

        const foreverCheckbox = document.createElement("input");
        foreverCheckbox.type = "checkbox";
        foreverCheckbox.id = "lock-forever-checkbox";
        foreverCheckbox.title = foreverLockTitleText;
        foreverCheckbox.addEventListener("change", handleLockToggle);

        const foreverCheckboxLabel = document.createElement("label");
        foreverCheckboxLabel.htmlFor = "lock-forever-checkbox";
        foreverCheckboxLabel.textContent = "Lock forever";
        foreverCheckboxLabel.title = foreverLockTitleText;

        foreverLockCheckbox = foreverCheckbox;

        const savedSpeedLockActive = JSON.parse(localStorage.getItem("savedSpeedLockActive")) || false;
        const savedSpeedLockRate = parseFloat(localStorage.getItem("savedSpeedLockRate")) || 1.0;

        if (savedSpeedLockActive) {
            foreverCheckbox.checked = true;
            checkbox.checked = true;
            playbackRateLocked = true;
            playbackRateForeverLocked = true;
            lockRate = savedSpeedLockRate;
            input.value = lockRate;
            handleRateChange(null, savedSpeedLockRate);
        }

        playbackRateControls.appendChild(label);
        playbackRateControls.appendChild(input);
        playbackRateControls.appendChild(checkboxLabel);
        playbackRateControls.appendChild(checkbox);
        playbackRateControls.appendChild(divider);
        playbackRateControls.appendChild(foreverCheckboxLabel);
        playbackRateControls.appendChild(foreverCheckbox);

        playbackRateOuter.appendChild(playbackRateControls);

        videoControlsMasterHolder.appendChild(playbackRateOuter);

        monitorPlaybackRate();
        log("Playback rate control panel inserted.");
    }

    let monitorPlaybackRateIsRunning = false;
    let rateChanging = false;
    let videoFound = false;

    // Monitor changes in the video playback rate
    function monitorPlaybackRate() {
        if (!monitorPlaybackRateIsRunning) {
            log("monitorPlaybackRate is running...");
            monitorPlaybackRateIsRunning = true;
        }
        const checkPlaybackRate = () => {
            findVideo();
            const input = document.getElementById("playback-rate-input");
            if (!video) {
                log("No video found.");
            } else {
                if (!videoFound) {
                    log("Video found.");
                    videoFound = true;
                }
            }
            if (playbackRateLocked) {
                // Lock is on, force the playback rate to lockRate
                if (video.playbackRate !== lockRate) {
                    log("Oh no you don't! Changing playback rate back...");
                    video.playbackRate = lockRate;
                }
            } else {
                // Update the input value if lock is not active
                if (!rateChanging && document.activeElement !== input) {
                    if (input.value !== video.playbackRate.toFixed(2)) {
                        log("Playback rate measured as " + video.playbackRate.toFixed(2) + ".");
                        input.value = video.playbackRate.toFixed(2);
                    }
                } else if ((rateChanging || document.activeElement == input) && !isNaN(input.value)) {
                    if (parseFloat(input.value) !== parseFloat(video.playbackRate)) {
                        rateChanging = true;
                        log(
                            "Video playback rate: " +
                                video.playbackRate +
                                "\nInput value: " +
                                input.value +
                                "\nDon't change that value while I'm changing it."
                        );
                        video.playbackRate = input.value;
                        // log("Don't change that value while I'm changing it.");
                        rateChanging = false;
                    }
                } else {
                    rateChanging = false;
                }
            }
        };

        // Run the check periodically
        setInterval(checkPlaybackRate, 100);
    }

    function insertLockControls() {
        // const existingControls = document.querySelector("#lock-controls-outer");
        // if (existingControls) {
        //     return;
        // }

        // Create a parent div for the play and pause lock buttons
        lockControlsOuterDiv = document.createElement("div");
        lockControlsOuterDiv.id = "lock-controls-outer";
        lockControlsOuterDiv.classList.add("video-manipulator-outer-div");

        const lockControlsDiv = document.createElement("div");
        lockControlsDiv.id = "lock-controls";
        lockControlsDiv.classList.add("video-manipulator-inner-item");

        // Create the Play Lock button
        const playLockButton = document.createElement("button");
        playLockButton.id = "playLockButton";
        playLockButton.classList.add("lock-button");
        // Create the play triangle span
        const playTriangleSpan = document.createElement("span");
        playTriangleSpan.textContent = "►"; // Unicode for the play triangle

        // Create the lock span
        const lockSpan = document.createElement("span");
        lockSpan.classList.add("lock-span");
        lockSpan.textContent = "🔒"; // Unicode for the lock icon

        // Append both elements to the playLockButton
        playLockButton.appendChild(playTriangleSpan);
        playLockButton.appendChild(lockSpan);

        playLockButton.title = "Play Lock - Prevents the video from getting unintentionally paused.";

        // Create the Pause Lock button
        const pauseLockButton = document.createElement("button");
        pauseLockButton.id = "pauseLockButton";
        pauseLockButton.classList.add("lock-button");
        // Create the pause bars span
        const pauseBarsSpan = document.createElement("span");
        pauseBarsSpan.textContent = "⏸"; // Unicode for pause symbol

        // Create the lock span
        const lockSpan2 = document.createElement("span");
        lockSpan2.classList.add("lock-span");
        lockSpan2.textContent = "🔒"; // Unicode for the lock icon

        // Append both elements to the pauseLockButton
        pauseLockButton.appendChild(pauseBarsSpan);
        pauseLockButton.appendChild(lockSpan2);
        pauseLockButton.title = "Pause Lock - Prevents the video from getting unintentionally unpaused.";

        // Append buttons to the parent div
        lockControlsDiv.appendChild(playLockButton);
        lockControlsDiv.appendChild(pauseLockButton);
        lockControlsOuterDiv.appendChild(lockControlsDiv);

        buttonRefs["play-lock-button"] = playLockButton;
        buttonRefs["pause-lock-button"] = pauseLockButton;

        videoControlsMasterHolder.appendChild(lockControlsOuterDiv);

        actions = topRow.querySelector("#actions");
        log("Lock controls inserted.");
        // Now add the behavior for the lock buttons
        addLockButtonListeners(playLockButton, pauseLockButton);
    }

    let playPauseListenersAdded = false;

    let intervalId = null;

    function addPlayPauseListeners() {
        log("addPlayPauseListeners...");

        function printLockStates() {
            log("playLock:", playLock, ", pauseLock", pauseLock);
        }

        printLockStates();

        // Listen for play and pause events
        findVideo();

        // Function to start or stop the interval
        function manageInterval() {
            // Start interval if either lock is active and interval isn't already running
            if ((playLock || pauseLock) && !intervalId) {
                log("Starting interval check...");
                intervalId = setInterval(() => {
                    if (playLock && video.paused) {
                        log("Interval fallback: Play lock is active, playing video...");
                        video.play();
                    } else if (pauseLock && !video.paused) {
                        log("Interval fallback: Pause lock is active, pausing video...");
                        video.pause();
                    } else if (!playLock && !pauseLock) {
                        // If neither lock is active, stop the interval
                        log("Neither lock is active, stopping interval...");
                        clearInterval(intervalId);
                        intervalId = null;
                    }
                }, 1000);
            }

            // Stop the interval if both locks are off and the interval is running
            else if (!playLock && !pauseLock && intervalId) {
                log("Stopping interval as both locks are inactive...");
                clearInterval(intervalId);
                intervalId = null;
            }
        }

        if (video) {
            manageInterval();

            if (playPauseListenersAdded) {
                return;
            }

            playPauseListenersAdded = true;
            log("Adding play/pause event listeners...");

            video.addEventListener("play", () => {
                log("Video playing...");
                printLockStates();
                if (pauseLock) {
                    video.pause(); // Pause the video if pauseLock is active
                }
                log("Video is playing.");
            });

            video.addEventListener("pause", () => {
                log("Video paused...");
                printLockStates();
                if (playLock) {
                    video.play(); // Play the video if playLock is active
                }
                log("Video is paused.");
            });
        }
    }

    function addLockButtonListeners(playLockButton, pauseLockButton) {
        function updateButtonStates() {
            if (playLock) {
                playLockButton.classList.add("active");
                pauseLockButton.classList.remove("active");
            } else if (pauseLock) {
                pauseLockButton.classList.add("active");
                playLockButton.classList.remove("active");
            } else {
                playLockButton.classList.remove("active");
                pauseLockButton.classList.remove("active");
            }
        }

        playLockButton.addEventListener("click", () => {
            findVideo();
            if (!video) {
                log("No video found.");
                return; // Exit if no video
            }
            log("Video found.");

            if (pauseLock) pauseLock = false; // Disable pause lock if active
            playLock = !playLock;
            if (playLock) {
                video.play();
            }
            updateButtonStates();
            addPlayPauseListeners();
        });

        pauseLockButton.addEventListener("click", () => {
            findVideo();
            if (!video) {
                log("No video found.");
                return; // Exit if no video
            }
            log("Video found.");

            if (playLock) playLock = false; // Disable play lock if active
            pauseLock = !pauseLock;
            if (pauseLock) {
                video.pause();
            }
            updateButtonStates();
            addPlayPauseListeners();
        });
    }

    // Event handler for changing the playback rate from the input box
    function handleRateChange(event, newRate) {
        rateChanging = true;

        if (newRate === undefined) {
            newRate = parseFloat(event.target.value);
        }

        if (playbackRateForeverLocked) {
            localStorage.setItem("savedSpeedLockRate", newRate);
        }

        findVideo();
        if (!isNaN(newRate) && video && input.value !== video.playbackRate.toFixed(2)) {
            if (playbackRateLocked) {
                lockRate = newRate;
                video.playbackRate = lockRate;
            } else {
                video.playbackRate = newRate;
            }
            log("Playback rate changed to:", newRate);
        }
    }

    // Event handler for toggling the lock
    function handleLockToggle(event) {
        const input = document.getElementById("playback-rate-input");
        findVideo();
        if (event.target.id === "lock-rate-checkbox") {
            log("Lock rate checkbox toggled");
            if (event.target.checked) {
                playbackRateLocked = true;
                lockRate = parseFloat(input.value);
                log("Playback rate locked at:", lockRate);
            } else {
                playbackRateLocked = false;
                foreverLockCheckbox.checked = false;
                lockRate = null;
                log("Playback rate unlocked");
            }
        } else if (event.target.id === "lock-forever-checkbox") {
            log("Lock forever checkbox toggled");
            if (event.target.checked) {
                playbackRateLocked = true;
                speedLockCheckbox.checked = true;
                localStorage.setItem("savedSpeedLockActive", true);
                lockRate = parseFloat(input.value);
                localStorage.setItem("savedSpeedLockRate", lockRate);
                log("Playback rate locked at:", lockRate);
                playbackRateForeverLocked = true;
            } else {
                localStorage.setItem("savedSpeedLockActive", false);
                playbackRateForeverLocked = false;
            }
        }
    }

    // New function to handle active class toggling
    function handleActiveClass(btn, className, isCustomOrZoom) {
        log("Button: " + btn);

        const clickedButton = buttonRefs[btn];

        log("Clicked button: " + clickedButton);

        let buttonsWithClass;

        // if (className)

        // Get all buttons with the matching class from the buttonRefs object
        buttonsWithClass = Object.values(buttonRefs).filter((button) => button.classList.contains(className));

        // Remove the 'active' class from all buttons except the passed one
        buttonsWithClass.forEach((button) => {
            if (button !== clickedButton && button.classList.contains("active")) {
                button.classList.remove("active");
            }
        });

        if (isCustomOrZoom) {
            if (!clickedButton.classList.contains("active")) {
                clickedButton.classList.add("active");
            } else if (lastCustomRepeated) {
                log("Last custom value was repeated. Making button inactive.");
                // setTimeout(() => {
                lastCustom = undefined;
                // }, 50);
                lastCustomRepeated = false;
                lastCustomReset = true;
                clickedButton.classList.remove("active");
                return true;
            }
            return false;
        }

        // Check if the passed button already has the 'active' class
        if (clickedButton.classList.contains("active")) {
            // If it has the 'active' class, remove it
            clickedButton.classList.remove("active");
            return true;
        } else {
            // Otherwise, add the 'active' class to the passed button
            clickedButton.classList.add("active");
            return false;
        }
    }

    function resetFlipRotate() {
        flipRotateStyle.textContent = "";
    }

    function resetAspect() {
        videoZoomStyle.textContent = "";
        tipAspectStyle.textContent = "";
        rawAspectRatio = undefined;
        aspectRatio = undefined;
        getNativeRatio();
        savedAspectRatio = nativeRatio;
        frameAspectStyle.textContent = "";
        frameIsRescaled = false;
    }

    // Event handler functions
    function handleFlip(btn) {
        const active = handleActiveClass(btn, "orientation");

        if (active) {
            resetFlipRotate();
        } else {
            flipRotateStyle.textContent = `
            video, .ytp-tooltip:not(.ytp-text-detail) .ytp-tooltip-bg {
                transform: scale(1, -1);
            }
        `;
        }
        log("Flip button pressed");
    }

    function handleMirror(btn) {
        const active = handleActiveClass(btn, "orientation");

        if (active) {
            resetFlipRotate();
        } else {
            flipRotateStyle.textContent = `
            video, .ytp-tooltip:not(.ytp-text-detail) .ytp-tooltip-bg {
                transform: scale(-1, 1);
            }
        `;
        }
        log("Mirror button pressed");
    }

    function handleRotate180(btn) {
        const active = handleActiveClass(btn, "orientation");

        if (active) {
            resetFlipRotate();
        } else {
            flipRotateStyle.textContent = `
            video, .ytp-tooltip:not(.ytp-text-detail) .ytp-tooltip-bg {
                rotate: 180deg;
            }
        `;
        }
        log("180° button pressed");
    }

    // let handleRepeat = 0;

    let scaleAndTopInProgress = false;
    let scaleAndTopQueued = false;
    let isStretched;

    function compareRatios() {
        findVideo();
        getNativeRatio();
        if (aspectRatio === nativeRatio || aspectRatio === null) {
            isStretched = false;
        } else {
            isStretched = true;
        }
    }

    function scaleAndTop(direct) {
        if (scaleAndTopInProgress) {
            scaleAndTopQueued = true;
            log("Scale and top already in progress.");
            return;
        } else {
            scaleAndTopInProgress = true;
            setTimeout(() => {
                scaleAndTopInProgress = false;
            }, 250);
        }

        compareRatios();

        if (noScaleAndTop) {
            log("scaleAndTop will not be run.");
            return;
        }

        // if (!scaleAndTopInProgress) {
        //     scaleAndTopInProgress = true;
        //     setTimeout(() => {
        //         scaleAndTopInProgress = false;
        //     }, 225);
        //     // return;
        // } else if (!scaleAndTopQueued) {
        //     scaleAndTopQueued = true;
        //     log("Queuing scaleAndTop.");
        //     return;
        // } else {
        //     log("Stopping scaleAndTop.");
        //     return;
        // }

        log("Running scaleAndTop...");

        let scaleDiff;
        let newWidth;
        let newHeight;
        let newTop;
        let newLeft;
        let isWiderThanContainer;
        let useThisRatio;

        findVideo();

        if (!video) {
            log("scaleAndTop found no video.");
            return;
        }

        if (!aspectRatio) {
            // Get the native aspect ratio of the video
            getNativeRatio();
            useThisRatio = nativeRatio;
            // aspectRatio = nativeRatio;
            // savedAspectRatio = aspectRatio;
        } else {
            useThisRatio = aspectRatio;
        }

        log("useThisRatio:", useThisRatio);
        if (isNaN(useThisRatio) || isNaN(nativeRatio)) {
            setTimeout(() => {
                scaleAndTop();
            }, 250);
            return;
        } else {
            log("useThisRatio, checked again:", useThisRatio);
        }

        findContainerRatio();

        // Determine whether to scale by width or height
        isWiderThanContainer = useThisRatio > containerRatio;
        if (isWiderThanContainer) {
            log("Video will be wider than container.");
            scaleDiff = useThisRatio - containerRatio;
            log("Scale difference:", scaleDiff);

            newWidth = containerWidth;
            newHeight = containerWidth / useThisRatio;
            newTop = (containerHeight - newHeight) / 2;
            newLeft = 0;
        } else {
            log("Video will not be wider than container.");
            newHeight = containerHeight;
            newWidth = containerHeight * useThisRatio;
            log("newHeight: " + newHeight + ", newWidth: " + newWidth);
            newTop = 0;
            newLeft = (containerWidth - newWidth) / 2;
        }

        // newHeight = Math.round(newHeight);
        // newWidth = Math.round(newWidth);

        const scaleX = (aspectRatio / nativeRatio).toFixed(8);

        reportVideoDimensions();

        isStretched = aspectRatio != nativeRatio;

        // if (direct) {
        // setTimeout(() => {
        ignoreChange = true;
        log("scaleAndTop will scale the video directly.");
        video.style.height = newHeight + "px";
        video.style.width = newWidth + "px";
        video.style.top = newTop + "px";
        video.style.left = newLeft + "px";
        if (isStretched) {
            video.style.objectFit = "unset";
        } else {
            video.style.objectFit = "";
        }

        // reportVideoDimensions();
        setTimeout(() => {
            ignoreChange = false;
        }, 250);
        // reportVideoDimensions();

        // }, 250);
        // } else {
        //     videoZoomStyle.textContent = `
        //     video {
        //         width: ${newWidth}px !important;
        //         height: ${newHeight}px !important;
        //         object-fit: unset !important;
        //         top: ${newTop}px !important;
        //         left: ${newLeft}px !important;
        //         scale: ${zoom};
        //     }
        //     `;
        // }

        reportVideoDimensions();

        tipAspectStyle.textContent = `
        .ytp-tooltip:not(.ytp-text-detail) .ytp-tooltip-bg {
            scale: ${isWiderThanContainer ? `${zoom} ${zoom / scaleX}` : `${scaleX * zoom} ${zoom}`};
        }
        `;

        log(`Aspect ratio set to ${aspectRatio}, scaleX: ${scaleX}`);

        if (scaleAndTopQueued) {
            scaleAndTopQueued = false;
            setTimeout(() => {
                scaleAndTop();
            }, 250);
        }
        startTestDifInterval();
    }

    let testDifInterval = null; // Global variable to store the interval ID
    const testDifIntervalTime = 250; // Interval time set to 250ms
    const testDifIntervalMaxIterations = 16;
    let testDifIntervalIterations = 0;

    function testDimensionDif() {
        findContainerRatio();
        const heightDif = Math.abs(parseFloat(video.style.height) - containerHeight);
        const widthDif = Math.abs(parseFloat(video.style.width) - containerWidth);
        const topDif = Math.abs(parseFloat(video.style.top) - (heightDif / 2));
        log("heightDif:", heightDif, "\nwidthDif:", widthDif, "\ntopDif:", topDif);
        if ((heightDif >= 1 && widthDif >= 1) || topDif >= 1) {
            log("Discrepancy detected. Rescaling...");
            scaleAndTop();
        }
        testDifIntervalIterations += 1;
        if (testDifIntervalIterations >= testDifIntervalMaxIterations) {
            stopTestDifInterval();
        }
    }

    function startTestDifInterval() {
        if (testDifInterval === null) {
            // Start the interval only if it's not already running
            testDifInterval = setInterval(testDimensionDif, testDifIntervalTime);
            log("testDifInterval started.");
        } else {
            log("testDifInterval is already running. Resetting iterations;");
            testDifIntervalIterations = 0;
        }
    }

    function stopTestDifInterval() {
        if (testDifInterval !== null) {
            clearInterval(testDifInterval);
            testDifInterval = null;
            testDifIntervalIterations = 0;
            log("testDifInterval stopped");
        }
    }

    function reportVideoDimensions() {
        const videoWidth = video.offsetWidth;
        const videoHeight = video.offsetHeight;
        log(`Video height: ${videoHeight}\nVideo width: ${videoWidth}`);
        log("videoZoomStyle:\n" + videoZoomStyle.textContent);
    }

    let handleAspectActive = false;
    let switchAspectOff = false;
    let ignoreChange = false;

    function handleAspectRatio(value, btn, isCustomOrZoom) {
        if (btn) {
            log("Handling aspect ratio. Button pressed was " + btn + ".");
            if (btn != "aspect-custom") {
                log("Button was not aspect-custom.");
                lastCustom = undefined;
                lastCustomRepeated = false;
            }
        } else {
            log("Handling aspect ration. No button was pressed.");
        }
        reportVideoDimensions();
        let failed;
        if (ignoreChange) {
            log("This change will be ignored.");
            // ignoreChange = false;
            // setTimeout(() => {
            //     ignoreChange = false;
            // }, 250);
            return;
        }
        // if (!frameIsRescaled && aspectRatio === undefined) {
        //     if (handleAspectActive === false) {
        //         log('Nothing to do. Resetting aspect style.');
        //         resetAspect();
        //         return;
        //     } else {
        //         log('Not resetting aspect style yet.');
        //         switchAspectOff = true;
        //     }
        // } else {
        //     handleAspectActive = true;
        //     switchAspectOff = false;
        // }

        findVideo();

        if (!video) {
            return;
        }

        log("zoom:", zoom);

        reportVideoDimensions();

        let active = false;

        // handleRepeat += 1;

        if (btn) {
            noAspect = false;
            if (isCustomOrZoom === "zoom") {
                handleActiveClass(btn, "zoom", true);
            } else {
                active = handleActiveClass(btn, "aspect", isCustomOrZoom);
            }
        }

        getNativeRatio();

        // reportVideoDimensions();

        if (value) {
            log("A value of " + value + " was specified to handleAspectRatio.");
            rawAspectRatio = value;

            log("value:", value);
            failed = parseAspectRatio();

            log("aspectRatio: ", aspectRatio);

            if (isCustomOrZoom === "custom" && aspectRatio === value) {
                handleActiveClass(btn, "aspect");
                noAspect = true;
            }
        } else {
            log("Aspect ratio will be native ratio.");
            aspectRatio = nativeRatio;
            noAspect = true;
            // savedAspectRatio = aspectRatio;
        }

        // reportVideoDimensions();

        // log("Aspect ratio: ", unparsedAspectRatio, "\nParsed:", aspectRatio);

        if (active) {
            log("Button was active. Unsetting aspect ratio...");
            aspectRatio = nativeRatio;
            savedAspectRatio = nativeRatio;
            noAspect = true;
            // scaleAndTop();
            // setTimeout(() => {
            //   scaleAndTop();
            // }, 250);
        }

        if (aspectRatio === nativeRatio) {
            noAspect = true;
        }

        // reportVideoDimensions();

        findContainerRatio();

        log(`Aspect ratio is ${aspectRatio}. Contaner ratio is ${containerRatio}.`);

        rescaleFrame();
        if (active) {
            scaleAndTop();
        }

        // reportVideoDimensions();

        // if (isNaN(zoom)) {
        //     log("Defaulting zoom to 1.");
        //     zoom = 1;
        // }

        // if (!video) {
        //     console.error("Video element not found");
        //     return;
        // }

        // reportVideoDimensions();

        // Get the aspect ratio of the container
        // const container = video.parentElement;
        // findContainerRatio();

        // Get the native aspect ratio of the video
        // getNativeRatio();
        // log("Native ratio:", nativeRatio);

        // reportVideoDimensions();

        // rescaleFrame();

        // reportVideoDimensions();

        if (!isNaN(zoom)) {
            videoZoomStyle.textContent = `
            video {
                scale: ${zoom};
            }

            .ytp-tooltip:not(.ytp-text-detail) .ytp-tooltip-bg {
                /* background-size: ${zoom}; */
            }
            `;
        }

        // Check if aspectRatio is undefined
        if (noAspect) {
            log("No aspect, and so...");
            // findVideo();

            // reportVideoDimensions();

            tipAspectStyle.textContent = "";

            // video {
            //     top: ${adjustedTop}px !important;
            // }

            // reportVideoDimensions();

            //             setTimeout(() => {
            //                 findContainerRatio();

            //                 const videoWidth = video.offsetWidth;
            //                 const videoHeight = video.offsetHeight;

            //                 const adjustedTop = (containerHeight - videoHeight) / 2;

            //                 log(
            //                     "videoHeight: " +
            //                         videoHeight +
            //                         "\ncontainerHeight: " +
            //                         containerHeight +
            //                         "\nadjustedTop: " +
            //                         adjustedTop
            //                 );

            //                 video.style.top = adjustedTop + "px";
            //             }, 0);

            // ignoreChange = true;
            // scaleAndTop(true);
        } else {
            noScaleAndTop = false;
            scaleAndTop();

            if (isCustomOrZoom === "custom" && btn && !failed) {
                handleActiveClass(btn, "aspect", true);
            }
        }

        reportVideoDimensions();

        // rescaleFrame();

        // if (handleRepeat != 2) {
        //   handleAspectRatio(value, btn, isCustomOrZoom);
        // } else {
        //   handleRepeat = 0;
        // }

        // if (switchAspectOff) {
        //     handleAspectActive = false;
        // }
    }

    function handleCustomAspect(btn) {
        const customValue = document.getElementById("aspect-custom-input").value;
        if (lastCustomReset) {
            lastCustom = undefined;
            lastCustomReset = false;
        }
        if (lastCustom === customValue) {
            lastCustomRepeated = true;
        } else {
            lastCustomRepeated = false;
        }
        let buttonItself = document.querySelector(`button#${btn}`);
        buttonItself.classList.remove("blinking");
        log("Custom value:", customValue);
        if (customValue === null || !customValue) {
            return;
        }
        handleAspectRatio(customValue, btn, "custom");
        lastCustom = customValue;
    }

    let zoomDebounceTimeout;

    function handleZoom(btn) {
        // log('Zooming...');
        clearTimeout(zoomDebounceTimeout);
        zoomDebounceTimeout = setTimeout(() => {
            if (zoom !== zoomInput.value) {
                isZoomed = true;
            } else {
                isZoomed = !isZoomed;
            }
            if (isZoomed) {
                zoom = zoomInput.value;
            } else {
                zoom = 1;
            }
            handleAspectRatio(aspectRatio, btn, "zoom");

            if (zoom === 1) {
                buttonRefs[btn].classList.remove("active");
            }
        }, 250);
    }

    function handleReset(btn) {
        resetFlipRotate();
        resetAspect();
        lastCustomRepeated = false;
        lastCustom = undefined;
        lastCustomReset = undefined;

        frameIsRescaled = false;

        const relevantButtons = controlPanel.querySelectorAll("button");

        relevantButtons.forEach((button) => {
            button.classList.remove("active");
        });

        zoom = 1;
        // zoomInput.value = 1;
        setTimeout(() => {
            scaleAndTop(true);
        }, 250);

        // noScaleAndTop = true;

        log("Reset button pressed");
    }

    function handleFrameResize(btn) {
        handleActiveClass(btn, "frame-resize");

        let direct;

        const isActive = buttonRefs[btn].classList.contains("active");
        if (isActive) {
            frameIsRescaled = true;
            rescaleFrame();
            direct = false;
        } else {
            frameIsRescaled = false;
            frameAspectStyle.textContent = "";
            direct = true;
        }
        setTimeout(() => {
            handleAspectRatio(aspectRatio);
            noScaleAndTop = false;
            setTimeout(() => {
                scaleAndTop(true);
            }, 250);
        }, 25);

        setTimeout(() => {
            scaleAndTop();
        }, 500);
    }

    let rescaleInProgress = false;
    let rescaleInQ = false;

    function rescaleFrame() {
        if (rescaleInProgress) {
            rescaleInQ = true;
            log("Rescale already in progress.");
            return;
        } else {
            rescaleInProgress = true;
            setTimeout(() => {
                rescaleInProgress = false;
            }, 250);
        }
        // return;
        log("Rescaling frame...");

        findVideo();

        if (!video) {
            setTimeout(() => {
                rescaleFrame();
            }, 1000);
            return;
        }

        if (!frameIsRescaled) {
            frameAspectStyle.textContent = "";
            log("Frame will not be rescaled.");
            return;
        } else {
            log("Frame will be rescaled.");
        }

        let useThisRatio;

        if (!aspectRatio) {
            getNativeRatio();

            useThisRatio = parseFloat(nativeRatio);
            // frameAspectStyle.textContent = "";
        } else {
            // parseAspectRatio();
            useThisRatio = aspectRatio;
        }

        if (isNaN(useThisRatio)) {
            setTimeout(() => {
                rescaleFrame();
            }, 1000);
            return;
        }

        log("useThisRatio: " + useThisRatio);

        if (frameIsRescaled) {
            frameAspectStyle.textContent = `
        ytd-watch-flexy[full-bleed-player]:not([fullscreen]) #full-bleed-container.ytd-watch-flexy,
        ytd-watch-flexy[default-layout] #player,
        ytd-watch-flexy[full-bleed-player]:not([fullscreen]) #full-bleed-container.ytd-watch-flexy #container,
        ytd-watch-flexy[full-bleed-player]:not([fullscreen]) #full-bleed-container.ytd-watch-flexy #container .html5-video-player
        {
            /* aspect-ratio: ${useThisRatio * 1.0011}; */
            aspect-ratio: ${useThisRatio};
            /* max-height: calc(100vh - 169px); */
            max-height: calc(100vh - 64px);
        }

        ytd-watch-flexy[full-bleed-player]:not([fullscreen]) #full-bleed-container.ytd-watch-flexy #ytd-player,
        ytd-watch-flexy[full-bleed-player]:not([fullscreen]) #full-bleed-container.ytd-watch-flexy #player-container {
          /* max-height: calc(100vh - 169px) !important; */
        }

        ytd-watch-flexy:not([full-bleed-player]):not([fullscreen]) #player {
          margin: auto;
        }

        ytd-watch-flexy[full-bleed-player]:not([fullscreen]) #full-bleed-container.ytd-watch-flexy {
            height: unset;
            /* max-height: unset; */
        }

        ytd-watch-flexy[full-bleed-player]:not([fullscreen]) #full-bleed-container.ytd-watch-flexy .html5-video-container {
            height: 100%;
        }

        ytd-watch-flexy[full-bleed-player]:not([fullscreen]) #full-bleed-container.ytd-watch-flexy video {
            /* transform-origin: top; */
            /* top: unset !important; */
            /* max-height: 100%; */
            /* max-width: 100%; */
            /* object-fit: unset; */
        }

        ytd-watch-flexy[default-layout] #player #player-container-outer,
        ytd-watch-flexy[default-layout] #player #player-container-outer #player-container-inner,
        ytd-watch-flexy[default-layout] #player #player-container-outer #player-container-inner .html5-video-container {
            width: 100%;
            height: 100%;
            padding-top: 0;
        }

        ytd-watch-flexy[default-layout] #player video {
            /* height: 100% !important; */
            /* width: 100% !important; */
            /* top: unset !important; */
            /* object-fit: contain; */
        }

        ytd-watch-flexy[default-layout] #player .html5-video-container,
        ytd-watch-flexy[full-bleed-player]:not([fullscreen]) #full-bleed-container.ytd-watch-flexy .html5-video-container {
            /display: flex;
            /align-items: center;
        }

        ytd-watch-flexy[full-bleed-player]:not([fullscreen]) #full-bleed-container.ytd-watch-flexy video {
            // height: 100% !important;
            // width: auto !important;
            /* position: relative; */
            transform-origin: center;
            /* margin: auto; */
            /* left: unset !important; */
            /* right: unset !important; */
            /* position: relative; */

        }
        `;
        }
        if (rescaleInQ) {
            rescaleInQ = false;
            setTimeout(() => {
                rescaleFrame();
            }, 250);
        }
    }

    let retryTimeout = null;

    // Function to get the most common background color from buttons in #top-row
    function getMostCommonButtonColor() {
        log("Finding most common button color...");

        function findColor() {
            // const buttons = document.querySelectorAll('#top-row button:not(#video-display-controls button)');
            const buttons = topRow.querySelectorAll("#actions button");
            if (buttons.length < 3) {
                // log(`Found ${buttons.length} buttons, retrying in 1 second...`);
                if (!retryTimeout) {
                    retryTimeout = setTimeout(() => {
                        retryTimeout = null;
                        findColor();
                    }, 1000);
                }
                return;
            }

            const colorCount = {};
            let mostCommonColor = "";
            let maxCount = 0;

            buttons.forEach((button) => {
                const color = window.getComputedStyle(button).backgroundColor;
                log("Button background color:", color);
                if (colorCount[color]) {
                    colorCount[color]++;
                } else {
                    colorCount[color] = 1;
                }

                if (colorCount[color] > maxCount) {
                    maxCount = colorCount[color];
                    mostCommonColor = color;
                }
            });

            log("Most common color found:", mostCommonColor);
            applyButtonColor(mostCommonColor);
        }

        findColor();
    }

    // Function to apply the most common color to the custom buttons
    function applyButtonColor(color) {
        const customStyles = additionalStyles;
        if (customStyles) {
            customStyles.textContent += `
            :root {
                --video-manipulator-button-color: ${color};
            }

            .video-manipulator-inner-item button, button.video-manipulator-inner-item {
                background-color: var(--video-manipulator-button-color);
            }
        `;
            log("Applied most common color to custom buttons:", color);
        } else {
            console.warn("video-display-controls stylesheet not found");
        }
    }

    // Function to insert custom styles
    function insertCustomStyles() {
        log("Inserting custom styles...");
        const mostCommonColor = getMostCommonButtonColor();
        const customStyles = additionalStyles;
        if (customStyles) {
            customStyles.textContent += `
                #video-display-controls button {
                    background-color: ${mostCommonColor};
                }
            `;
            log("Custom styles inserted.");
        } else {
            console.warn("video-display-controls stylesheet not found");
        }
    }

    function appendSquareCornersStyle() {
        squareCornersStyle = document.createElement("style");
        squareCornersStyle.id = "square-corners-style";

        head.appendChild(squareCornersStyle);

        log("Appending square corners style...");

        squareCorners = JSON.parse(localStorage.getItem("squareCorners") || false);

        log("squareCorners:", squareCorners);

        makeCornersSquareOrNot();
    }

    appendSquareCornersStyle();

    function makeCornersSquareOrNot() {
        if (squareCorners) {
            squareCornersStyle.textContent = `
            #player-api.round, ytd-player {
              border-radius: unset !important;
            }
            `;
        } else {
            squareCornersStyle.textContent = "";
        }
    }

    let cosmeticCheckboxesDiv;

    function insertCosmeticControls() {
        function insertSquareCornerControl() {
            cosmeticCheckboxesDiv = document.createElement("div");
            cosmeticCheckboxesDiv.id = "cosmetic-checkboxes-div";
            cosmeticCheckboxesDiv.classList.add("video-manipulator-inner-item");

            cosmeticCheckboxesOuterDiv = document.createElement("div");
            cosmeticCheckboxesOuterDiv.id = "cosmetic-checkboxes-outer-div";
            cosmeticCheckboxesOuterDiv.classList.add("video-manipulator-outer-div");

            const squareCornersInnerDiv = document.createElement("div");
            squareCornersInnerDiv.id = "square-corners-inner-div";
            squareCornersInnerDiv.classList.add("video-manipulator-sub-item");
            squareCornersInnerDiv.title = "Give the video normal square corners, because all pixels matter.";

            const squareCornersCheckbox = document.createElement("input");
            squareCornersCheckbox.type = "checkbox";
            squareCornersCheckbox.id = "square-corners-checkbox";

            const squareCornersCheckboxLabel = document.createElement("label");
            squareCornersCheckboxLabel.htmlFor = "square-corners-checkbox";
            squareCornersCheckboxLabel.textContent = "Square Corners";

            squareCornersInnerDiv.appendChild(squareCornersCheckboxLabel);
            squareCornersInnerDiv.appendChild(squareCornersCheckbox);

            cosmeticCheckboxesDiv.appendChild(squareCornersInnerDiv);

            cosmeticCheckboxesOuterDiv.appendChild(cosmeticCheckboxesDiv);

            videoControlsMasterHolder.appendChild(cosmeticCheckboxesOuterDiv);

            squareCorners = JSON.parse(localStorage.getItem("squareCorners") || false);
            log("squareCorners:", squareCorners);
            squareCornersCheckbox.checked = squareCorners;
            makeCornersSquareOrNot();

            squareCornersCheckbox.addEventListener("change", () => {
                squareCorners = squareCornersCheckbox.checked;
                localStorage.setItem("squareCorners", squareCorners);
                makeCornersSquareOrNot();
            });
        }

        function insertOverlayButton() {
            const existingControls = document.querySelector("#overlay-button-outer");
            if (existingControls) {
                return;
            }

            // const overlayButtonDiv = document.createElement("div");
            // overlayButtonDiv.id = "overlay-button-outer";
            // overlayButtonDiv.classList.add("video-manipulator-outer-div");

            // const overlayButton = document.createElement("button");
            // overlayButton.id = "overlay-button";
            // overlayButton.classList.add("video-manipulator-inner-item");
            // overlayButton.textContent = "Show Overlays";
            // overlayButton.title = 'Show or hide all video overlays, depending.'

            const overlayButtonInner = document.createElement("div");
            overlayButtonInner.id = "overlay-button-inner";
            overlayButtonInner.classList.add("video-manipulator-sub-item");
            // overlayButtonInner.textContent = "Show Overlays";
            overlayButtonInner.title = "Show or hide all video overlays, including title cards and links.";

            const overlayCheckbox = document.createElement("input");
            overlayCheckbox.id = "overlay-checkbox";
            overlayCheckbox.type = "checkbox";

            const overlayCheckboxLabel = document.createElement("label");
            overlayCheckboxLabel.htmlFor = "overlay-checkbox";
            overlayCheckboxLabel.textContent = "Hide Overlays";

            overlayButtonInner.appendChild(overlayCheckboxLabel);
            overlayButtonInner.appendChild(overlayCheckbox);

            // log('Attempting to insert overlay button...');
            // overlayButtonDiv.appendChild(overlayButtonInner);

            // if (controlPanelOuter) {
            //     controlPanelOuter.after(overlayButtonDiv);
            //     log("Overlay button inserted.");
            // } else {
            //     console.warn("controlPanelOuter element not found");
            // }

            const divider = createDivider();

            cosmeticCheckboxesDiv.appendChild(divider);

            cosmeticCheckboxesDiv.appendChild(overlayButtonInner);

            log("hideOverlaysVar:", hideOverlaysVar);

            if (hideOverlaysVar) {
                overlayCheckbox.checked = true;
            } else {
                overlayCheckbox.checked = false;
            }

            overlayCheckbox.addEventListener("change", () => {
                hideOverlaysVar = !overlayCheckbox.checked;
                log("Overlay checkbox has been clicked...");
                if (hideOverlaysVar) {
                    showOverlays();
                } else {
                    hideOverlays();
                }
            });
        }

        function insertChapterMover() {
            const chapterMoverInner = document.createElement("div");
            chapterMoverInner.id = "chapter-mover-inner";
            chapterMoverInner.classList.add("video-manipulator-sub-item");
            chapterMoverInner.title =
                "Move the chapter selector from the description to a higher, more accessible location.";

            const moveChapterSelectorLabel = document.createElement("label");
            moveChapterSelectorLabel.htmlFor = "move-chapter-selector-checkbox";
            moveChapterSelectorLabel.textContent = "Move Chapter Selector";

            const moveChapterSelectorCheckbox = document.createElement("input");
            moveChapterSelectorCheckbox.id = "move-chapter-selector-checkbox";
            moveChapterSelectorCheckbox.type = "checkbox";

            const chapterMoverRadios = document.createElement("div");
            chapterMoverRadios.id = "chapter-mover-radios";
            chapterMoverRadios.classList.add("radio-div");

            const moveChaptersLowRadio = document.createElement("input");
            moveChaptersLowRadio.type = "radio";
            moveChaptersLowRadio.name = "move-chapters-group";
            moveChaptersLowRadio.id = "move-chapters-low-radio";
            moveChaptersLowRadio.disabled = true;
            const moveChaptersLowLabel = document.createElement("label");
            moveChaptersLowLabel.htmlFor = "move-chapters-low-radio";
            moveChaptersLowLabel.textContent = "Low";

            const moveChaptersMiddleRadio = document.createElement("input");
            moveChaptersMiddleRadio.type = "radio";
            moveChaptersMiddleRadio.name = "move-chapters-group";
            moveChaptersMiddleRadio.id = "move-chapters-middle-radio";
            moveChaptersMiddleRadio.disabled = true;
            const moveChaptersMiddleLabel = document.createElement("label");
            moveChaptersMiddleLabel.htmlFor = "move-chapters-middle-radio";
            moveChaptersMiddleLabel.textContent = "Middle";

            const moveChaptersHighRadio = document.createElement("input");
            moveChaptersHighRadio.type = "radio";
            moveChaptersHighRadio.name = "move-chapters-group";
            moveChaptersHighRadio.id = "move-chapters-high-radio";
            moveChaptersHighRadio.disabled = true;
            const moveChaptersHighLabel = document.createElement("label");
            moveChaptersHighLabel.htmlFor = "move-chapters-high-radio";
            moveChaptersHighLabel.textContent = "High";

            chapterMoverRadios.appendChild(moveChaptersLowRadio);
            chapterMoverRadios.appendChild(moveChaptersLowLabel);

            chapterMoverRadios.appendChild(moveChaptersMiddleRadio);
            chapterMoverRadios.appendChild(moveChaptersMiddleLabel);

            chapterMoverRadios.appendChild(moveChaptersHighRadio);
            chapterMoverRadios.appendChild(moveChaptersHighLabel);

            chapterMoverInner.appendChild(moveChapterSelectorLabel);
            chapterMoverInner.appendChild(moveChapterSelectorCheckbox);
            chapterMoverInner.appendChild(chapterMoverRadios);

            const divider = createDivider();

            cosmeticCheckboxesDiv.appendChild(divider);

            cosmeticCheckboxesDiv.appendChild(chapterMoverInner);

            // Function to enable or disable chapter radio buttons
            function toggleChapterRadios(arg) {
                const radios = [moveChaptersLowRadio, moveChaptersMiddleRadio, moveChaptersHighRadio];

                // Enable or disable based on the argument
                if (arg === "enable") {
                    radios.forEach((radio) => (radio.disabled = false));
                } else if (arg === "disable") {
                    radios.forEach((radio) => (radio.disabled = true));
                }
            }

            // Retrieve and set values from localStorage
            const savedChapterMoving = localStorage.getItem("chapterMoving");
            const savedChapterPosition = localStorage.getItem("chapterPosition");

            // Set chapterMoving state and update checkbox
            if (savedChapterMoving !== null) {
                chapterMoving = JSON.parse(savedChapterMoving); // Parse as boolean
                moveChapterSelectorCheckbox.checked = chapterMoving; // Set the checkbox
            }

            // Enable/Disable radios based on chapterMoving
            if (chapterMoving) {
                toggleChapterRadios("enable");
            } else {
                toggleChapterRadios("disable");
            }

            // Set chapterPosition and select the corresponding radio
            if (savedChapterPosition) {
                chapterPosition = savedChapterPosition;
            } else {
                chapterPosition = "low"; // Default position
            }

            // Select the correct radio based on saved position
            switch (chapterPosition) {
                case "low":
                    moveChaptersLowRadio.checked = true;
                    break;
                case "middle":
                    moveChaptersMiddleRadio.checked = true;
                    break;
                case "high":
                    moveChaptersHighRadio.checked = true;
                    break;
            }

            // Add event listeners to update saved values
            moveChapterSelectorCheckbox.addEventListener("change", () => {
                chapterMoving = moveChapterSelectorCheckbox.checked;
                localStorage.setItem("chapterMoving", JSON.stringify(chapterMoving));

                // Enable or disable radios based on the checkbox state
                if (chapterMoving) {
                    moveChapters();
                    toggleChapterRadios("enable");
                } else {
                    restoreOriginalChapterPosition();
                    toggleChapterRadios("disable");
                }
            });

            chapterMoverRadios.addEventListener("change", (event) => {
                chapterPosition = event.target.id.replace("move-chapters-", "").replace("-radio", "");
                localStorage.setItem("chapterPosition", chapterPosition);
                moveChapters();
            });

            let originalChapterPosition = {
                parent: null,
                sibling: null
            };

            function storeOriginalChapterPosition() {
                if (chapters) {
                    originalChapterPosition.parent = chapters.parentNode; // Store the parent node
                    originalChapterPosition.sibling = chapters.previousSibling; // Store the sibling before it (if any)
                }
            }

            moveChapters = function () {
                if (!chapters) {
                    if (chapterMoveAttempts < chapterMoveAttemptsMax) {
                        setTimeout(() => {
                            moveChapters();
                        }, 1000);
                        chapterMoveAttempts += 1;
                    } else {
                        log("Chapters element not found. No movement performed.");
                    }
                    return;
                }

                toggleMovedChaptersStyles("on");

                // Check the current value of chapterPosition and move chapters accordingly
                switch (chapterPosition) {
                    case "low":
                        // Move chapters after topRow
                        topRow.parentNode.insertBefore(chapters, topRow.nextSibling);
                        // chapters.style.marginTop = '';
                        break;
                    case "high":
                        // Move chapters before topRow
                        topRow.parentNode.insertBefore(chapters, topRow);
                        // chapters.style.marginTop = '';
                        break;
                    case "middle":
                        // Move chapters after actions
                        // chapters.style.marginTop = '10px';
                        actions.parentNode.insertBefore(chapters, actions.nextSibling);

                        break;
                    default:
                        log("Invalid chapter position.");
                }
            };

            establishChaptersAttempts = 0;
            maxEstablishChaptersAttempts = 60;
            establishChaptersAttemptsInterval = 250;
            let establishChaptersInProgress = false;
            let establishChaptersInQ = false;

            establishChapters = function () {
                if (establishChaptersInProgress) {
                    establishChaptersInQ = true;
                    return;
                } else {
                    establishChaptersInProgress = true;
                    setTimeout(() => {
                        establishChaptersInProgress = false;
                    }, 250);
                }
                const existingChapters = document.querySelector(
                    "#above-the-fold ytd-horizontal-card-list-renderer[modern-chapters]"
                );
                const unmovedChapters = document.querySelector(
                    "#bottom-row ytd-structured-description-content-renderer ytd-horizontal-card-list-renderer[modern-chapters]"
                );

                if (existingChapters && existingChapters != chapters && existingChapters != unmovedChapters) {
                    log("Removing existing chapters from previous video...");
                    existingChapters.remove();
                }

                log("Establishing chapters...");

                chapters = document.querySelector(
                    "#bottom-row ytd-structured-description-content-renderer ytd-horizontal-card-list-renderer[modern-chapters]"
                );

                if (chapters) {
                    storeOriginalChapterPosition();
                    if (chapterMoving) {
                        moveChapters();
                    }
                } else {
                    setTimeout(() => {
                        establishChapters();
                        establishChaptersAttempts += 1;
                        if (establishChaptersAttempts >= maxEstablishChaptersAttempts) {
                            establishChaptersAttemptsInterval = 2500;
                        }
                    }, establishChaptersAttemptsInterval);
                }
                if (establishChaptersInQ) {
                    establishChaptersInQ = false;
                    setTimeout(() => {
                        establishChapters();
                    }, 250);
                }
            };

            establishChapters();

            function toggleMovedChaptersStyles(arg) {
                if (arg === "on") {
                    chapters.style.borderTop = "unset";
                    chapters.style.padding = "0";
                    chapters.style.maxWidth = "100%";
                }

                if (arg === "off") {
                    // chapters.style.marginTop = '';
                    chapters.style.borderTop = "";
                    chapters.style.padding = "";
                    chapters.style.maxWidth = "";
                }
            }

            function restoreOriginalChapterPosition() {
                log("Restoring original chapter selector position...");
                if (chapters && originalChapterPosition.parent) {
                    if (originalChapterPosition.sibling) {
                        originalChapterPosition.parent.insertBefore(chapters, originalChapterPosition.sibling);
                    } else {
                        originalChapterPosition.parent.appendChild(chapters);
                    }

                    toggleMovedChaptersStyles("off");
                }
            }
        }

        insertSquareCornerControl();
        insertOverlayButton();
        insertChapterMover();
    }

    function addPressEffectToButtons() {
        // Iterate over each button in the buttonRefs object
        Object.values(buttonRefs).forEach((btn) => {
            btn.addEventListener("click", () => {
                // Add the 'just-pressed' class to the button
                btn.classList.add("just-pressed");

                // Remove the 'just-pressed' class after 1 second
                setTimeout(() => {
                    btn.classList.remove("just-pressed");
                }, 250);
            });
        });
    }

    // let insertAttempts = 0;

    //     function handleVideoSizeChangeFunction() {
    //         // Add the temporary CSS to set the zoom transition time to 0
    //         video.style.transition = "zoom 0s";

    //         // Wait 25ms to ensure the CSS takes effect before zooming
    //         setTimeout(() => {
    //             handleAspectRatio(aspectRatio, null, "zoom");
    //             log("Video size changed");

    //             setTimeout(() => {
    //                 // Remove the temporary transition style
    //                 video.style.transition = "";
    //             }, 25);
    //         }, 25);
    //     }

    function monitorVideoSize() {
        video = document.querySelector("video.html5-main-video");

        const handleVideoSizeChange = () => {
            // Add the temporary CSS to set the zoom transition time to 0
            video.style.transition = "zoom 0s";

            // Wait 25ms to ensure the CSS takes effect before zooming
            setTimeout(() => {
                handleAspectRatio(aspectRatio, null, "zoom");
                log("Video size changed");

                setTimeout(() => {
                    // Remove the temporary transition style
                    video.style.transition = "";
                }, 25);
            }, 25);
        };

        if (video) {
            const resizeObserver = new ResizeObserver(handleVideoSizeChange);
            const windowResizeObserver = new ResizeObserver(handleVideoSizeChange);
            resizeObserver.observe(video);
            windowResizeObserver.observe(document.body);
        } else {
            console.error("Video element not found");
        }
    }

    function setCompressorValues() {
        log("compressorValues: " + JSON.stringify(compressorValues));

        thresholdGain.gain.setValueAtTime(1 / Math.pow(2, compressorValues.threshold / 6), audioContext.currentTime);
        finalGain.gain.setValueAtTime(Math.pow(2, compressorValues.threshold / 6), audioContext.currentTime);

        //preGain.gain.setValueAtTime(Math.pow(2, compressorValues.preGain / 6), audioContext.currentTime);
        preGain.gain.setValueAtTime(compressorValues.preGain, audioContext.currentTime);

        compressor.threshold.setValueAtTime(compressorValues.knee * -1 - 1, audioContext.currentTime); // Threshold
        compressor.knee.setValueAtTime(compressorValues.knee, audioContext.currentTime); // Soft knee
        compressor.ratio.setValueAtTime(compressorValues.ratio, audioContext.currentTime); // High ratio for limiting
        compressor.attack.setValueAtTime(compressorValues.attack, audioContext.currentTime); // Fast attack
        compressor.release.setValueAtTime(compressorValues.release, audioContext.currentTime); // Release time
    }

    function initiateCompressor() {
        if (!audioContext) {
            // Create an AudioContext
            audioContext = new (window.AudioContext || window.webkitAudioContext)();

            // Add a pre-gain (included in compressor values)
            preGain = audioContext.createGain();

            // Add threshold gain to simulate the threshold
            thresholdGain = audioContext.createGain();

            // Create a DynamicsCompressorNode (limiter with soft knee)
            compressor = audioContext.createDynamicsCompressor();

            // Create a gain node for final output level control (included in compressor values)
            finalGain = audioContext.createGain();

            // finalGain.gain.setValueAtTime(compressorValues.finalGain, audioContext.currentTime); // Default gain is 1 (no change)
        }

        connectCompressor();

        // Set the compressor values using the new function
        setCompressorValues();
    }

    function changeCompressorValue(property, value, rawValue) {
        log("Passed values to change compressor values: ", property, value, rawValue);
        if (property === "preGain") {
            preGain.gain.setValueAtTime(value, audioContext.currentTime);
            log("PreGain value: " + preGain.gain.value);
            // } else if (compressor.hasOwnProperty(property)) {
            //     compressor[property].setValueAtTime(value, audioContext.currentTime);
            // } else {
            //     console.error('Invalid property:', property);
            // }
        } else if (property === "knee") {
            compressor[property].setValueAtTime(value, audioContext.currentTime);
            compressor.threshold.setValueAtTime(value - 1, audioContext.currentTime);
        } else if (property === "threshold") {
            thresholdGain.gain.setValueAtTime(1 / value, audioContext.currentTime);
            // Log the threshold gain value
            log("Threshold Gain value set to:", thresholdGain.gain.value);
            finalGain.gain.setValueAtTime(value, audioContext.currentTime);
            log("Final Gain value set to:", finalGain.gain.value);
        } else {
            compressor[property].setValueAtTime(value, audioContext.currentTime);
        }
    }

    function connectCompressor() {
        findVideo();

        if (video) {
            // Check if there's a video and no source node
            if (source) {
                log("Source found. Disconnecting...");
                source.disconnect(); // Disconnect the previous source (if any)
            } else {
                // Create a MediaElementSourceNode to use the video's audio
                source = audioContext.createMediaElementSource(video);
            }

            // Connect the video audio to the compressor
            source.connect(preGain);

            preGain.connect(thresholdGain);

            thresholdGain.connect(compressor);

            // Connect the compressor to the final gain control
            compressor.connect(finalGain);

            // Connect the final gain control to the audio context's destination (speakers)
            finalGain.connect(audioContext.destination);

            log("Video is being processed with compression and gain control.");
        } else {
            log("No video found or source already connected.");
        }
    }

    function disconnectCompressor() {
        if (source) {
            source.disconnect(); // Disconnect the video audio source
            preGain.disconnect();
            thresholdGain.disconnect();
            compressor.disconnect(); // Disconnect the compressor
            finalGain.disconnect(); // Disconnect the gain node
            source.connect(audioContext.destination);

            log("Compressor and nodes disconnected.");

            // Reset source to null to allow future processing
            // source = null;
        }
    }

    const timeVariables = {
        seekTime: null,
        requestedCurrentTime: null,
        loopStartTime: null,
        loopEndTime: null,
        lastMeasuredTime: null
    };

    const elementConfigMap = {
        "time-seek-input": "seekTime",
        "get-time-input": "requestedCurrentTime",
        "loop-start-input": "loopStartTime",
        "loop-end-input": "loopEndTime",
        "last-measured-time-input": "lastMeasuredTime"
    };

    // Global object to store previous values of inputs
    const previousInputValues = {};

    // Function to handle the time format input
    function formatTimeInput(inputElement) {
        inputElement.placeholder = "HH:MM:SS.mil";

        inputElement.addEventListener("input", (event) => {
            let input = event.target.value;
            let inputId = event.target.id; // Get the input element's ID

            // Store the previous value in the global object if it's the first time we're checking it
            if (!previousInputValues[inputId]) {
                previousInputValues[inputId] = input;
            }

            // Get the previous valid input value from the global object
            let previousInput = previousInputValues[inputId];

            // Check for decimal points and colons in the input string
            let decimalIndexes = [];
            let colonIndexes = [];

            // Loop through the string and collect all indexes of `.` and `:`
            for (let i = 0; i < input.length; i++) {
                if (input[i] === ".") {
                    decimalIndexes.push(i);
                }
                if (input[i] === ":") {
                    colonIndexes.push(i);
                }
            }

            // If there's a decimal point before any colon
            for (let decimalIndex of decimalIndexes) {
                for (let colonIndex of colonIndexes) {
                    if (decimalIndex < colonIndex) {
                        log("Blocked: Decimal comes before Colon");
                        event.preventDefault();
                        event.target.value = previousInput; // Revert to previous valid input
                        return;
                    }
                }
            }

            // If there's a colon after a decimal point
            for (let colonIndex of colonIndexes) {
                for (let decimalIndex of decimalIndexes) {
                    if (colonIndex > decimalIndex) {
                        log("Blocked: Colon comes after Decimal");
                        event.preventDefault();
                        event.target.value = previousInput; // Revert to previous valid input
                        return;
                    }
                }
            }

            // Remove any invalid characters (anything other than digits, colons, or periods)
            input = input.replace(/[^0-9:.]/g, "");

            // Split input based on period and colon
            let groups = input.split(".");

            // Ensure that the colon part is formatted as HH:MM:SS
            let colonGroups = groups[0].split(":");

            // Limit to no more than 3 groups (HH:MM:SS)
            if (colonGroups.length > 3) {
                colonGroups = colonGroups.slice(0, 3);
            }

            // Ensure that each group after the first one (MM, SS) has no more than 2 digits
            if (colonGroups[1] && colonGroups[1].length > 2) {
                colonGroups[1] = colonGroups[1].slice(0, 2);
            }
            if (colonGroups[2] && colonGroups[2].length > 2) {
                colonGroups[2] = colonGroups[2].slice(0, 2);
            }

            // Rebuild the colon-separated time part (HH:MM:SS)
            input = colonGroups.join(":");

            // Handle the decimal part (milliseconds)
            if (groups.length > 1) {
                let decimalGroup = groups[1].slice(0, 3); // Limit to 3 digits
                input += "." + decimalGroup;
            }

            // Update the input field with the valid value
            event.target.value = input;

            // Update the global object with the current valid value
            previousInputValues[inputId] = input;
        });

        // Ensure proper formatting when the user leaves the input field (blur event)
        inputElement.addEventListener("blur", () => {
            let input = inputElement.value;
            let inputId = event.target.id; // Get the input element's ID

            if (!input || input === null) {
                log("No input and nothing to convert.");
                const variableName = elementConfigMap[inputId];
                timeVariables[variableName] = null;
                log(`Updated timeVariables[${variableName}] to ${timeVariables[variableName]}.`);
                return;
            }

            // Split the input into colon-separated parts and decimal part
            let groups = input.split(":");
            let decimalGroup = "";

            // If there's a decimal part, separate it out
            if (groups[groups.length - 1].includes(".")) {
                const lastGroupParts = groups[groups.length - 1].split(".");
                decimalGroup = lastGroupParts[1] || "";
                groups[groups.length - 1] = lastGroupParts[0]; // Keep the part before the decimal
            }

            // Pad empty groups with "00"
            for (let i = 0; i < groups.length; i++) {
                if (groups[i] === "") {
                    groups[i] = "00"; // Fill empty group with "00"
                } else if (i > 0 && groups[i].length < 2) {
                    groups[i] = groups[i].padStart(2, "0"); // Pad with leading zero if needed (except for the first group)
                }
            }

            // Rebuild the string with fixed colon-separated groups
            input = groups.join(":");

            // Handle the decimal part and ensure it's at most 3 digits
            if (decimalGroup) {
                decimalGroup = decimalGroup.slice(0, 3); // Limit to 3 digits after the decimal point
                input += "." + decimalGroup;
            }

            // Update the input field with the final value
            inputElement.value = input;

            // Check if the value is valid and convert accordingly
            if (isValidTimeFormat(input)) {
                // log('The input is valid.');
                const rawSeconds = convertToRawSeconds(input, inputId);
                // You can store rawSeconds in a map or take other actions here
                // Store the rawSeconds in the appropriate variable using the elementConfigMap

                storeTimeVariable(rawSeconds, inputId);

                //         // Get the corresponding variable name from the map
                //         const variableName = elementConfigMap[inputId];

                //         if (variableName && timeVariables.hasOwnProperty(variableName)) {
                //             // Update the actual variable
                //             timeVariables[variableName] = rawSeconds;

                //           log(`Updated timeVariables[${variableName}] to ${input}.`);

                //     } else {
                //         console.error(`No matching entry for inputId ${inputId} in elementConfigMap`);
                //     }
            } else {
                console.error(`Invalid time format for input ${inputId}`);
            }

            if (inputId === "loop-start-input" || inputId === "loop-end-input") {
                let alertTriggered = getLoopLength();
                if (
                    isValidTimeFormat &&
                    !isNaN(loopLength) &&
                    !alertTriggered &&
                    loopStartInput.value != null &&
                    loopEndInput.value != null &&
                    looping
                ) {
                    startLoopingButton.classList.add("blinking");

                    clearTimeout(startLoopingBlink);
                    startLoopingBlink = setTimeout(() => {
                        startLoopingButton.classList.remove("blinking");
                    }, 5000); // Adjust duration based on your preference
                }
            }
        });
    }

    function storeTimeVariable(value, id) {
        // Get the corresponding variable name from the map
        const variableName = elementConfigMap[id];

        if (variableName && timeVariables.hasOwnProperty(variableName)) {
            // Update the actual variable
            timeVariables[variableName] = parseFloat(value);

            log(`Updated timeVariables[${variableName}] to ${timeVariables[variableName]}.`);
        } else {
            console.error(`No matching entry for inputId ${inputId} in elementConfigMap`);
        }
    }

    function convertToRawSeconds(timeString, elementId) {
        log(`Converting time for element ${elementId}: ${timeString}`);

        // Remove any extra whitespace
        timeString = timeString.trim();

        // Split the string by the colon separator
        const parts = timeString.split(":");

        let hours = 0,
            minutes = 0,
            seconds = 0;

        // If there is no colon, it's just seconds
        if (parts.length === 1) {
            // If there's a decimal, we need to split that as well
            const [sec, milli] = parts[0].split(".");
            seconds = parseInt(sec, 10) || 0;
            // Add milliseconds if present
            if (milli) {
                seconds += parseInt(milli, 10) / Math.pow(10, milli.length);
            }
        } else {
            // If there are parts, we process them
            if (parts.length === 2) {
                // Minutes:Seconds
                minutes = parseInt(parts[0], 10) || 0;
                seconds = parseFloat(parts[1]) || 0;
            } else if (parts.length === 3) {
                // Hours:Minutes:Seconds
                hours = parseInt(parts[0], 10) || 0;
                minutes = parseInt(parts[1], 10) || 0;
                seconds = parseFloat(parts[2]) || 0;
            }

            // Handle decimal in the last part (if any)
            if (seconds.toString().includes(".")) {
                const [sec, milli] = seconds.toString().split(".");
                seconds = parseInt(sec, 10) || 0;
                const milliseconds = parseInt(milli, 10) || 0;
                seconds += milliseconds / Math.pow(10, milli.length);
            }
        }

        // Now, calculate the total in raw seconds
        const rawSeconds = hours * 3600 + minutes * 60 + seconds;

        log(`Converted to raw seconds: ${rawSeconds}`);

        // You can store or do other things with rawSeconds here
        return rawSeconds;
    }

    function convertToTimeFormat(rawSeconds, elementId) {
        log(`Converting raw seconds for element ${elementId}: ${rawSeconds}`);

        // Calculate hours, minutes, and seconds (with potential decimal)
        const hours = Math.floor(rawSeconds / 3600);
        const minutes = Math.floor((rawSeconds % 3600) / 60);
        let seconds = rawSeconds % 60; // This could be a floating-point value

        // Format the time components into a string
        let timeString = `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;

        log(`Converted to time format (before modification): ${timeString}`);

        // Split into main part (HH:MM:SS) and decimal part
        let [mainPart, decimalPart] = timeString.split(".");

        // Trim leading zeros and colons from the main part
        while (mainPart.length > 1 && (mainPart.startsWith("0") || mainPart.startsWith(":"))) {
            mainPart = mainPart.slice(1); // Remove the first character (0 or :)
        }

        // If there's no decimal part, set it to an empty string
        if (decimalPart !== undefined) {
            // Prefix "0." to ensure it's a number
            let decimalValue = parseFloat("0." + decimalPart);

            // Round to 3 decimal places (you can change this to any precision you need)
            decimalValue = Math.round(decimalValue * 1000) / 1000;

            // Convert back to string, removing trailing zeros
            decimalPart = decimalValue.toString().split(".")[1] || "";

            // Trim trailing zeros from the decimal part
            while (decimalPart.length > 1 && decimalPart.endsWith("0")) {
                decimalPart = decimalPart.slice(0, -1); // Remove the last character (0)
            }

            // Combine the main part and the decimal part back
            timeString = `${mainPart}.${decimalPart}`;
        } else {
            timeString = `${mainPart}`;
        }

        log(`Final time string: ${timeString}`);

        return timeString;
    }

    function isValidTimeFormat(timeString) {
        log("Raw input value:", timeString); // Log the raw value
        log("Trimmed value:", timeString.trim()); // Log the value after trimming whitespace
        const regex = /^(\d+)(?::(\d{2}))?(?::(\d{2}))?(?:\.(\d+))?$/;
        log(regex.test(timeString));
        log(regex.test(timeString.trim()));
        return regex.test(timeString.trim());
    }

    function getCurrentTime(target) {
        log("Getting current time...");
        // Check if the video element is valid and exists

        const currentTime = video.currentTime; // Get the current time of the video
        if (!currentTime) {
            return;
        }
        log(`Current video time (raw): ${currentTime} seconds`);

        const convertedTime = convertToTimeFormat(currentTime, "get-time-input");
        log(`Current video time (converted): ${convertedTime} seconds`);

        storeTimeVariable(currentTime, "get-time-input");
        target.value = convertedTime;
    }

    let loopLength;

    function getLoopLength(start) {
        log("Loop start:", timeVariables.loopStartTime);
        log("Loop end:", timeVariables.loopEndTime);
        if (timeVariables.loopEndTime == null || timeVariables.loopStartTime == null) {
            log("No loop length to get.");
            return true;
        }
        loopLength = timeVariables.loopEndTime - timeVariables.loopStartTime;
        log("Loop length:", loopLength);

        let alertText;
        let alertTriggered = false;

        if (loopLength < 0) {
            // log('Condition 1.');
            looping = false;
            alertTriggered = true;
            alertText = "The loop length is negative. Looping cannot take place.";
        } else if (loopLength === 0) {
            // log('Condition 2.');
            looping = false;
            alertTriggered = true;
            alertText = "The loop length is 0. Looping cannot take place.";
        } else if (loopLength <= 1 / 30) {
            // log('Condition 3.');
            looping = false;
            alertTriggered = true;
            alertText = "The loop length is too short. Looping cannot take place.";
        } else {
            // log('Condition 4.');
            alertTriggered = false;
        }

        if (alertTriggered) {
            log(alertText);

            if (start) {
                loopErrorSpan.textContent = alertText;
                loopErrorHolderOuter.removeAttribute("invisible");
                if (hideLoopErrorTimeout) {
                    clearTimeout(hideLoopErrorTimeout); // Clear existing timeout
                }

                hideLoopErrorTimeout = setTimeout(() => {
                    loopErrorHolderOuter.setAttribute("invisible", "");
                }, 5000);
                return alertTriggered;
            }
        }
    }

    let hideLoopErrorTimeout;
    let measureRateInput;
    let lastMeasuredTimeInput;
    let loopStartInput;
    let loopEndInput;
    let startLoopingButton;
    let loopErrorSpan;
    let loopErrorPreSpan;
    let loopErrorHolderOuter;

    function insertSeekAndLoopControls() {
        const timeFormattedInputs = []; // Array to store the time-formatted inputs

        // const emptySpanner = insertEmptySpanner();
        // videoControlsMasterHolder.appendChild(emptySpanner);

        const videoSeekControls = document.createElement("div");
        videoSeekControls.id = "video-seek-controls";
        videoSeekControls.classList.add("video-manipulator-inner-item");

        videoSeekControlsOuterDiv = document.createElement("div");
        videoSeekControlsOuterDiv.id = "video-seek-controls-outer-div";
        videoSeekControlsOuterDiv.classList.add("video-manipulator-outer-div");

        const videoLoopControls = document.createElement("div");
        videoLoopControls.id = "video-loop-controls";
        videoLoopControls.classList.add("video-manipulator-inner-item");

        videoLoopControlsOuterDiv = document.createElement("div");
        videoLoopControlsOuterDiv.id = "video-loop-controls-outer-div";
        videoLoopControlsOuterDiv.classList.add("video-manipulator-outer-div");

        // Jump section
        const jumpSection = document.createElement("div");
        jumpSection.id = "jump-section";
        jumpSection.classList.add("video-manipulator-sub-item");

        const timeSeekButton = document.createElement("button");
        timeSeekButton.id = "time-seek-button";
        timeSeekButton.textContent = "Jump to";
        buttonRefs[timeSeekButton.id] = timeSeekButton;

        const timeSeekInput = document.createElement("input");
        timeSeekInput.id = "time-seek-input";
        timeSeekInput.type = "text"; // Only numbers allowed
        timeSeekInput.classList.add("time-formatted");
        timeFormattedInputs.push(timeSeekInput);

        jumpSection.appendChild(timeSeekButton);
        jumpSection.appendChild(timeSeekInput);

        // Divider
        const divider = createDivider();

        // Get time section
        const getTimeSection = document.createElement("div");
        getTimeSection.id = "get-time-section";
        getTimeSection.classList.add("video-manipulator-sub-item");

        const getTimeButton = document.createElement("button");
        getTimeButton.id = "get-time-button";
        getTimeButton.textContent = "Get Current Time";
        getTimeButton.title = "Get the current time for the video, with millisecond precision.";
        buttonRefs[getTimeButton.id] = getTimeButton;

        const getTimeInput = document.createElement("input");
        getTimeInput.id = "get-time-input";
        getTimeInput.type = "text"; // Only numbers allowed
        getTimeInput.readOnly = true;
        getTimeInput.classList.add("time-formatted");
        timeFormattedInputs.push(getTimeInput);

        const getTimeUrlButton = document.createElement("button");
        getTimeUrlButton.id = "get-time-url-button";
        getTimeUrlButton.textContent = "Copy URL at current time";
        getTimeUrlButton.title =
            "Copy the URL of the video at the current time to the clipboard, with millisecond precision.";
        buttonRefs[getTimeUrlButton.id] = getTimeUrlButton;

        getTimeSection.appendChild(getTimeButton);
        getTimeSection.appendChild(getTimeInput);

        // The following is disabled because YouTube just rounds anyway.
        // getTimeSection.appendChild(getTimeUrlButton);

        // Divider
        const divider2 = createDivider();

        // Loop section
        const loopSection = document.createElement("div");
        loopSection.id = "loop-section";
        loopSection.classList.add("video-manipulator-sub-item");

        const loopSpan = document.createElement("span");
        loopSpan.textContent = "Loop";

        loopStartInput = document.createElement("input");
        loopStartInput.id = "loop-start-input";
        loopStartInput.type = "text"; // Only numbers allowed
        loopStartInput.classList.add("time-formatted");
        timeFormattedInputs.push(loopStartInput);

        const loopEndSpan = document.createElement("span");
        loopEndSpan.textContent = "to";

        loopEndInput = document.createElement("input");
        loopEndInput.id = "loop-end-input";
        loopEndInput.type = "text"; // Only numbers allowed
        loopEndInput.classList.add("time-formatted");
        timeFormattedInputs.push(loopEndInput);

        const loopingButtonsOuterDiv = document.createElement("div");
        loopingButtonsOuterDiv.id = "looping-buttons-outer-div";
        loopingButtonsOuterDiv.classList.add("video-manipulator-sub-item");

        const loopingButtonsInnerDiv = document.createElement("div");
        loopingButtonsInnerDiv.id = "looping-buttons-inner-div";
        loopingButtonsInnerDiv.classList.add("video-manipulator-sub-item");

        startLoopingButton = document.createElement("button");
        startLoopingButton.id = "start-looping-button";
        startLoopingButton.textContent = "Start Looping";
        buttonRefs[startLoopingButton.id] = startLoopingButton;

        const stopLoopingButton = document.createElement("button");
        stopLoopingButton.id = "stop-looping-button";
        stopLoopingButton.textContent = "Stop Looping";
        buttonRefs[stopLoopingButton.id] = stopLoopingButton;

        loopErrorHolderOuter = document.createElement("div");
        loopErrorHolderOuter.id = "loop-error-holder-outer";
        loopErrorHolderOuter.setAttribute("invisible", "");

        const loopErrorHolderInner = document.createElement("div");
        loopErrorHolderInner.id = "loop-error-holder-inner";

        loopErrorPreSpan = document.createElement("div");
        loopErrorPreSpan.id = "loop-error-pre-span";

        loopErrorSpan = document.createElement("div");
        loopErrorSpan.id = "loop-error-span";
        loopErrorSpan.textContent =
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " + "Vivamus lacinia odio vitae vestibulum.";

        loopErrorHolderInner.appendChild(loopErrorPreSpan);
        loopErrorHolderInner.appendChild(loopErrorSpan);
        loopErrorHolderOuter.appendChild(loopErrorHolderInner);

        loopingButtonsInnerDiv.appendChild(startLoopingButton);
        loopingButtonsInnerDiv.appendChild(stopLoopingButton);

        loopingButtonsOuterDiv.appendChild(loopingButtonsInnerDiv);
        loopingButtonsOuterDiv.appendChild(loopErrorHolderOuter);

        const loopForeverRadio = document.createElement("input");
        loopForeverRadio.id = "loop-forever-radio";
        loopForeverRadio.type = "radio";
        loopForeverRadio.name = "loop-type";
        loopForeverRadio.checked = true;
        const loopForeverLabel = document.createElement("label");
        loopForeverLabel.setAttribute("for", "loop-forever-radio");
        loopForeverLabel.textContent = "Loop forever";

        const loopForeverDiv = document.createElement("div");

        loopForeverDiv.appendChild(loopForeverRadio);
        loopForeverDiv.appendChild(loopForeverLabel);
        loopForeverDiv.classList.add("radio-div");

        const loopXTimesRadio = document.createElement("input");
        loopXTimesRadio.id = "loop-x-times-radio";
        loopXTimesRadio.type = "radio";
        loopXTimesRadio.name = "loop-type";
        const loopXTimesLabel = document.createElement("label");
        loopXTimesLabel.setAttribute("for", "loop-x-times-radio");

        // Create the input element
        const loopTimesInput = document.createElement("input");
        loopTimesInput.id = "loop-times-input";
        loopTimesInput.type = "number";
        loopTimesInput.min = 1;

        // Create the label text node
        const labelText = document.createTextNode("Loop ");

        // Clear existing content and append the label text and input element
        loopXTimesLabel.textContent = ""; // Clear any previous content
        loopXTimesLabel.appendChild(labelText);
        loopXTimesLabel.appendChild(loopTimesInput);
        loopXTimesLabel.appendChild(document.createTextNode(" times"));

        const loopTimesDiv = document.createElement("div");

        loopTimesDiv.appendChild(loopXTimesRadio);
        loopTimesDiv.appendChild(loopXTimesLabel);
        loopTimesDiv.classList.add("radio-div");

        loopSection.appendChild(loopSpan);
        loopSection.appendChild(loopStartInput);
        loopSection.appendChild(loopEndSpan);
        loopSection.appendChild(loopEndInput);
        loopSection.appendChild(loopingButtonsOuterDiv);
        loopSection.appendChild(loopForeverDiv);
        loopSection.appendChild(loopTimesDiv);

        // Append all sections to the outer div
        videoSeekControls.appendChild(jumpSection);
        videoSeekControls.appendChild(divider);
        videoSeekControls.appendChild(getTimeSection);
        // videoSeekControls.appendChild(divider2);

        // Append the loop controls separately
        videoLoopControls.appendChild(loopSection);

        // Insert diagnostic section if timeLoopDebug is true
        if (timeLoopDebug) {
            const diagnosticDivider = createDivider();

            const diagnosticDiv = document.createElement("div");
            diagnosticDiv.id = "diagnostic-div";
            diagnosticDiv.classList.add("video-manipulator-sub-item");

            lastMeasuredTimeInput = document.createElement("input");
            lastMeasuredTimeInput.id = "last-measured-time-input";
            lastMeasuredTimeInput.type = "text";
            lastMeasuredTimeInput.readOnly = true; // Cannot be edited
            lastMeasuredTimeInput.classList.add("time-formatted");
            timeFormattedInputs.push(lastMeasuredTimeInput);

            const measuringSpan = document.createElement("span");
            measuringSpan.textContent = "Measuring";

            // Create the measure rate input
            measureRateInput = document.createElement("input");
            measureRateInput.id = "measure-rate-input";
            measureRateInput.type = "number"; // Accepts only numbers
            measureRateInput.min = 1; // Min value 1
            measureRateInput.max = 240; // Max value 240
            measureRateInput.step = "1"; // Only accepts integer steps
            measureRateInput.value = 1; // Default value (could be set to whatever you'd like)

            const timesPerSecondSpan = document.createElement("span");
            timesPerSecondSpan.textContent = "times per second";

            diagnosticDiv.appendChild(lastMeasuredTimeInput);
            diagnosticDiv.appendChild(measuringSpan);
            diagnosticDiv.appendChild(measureRateInput);
            diagnosticDiv.appendChild(timesPerSecondSpan);

            // Append to the videoLoopControlsOuterDiv
            videoLoopControls.appendChild(diagnosticDivider);
            videoLoopControls.appendChild(diagnosticDiv);

            measureRateInput.addEventListener("input", (event) => {
                // Clear the previous timer if there's one
                clearTimeout(debounceCheckTimeIntervalTimer);

                // Set a new timer for debounce (1 second delay)
                debounceCheckTimeIntervalTimer = setTimeout(() => {
                    let timeDivider = measureRateInput.value;
                    // Check if timeDivider is undefined, NaN, or less than or equal to zero
                    if (isNaN(timeDivider) || timeDivider <= 0) {
                        timeDivider = 0.000001; // Set to a small positive value
                    }
                    // Calculate the new interval based on input value
                    checkTimeIntervalTime = 1000 / timeDivider;
                    log(`New rate: ${measureRateInput.value} actions per second.`);
                    // Restart the interval with the new rate
                    startCheckTimeInterval();
                }, 1000); // Debounce by 1 second
            });
        }

        // Finally, append everything to the outer div
        videoSeekControlsOuterDiv.appendChild(videoSeekControls);
        videoLoopControlsOuterDiv.appendChild(videoLoopControls);

        // Append to topRow
        const playbackRateControls = document.querySelector(
            ".video-manipulator-outer-div#playback-rate-controls-outer"
        );
        // the element after which you want to append

        videoControlsMasterHolder.appendChild(videoSeekControlsOuterDiv);
        videoControlsMasterHolder.appendChild(videoLoopControlsOuterDiv);

        // if (playbackRateControls.nextSibling) {
        //     // If there is a next sibling, insert the new element before the next sibling
        //     topRow.insertBefore(videoSeekControlsOuterDiv, playbackRateControls.nextSibling);
        // } else {
        //     // If there is no next sibling, append the new element at the end of the parent
        //     topRow.appendChild(videoSeekControlsOuterDiv);
        // }

        timeFormattedInputs.forEach((input) => {
            formatTimeInput(input); // Apply formatting
        });

        // Add event listener to the button
        getTimeButton.addEventListener("click", function () {
            getCurrentTime(getTimeInput);
        });

        // Disabled because YouTube just rounds it anyway.
        // Add the event listener
        //         getTimeUrlButton.addEventListener("click", () => {
        //             getCurrentTime(getTimeInput);

        //             // Get the current time of the video in seconds, rounded to 3 decimal places
        //             const currentTime = video.currentTime.toFixed(3);

        //             // Get the current URL (from window.location.href)
        //             let currentUrl = window.location.href;

        //             // Remove all query parameters except for 'v' (the video ID)
        //             const urlParams = new URLSearchParams(window.location.search);
        //             // urlParams.delete('t');  // Remove any existing 't' parameter
        //             currentUrl = currentUrl.split("?")[0] + "?" + `v=${urlParams.get("v")}`;
        //             // Retain only the video ID and other relevant parameters

        //             // Add the 't' parameter with the current time
        //             currentUrl += `&t=${currentTime}` + "s";

        //             // Copy the final URL to the clipboard
        //             navigator.clipboard
        //                 .writeText(currentUrl)
        //                 .then(() => {
        //                     log(`Video URL at current time (${currentTime}s): ${currentUrl}`);
        //                     // alert('URL copied to clipboard!');
        //                 })
        //                 .catch((err) => {
        //                     console.error("Error copying to clipboard: ", err);
        //                 });
        //         });

        // Add event listener for the timeSeekButton
        timeSeekButton.addEventListener("click", () => {
            // Check if timeVariables.seekTime has a valid value
            if (timeVariables.seekTime !== undefined) {
                // Set the video time to the value stored in timeVariables.seekTime
                video.currentTime = timeVariables.seekTime;
                log(`Jumping to time: ${timeVariables.seekTime} seconds.`);
            } else {
                console.error(`No valid time found in timeVariables.seekTime.`);
            }
        });

        startLoopingButton.addEventListener("click", () => {
            // if ()
            const dontStart = getLoopLength(true);
            log("dontStart:", dontStart);
            if (dontStart) {
                return;
            }
            looping = true;
            loopIterations = 0;
            startLoopingButton.classList.add("active");
            startLoopingButton.classList.remove("blinking");
            // startCheckTimeInterval();

            log("dontStart:", dontStart);

            loopIntervalStart();
            video.play();
        });

        stopLoopingButton.addEventListener("click", () => {
            looping = false;
            startLoopingButton.classList.remove("active");
            if (checkTimeIntervalId) clearInterval(checkTimeIntervalId);
            loopIntervalEnd();
        });

        loopForeverRadio.addEventListener("click", () => {
            loopMode = "forever";
        });

        loopXTimesRadio.addEventListener("click", () => {
            loopMode = "x-times";
        });

        loopTimesInput.addEventListener("blur", () => {
            loopTimes = Math.round(parseFloat(loopTimesInput.value));
            if (loopTimes != parseFloat(loopTimesInput.value)) {
                loopTimesInput.value = loopTimes;
            }
            loopXTimesRadio.checked = true;
            loopMode = "x-times";
        });

        // Create a MutationObserver to watch for changes in text content
        const loopErrorMutationObserver = new MutationObserver(() => {
            // Log the change in text content
            log("Text content of loopErrorSpan has changed.");

            // Adjust loopErrorPreSpan width and height based on the new content of loopErrorSpan
            loopErrorPreSpan.style.width = `${loopErrorSpan.offsetWidth}px`;
            loopErrorPreSpan.style.height = `${loopErrorSpan.offsetHeight}px`;
        });

        // Configure the observer to watch for text content changes (childList or characterData)
        const config = {
            childList: true, // Watch for additions or removals of child nodes
            characterData: true, // Watch for changes to the text content
            subtree: true // Watch all descendants, not just immediate children
        };

        // Start observing loopErrorSpan for text content changes
        loopErrorMutationObserver.observe(loopErrorSpan, config);

        loopErrorPreSpan.style.width = `${loopErrorSpan.offsetWidth}px`;
        loopErrorPreSpan.style.height = `${loopErrorSpan.offsetHeight}px`;

        getTimeInput.addEventListener("focus", () => {
            getTimeInput.select();
        });
    }

    let loopIntervalTime;
    let loopIntervalId;
    let deCapo = false;
    let tooFar = false;
    let loopTimes = 0;
    let loopIterations = 0;
    let loopInitialInterval;
    let loopStartTime;
    let loopEndTime;

    // Function to evaluate loop time
    function loopTimeEvaluator(timeLength) {
        deCapo = false; // Reset deCapo before starting evaluations
        let intervalLength;
        tooFar = false;

        // Boundary Conditions for Interval Duration
        if (timeLength > 2) {
            intervalLength = 1000; // 1 second
        } else if (timeLength <= 2 && timeLength > 0.25) {
            intervalLength = 250; // 250 ms
        } else if (timeLength <= 0.25) {
            intervalLength = timeLength * 1000; // Set interval to the remaining time
            deCapo = true;
            tooFar = timeLength < 0; // Check if the time goes beyond the end
        }

        return { intervalLength, deCapo, tooFar };
    }

    // Function to evaluate remaining time and adjust interval
    function loopRemainingTimeCalculator(currentTime) {
        log("loopRemainingTimeCalculator...");
        let remainingTime = loopEndTime - currentTime; // Time left in the loop

        // if (remainingTime <= 1/30) {
        //     log('Loop time is too short. Terminating.');
        //     clearInterval(loopIntervalId);
        //     return;
        // }

        let { intervalLength, deCapo, tooFar } = loopTimeEvaluator(remainingTime);

        if (timeLoopDebug) {
            const convertedTime = convertToTimeFormat(remainingTime, "get-time-input");
            lastMeasuredTimeInput.value = convertedTime;
        }

        // // If the video time is past the end, restart the loop
        // if (tooFar) {
        //     video.currentTime = loopStartTime; // Reset video time
        //     loopIterations += 1;
        // }

        // If the interval has changed, reset the interval
        if (loopIntervalTime !== intervalLength) {
            // clearInterval(loopIntervalId);
            // if (tooFar) {
            //     log('tooFar');
            //     loopIntervalTime = loopInitialInterval;
            // } else {
            loopIntervalTime = intervalLength; // Update the interval time
            // }
            clearInterval(loopIntervalId);
            if (looping) {
                loopIntervalId = setInterval(loopInterval, loopIntervalTime);
            }
        }
    }

    // Loop interval function
    function loopInterval() {
        if (loopMode === "x-times" && loopIterations >= loopTimes) {
            log("loopIterations:", +loopIterations);
            loopIntervalEnd();
            return;
        }

        if (!looping) {
            log("Looping is false.");
            clearInterval(loopIntervalId);
            loopIntervalEnd();
            return;
        }

        let currentTime = video.currentTime;

        if (looping) {
            loopRemainingTimeCalculator(currentTime);
        }

        if (deCapo || tooFar) {
            video.currentTime = loopStartTime; // Reset to loop start if deCapo is true
            deCapo = false; // Reset deCapo after looping
            loopIterations += 1;
            log("loopIterations:", +loopIterations);
        }

        if (video.paused) {
            return;
            // clearInterval(loopIntervalId); // Pause the loop interval if video is paused
        }
    }

    // Start loop interval
    function loopIntervalStart() {
        loopStartTime = timeVariables.loopStartTime; // Set start time
        loopEndTime = timeVariables.loopEndTime; // Set end time
        loopIterations = 0; // Reset loop iterations

        let timeLength = loopEndTime - loopStartTime; // Calculate loop length
        let { intervalLength, deCapo, tooFar } = loopTimeEvaluator(timeLength);

        loopInitialInterval = intervalLength; // Store initial interval

        video.currentTime = loopStartTime;

        clearInterval(loopIntervalId);

        loopIntervalId = setInterval(loopInterval, intervalLength); // Start interval
    }

    // End loop interval
    function loopIntervalEnd() {
        clearInterval(loopIntervalId); // Clear the interval when ending
        loopIterations = 0; // Reset loop iteration count
        looping = false;
        video.pause();
        log("Loop ended");
    }

    // Resize observer for individual inner elements (resizes the after pseudoelements)

    // Array to store content widths and conclusions (same or width value)
    const innerItemElements = [];
    const widthConclusions = [];

    // ResizeObserver for monitoring changes
    const innerItemResizeObserver = new ResizeObserver((entries) => {
        entries.forEach((entry) => {
            const parentElement = entry.target;
            const parentId = parentElement.id || parentElement.className;

            log(`Observed resize for: ${parentId}`);

            // Get the current width of the parent element and its content
            const parentRect = parentElement.getBoundingClientRect();
            const contentWidth = calculateContentWidth(parentElement);

            log(`For ${parentId}:`);
            log(`Container width: ${parentRect.width}`);
            log(`Content width: ${contentWidth}`);

            // Compare the current width of the parent and the content width
            const conclusion = parentRect.width > contentWidth ? contentWidth : "same";

            // Log the conclusion
            log(`Conclusion for ${parentId}: ${conclusion}`);

            // Store the measurement result
            if (!innerItemElements.includes(parentId)) {
                log(`Adding ${parentId} to innerItemElements.`);
                innerItemElements.push(parentId);
            } else {
                log(`${parentId} already in innerItemElements, updating conclusion.`);
            }

            widthConclusions[innerItemElements.indexOf(parentId)] = conclusion;

            // Update the styles after measuring all elements
            applyAfterPseudoCssRules();
        });
    });

    function calculateContentWidth(parent) {
        log(`Calculating content width for ${parent.id || parent.className}`);

        let left = Number.POSITIVE_INFINITY;
        let right = Number.NEGATIVE_INFINITY;

        Array.from(parent.children).forEach((child, index) => {
            // Check if the child element's display property is not 'none'
            if (window.getComputedStyle(child).display !== "none") {
                const childRect = child.getBoundingClientRect();
                // log(`Child ${index}: left: ${childRect.left}, right: ${childRect.right}`);
                left = Math.min(left, childRect.left);
                right = Math.max(right, childRect.right);
            } else {
                // log(`Child ${index} is hidden (display: none), skipping.`);
            }
        });

        const contentWidth = right - left;
        // log(`Content width for ${parent.id || parent.className}: ${contentWidth}`);
        return contentWidth;
    }

    // Function to apply CSS rules dynamically to the stylesheet
    function applyAfterPseudoCssRules() {
        log("Applying CSS rules...");

        let newRules = "";
        innerItemElements.forEach((parentId, index) => {
            const conclusion = widthConclusions[index];
            log(`Processing ${parentId}: Conclusion - ${conclusion}`);

            if (conclusion !== "same") {
                newRules += `#${parentId}:after { content: ""; max-width: ${conclusion}px; }\n`;
                log(`Rule for ${parentId}: max-width: ${conclusion}px`);
            }
        });

        // Apply the new rules to the stylesheet
        innerItemAfterStyles.textContent = newRules;
        log(`CSS rules applied:\n${newRules}`);
    }

    function observeInnerElements() {
        log("Starting to observe elements with the class '.video-manipulator-inner-item'.");

        // Start observing all elements with the class '.video-manipulator-inner-item'
        const videoManipulatorItems = document.querySelectorAll(".video-manipulator-inner-item");
        log(`Found ${videoManipulatorItems.length} elements to observe.`);

        videoManipulatorItems.forEach((item) => {
            log(`Observing: ${item.id || item.className}`);
            innerItemResizeObserver.observe(item);
        });
    }

    function recalculateAllAfterPseudoElements() {
        log("Inner item elements: " + JSON.stringify(innerItemElements));
        innerItemElements.forEach((parentId, index) => {
            // Retrieve the parent element by its ID or class name
            let parentElement = document.querySelector(`#${parentId}`) || document.querySelector(`.${parentId}`);

            if (parentElement) {
                // Get the current width of the parent element and its content
                const parentRect = parentElement.getBoundingClientRect();
                const contentWidth = calculateContentWidth(parentElement);

                log(`For ${parentId}:`);
                log(`Container width: ${parentRect.width}`);
                log(`Content width: ${contentWidth}`);

                // Compare the current width of the parent and the content width
                const conclusion = parentRect.width > contentWidth ? contentWidth : "same";

                // Update the conclusion stored in the array
                widthConclusions[index] = conclusion;

                // Log the result
                log(`Recalculated conclusion for ${parentId}: ${conclusion}`);

                // Update the styles after measuring all elements
                applyAfterPseudoCssRules();
            }
        });
    }

    function recalculateForElement(element) {
        // Ensure the element is valid
        if (!element) {
            log("Invalid element passed.");
            return;
        }

        // Get the element's ID or class name (just like in ResizeObserver)
        const parentId = element.id || element.className;
        log(`Recalculating for: ${parentId}`);

        // Get the current width of the parent element and its content
        const parentRect = element.getBoundingClientRect();
        const contentWidth = calculateContentWidth(element);

        log(`For ${parentId}:`);
        log(`Container width: ${parentRect.width}`);
        log(`Content width: ${contentWidth}`);

        // Compare the current width of the parent and the content width
        const conclusion = parentRect.width > contentWidth ? contentWidth : "same";

        // Update the conclusion in the widthConclusions array for this element
        const index = innerItemElements.indexOf(parentId);
        if (index !== -1) {
            widthConclusions[index] = conclusion;
            log(`Updated conclusion for ${parentId}: ${conclusion}`);
        } else {
            log(`${parentId} is not found in innerItemElements.`);
        }

        // Now, apply the styles after recalculating for this single element
        applyAfterPseudoCssRules();
    }

    // Variable to store the interval time in milliseconds (default 1000 / 60)
    let checkTimeIntervalTime = 100000;

    // Interval ID for later clearing
    let checkTimeIntervalId = null;

    // Function to handle the action we want to perform at intervals
    function checkTimeAtInterval() {
        // log("Action performed at rate of", measureRateInput.value, "per second.");
        // Add whatever action needs to happen here
        if (timeLoopDebug) {
            getCurrentTime(lastMeasuredTimeInput);
        }
    }

    // Start the interval based on the input value
    function startCheckTimeInterval() {
        // Clear any existing interval
        if (checkTimeIntervalId) clearInterval(checkTimeIntervalId);

        // Set the new interval
        checkTimeIntervalId = setInterval(checkTimeAtInterval, checkTimeIntervalTime);
    }

    // Debounced input handling
    let debounceCheckTimeIntervalTimer = null;

    function handleSrcChange() {
        log("Handling video source change...");
        handleReset();
        resizeByDefault = JSON.parse(localStorage.getItem("resizeByDefault")) || false;
        if (resizeByDefault) {
            resizeDefaultCheckbox.checked = true;
            frameIsRescaled = true;
            handleFrameResize("resize-frame");
            rescaleFrame();
            buttonRefs["resize-frame"].classList.add("active");
        }

        // if (chapters) {
        //   chapters.remove();
        // }
    }

    function reEstablishChapters() {
        establishChaptersAttempts = 0;
        establishChaptersAttemptsInterval = 250;

        establishChapters();
    }

    let currentUrl = window.location.href;
    function checkUrl() {
        if (window.location.href !== currentUrl) {
            log("URL changed to (polling):", window.location.href);
            currentUrl = window.location.href;
            reEstablishChapters();
        }
        setTimeout(checkUrl, 250); // Check every 100ms
    }
    checkUrl(); // Start the polling

    // Create the observer for the video element
    function createSrcObserver() {
        findVideo();

        if (!video) {
            log("No video element found.");
            return;
        }

        // Create a mutation observer to detect changes in the video element's src
        const observer = new MutationObserver((mutationsList, observer) => {
            for (const mutation of mutationsList) {
                if (mutation.type === "attributes" && mutation.attributeName === "src") {
                    log("Video source has changed.");
                    handleSrcChange();
                }
            }
        });

        // Observe the video element for attribute changes (such as src)
        observer.observe(video, {
            attributes: true, // Observe changes to attributes (e.g., src)
            childList: false, // Do not observe child elements
            subtree: false // Do not observe descendants
        });

        // If the video element is removed, disconnect the observer
        const videoParentObserver = new MutationObserver(() => {
            if (!document.contains(video)) {
                observer.disconnect();
                initialize();
                log("Video element removed from the DOM. Observer disconnected.");
            }
        });

        // Observe the parent node to detect when the video is removed
        videoParentObserver.observe(document.body, {
            childList: true, // Observe additions and removals of child nodes
            subtree: true // Observe the entire DOM tree
        });
    }

    function attachResizeObserverOnVideoPlayer() {
        let html5VideoPlayer = document.querySelector(".html5-video-player");

        // Check if the element exists, if not, retry every 250ms
        const checkInterval = setInterval(() => {
            html5VideoPlayer = document.querySelector(".html5-video-player");

            if (html5VideoPlayer) {
                clearInterval(checkInterval); // Stop checking once we find the element

                // Attach ResizeObserver
                const resizeObserver = new ResizeObserver(() => {
                    // Function to run on resize
                    log("Video player resized!");
                    scaleAndTop();
                });

                // Start observing the element for resizing
                resizeObserver.observe(html5VideoPlayer);

                log("Resize observer attached to .html5-video-player");
            }
        }, 250); // Retry every 250ms until found
    }

    /* Manual */

    function insertManual() {
        const manualDiv = document.createElement("div");
        manualDiv.id = "video-controls-manual";
        manualDiv.innerHTML = `
      <div class="empty-spanner line"></div>

      <h2>Speed Control</h2>

<p>This <b>playback rate controller</b> has a simple number input. It lets you enter the speed
  you want, or use the spinners to move up or down by 5%.</p>

<p>The controls also include a <b>speed lock</b>. Sometimes, after you dial in just the right playback speed,
scripts on YouTube try to change it. When this happens, the speed lock kicks in to put the speed back where
you had it. You can lock the speed just for now, or lock it forever, so that every video you open will play
  at your custom speed.</p>

<p>(<b>Note:</b> Some scripts and extensions may have their own speed locks, which will put them in a deadlock
  with this extension. In these cases, disabling the speed lock for this script is easy enough.)</p>

<h2>Play/Pause Lock</h2>

<p>Sometimes, scripts or extensions may try to play or pause a video when you didn't ask them to. The <b>play
  lock</b> and <b>pause lock</b> are designed to stop this. Because you should decide when your videos play.</p>

<p>(<b>Note:</b> Sometimes, YouTube's native scripts may be so aggressive that the play lock cannot overcome
  them.)</p>

<h2>Aspect, Zoom, Flip, & Frame</h2>

<p>The <b>aspect</b> controls let you correct videos that were thoughtlessly stretched by the uploader. Because
people don't look good when they get stretched out of shape. The input for <b>custom aspect ratios</b> lets
  you set ratios precisely, for when <b>4/3</b> or <b>16/9</b> are not the correct ratio.</p>

<p>(<b>Note</b>: When you input a custom aspect ratio, you have to press the <b>Custom</b> button to apply it,
every time.)</p>

<p>The <b>zoom</b> control can help fix videos that were uploaded with a hard matte, getting rid of pointless
black bars and allowing the video to fill its frame.</p>

<p>The <b>flip, mirror, and 180°</b> buttons let you easily correct videos that have been altered by their
uploader. Was the video flipped horizontally to avoid copyright bots, and does the text look wrong backwards?
You can flip it back using the <b>Mirror</b> button. The <b>Flip</b> button is there just in case a video has
been flipped vertically. And the 180° can help correct videos that were shot in the southern hemisphere,
or Yes's music video for "Leave it".</p>

<p>The <b>Frame Resize</b> button resizes the video frame to match the video it contains, avoiding unnecessary
letterboxing or pillarboxing.</p>

<p>(<b>Note:</b> Implementing frame resize has been challenging, and you may still encounter a few bugs.)</p>

<p>The <b>Reset</b> button puts all of these controls back the way they were. It does not, however, clear the
input boxes, which makes reapplying a custom aspect ratio or zoom easy.</p>

<h2>Jump to Time / Get Current Time</h2>

<p>YouTube has ways of getting to different chapters in a video, but getting to any other specific point is
difficult. Now, you can enter a time value in hours, minutes, seconds, and milliseconds — that's how precise
it is — and press the <b>Jump to</b> button to go directly to any point in the video. Any standard time value
will work: hours, minutes, and seconds, or just minutes and seconds, or just seconds — any of these with or
without milliseconds.</p>

<p>The <b>Get Current Time</b> button will tell you exactly where you are in a video, with millisecond
precision, making it easy to identify points you want to revisit.</p>

<h2>Nice 'n' Accurate Looper</h2>

<p>The time seeking continues with my own version of a <b>looper</b>. There are a number of available loopers
for YouTube, but they tend to limit their accuracy to whole seconds, and sometimes, that just isn't enough.
This looper accepts inputs that include milliseconds, just like the the time seeker in the last section.
This allows you to specify loops right down to the frame. Additional controls let you decide if the video
will loop forever, or just a set number of times.</p>

<p>(<b>Note:</b> If your system is overworked, accuracy may suffer. However, in tests, the results have been
impressive.)</p>

<h2>Corners, Overlays, & Chapters</h2>

<p>This set of cosmetic controls are somewhat miscellaneous, and have been grouped together for convenience.</p>

<p>The <b>Square Corners</b> control undoes YouTube's corner rounding. Because all pixels matter.</p>

<p>The <b>Hide Overlays</b> control gets rid of distracting video overlays, like channel logos, popup links,
and title cards that interrupt the ends of music videos.</p>

<p>The <b>Move Chapter Selector</b> takes the nice chapter selector that YouTube hides away in the video
description, and moves it to a more convenient place. The <b>Low</b> option puts the selector just below
Jupiter's Tools for YouTube. The <b>Middle</b> option puts it just above these tools. And the <b>High</b>
option puts it even higher: right below the video's title.</p>

<h2>Volume Boost</h2>

<p>For videos that are too quiet, this control can <b>boost</b> the gain. You decide the amount of boost.
The input works in decibels, with a helpful conversion to percent for people who can't think in decibels.
To prevent unpleasant clipping, the audio is sent through a limiter. Not using one would be simply
irresponsible.</p>

<p>The following paragraphs will likely only appeal to audio engineering and web coding enthusiasts.</p>

<p>This volume booster uses the <a href="https://webaudio.github.io/web-audio-api/#DynamicsCompressorNode">Web
  Audio API compressor</a>. By default, the ratio is set to 20:1 — as high as it will go — with a slightly
soft knee, instantaneous attack, and a medium release time. For those who want to tinker, the <b>Expert</b>
button opens another control panel that gives you full access to the compressor.</p>

<p>Note: Because Web Audio API ties threshold to makeup gain, and gives the user no control over that makeup
gain, the stock threshold has been replaced with a boost going in and a cut coming out, to make the
compressor easier to control.</p>

<div class="empty-spanner line"></div>
      `;
        videoControlsMasterHolder.appendChild(manualDiv);
    }

    /* INITIALIZE SECTION */

    function insertCombinedControls() {
        const existingControls = topRow.querySelector(".video-manipulator-outer-div");
        if (existingControls) {
            return;
        } else {
            log("Inserting controls...");
        }

        actions = topRow.querySelector("#actions");
        if (!actions) {
            log("Actions element not found.");
            // insertAttempts += 1;
            // if (insertAttempts < 60) {
            setTimeout(() => {
                insertCombinedControls();
            }, 250);
            return;
            // }
        }

        let insertDelayIncrease = 10;
        let insertDelay = insertDelayIncrease;

        setTimeout(() => {
            const emptySpanner = insertEmptySpanner();
            topRow.appendChild(emptySpanner);
        }, insertDelay);
        insertDelay += insertDelayIncrease;

        setTimeout(() => {
            insertVideoControlsShowHideMenu();
        }, insertDelay);
        insertDelay += insertDelayIncrease;

        setTimeout(() => {
            const emptySpanner = insertEmptySpanner(true);
            topRow.appendChild(emptySpanner);
        }, insertDelay);
        insertDelay += insertDelayIncrease;

        setTimeout(() => {
            createVideoControlsMasterHolder();
        }, insertDelay);
        insertDelay += insertDelayIncrease;

        setTimeout(() => {
            insertPlaybackRateControls();
        }, insertDelay);
        insertDelay += insertDelayIncrease;

        setTimeout(() => {
            insertLockControls();
        }, insertDelay);
        insertDelay += insertDelayIncrease;

        setTimeout(() => {
            // log('This is where the control panel SHOULD be inserted.');
            insertControlPanel();
        }, insertDelay);
        insertDelay += insertDelayIncrease;

        setTimeout(() => {
            insertSeekAndLoopControls();
        }, insertDelay);
        insertDelay += insertDelayIncrease;

        setTimeout(() => {
            insertCosmeticControls();
        }, insertDelay);
        insertDelay += insertDelayIncrease;

        // Initialize the compressor controls
        setTimeout(() => {
            insertCompressorControls();
        }, insertDelay);
        insertDelay += insertDelayIncrease;

        setTimeout(() => {
            insertManual();
        }, insertDelay);
        insertDelay += insertDelayIncrease;

        setTimeout(() => {
            insertAboutDiv();
        }, insertDelay);
        insertDelay += insertDelayIncrease;

        setTimeout(() => {
            populateVideoControlsShowHideMenu();
        }, insertDelay);
        insertDelay += insertDelayIncrease;

        setTimeout(() => {
            addPressEffectToButtons();
        }, insertDelay);
        insertDelay += insertDelayIncrease;

        setTimeout(() => {
            monitorVideoSize();
            observeInnerElements();
            createSrcObserver();
            attachResizeObserverOnVideoPlayer();
            // if (timeLoopDebug) {
            //     // startCheckTimeInterval();
            // }
        }, insertDelay);
        insertDelay += insertDelayIncrease;

        setTimeout(() => {
            insertCombinedControls();
        }, 5000);
    }

    let initializeMessageRecent = false;

    // Function to initialize the userscript
    function initialize() {
        if (!initializeMessageRecent) {
            log("The initialize funtion is running.");
            initializeMessageRecent = true;
            setTimeout(() => {
                initializeMessageRecent = false;
            }, 1000);
        }

        findVideo();

        if (!video) {
            setTimeout(() => {
                initialize();
            }, 1000);
            return;
        }

        topRow = document.querySelector("ytd-watch-metadata #top-row");

        if (!topRow) {
            setTimeout(() => {
                initialize();
            }, 1000);
            return;
        }

        insertStylesheets();

        insertCombinedControls();

        //         if (!insertControlPanel()) {
        //             const observer = new MutationObserver((mutations) => {
        //                 const now = Date.now();
        //                 if (now - lastChecked >= 2000) {
        //                     lastChecked = now;
        //                     if (insertControlPanel()) {
        //                         insertCombinedControls();
        //                         observer.disconnect();
        //                     }
        //                 }
        //             });

        //             observer.observe(document, {
        //                 childList: true,
        //                 subtree: true
        //             });
        //         } else {
        //             insertCombinedControls();
        //         }
    }

    // Run the initialize function when the page has fully loaded
    // window.addEventListener('load', initialize);
    initialize();
})();