SUKEBEI PLUS

Add original video preview.

Mint 2024.08.20.. Lásd a legutóbbi verzió

// ==UserScript==
// @name        SUKEBEI PLUS
// @namespace   Violentmonkey Scripts
// @match       *://sukebei.nyaa.si/*
// @grant		GM_addStyle
// @grant		GM_xmlhttpRequest
// @grant       GM_setValue
// @grant       GM_getValue
// @grant       GM_registerMenuCommand
// @grant       GM_xmlhttpRequest
// @version     1.0.5
// @author      Chaewon
// @description Add original video preview.
// @license     Unlicense
// @icon	    https://sukebei.nyaa.si/static/favicon.png
// ==/UserScript==

(function () {
	"use strict";

	const stylesheet = `
    .overlay-video-container {
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-color: rgba(0, 0, 0, 0.9);
        display: flex;
        justify-content: center;
        align-items: center;
        z-index: 9999;
    }

    .overlay-video {
        width: auto;
        max-width: 90%;
        min-height: 60%;
        height: auto;
        max-height: 90%;
        border: 1px solid #919191;
        background: #000;
    }

    .close-button {
        position: absolute;
        padding: 6px 14px;
        top: 10px;
        right: 10px;
        background: none;
        border: none;
        color: white;
        cursor: pointer;
        border: 1px solid #333;
    }

    .settings-container {
        position: fixed;
        right: 1em;
        top: 2em;
        max-width: 400px;
        width: 100%;
        padding: 10px 20px;
        border: 1px solid #ddd;
        border-radius: 8px;
        background-color: #fff;
        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
        z-index: 9999;
    }
    .settings-container .settings-item:not(:last-of-type) {
        margin-bottom: 20px;
    }

    .settings-container label {
        display: block;
        margin-bottom: 8px;
        font-weight: 600;
        color: #333;
    }

    .settings-container input[type="text"],
    .settings-container input[type="range"] {
        width: 100%;
        padding: 8px;
        border: 1px solid #ccc;
        border-radius: 4px;
        box-sizing: border-box;
    }

    .settings-container input[type="checkbox"] {
        margin-right: 10px;
    }

    .settings-container .button {
        display: inline-block;
        padding: 10px 15px;
        color: #fff;
        background-color: #007bff;
        border: none;
        border-radius: 4px;
        cursor: pointer;
        text-align: center;
        transition: background-color 0.3s ease;
    }

    .settings-container .button:hover {
        background-color: #0056b3;
    }

    .settings-container range-label {
        margin-bottom: 5px;
        color: #333;
    }
        
    .settings-container #quality {
        color: black;
    }
    .settings-container option {
        color: black;
    }`;

	GM_addStyle(stylesheet);
	GM_registerMenuCommand("Config", openSettings);

	let userConfig;
	const fetchConfig = GM_getValue("config");

	if (fetchConfig) {
		userConfig = fetchConfig;
	} else {
		console.log("[US:DEBUG] : ", "No local config found. Uses default.");
		userConfig = {
			darkTheme: false,
			playerAutoplay: false,
			playerVolume: 0.1,
			playerLoop: true,
			playerClickAnywhereToClose: false,
            previewQuality: 5,
		};
	}

	console.log("[US:DEBUG] : ", "CONFIG: ", userConfig);

	// Manually added. Not all code added nor tested.
	const studios = {
		general: ["PFES"],
		das: ["DASD", "DASS", "DAZD", "PLA", "PLB"],
		sOne: ["SSIS", "SOE", "SNIS", "SSNI", "OFJE", "SONE", "ONSD"],
		wanz: [
			"WAAA",
			"BMW",
			"WANZ",
			"WNZ",
			"PPS",
			"WNZS",
			"WAB",
			"WFS",
			"SWF",
		],
		eBody: ["EBOD", "EBWH", "MKCK", "EYAN"],
		oppai: ["PPPD", "PPPE", "PPBD", "PPMD", "PPSD"],
		aurora: [
			"APNS",
			"APGH",
			"APAK",
			"APAA",
			"APGG",
			"APAE",
			"APKH",
			"APNH",
		],
		bibian: ["BBAN", "BBSS"],
		dahlia: ["DLDSS"],
		faleno: ["FSDSS", "FCDSS", "FTBLD", "FTKD", "FTHTD", "MGOLD"],
		hunter: ["HUNTC", "HUBLK", "HHF", "HUNTA", "HUNBL", "HUNTB"],
		kawaii: ["CAWD", "KAWD", "KWBD", "KANE", "KAPD"],
		moodyz: [
			"MIDV",
			"MIMK",
			"MIFD",
			"MIAB",
			"MIZD",
			"MIRD",
			"MIAA",
			"MIDE",
			"KMIDE",
			"MIAE",
			"MIGD",
			"MIAD",
			"MIBD",
			"MIDD",
			"MDED",
			"MDLD",
			"MDUD",
		],
		madonna: [
			"JUQ",
			"JUY",
			"ROE",
			"JUMS",
			"ACHJ",
			"URE",
			"JUSD",
			"JUL",
			"OBA",
		],
		oneMore: ["ONEX"], //also has ONEZ - Prestige is bigger therefor priortized over this studio.
		premium: ["PRED", "PBD", "PRWF", "PRST", "PGD", "PXD", "PJD", "PID"],
		jetEizou: ["NGOD", "NKKD", "NDRA", "NBES", "LLAN"],
		prestige: [
			"ABF",
			"ABP",
			"YRK",
			"FIG",
			"SHF",
			"HHE",
			"AAS",
			"THU",
			"PPX",
			"HEO",
			"PXM",
			"VPC",
			"ONEZ",
			"PPT",
			"ICHK",
			"ABW",
			"AFS",
			"DCX",
			"CPDE",
			"MGT",
			"KUM",
			"TRE",
			//"MBMH",
			"FIR",
			"DNW",
			"DOCP",
			"TEN",
			"KBI",
			"GOAL",
			"MFCC",
			"GNAB",
			//"MBM",
			"GZAP",
			"JNT",
			"CHN",
			"JAC",
			"FIV",
			"TUS",
			"BGN",
			"ASI",
			"PXH",
			"MTM",
			//"DCV",
			"GGEN",
			"DTT",
			"CPDE",
			"KPB",
			"DIC",
			"AMA",
			"YRH",
			"CDC",
			"SOUD",
			"NAM",
			"DCX",
			"SIM",
		],
		attackers: [
			"ADN",
			"ATK",
			"ATID",
			"SAME",
			"YUJ",
			"SSPD",
			"ATKD",
			"JBD",
			"ATAD",
			"RBK",
			"SHKD",
		],
		sodCreate: [
			"STAR",
			"STARS",
			"START",
			"STARTS",
			"SDNM",
			"SDMM",
			"SDMF",
			"SDDE",
			"SDAM",
			"SETM",
			"SDMUA",
			"SDJS",
			"FTAV",
			"SUWK",
			"MOGI",
			"KKBT",
			"SDMU",
			"KIRE",
			"KMHRS",
			"SDTH",
			"KUSE",
			"MSFH",
			"SDNT",
			"SDEN",
		],
		aliceJapan: ["DVAJ", "DV"],
		ideaPocket: [
			"IPX",
			"IPZ",
			"IPZZ",
			"IPTD",
			"IDBD",
			"IPIT",
			"SUPD",
			"IPSE",
		],
		nagaeStyle: ["NSFS"],
		naturalHigh: ["NHDTB", "NHDTA", "NHDT"],
		tameikeiGoro: ["MEYD", "MDYD", "MBYD"],
		sQute: ["SQTE", "KRAY"],
		royal: ["ROYD"],
		materiall: ["MTATA", "MTALL", "MTABS"],
		honnaka: ["MIH", "HMN", "HNDB", "HNDS", "HND", "KRND"],
		lunatics: ["LULU"],
		nampaJapan: ["NPJS", "NNPJ", "NPJB", "TNB"],
		serebuNoTomo: ["CEMD", "CEAD", "CESD", "CETD"],
		barutan: [
			"BASJ",
			"BASB",
			"BAGR",
			"BACJ",
			"BAHP",
			"BAEM",
			"BACN",
			"BAVC",
			"BADA",
		],
		guppi: ["GUPP"],
		shiroutoKissa: ["HAZU"],
		cineMagic: ["CNY", "CMC", "CMN", "CMA", "CMV", "CMF"],
		globalMediaAnnex: ["GMA", "GARA", "GAJK", "GMAB"],
		takaraEizou: [
			"MOND",
			"ALDN",
			"NTRD",
			"MGHT",
			"SPRD",
			"AVOP",
			"RADC",
			"CEMN",
			"DTKM",
		],
		fairAndWay: ["FWAY"],
		hsoda: ["HSODA", "PFES"],
		ieEnergy: ["IESP", "IENF", "IESM"],
		kmProduce: [
			"SCOP",
			"REAL",
			"MKMP",
			"MDTM",
			"MDBK",
			"BOKD",
			"BAZX",
			"UMSO",
			"SCPX",
			"OKAX",
			"ENKI",
			"BAZE",
			"MDTE",
			"NANX",
		],
		kaguyaHimePtMousozoku: ["KPIE", "KAGP", "MASM", "MKON", "BABM"],
		hotEntertainment: [
			"HEZ",
			"SHE",
			"HOC",
			"HFF",
			"HJT",
			"HZM",
			"HVY",
			"HNU",
			"HNK",
		],
		crystalEizou: ["NITR", "EKDV", "MADV", "CADV", "MADM", "GEKI"],
		rocket: ["RCTD", "RCT"],
	};

	const studiosInDMM = [
			...studios.general,
			...studios.sOne,
			...studios.ideaPocket,
			...studios.wanz,
			...studios.attackers,
			...studios.kawaii,
			...studios.madonna,
			...studios.hunter,
			...studios.jetEizou,
			...studios.bibian,
			...studios.das,
			...studios.aurora,
			...studios.eBody,
			...studios.tameikeiGoro,
			...studios.nagaeStyle,
			...studios.moodyz,
			...studios.oppai,
			...studios.premium,
			...studios.aliceJapan,
			...studios.sQute,
			...studios.royal,
			...studios.honnaka,
			...studios.lunatics,
			...studios.nampaJapan,
			...studios.serebuNoTomo,
			...studios.barutan,
			...studios.guppi,
			...studios.shiroutoKissa,
			...studios.cineMagic,
			...studios.globalMediaAnnex,
			...studios.takaraEizou,
			...studios.fairAndWay,
			...studios.hsoda,
			...studios.kmProduce,
			...studios.kaguyaHimePtMousozoku,
		],
		plusOne = [
			...studios.faleno,
			...studios.dahlia,
			...studios.naturalHigh,
			...studios.sodCreate,
			...studios.materiall,
			...studios.ieEnergy,
			...studios.rocket,
		],
		prestigeStudios = [...studios.prestige];

	const regexPatterns = {
		dmm: new RegExp(`\\b(?:${studiosInDMM.join("|")})(?:-)?\\d{3}\\b`, "i"),
		plusOne: new RegExp(`\\b(?:${plusOne.join("|")})(?:-)?\\d{3}\\b`, "i"),
		prestige: new RegExp(
			`\\b(?:${prestigeStudios.join("|")})(?:-)?\\d{3}\\b`,
			"i"
		),
		oneMore: new RegExp(
			`\\b(?:${studios.oneMore.join("|")})(?:-)?\\d{3}\\b`,
			"i"
		),
		hotEntertainment: new RegExp(
			`\\b(?:${studios.hotEntertainment.join("|")})(?:-)?\\d{3}\\b`,
			"i"
		),
		//faleno: new RegExp(`\\b(?:${faleno.join('|')})(?:-)?\\d{3}\\b`, 'i'),
		//dahlia: new RegExp(`\\b(?:${dahlia.join('|')})(?:-)?\\d{3}\\b`, 'i')
	};

	//SECTION - MAIN
	if (window.location.pathname.startsWith("/view/")) {
		console.log("[US:DEBUG] : ", "Torrent Detail Page");
		const titlePanel = document.getElementsByClassName("panel-title");
		if (
			titlePanel[0].parentElement.nextElementSibling.classList.contains(
				"panel-body"
			) &&
			titlePanel[0].parentElement.nextElementSibling.children[0].classList.contains(
				"row"
			)
		) {
			//Append Button
			const code = detectCode(titlePanel[0].innerText, regexPatterns);
			if (code && code.match) {
				console.log("[US:DEBUG] : ", "DMM studios detected: ", code);
				let codeId = code.match.toLowerCase();
				const buttonDom = document.getElementsByClassName(
					"panel-footer clearfix"
				)[0];
				const newButton = document.createElement("a");
				newButton.setAttribute("href", "?preview=" + codeId);
				newButton.setAttribute(
					"title",
					"Original DVD Preview (Not Torrent Preview!)"
				);
				newButton.innerHTML = `<i class="fa fa-video-camera"></i> Preview`;
				const buttonDivider = document.createTextNode(" ・");
				buttonDom.insertBefore(newButton, buttonDom.firstChild);
				buttonDom.insertBefore(
					buttonDivider,
					buttonDom.firstChild.nextSibling
				);
				newButton.addEventListener("click", function (event) {
					event.preventDefault();
					openPreview(codeId, code.cdn);
				});
			} else {
				return;
			}
		} else {
			return;
		}
	} else {
		console.log("[US:DEBUG] : ", "Non Torrent Detail Page");
		const rows = document.querySelectorAll("tr");
		//Append Button
		//TODO - Only check if AV category?
		rows.forEach((row, index) => {
			if (!row || index === 0) return;

			const categoryCell =
				row.querySelector("td:nth-child(1) a")["title"];
			const titleCell = row.querySelector("td:nth-child(2)");
			const linkCell = row.querySelector("td:nth-child(3)");
			if (categoryCell === "Real Life - Videos") {
				const code = detectCode(titleCell.innerText, regexPatterns);
				if (code && code.match) {
					console.log(
						"[US:DEBUG] : ",
						"DMM studios detected: ",
						code
					);
					let codeId = code.match.toLowerCase();
					//const buttonDom =
					//	titleCell.parentElement.querySelector("td:nth-child(3)");
					const newButton = document.createElement("a");
					newButton.setAttribute("href", "?preview=" + codeId);
					newButton.setAttribute(
						"title",
						"Original DVD Preview (Not Torrent Preview!)"
					);
					newButton.innerHTML = `<i class="fa fa-video-camera"></i>`;
					linkCell.appendChild(newButton);
					newButton.addEventListener("click", function (event) {
						event.preventDefault();
						openPreview(codeId, code.cdn);
					});
				} else {
					return;
				}
			}
		});
	}

	function detectCode(title, patterns) {
		for (const [key, pattern] of Object.entries(patterns)) {
			const match = title.match(pattern);
			if (match) {
				return {
					match: match[0],
					cdn: key,
				};
			}
		}
		return { match: null, cdn: null };
	}

	function fetchData(id, cdn, callback) {
		//NOTE PER WEBSITE METHOD
		// switch (cdn) {
		//     case 'dmm':
		//         GM_xmlhttpRequest({
		//             method: "GET",
		//             url: 'https://www.dmm.co.jp/service/digitalapi/-/html5_player/=/cid=' + id.toLowerCase(),
		//             onload: function (response) {
		//                 if (response.status === 200) {
		//                     let scriptData, scriptObj;
		//                     let scripts = response.responseXML.scripts;
		//                     for (let i = 0; i < scripts.length; i++) {
		//                         const script = scripts[i];
		//                         if (script.textContent.includes('dmm')) {
		//                             scriptData = script.textContent;
		//                         }
		//                     }
		//                     const regex = /const args = ({.*?});/s;
		//                     const match = scriptData.match(regex);
		//                     if (match) {
		//                         const jsonString = match[1];
		//                         try {
		//                             scriptObj = JSON.parse(jsonString.replace(/\\/g, ''));
		//                         } catch (error) {
		//                             console.error('Error parsing JSON:', error);
		//                         }
		//                         callback(scriptObj.src)
		//                     }
		//                 } else {
		//                     console.error("Request failed with status:", response.status);
		//                 }
		//             }
		//         });
		//         break;
		//     case 'faleno':
		//         GM_xmlhttpRequest({
		//             method: "GET",
		//             url: 'https://faleno.jp/top/works/' + id.toLowerCase() + '/',
		//             onload: function (response) {
		//                 if (response.status === 200) {
		//                     const links = response.responseXML.links;
		//                     const findPreview = (links) => {
		//                         for (let i = 0; i < links.length; i++) {
		//                             const link = links[i];
		//                             if (
		//                                 link.classList.contains('pop_sample') &&
		//                                 link.href.toLowerCase().replace(/\s+/g, '').replace(/[^\w]/g, '').includes(id.toLowerCase()) &&
		//                                 link.href.endsWith('.mp4')
		//                             ) {
		//                                 return link.href;
		//                             }
		//                         }
		//                         return null;
		//                     };
		//                     const result = findPreview(links);
		//                     callback(result)
		//                 } else {
		//                     console.error("Request failed with status:", response.status);
		//                 }
		//             }
		//         });
		//         break;
		//     default:
		//         console.log("[US:DEBUG] : ", `No CDN found: ${expr}.`);
		// }

		//NOTE DMM ONLY METHOD
		let dvdId = id;

		//if (cdn === 'faleno' || cdn === 'dahlia') {
		if (cdn === "plusOne") {
			dvdId = "1" + dvdId;
		}

		if (cdn === "prestige") {
			dvdId = "118" + dvdId;
		}

		if (cdn === "oneMore") {
			dvdId = "h_1674" + dvdId;
		}

		if (cdn === "hotEntertainment") {
			dvdId = "59" + dvdId;
		}

		GM_xmlhttpRequest({
			method: "GET",
			url:
				"https://www.dmm.co.jp/service/digitalapi/-/html5_player/=/cid=" +
				dvdId.toLowerCase(),
			onload: function (response) {
				if (response.status === 200) {
					let scriptData, scriptObj;
					let scripts = response.responseXML.scripts;
					for (let i = 0; i < scripts.length; i++) {
						const script = scripts[i];
						if (script.textContent.includes("dmm")) {
							scriptData = script.textContent;
						}
					}
					const regex = /const args = ({.*?});/s;
					const match = scriptData.match(regex);

					if (match) {
						const jsonString = match[1];
						try {
							scriptObj = JSON.parse(
								jsonString.replace(/\\/g, "")
							);
						} catch (error) {
							console.error("Error parsing JSON:", error);
						}
						//callback(scriptObj.src);
						callback(scriptObj.bitrates);
					}
				} else {
					console.error(
						"Request failed with status:",
						response.status
					);
				}
			},
		});
	}

	function qualitySorter(items) {
		const qualityTiers = {
			5: { min: 1440, max: 2160 },
			4: { min: 1080, max: 1439 },
			3: { min: 720, max: 1079 },
			2: { min: 480, max: 719 },
			1: { min: 0, max: 479 },
		};

		const extractResolution = (bitrate) => {
			const match = bitrate.match(/\((\d+)p\)/);
			return match ? parseInt(match[1], 10) : null;
		};
		const getQualityTier = (resolution) => {
			for (const [tier, { min, max }] of Object.entries(qualityTiers)) {
				if (resolution >= min && resolution <= max) {
					return tier;
				}
			}
			return "Unknown";
		};

		const tierMap = new Map();

		items.forEach((item) => {
			const resolution = extractResolution(item.bitrate);
			if (resolution) {
				const qualityTier = getQualityTier(resolution);
				if (!tierMap.has(qualityTier)) {
					tierMap.set(qualityTier, {
						quality: qualityTier,
						bitrate: item.bitrate,
						src: item.src,
					});
				}
			}
		});

		return Array.from(tierMap.values());
	}

    function qualitySelector(desiredQuality, array) {
        const sortedArray = array.slice().sort((a, b) => b.quality - a.quality);
    
        for (const item of sortedArray) {
            if (item.quality <= desiredQuality) {
                return item.src;
            }
        }
        
        return null;
    }

	function openPreview(code, cdn) {
		code = code.replace(/\s+/g, "").replace(/[^\w]/g, "");
		fetchData(code, cdn, (response) => {
			//if (!response) return;

			//Player
			const video = document.createElement("video");
			video.src = qualitySelector(userConfig.previewQuality, qualitySorter(response));
			video.autoplay = userConfig.playerAutoplay;
			video.volume = userConfig.playerVolume;
			video.loop = userConfig.playerLoop;
			video.controls = true;
			video.classList.add("overlay-video");
			video.addEventListener("error", function (event) {
				console.error("Video failed to load:");
				videoContainer.innerHTML = `<p style="color: white; margin: 0; text-align: center;">Preview Not Available.<br>This window will auto close in 3 seconds</p>`;
				setTimeout(() => {
					videoContainer.remove();
				}, 3000);
			});

			const closeButton = document.createElement("button");
			closeButton.textContent = "Close";
			closeButton.classList.add("close-button");
			closeButton.addEventListener("click", () => {
				videoContainer.remove();
			});

			const videoContainer = document.createElement("div");
			videoContainer.classList.add("overlay-video-container");
			videoContainer.classList.add(`${code}`);
			videoContainer.appendChild(video);
			videoContainer.appendChild(closeButton);
			document.body.appendChild(videoContainer);
			if (userConfig.playerClickAnywhereToClose) {
				videoContainer.addEventListener("click", (event) => {
					if (event.target !== video) {
						videoContainer.remove();
					}
				});
			}
		});
	}

	//!SECTION

	// SECTION - Settings

	//const footer = document.querySelector('footer');
	const footerLink = document.querySelector("footer p");
	const settingButton = document.createElement("a");
	const buttonDivider = document.createTextNode("・");
	settingButton.setAttribute("href", "?setting");
	settingButton.setAttribute("title", "Settings");
	settingButton.innerHTML = `<i class="fa fa-cogs"></i> Settings`;
	footerLink.insertBefore(settingButton, footerLink.firstChild);
	footerLink.insertBefore(buttonDivider, footerLink.firstChild.nextSibling);
	settingButton.addEventListener("click", function (event) {
		event.preventDefault();
		openSettings();
	});

    function openSettings() {
        const isExist = document.querySelector(".settings-container");
        if (isExist) return;
    
        const container = document.createElement("div");
        container.classList.add("settings-container");
        container.setAttribute("aria-label", "Settings");
    
        // Parse config
        const parsePlayerAutoplay = userConfig.playerAutoplay ? "checked" : "";
        const parsePlayerLoop = userConfig.playerLoop ? "checked" : "";
        const parsePlayerClickAnywhereToClose = userConfig.playerClickAnywhereToClose ? "checked" : "";
        const parseDarkTheme = userConfig.darkTheme ? "checked" : "";
    
        container.innerHTML = `
            <div class="settings-item">
                <!--
                    <label for="video-width">Video Player Width (px) <i>[Default: 320]</i></label>
                    <input type="text" id="video-width" name="video-width" placeholder="Enter width in px" value="${userConfig.playerWidth}">
                </div>
                -->
                <div class="settings-item">
                    <label for="volume-slider" class="range-label">Volume:</label>
                    <input type="range" id="volume-slider" name="volume-slider" min="0" max="1" value="${userConfig.playerVolume}" step="0.01">
                </div>
                <div class="settings-item">
                <label for="quality">Video Quality (if available):</label>
                <select name="qualities" id="quality">
                    <option value="5">QHD (2K/1440p)</option>
                    <option value="4">FHD (1080p)</option>
                    <option value="3">HD (720p)</option>
                    <option value="2">Medium</option>
                    <option value="1">Low</option>
                </select> 
                </div>
                <div class="settings-item">
                    <label>
                        <input type="checkbox" id="autoplay" name="autoplay" ${parsePlayerAutoplay}>
                        Video Autoplay
                    </label>
                </div>
                <div class="settings-item">
                    <label>
                        <input type="checkbox" id="loop" name="loop" ${parsePlayerLoop}>
                        Video Loop
                    </label>
                </div>
                <div class="settings-item">
                    <label>
                        <input type="checkbox" id="clickanywhere" name="clickanywhere" ${parsePlayerClickAnywhereToClose}>
                        Click Anywhere To Close Player
                    </label>
                </div>
                <div class="settings-item last">
                    <label disabled>
                        <input type="checkbox" id="darktheme" name="darktheme" ${parseDarkTheme} disabled>
                        Auto Dark Theme
                    </label>
                </div>
                <div class="settings-item">
                    <button id="saveButton" class="button" type="button">Save Settings</button>
                    <button id="closeButton" class="button" type="button">Close</button>
                </div>`;
    
        // Append the container to the DOM
        document.body.appendChild(container);
    
        // Access the quality select element and set its value
        const preQuality = document.getElementById("quality");
        if (preQuality) {
            preQuality.value = userConfig.previewQuality || 5;
        }
    
        // Add event listeners for buttons
        let saveButton = document.getElementById("saveButton");
        saveButton.addEventListener("click", saveConfigMenu);
    
        let closeButton = document.getElementById("closeButton");
        closeButton.addEventListener("click", () => {
            const toRemove = document.querySelector(".settings-container");
            if (toRemove) {
                toRemove.remove();
            } else {
                console.log("[US:DEBUG] : ", "Bruh.");
            }
        });
    
        function saveConfigMenu() {
            const preQuality = document.getElementById("quality");
            const newVolume = document.getElementById("volume-slider");
            const autoplay = document.getElementById("autoplay");
            const loop = document.getElementById("loop");
            const darktheme = document.getElementById("darktheme");
            const clickanywhere = document.getElementById("clickanywhere");
            let finalVolume;
    
            if (
                newVolume.value !== null &&
                !isNaN(newVolume.value) &&
                newVolume.value >= 0 &&
                newVolume.value <= 1
            ) {
                finalVolume = parseFloat(newVolume.value);
            }
    
            const newUserConfig = {
                darkTheme: darktheme.checked,
                playerAutoplay: autoplay.checked,
                playerVolume: finalVolume,
                playerLoop: loop.checked,
                playerClickAnywhereToClose: clickanywhere.checked,
                previewQuality: preQuality.value,
            };
            GM_setValue("config", newUserConfig);
            location.reload();
        }
    }
	//!SECTION
})();