R34 Auto Max Quality

Automatically selects maximum available video quality on tab focus.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         R34 Auto Max Quality
// @namespace    r34-auto-max-quality
// @version      2.0
// @description  Automatically selects maximum available video quality on tab focus.
// @description:ru Автоматически выбирает максимальное доступное качество видео при фокусе вкладки.
// @author       Grok Assisted
// @match        https://rule34video.com/video/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=rule34video.com
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    // Максимальное желаемое качество — меняй здесь / Maximum desired quality — change here
    // 5 = 4K, 4 = 1080p, 3 = 720p, 2 = 480p, 1 = 360p
    const MAX_QUALITY = 4;

    const FORMATS = [5, 4, 3, 2, 1]; // Список форматов от высокого к низкому / Format list from high to low

    // Получает текущий выбранный формат из DOM / Gets currently selected format from DOM
    function getSelectedFormat() {
        const sel = document.querySelector('.fp-settings-list-item.is-selected a[data-format]');
        return sel ? parseInt(sel.getAttribute('data-format')) : 0;
    }

    // Определяет реальное качество по суффиксу src видео / Determines real quality from video src suffix
    function getRealFormatFromSrc() {
        const vid = document.querySelector('video.fp-engine');
        if (!vid || !vid.src) return 0;

        const src = vid.src;
        if (src.includes('_2160p.mp4')) return 5;
        if (src.includes('_1080p.mp4')) return 4;
        if (src.includes('_720p.mp4'))  return 3;
        if (src.includes('_480p.mp4'))  return 2;
        if (src.includes('_360.mp4'))   return 1;
        return 0;
    }

    // Находит самый высокий доступный формат ≤ MAX_QUALITY / Finds highest available format ≤ MAX_QUALITY
    function getMaxAvailable() {
        for (let fmt of FORMATS) {
            if (fmt > MAX_QUALITY) continue;
            if (document.querySelector(`a[data-format="${fmt}"]`)) return fmt;
        }
        return 1;
    }

    // Кликает по кнопке качества / Clicks quality button
    function clickQuality(fmt) {
        const btn = document.querySelector(`a[data-format="${fmt}"]`);
        if (!btn) return false;

        // Убираем tooltip, если курсор над timeline / Remove tooltip if cursor over timeline
        const timeline = document.querySelector('.fp-timeline');
        if (timeline) {
            timeline.dispatchEvent(new MouseEvent('mouseleave', { bubbles: true }));
        }

        // Открываем меню качества, если оно закрыто / Open quality menu if closed
        const settingsBtn = document.querySelector('a.fp-settings');
        if (settingsBtn && !document.querySelector('.fp-settings-list.is-open')) {
            settingsBtn.click();
        }

        btn.click();
        console.log(`[R34-Q] Кликнули ${fmt}p / Clicked ${fmt}p`);
        return true;
    }

    // Основная функция синхронизации качества / Main quality sync function
    function syncQuality(attempt = 1) {
        if (document.visibilityState !== 'visible') return;

        const selected = getSelectedFormat();
        const real    = getRealFormatFromSrc();
        const target  = getMaxAvailable();

        console.log(`[R34-Q] Попытка ${attempt} | Выбрано: ${selected}, Реально: ${real}, Цель: ${target} / Attempt ${attempt} | Selected: ${selected}, Real: ${real}, Target: ${target}`);

        if (real === target) {
            console.log('[R34-Q] Качество совпало с максимумом / Quality matches max');
            return;
        }

        if (attempt > 20) {
            console.log('[R34-Q] Лимит попыток (20), останавливаюсь / Max attempts (20) reached, stopping');
            return;
        }

        if (clickQuality(target)) {
            setTimeout(() => syncQuality(attempt + 1), 1800);
        } else {
            setTimeout(() => syncQuality(attempt + 1), 1200);
        }
    }

    // Срабатывание при фокусе вкладки / Trigger on tab focus
    document.addEventListener('visibilitychange', () => {
        if (document.visibilityState === 'visible') {
            setTimeout(() => syncQuality(1), 1000);
        }
    });

    // Первичная проверка, если вкладка уже активна / Initial check if tab is already visible
    if (document.visibilityState === 'visible') {
        setTimeout(() => syncQuality(1), 4000);
    }

    console.log(`[R34-Q] Скрипт запущен, максимум: ${MAX_QUALITY}p / Script active, max: ${MAX_QUALITY}p`);
})();