YouTube 화질설정

항상 최고 화질 + 영화관 모드

// ==UserScript==
// @name               YouTube 화질설정
// @version            1.0
// @description        항상 최고 화질 + 영화관 모드
// @author             김머시기
// @icon               https://cdn-icons-png.flaticon.com/64/2504/2504965.png
// @match              https://www.youtube.com/*
// @match              https://m.youtube.com/*
// @match              https://music.youtube.com/*
// @exclude            https://studio.youtube.com/*
// @grant              GM_registerMenuCommand
// @grant              GM_getValue
// @grant              GM_setValue
// @grant              GM_unregisterMenuCommand
// @license            MIT
// @namespace https://greasyfork.org/users/1307101
// ==/UserScript==

(function () {
    'use strict';
    function getSetting(key, def = true) { return GM_getValue(key, def); }
    function setSetting(key, value) { return GM_setValue(key, value); }
    let menuID = null;
    async function toggleTheaterMode() {
        const current = await getSetting('theaterMode', true);
        await setSetting('theaterMode', !current);
        updateMenu();
    }
    async function updateMenu() {
        const isOn = await getSetting('theaterMode', true);
        if (menuID !== null) GM_unregisterMenuCommand(menuID);
        menuID = GM_registerMenuCommand(`🎬 영화관 모드  ${isOn ? 'ON' : 'OFF'}`, toggleTheaterMode, {
            autoClose: false,
            title: `영화관 모드 ${isOn ? '켜짐' : '꺼짐'}`
        });
    }
    updateMenu();
    let alreadyApplied = false;
    function applyTheaterMode() {
        if (!getSetting('theaterMode', true)) return;
        const theaterBtn = document.querySelector('.ytp-size-button');
        const isInTheater = document.querySelector('ytd-watch-flexy[theater]');
        if (theaterBtn && !isInTheater) theaterBtn.click();
    }
    function applyHighestQuality() {
        const playerApi = document.getElementById('movie_player');
        if (playerApi && typeof playerApi.getAvailableQualityLevels === 'function') {
            const qualities = playerApi.getAvailableQualityLevels();
            if (qualities.length > 0) {
                const best = qualities[0];
                playerApi.setPlaybackQualityRange(best);
                playerApi.setPlaybackQuality(best);
            }
        }
    }
    function setQualityAndTheater() {
        if (alreadyApplied) return;
        alreadyApplied = true;
        applyTheaterMode();
        applyHighestQuality();
    }
    function scheduleSetQualityAndTheater() {
        if ('requestIdleCallback' in window) requestIdleCallback(setQualityAndTheater, { timeout: 2000 });
        else setTimeout(setQualityAndTheater, 1000);
    }
    function observePageChange() {
        const observer = new MutationObserver(() => {
            alreadyApplied = false;
            scheduleSetQualityAndTheater();
        });
        observer.observe(document.body, { childList: true, subtree: true });
    }
    window.addEventListener('yt-navigate-finish', () => {
        alreadyApplied = false;
        scheduleSetQualityAndTheater();
    });
    window.addEventListener('DOMContentLoaded', () => {
        scheduleSetQualityAndTheater();
        observePageChange();
    });
})();