OnlyFans - Hide Video Controls Overlay

Hide the controls overlay on Onlyfans video player

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         OnlyFans - Hide Video Controls Overlay
// @version      0.6.3
// @description  Hide the controls overlay on Onlyfans video player
// @author       pipstar
// @match        https://onlyfans.com/*
// @run-at       document-start
// @grant        GM_registerMenuCommand
// @grant        GM_unregisterMenuCommand
// @grant        GM_getValue
// @grant        GM_setValue
// @icon         data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMiAzMiI+PHJlY3QgeD0iMiIgeT0iMTAuNSIgd2lkdGg9IjI4IiBoZWlnaHQ9IjExIiByeD0iMy4yIiBmaWxsPSIjMDBBRkYwIi8+PHBhdGggZD0iTTcgMTMuNCBMNyAxOC42IEwxMS40IDE2IFoiIGZpbGw9IiNmZmYiLz48cmVjdCB4PSIxMy41IiB5PSIxNS4xIiB3aWR0aD0iMTQiIGhlaWdodD0iMS44IiByeD0iMC45IiBmaWxsPSIjZmZmIiBvcGFjaXR5PSIwLjQ1Ii8+PHJlY3QgeD0iMTMuNSIgeT0iMTUuMSIgd2lkdGg9IjYiIGhlaWdodD0iMS44IiByeD0iMC45IiBmaWxsPSIjZmZmIi8+PGNpcmNsZSBjeD0iMTkuNSIgY3k9IjE2IiByPSIyLjQiIGZpbGw9IiNmZmYiLz48bGluZSB4MT0iNCIgeTE9IjI4IiB4Mj0iMjgiIHkyPSI0IiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iNiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PGxpbmUgeDE9IjQiIHkxPSIyOCIgeDI9IjI4IiB5Mj0iNCIgc3Ryb2tlPSIjZmYyZDU1IiBzdHJva2Utd2lkdGg9IjMuNCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PC9zdmc+
// @license      MIT
// @namespace https://greasyfork.org/users/1275465
// ==/UserScript==

(function () {
    'use strict';

    /* ------------------------------------------------------------------ *
     * CONFIG - which elements count as "the controls" the toggle governs.
     * ------------------------------------------------------------------ */
    const HIDE_CONTROL_BAR     = true;  // bottom bar: play, scrubber, volume, quality, fullscreen, "record"
    const HIDE_BIG_PLAY_BUTTON = true;  // large centered play button overlay

    const selectors = [];
    if (HIDE_CONTROL_BAR)     selectors.push('.video-js .vjs-control-bar');
    if (HIDE_BIG_PLAY_BUTTON) selectors.push('.video-js .vjs-big-play-button');

    const HIDE_CSS = `${selectors.join(',\n')} {
        display: none !important;
        opacity: 0 !important;
        pointer-events: none !important;
    }`;

    /* ------------------------------------------------------------------ *
     * STATE - persisted across page loads. Defaults to hidden.
     * ------------------------------------------------------------------ */
    const STORAGE_KEY = 'of_controls_hidden';
    let hidden = GM_getValue(STORAGE_KEY, true);

    // Single <style> element we flip on/off. Injected at document-start so
    // the bar never flashes when controls are meant to be hidden.
    const style = document.createElement('style');
    style.id = 'of-hide-controls-style';
    (document.head || document.documentElement).appendChild(style);

    function applyState() {
        // When hidden, inject the rules; when shown, clear them so video.js
        // resumes its normal hover/autohide behavior. Updates live.
        style.textContent = (hidden && selectors.length) ? HIDE_CSS : '';
    }

    /* ------------------------------------------------------------------ *
     * MENU TOGGLE - appears in the Tampermonkey popup under this script.
     * Re-registered on each toggle so its label reflects the current state.
     * ------------------------------------------------------------------ */
    let menuId;
    function registerMenu() {
        if (menuId !== undefined && typeof GM_unregisterMenuCommand === 'function') {
            try { GM_unregisterMenuCommand(menuId); } catch (e) { /* older TM */ }
        }
        const label = hidden
            ? 'Video controls: HIDDEN  \u2014  click to show  (Ctrl+Alt+V)'
            : 'Video controls: SHOWN  \u2014  click to hide  (Ctrl+Alt+V)';
        menuId = GM_registerMenuCommand(label, toggle);
    }

    function toggle() {
        hidden = !hidden;
        GM_setValue(STORAGE_KEY, hidden);
        applyState();
        registerMenu(); // refresh the menu label
    }

    /* ------------------------------------------------------------------ *
     * FULLSCREEN HELPERS - target the .video-js container, not the raw
     * <video>, so the browser doesn't draw its own native controls.
     * ------------------------------------------------------------------ */
    function pickPlayer() {
        const players = [...document.querySelectorAll('.video-js')];
        if (!players.length) return null;
        // Prefer a player that's actually playing.
        const playing = players.find(p => {
            const v = p.querySelector('video');
            return v && !v.paused && !v.ended && v.readyState > 2;
        });
        if (playing) return playing;
        // Otherwise, the one with the largest visible area in the viewport.
        let best = null, bestArea = -1;
        for (const p of players) {
            const r = p.getBoundingClientRect();
            const w = Math.max(0, Math.min(r.right, innerWidth) - Math.max(r.left, 0));
            const h = Math.max(0, Math.min(r.bottom, innerHeight) - Math.max(r.top, 0));
            const area = w * h;
            if (area > bestArea) { bestArea = area; best = p; }
        }
        return best || players[0];
    }

    function toggleFullscreen() {
        const fsEl = document.fullscreenElement || document.webkitFullscreenElement;
        if (fsEl) {
            (document.exitFullscreen || document.webkitExitFullscreen || function () {}).call(document);
            return;
        }
        const el = pickPlayer();
        if (!el) return;
        const req = el.requestFullscreen || el.webkitRequestFullscreen;
        if (req) req.call(el);
    }

    /* ------------------------------------------------------------------ *
     * KEYBOARD SHORTCUTS
     *   Ctrl+Alt+V : toggle controls (works regardless of state)
     *   F          : fullscreen the video, ONLY while controls are hidden
     *                and only when not typing in a field. Press again (or
     *                Esc) to exit.
     * Uses e.code (physical key) so it's layout-independent.
     * ------------------------------------------------------------------ */
    function isTyping(e) {
        const t = e.target;
        if (!t) return false;
        return t.isContentEditable ||
            t.tagName === 'INPUT' || t.tagName === 'TEXTAREA' || t.tagName === 'SELECT';
    }

    document.addEventListener('keydown', e => {
        // Ctrl+Alt+V -> toggle controls
        if (e.ctrlKey && e.altKey && !e.shiftKey && !e.metaKey &&
            (e.code === 'KeyV' || (e.key && e.key.toLowerCase() === 'v'))) {
            e.preventDefault();
            e.stopPropagation();
            toggle();
            return;
        }
        // F (no modifiers) -> fullscreen, only while controls are hidden
        if (!e.ctrlKey && !e.altKey && !e.metaKey && !e.shiftKey &&
            (e.code === 'KeyF' || (e.key && e.key.toLowerCase() === 'f'))) {
            if (hidden && !isTyping(e)) {
                e.preventDefault();
                e.stopPropagation();
                toggleFullscreen();
            }
        }
    }, true); // capture phase so we act before the page's own handlers

    /* ------------------------------------------------------------------ *
     * BOOT
     * ------------------------------------------------------------------ */
    applyState();
    registerMenu();
})();