OnlyFans - Hide Video Controls Overlay

Hide the controls overlay on Onlyfans video player

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(Tôi đã có Trình quản lý tập lệnh người dùng, hãy cài đặt nó!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==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();
})();