Auto-play video thumbnails

Auto-play video thumbnails with playback speed control and pause functionality on adult sites

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği yüklemek için Tampermonkey gibi bir uzantı yüklemeniz gerekir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

Bu stili yüklemek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için Stylus gibi bir uzantı kurmanız gerekir.

Bu stili yükleyebilmek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı kurmanız gerekir.

Bu stili yükleyebilmek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

(Zateb bir user-style yöneticim var, yükleyeyim!)

// ==UserScript==
// @name         Auto-play video thumbnails
// @namespace    https://greasyfork.org/users/1168969
// @version      2.0.3.1
// @description  Auto-play video thumbnails with playback speed control and pause functionality on adult sites
// @author       6969RandomGuy6969
// @match        https://www.sxyprn.com/*
// @match        https://sxyprn.com/*
// @match        https://watchporn.to/*
// @match        https://yesporn.vip/*
// @match        https://www.theyarehuge.com/*
// @match        https://www.eporner.com/*
// @match        https://www.shyfap.net/*
// @match        https://www.wow.xxx/*
// @match        https://pornone.com/*
// @match        https://www.tnaflix.com/*
// @match        https://www.pornhits.com/*
// @match        https://hqporner.com/*
// @match        https://www.hqporner.com/*
// @match        https://m.hqporner.com/*
// @match        https://pornmz.com/*
// @match        https://youperv.com/*
// @match        https://*.youperv.com/*
// @match        https://superporn.com/*
// @match        https://www.superporn.com/*
// @grant        GM_registerMenuCommand
// @grant        GM_openInTab
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_xmlhttpRequest
// @connect      *
// @icon         https://cdn-icons-png.flaticon.com/512/3998/3998861.png
// ==/UserScript==

(function () {
  'use strict';

  const SETTINGS = {
    playbackSpeed: GM_getValue('playbackSpeed', 1),
    isPaused: GM_getValue('isPaused', false),
    panelX: GM_getValue('panelX', null),
    panelY: GM_getValue('panelY', null)
  };

  const videoRegistry = new Set();
  let configPanel = null;

  const visibleVideos = new Set();
  const globalPlayObserver = new IntersectionObserver(entries => {
    entries.forEach(entry => {
      const video = entry.target;
      if (entry.isIntersecting) {
        visibleVideos.add(video);
        if (!SETTINGS.isPaused && typeof video.play === 'function') video.play().catch(() => {});
      } else {
        visibleVideos.delete(video);
        if (typeof video.pause === 'function') video.pause();
      }
    });
  }, { rootMargin: '300px', threshold: 0.01 });

  // Block site's JS hover previews on handled cards to prevent disruption
  ['mouseenter', 'mouseleave', 'mouseover', 'mouseout', 'mousemove'].forEach(evt => {
    document.addEventListener(evt, e => {
      if (e.target instanceof Element && e.target.closest('.apt-handled')) {
        e.stopPropagation();
      }
    }, true);
  });

  function updateAllVideos() {
    videoRegistry.forEach(video => {
      if (video && video.parentNode) {
        if (typeof video.playbackRate !== 'undefined') {
          video.playbackRate = SETTINGS.playbackSpeed;
        }
        if (SETTINGS.isPaused) {
          if (typeof video.pause === 'function') video.pause();
        } else {
          if (visibleVideos.has(video)) {
            if (typeof video.play === 'function') video.play().catch(() => {});
          }
        }
      }
    });
  }

  function setPlaybackSpeed(speed) {
    speed = Math.max(0.25, Math.min(2, speed));
    SETTINGS.playbackSpeed = speed;
    GM_setValue('playbackSpeed', speed);
    updateAllVideos();
    updatePanelDisplay();
  }

  function togglePause() {
    SETTINGS.isPaused = !SETTINGS.isPaused;
    GM_setValue('isPaused', SETTINGS.isPaused);
    updateAllVideos();
    updatePanelDisplay();
  }

  function updatePanelDisplay() {
    if (!configPanel) return;
    const speedDisplay = configPanel.querySelector('.speed-display');
    const pauseBtn = configPanel.querySelector('.pause-btn');
    if (speedDisplay) speedDisplay.textContent = `${SETTINGS.playbackSpeed.toFixed(2)}x`;
    if (pauseBtn) pauseBtn.textContent = SETTINGS.isPaused ? '▶️ Play' : '⏸️ Pause';
  }

  function createConfigPanel() {
    if (configPanel) {
      configPanel.style.display = 'block';
      return;
    }

    const panel = document.createElement('div');
    panel.id = 'video-config-panel';
    panel.innerHTML = `
      <div class="panel-header">
        <span class="panel-title">Thumbnail Control</span>
        <button class="close-btn">×</button>
      </div>
      <div class="panel-body">
        <div class="speed-control">
          <button class="speed-btn minus-btn">−</button>
          <span class="speed-display">${SETTINGS.playbackSpeed.toFixed(2)}x</span>
          <button class="speed-btn plus-btn">+</button>
        </div>
        <button class="pause-btn">${SETTINGS.isPaused ? '▶️ Play' : '⏸️ Pause'}</button>
      </div>
    `;

    const style = document.createElement('style');
    style.textContent = `
      #video-config-panel {
        position: fixed;
        z-index: 999999;
        background: rgba(20, 20, 20, 0.95);
        backdrop-filter: blur(10px);
        -webkit-backdrop-filter: blur(10px);
        border: 1px solid rgba(255, 255, 255, 0.1);
        border-radius: 12px;
        padding: 0;
        font-family: Arial, sans-serif;
        box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
        user-select: none;
        min-width: 160px;
        max-width: 200px;
      }
      #video-config-panel .panel-header {
        background: rgba(40, 40, 40, 0.8);
        padding: 8px 10px;
        border-bottom: 1px solid rgba(255, 255, 255, 0.1);
        display: flex;
        justify-content: space-between;
        align-items: center;
        cursor: move;
        border-radius: 11px 11px 0 0;
      }
      #video-config-panel .panel-title {
        color: #fff;
        font-size: 12px;
        font-weight: bold;
        text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
        white-space: nowrap;
      }
      #video-config-panel .close-btn {
        background: rgba(255, 255, 255, 0.1);
        border: none;
        color: #fff;
        font-size: 20px;
        font-weight: bold;
        cursor: pointer;
        padding: 0;
        width: 22px;
        height: 22px;
        line-height: 20px;
        border-radius: 4px;
        transition: all 0.2s;
        flex-shrink: 0;
      }
      #video-config-panel .close-btn:hover {
        background: rgba(255, 68, 68, 0.8);
        box-shadow: 0 0 10px rgba(255, 68, 68, 0.5);
      }
      #video-config-panel .panel-body {
        padding: 12px;
        background: rgba(30, 30, 30, 0.5);
        border-radius: 0 0 11px 11px;
      }
      #video-config-panel .speed-control {
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 8px;
        margin-bottom: 10px;
      }
      #video-config-panel .speed-btn {
        background: rgba(255, 255, 255, 0.15);
        backdrop-filter: blur(5px);
        -webkit-backdrop-filter: blur(5px);
        border: 1px solid rgba(255, 255, 255, 0.2);
        color: #fff;
        font-size: 18px;
        font-weight: bold;
        width: 32px;
        height: 32px;
        border-radius: 6px;
        cursor: pointer;
        transition: all 0.2s;
        padding: 0;
        text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
        display: flex;
        align-items: center;
        justify-content: center;
      }
      #video-config-panel .speed-btn:hover {
        background: rgba(255, 255, 255, 0.2);
        border-color: rgba(255, 255, 255, 0.3);
        box-shadow: 0 0 10px rgba(255, 255, 255, 0.2);
      }
      #video-config-panel .speed-btn:active { transform: scale(0.95); }
      #video-config-panel .speed-display {
        color: #fff;
        font-size: 14px;
        font-weight: bold;
        min-width: 50px;
        text-align: center;
        text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
      }
      #video-config-panel .pause-btn {
        width: 100%;
        background: rgba(255, 255, 255, 0.15);
        backdrop-filter: blur(5px);
        -webkit-backdrop-filter: blur(5px);
        border: 1px solid rgba(255, 255, 255, 0.2);
        color: #fff;
        padding: 8px;
        font-size: 13px;
        font-weight: 600;
        border-radius: 6px;
        cursor: pointer;
        transition: all 0.2s;
        text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
      }
      #video-config-panel .pause-btn:hover {
        background: rgba(255, 255, 255, 0.2);
        border-color: rgba(255, 255, 255, 0.3);
        box-shadow: 0 0 10px rgba(255, 255, 255, 0.2);
      }
      #video-config-panel .pause-btn:active { transform: scale(0.98); }
      @media (max-width: 600px) {
        #video-config-panel { min-width: 140px; max-width: 160px; }
        #video-config-panel .panel-header { padding: 6px 8px; }
        #video-config-panel .panel-title { font-size: 11px; }
        #video-config-panel .close-btn { width: 20px; height: 20px; font-size: 18px; }
        #video-config-panel .panel-body { padding: 8px; }
        #video-config-panel .speed-btn { width: 28px; height: 28px; font-size: 16px; }
        #video-config-panel .speed-display { font-size: 12px; min-width: 40px; }
        #video-config-panel .pause-btn { padding: 6px; font-size: 12px; }
      }
      @media (max-width: 400px) {
        #video-config-panel { min-width: 120px; max-width: 140px; }
        #video-config-panel .speed-control { gap: 4px; }
        #video-config-panel .speed-btn { width: 24px; height: 24px; font-size: 14px; }
        #video-config-panel .speed-display { font-size: 11px; min-width: 35px; }
      }
    `;
    document.head.appendChild(style);

    document.body.appendChild(panel);
    configPanel = panel;

    const panelWidth = 200;
    const panelHeight = 120;
    const margin = 10;

    if (SETTINGS.panelX !== null && SETTINGS.panelY !== null) {
      const maxX = window.innerWidth - panelWidth - margin;
      const maxY = window.innerHeight - panelHeight - margin;
      panel.style.left = Math.max(margin, Math.min(SETTINGS.panelX, maxX)) + 'px';
      panel.style.top  = Math.max(margin, Math.min(SETTINGS.panelY, maxY)) + 'px';
    } else {
      panel.style.right  = Math.min(20, window.innerWidth  - panelWidth  - margin) + 'px';
      panel.style.bottom = Math.min(20, window.innerHeight - panelHeight - margin) + 'px';
    }

    panel.querySelector('.close-btn').addEventListener('click', () => { panel.style.display = 'none'; });
    panel.querySelector('.minus-btn').addEventListener('click', () => { setPlaybackSpeed(SETTINGS.playbackSpeed - 0.25); });
    panel.querySelector('.plus-btn').addEventListener('click',  () => { setPlaybackSpeed(SETTINGS.playbackSpeed + 0.25); });
    panel.querySelector('.pause-btn').addEventListener('click', togglePause);

    // Draggable
    let isDragging = false, currentX, currentY, initialX, initialY;
    const header = panel.querySelector('.panel-header');

    header.addEventListener('mousedown', e => {
      if (e.target.classList.contains('close-btn')) return;
      isDragging = true;
      initialX = e.clientX - (SETTINGS.panelX || panel.offsetLeft);
      initialY = e.clientY - (SETTINGS.panelY || panel.offsetTop);
    });

    document.addEventListener('mousemove', e => {
      if (!isDragging) return;
      e.preventDefault();
      const rect = panel.getBoundingClientRect();
      const maxX = window.innerWidth  - rect.width  - margin;
      const maxY = window.innerHeight - rect.height - margin;
      currentX = Math.max(margin, Math.min(e.clientX - initialX, maxX));
      currentY = Math.max(margin, Math.min(e.clientY - initialY, maxY));
      panel.style.left   = currentX + 'px';
      panel.style.top    = currentY + 'px';
      panel.style.right  = 'auto';
      panel.style.bottom = 'auto';
    });

    document.addEventListener('mouseup', () => {
      if (isDragging) {
        SETTINGS.panelX = currentX || panel.offsetLeft;
        SETTINGS.panelY = currentY || panel.offsetTop;
        GM_setValue('panelX', SETTINGS.panelX);
        GM_setValue('panelY', SETTINGS.panelY);
      }
      isDragging = false;
    });

    window.addEventListener('resize', () => {
      if (!configPanel || configPanel.style.display === 'none') return;
      const rect = configPanel.getBoundingClientRect();
      let newX = rect.left, newY = rect.top, needs = false;
      if (rect.right  > window.innerWidth  - margin) { newX = window.innerWidth  - rect.width  - margin; needs = true; }
      if (rect.left   < margin)                       { newX = margin;                                     needs = true; }
      if (rect.bottom > window.innerHeight - margin)  { newY = window.innerHeight - rect.height - margin; needs = true; }
      if (rect.top    < margin)                       { newY = margin;                                     needs = true; }
      if (needs) {
        configPanel.style.left = newX + 'px'; configPanel.style.top = newY + 'px';
        configPanel.style.right = 'auto';     configPanel.style.bottom = 'auto';
        SETTINGS.panelX = newX; SETTINGS.panelY = newY;
        GM_setValue('panelX', newX); GM_setValue('panelY', newY);
      }
    });
  }

  // ==================== GM MENU ====================
  GM_registerMenuCommand('⚙️ Open Config UI', createConfigPanel);

  // ── Supported Sites ──
  GM_registerMenuCommand('🌐 Sxyprn', () => GM_openInTab('https://sxyprn.com', { active: true }));
  GM_registerMenuCommand('🌐 WatchPorn', () => GM_openInTab('https://watchporn.to', { active: true }));
  GM_registerMenuCommand('🌐 YesPorn', () => GM_openInTab('https://yesporn.vip', { active: true }));
  GM_registerMenuCommand('🌐 TheyAreHuge', () => GM_openInTab('https://www.theyarehuge.com', { active: true }));
  GM_registerMenuCommand('🌐 Eporner', () => GM_openInTab('https://www.eporner.com', { active: true }));
  GM_registerMenuCommand('🌐 ShyFap', () => GM_openInTab('https://www.shyfap.net', { active: true }));
  GM_registerMenuCommand('🌐 Wow.xxx', () => GM_openInTab('https://www.wow.xxx', { active: true }));
  GM_registerMenuCommand('🌐 Pornone', () => GM_openInTab('https://pornone.com', { active: true }));
  GM_registerMenuCommand('🌐 Tnaflix', () => GM_openInTab('https://www.tnaflix.com', { active: true }));
  GM_registerMenuCommand('🌐 PornHits', () => GM_openInTab('https://www.pornhits.com', { active: true }));
  GM_registerMenuCommand('🌐 HQPorner', () => GM_openInTab('https://hqporner.com', { active: true }));
  GM_registerMenuCommand('🌐 PornMZ', () => GM_openInTab('https://pornmz.com', { active: true }));
  GM_registerMenuCommand('🌐 YouPerv', () => GM_openInTab('https://youperv.com', { active: true }));
  GM_registerMenuCommand('🌐 SuperPorn', () => GM_openInTab('https://www.superporn.com', { active: true }));

  // ── Script Links ──
  GM_registerMenuCommand('🔞 More Scripts (Sleazyfork)', () => {
    GM_openInTab('https://sleazyfork.org/en/users/1168969-6969randomguy6969', { active: true });
  });
  GM_registerMenuCommand('📜 More Scripts (Greasyfork)', () => {
    GM_openInTab('https://greasyfork.org/en/users/1168969-6969randomguy6969', { active: true });
  });

  // ==================== CORE FUNCTIONALITY ====================
  const hostname = window.location.hostname;

  // ---- FIX 1: Don't hide the image until the video is actually ready to play ----
  // ---- FIX 2: Keep the image visible as fallback if video fails ----
  function insertPreviewVideo(image, videoUrl) {
    if (!videoUrl) return;
    if (image.dataset.previewAttached) return;
    image.dataset.previewAttached = '1';

    const card = image.closest('a, article, .thumb, .card, .post, .mb, .media-card_preview') || image.parentNode;
    if (card) card.classList.add('apt-handled');

    const video = document.createElement('video');
    video.src = videoUrl;
    video.muted = true;
    video.loop = true;
    video.playsInline = true;
    video.preload = 'auto';
    video.playbackRate = SETTINGS.playbackSpeed;
    video.style.cssText = 'width:100%;height:100%;object-fit:cover;position:absolute;top:0;left:0;z-index:10;pointer-events:none;';

    video.setAttribute('importance', 'high');
    video.setAttribute('fetchpriority', 'high');

    videoRegistry.add(video);

    const parent = image.parentNode;
    parent.style.position = 'relative';
    parent.appendChild(video);

    const showVideo = () => {
      video.style.opacity = '1';
      image.style.opacity = '0';
      if (!SETTINGS.isPaused && visibleVideos.has(video)) video.play().catch(() => {});
    };

    // Try canplay first
    video.addEventListener('canplay', showVideo, { once: true });

    // Fallback: if canplay doesn't fire in 800ms, show anyway
    // (site JS may suppress the event by manipulating the element)
    const fallbackTimer = setTimeout(() => {
      video.removeEventListener('canplay', showVideo);
      showVideo();
    }, 800);

    video.addEventListener('canplay', () => clearTimeout(fallbackTimer), { once: true });

    video.load();
    globalPlayObserver.observe(video);

    video.onerror = () => {
      clearTimeout(fallbackTimer);
      globalPlayObserver.unobserve(video);
      visibleVideos.delete(video);
      videoRegistry.delete(video);
      video.remove();
      image.style.opacity = '1';
    };
  }

  // IntersectionObserver wrapper
  const activeObservers = new Set();

  function observeElements(selector, getUrl) {
    // Don't set up duplicate observers for the same selector
    if (activeObservers.has(selector)) return;
    activeObservers.add(selector);
    const observer = new IntersectionObserver(entries => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const el = entry.target;
          const url = getUrl(el);
          if (url) insertPreviewVideo(el, url);
          observer.unobserve(el);
        }
      });
    }, { rootMargin: '500px', threshold: 0.01 });

    const observedElements = new WeakSet();

    function watch() {
      document.querySelectorAll(selector).forEach(el => {
        if (!observedElements.has(el)) {
          observer.observe(el);
          observedElements.add(el);
        }
      });
    }

    watch();

    let mutationTimeout;
    new MutationObserver(() => {
      clearTimeout(mutationTimeout);
      mutationTimeout = setTimeout(watch, 100);
    }).observe(document.body, { childList: true, subtree: true });

    setTimeout(watch, 500);
    setTimeout(watch, 1500);
  }

  // ==================== SITE HANDLERS ====================
  const siteHandlers = {

    "eporner.com": function () {
      function getPreviewUrl(id) {
        const s = id.toString();
        if (s.length < 5) return null;
        return `https://static-eu-cdn.eporner.com/thumbs/static4/${s[0]}/${s.slice(0,2)}/${s.slice(0,3)}/${s}/${s}-preview.webm`;
      }

      function initThumb(thumb) {
        if (thumb.dataset.epInit) return;
        thumb.dataset.epInit = '1';
        thumb.classList.add('apt-handled');

        const url = getPreviewUrl(thumb.dataset.id);
        if (!url) return;

        let vid = thumb.querySelector('video');
        if (!vid) {
          vid = document.createElement('video');
          vid.muted = true;
          vid.loop = true;
          vid.playsInline = true;
          vid.preload = 'auto';
          vid.style.cssText = 'position:absolute !important;inset:0 !important;width:100% !important;height:100% !important;object-fit:cover !important;z-index:10 !important;background:#000;opacity:1 !important;pointer-events:none;';
          const cont = thumb.querySelector('.mbimg, .mbcontent') || thumb;
          cont.style.position = 'relative';
          cont.style.overflow = 'hidden';
          cont.appendChild(vid);
        }

        if (vid.src !== url) {
          vid.removeAttribute('src');
          vid.src = url;
          vid.load();
        }

        // Register for global pause/speed control
        videoRegistry.add(vid);
        vid.playbackRate = SETTINGS.playbackSpeed;
        globalPlayObserver.observe(vid);
      }

      // Hide static img/badges so video shows through
      const style = document.createElement('style');
      style.textContent = `.mb img,.mvhdico,[style*="ajax_loader"]{opacity:0 !important;pointer-events:none !important}.mb .mbimg,.mb .mbcontent{background:#000 !important}`;
      document.head.appendChild(style);

      // Process existing cards
      document.querySelectorAll('div.mb[data-id]').forEach(initThumb);

      // Watch for new cards (infinite scroll / AJAX)
      new MutationObserver(() => {
        document.querySelectorAll('div.mb[data-id]:not([data-ep-init])').forEach(initThumb);
      }).observe(document.body, { childList: true, subtree: true });

      // Safety interval for any missed cards
      setInterval(() => {
        document.querySelectorAll('div.mb[data-id]').forEach(initThumb);
      }, 4000);
    },

    "sxyprn.com": function () {
      function watchSxy() {
        document.querySelectorAll('.mini_post_vid_thumb').forEach(img => {
          if (img.dataset.sxInit) return;
          img.dataset.sxInit = '1';

          let handled = false;
          const video = img.nextElementSibling;

          if (video && video.tagName === 'VIDEO') {
            // Strip inline JS that restricts playback (e.g., hvponplay)
            video.removeAttribute('onplay');
            video.removeAttribute('onpause');
            video.preload = 'auto';

            // Force it to be visible without overriding native layout dimensions
            video.style.display = 'block';
            video.style.opacity = '1';
            video.style.pointerEvents = 'none'; // Ensure clicks hit the wrapper
            img.style.opacity = '0';

            const src = video.getAttribute('src') || video.getAttribute('data-src') || video.dataset.src;
            if (src && !video.getAttribute('src')) {
              video.setAttribute('src', src);
            }

            if (src || video.currentSrc || video.querySelector('source')) {
              handled = true;
              if (typeof video.playbackRate !== 'undefined') {
                video.playbackRate = SETTINGS.playbackSpeed;
              }
              videoRegistry.add(video);
              globalPlayObserver.observe(video);
            }
          } else {
            // Fallback for elements without native video tag
            const fallbackSrc = img.getAttribute('data-video') || img.getAttribute('data-preview');
            if (fallbackSrc) {
              handled = true;
              insertPreviewVideo(img, fallbackSrc);
            }
          }

          if (handled) {
            const card = img.closest('a, .post_el') || img.parentNode;
            if (card) card.classList.add('apt-handled');
          }
        });
      }
      watchSxy();
      new MutationObserver(watchSxy).observe(document.body, { childList: true, subtree: true });
      setInterval(watchSxy, 5000);
    },

    "watchporn.to": () =>
      observeElements('img[data-preview]', el => el.getAttribute('data-preview')),

    "yesporn.vip": () =>
      observeElements('img[data-preview]', el => el.getAttribute('data-preview')),

    "theyarehuge.com": function () {
      observeElements('img[data-preview]', el => el.getAttribute('data-preview'));

      const style = document.createElement('style');
      style.textContent = `
        body, html { background-color:#000 !important; color:#d1d1d1 !important; }
        * { background-color:transparent !important; border-color:#444 !important; color:inherit !important; }
        a, p, h1, h2, h3, h4, h5, h6, span, div { color:#d1d1d1 !important; }
        img, video { filter:brightness(0.95) contrast(1.1); }
        .header, .footer, .sidebar, .navbar, .top-menu, .main-header { background-color:#000 !important; }
      `;
      document.head.appendChild(style);

      const logo = document.querySelector('img[src*="tah-logo-m.png"]');
      if (logo) logo.style.filter = 'invert(1) hue-rotate(-180deg) brightness(1) saturate(10)';
    },

    "shyfap.net": function () {
      function watchShyfap() {
        document.querySelectorAll('.media-card_preview').forEach(card => {
          if (card.dataset.sfInit) return;
          card.dataset.sfInit = '1';

          const videoUrl = card.getAttribute('data-preview');
          const video = card.querySelector('video');
          const img   = card.querySelector('img');

          let handled = false;
          if (video) {
            handled = true;
            video.muted = true;
            video.loop = true;
            video.playsInline = true;
            video.preload = 'auto';
            video.playbackRate = SETTINGS.playbackSpeed;
            video.style.width = '100%';
            video.style.height = '100%';
            video.style.objectFit = 'cover';
            video.style.pointerEvents = 'none';
            videoRegistry.add(video);
            if (img) img.style.display = 'none';
            globalPlayObserver.observe(video);
          } else if (img && videoUrl) {
            handled = true;
            insertPreviewVideo(img, videoUrl);
          }

          if (handled) card.classList.add('apt-handled');
        });
      }
      watchShyfap();
      new MutationObserver(watchShyfap).observe(document.body, { childList: true, subtree: true });
      setInterval(watchShyfap, 5000);
    },

    "wow.xxx": function () {
      observeElements('.thumb__img[data-preview] img', img => {
        const container = img.closest('.thumb__img');
        return container ? container.getAttribute('data-preview') : null;
      });
    },

    "pornone.com": function () {
      // pornone.com has NO mp4 previews — it cycles JPG frames from data-thumbs.
      // Frame URL: {data-path}d{thumbNum}.jpg
      // The site's own showImage() cycles every 800ms; we replicate it autonomously,
      // respecting isPaused and mapping playbackSpeed -> interval delay.
      // Speed 1x=800ms, 2x=400ms, 0.5x=1600ms, etc.

      const pnCyclers = new Map(); // img el -> { timer }

      function getIntervalMs() {
        return Math.round(800 / Math.max(0.25, SETTINGS.playbackSpeed));
      }

      function startCycler(img) {
        if (img.dataset.pnInit) return;
        img.dataset.pnInit = '1';

        const path = img.getAttribute('data-path');
        const thumbs = JSON.parse(img.getAttribute('data-thumbs') || '[]');
        if (!path || thumbs.length < 2) return;

        const card = img.closest('a, .thumb, .item') || img.parentNode;
        if (card) card.classList.add('apt-handled');

        // Preload first few frames
        thumbs.slice(0, 5).forEach(n => { (new Image()).src = path + 'd' + n + '.jpg'; });

        let idx = 1;
        img.dataset.pnIdx = '1';

        const state = { timer: null };
        pnCyclers.set(img, state);

        function tick() {
          if (!SETTINGS.isPaused) {
            img.src = path + 'd' + thumbs[idx] + '.jpg';
            // Preload next
            const next = thumbs[(idx + 1) % thumbs.length];
            (new Image()).src = path + 'd' + next + '.jpg';
            idx = (idx + 1) % thumbs.length;
            img.dataset.pnIdx = String(idx);
          }
          state.timer = setTimeout(tick, getIntervalMs());
        }

        if (!SETTINGS.isPaused) {
          state.timer = setTimeout(tick, getIntervalMs());
        } else {
          // Still schedule, but tick() will skip frame when paused
          state.timer = setTimeout(tick, getIntervalMs());
        }
      }

      // IntersectionObserver: only cycle visible thumbs
      const pnObserver = new IntersectionObserver(entries => {
        entries.forEach(entry => {
          const img = entry.target;
          const state = pnCyclers.get(img);
          if (entry.isIntersecting) {
            startCycler(img);
            // If previously stopped (scrolled away), restart
            if (state && !state.timer) {
              const path = img.getAttribute('data-path');
              const thumbs = JSON.parse(img.getAttribute('data-thumbs') || '[]');
              let idx = parseInt(img.dataset.pnIdx || '1', 10);
              function tick() {
                if (!SETTINGS.isPaused) {
                  img.src = path + 'd' + thumbs[idx] + '.jpg';
                  const next = thumbs[(idx + 1) % thumbs.length];
                  (new Image()).src = path + 'd' + next + '.jpg';
                  idx = (idx + 1) % thumbs.length;
                  img.dataset.pnIdx = String(idx);
                }
                state.timer = setTimeout(tick, getIntervalMs());
              }
              state.timer = setTimeout(tick, getIntervalMs());
            }
          } else {
            // Pause cycling off-screen to save resources
            if (state && state.timer) {
              clearTimeout(state.timer);
              state.timer = null;
            }
          }
        });
      }, { rootMargin: '300px', threshold: 0.01 });

      function watchThumbs() {
        document.querySelectorAll('img.thumbimg[data-thumbs][data-path]').forEach(img => {
          if (!img.dataset.pnObserved) {
            img.dataset.pnObserved = '1';
            pnObserver.observe(img);
          }
        });
      }

      watchThumbs();
      new MutationObserver(watchThumbs).observe(document.body, { childList: true, subtree: true });
      setTimeout(watchThumbs, 500);
      setTimeout(watchThumbs, 2000);
      setInterval(watchThumbs, 5000);
    },

    "tnaflix.com": function () {
      // tnaflix.com provides a direct `data-trailer` mp4 URL on the <a> tag.
      // Selector: a.thumb-chrome[data-trailer]  →  img inside it is the thumbnail.
      // Just grab data-trailer and hand it to insertPreviewVideo — cleanest possible.

      function initCard(anchor) {
        if (anchor.dataset.tnInit) return;
        anchor.dataset.tnInit = '1';

        const url = anchor.getAttribute('data-trailer');
        const img = anchor.querySelector('img');
        if (!url || !img) return;

        anchor.classList.add('apt-handled');
        insertPreviewVideo(img, url);
      }

      // IntersectionObserver — only load trailers near the viewport
      const tnObserver = new IntersectionObserver(entries => {
        entries.forEach(entry => {
          if (entry.isIntersecting) {
            initCard(entry.target);
            tnObserver.unobserve(entry.target);
          }
        });
      }, { rootMargin: '400px', threshold: 0.01 });

      function watchCards() {
        document.querySelectorAll('a.thumb-chrome[data-trailer]').forEach(anchor => {
          if (!anchor.dataset.tnObserved) {
            anchor.dataset.tnObserved = '1';
            tnObserver.observe(anchor);
          }
        });
      }

      watchCards();
      new MutationObserver(watchCards).observe(document.body, { childList: true, subtree: true });
      setTimeout(watchCards, 500);
      setTimeout(watchCards, 2000);
      setInterval(watchCards, 5000);
    },

    "pornhits.com": function () {
      // pornhits.com: img[data-preview] carries the preview URL directly.
      // URL scheme: //pv2.pornhits.com/v2/preview/ID.mp4  (protocol-relative)
      // Just prefix https: and feed to insertPreviewVideo — done.

      observeElements('img[data-preview]', img => {
        const raw = img.getAttribute('data-preview');
        if (!raw) return null;
        return raw.startsWith('//') ? 'https:' + raw : raw;
      });
    },

    "hqporner.com": function () {
      // hqporner.com has NO mp4 previews — it cycles 10 JPG frames per card.
      // Each img[id^="slide"] or img[id^="cover_"] has src like: //cdn.../imgs/AA/BB/HASH_main.jpg
      // Frame URLs: //cdn.../imgs/AA/BB/HASH_1.jpg ... HASH_10.jpg  (10 frames)
      // Site cycles at 600ms; we replicate autonomously respecting isPaused/speed.
      // Speed 1x=600ms, 2x=300ms, 0.5x=1200ms etc.
      // The "play images" button just enables slideShowPlayer on click — we bypass
      // it entirely and start cycling immediately on IntersectionObserver trigger.

      const hqCyclers = new Map(); // img el -> { timer }

      function getIntervalMs() {
        return Math.round(600 / Math.max(0.25, SETTINGS.playbackSpeed));
      }

      function getFrameUrls(img) {
        // src: //fastporndelivery.hqporner.com/imgs/AA/BB/HASH_main.jpg
        // OR after "play images" click: HASH_10.jpg
        const src = img.getAttribute('src') || '';
        const base = src.replace(/https?:/, '').replace(/_(?:main|\d+)\.jpg$/, '');
        if (!base || !base.includes('/imgs/')) return null;
        const frames = [];
        for (let i = 1; i <= 10; i++) frames.push('https:' + base + '_' + i + '.jpg');
        return frames;
      }

      function startCycler(img) {
        if (img.dataset.hqInit) return;
        img.dataset.hqInit = '1';

        const frames = getFrameUrls(img);
        if (!frames) return;

        const card = img.closest('a, .video-box') || img.parentNode;
        if (card) card.classList.add('apt-handled');

        // Preload first 3 frames eagerly
        frames.slice(0, 3).forEach(u => { (new Image()).src = u; });

        let idx = 0;
        const state = { timer: null };
        hqCyclers.set(img, state);

        function tick() {
          if (!SETTINGS.isPaused) {
            img.setAttribute('src', frames[idx]);
            idx = (idx + 1) % frames.length;
            // Preload next
            (new Image()).src = frames[idx];
          }
          state.timer = setTimeout(tick, getIntervalMs());
        }
        state.timer = setTimeout(tick, getIntervalMs());
      }

      function stopCycler(img) {
        const state = hqCyclers.get(img);
        if (state && state.timer) {
          clearTimeout(state.timer);
          state.timer = null;
        }
      }

      function resumeCycler(img) {
        const state = hqCyclers.get(img);
        if (!state || state.timer) return;
        const frames = getFrameUrls(img);
        if (!frames) return;
        let idx = 0;
        function tick() {
          if (!SETTINGS.isPaused) {
            img.setAttribute('src', frames[idx]);
            idx = (idx + 1) % frames.length;
            (new Image()).src = frames[idx];
          }
          state.timer = setTimeout(tick, getIntervalMs());
        }
        state.timer = setTimeout(tick, getIntervalMs());
      }

      const hqObserver = new IntersectionObserver(entries => {
        entries.forEach(entry => {
          const img = entry.target;
          if (entry.isIntersecting) {
            startCycler(img);
            resumeCycler(img);
          } else {
            stopCycler(img);
          }
        });
      }, { rootMargin: '300px', threshold: 0.01 });

      function watchThumbs() {
        document.querySelectorAll('img[id^="slide"], img[id^="cover_"]').forEach(img => {
          if (!img.dataset.hqObserved) {
            img.dataset.hqObserved = '1';
            hqObserver.observe(img);
          }
        });
      }

      watchThumbs();
      new MutationObserver(watchThumbs).observe(document.body, { childList: true, subtree: true });
      setTimeout(watchThumbs, 500);
      setTimeout(watchThumbs, 2000);
      setInterval(watchThumbs, 5000);
    },

    "pornmz.com": function () {
      // pornmz.com: data-trailer on <article> carries a direct mp4 URL.
      // The thumbnail img.video-main-thumb sits inside .post-thumbnail-container
      // inside .post-thumbnail inside the <a> inside the <article>.
      // Strategy: find article[data-trailer], grab img.video-main-thumb inside it,
      // feed data-trailer to insertPreviewVideo — identical pattern to tnaflix.

      function initCard(article) {
        if (article.dataset.pmzInit) return;
        article.dataset.pmzInit = '1';

        const url = article.getAttribute('data-trailer');
        const img = article.querySelector('img.video-main-thumb');
        if (!url || !img) return;

        article.classList.add('apt-handled');
        insertPreviewVideo(img, url);
      }

      const pmzObserver = new IntersectionObserver(entries => {
        entries.forEach(entry => {
          if (entry.isIntersecting) {
            initCard(entry.target);
            pmzObserver.unobserve(entry.target);
          }
        });
      }, { rootMargin: '400px', threshold: 0.01 });

      function watchCards() {
        document.querySelectorAll('article[data-trailer]').forEach(article => {
          if (!article.dataset.pmzObserved) {
            article.dataset.pmzObserved = '1';
            pmzObserver.observe(article);
          }
        });
      }

      watchCards();
      new MutationObserver(watchCards).observe(document.body, { childList: true, subtree: true });
      setTimeout(watchCards, 500);
      setTimeout(watchCards, 2000);
      setInterval(watchCards, 5000);
    },

    "youperv.com": function () {
      // 1. Inject Theme (as requested by user)
      let isDarkMode = GM_getValue('ypDarkMode', true);
      GM_registerMenuCommand('🌓 YouPerv Toggle Dark/Light Theme', () => {
          isDarkMode = !isDarkMode;
          GM_setValue('ypDarkMode', isDarkMode);
          location.reload();
      });

      const style = document.createElement('style');
      style.id = 'youperv-modern-theme';
      if (isDarkMode) {
          style.textContent = `
*{transition:background-color .2s ease,color .2s ease,border-color .2s ease!important}
body,.js{background:linear-gradient(135deg,#0a0a0a 0%,#1a1a1a 100%)!important;color:#b0b0b0!important;-webkit-font-smoothing:antialiased!important;-moz-osx-font-smoothing:grayscale!important}
.header img[src*="logo.png"],.header img[alt="logo"]{filter:drop-shadow(0 0 8px rgba(255,107,107,.6))drop-shadow(0 0 20px rgba(255,107,107,.3))!important}
.header,.nav,.footer,.bottom-nav{background:rgba(26,26,26,.95)!important;backdrop-filter:blur(10px)!important;-webkit-backdrop-filter:blur(10px)!important;border-color:rgba(255,107,107,.1)!important}
.header,.nav{box-shadow:0 4px 16px rgba(0,0,0,.3)!important}
.header a,.nav-in a{color:#b0b0b0!important;font-weight:500!important}
.header a:hover,.nav-in a:hover,.footer a:hover,a:hover{color:#ff8787!important}
.nav-in a{position:relative!important;overflow:hidden!important}
.nav-in a::before{content:''!important;position:absolute!important;bottom:0!important;left:0!important;width:0!important;height:2px!important;background:linear-gradient(90deg,#ff6b6b,#ff8787)!important;transition:width .3s ease!important}
.nav-in a:hover{background:rgba(255,135,135,.08)!important}
.nav-in a:hover::before{width:100%!important}
.items-title{background:linear-gradient(135deg,#fff 0%,#ff8787 100%)!important;-webkit-background-clip:text!important;-webkit-text-fill-color:transparent!important;background-clip:text!important;font-weight:600!important;letter-spacing:-.5px!important}
form[name="news_set_sort"] ul li,.catmen,.clouds_xsmall,.clouds_small,.clouds_medium,.clouds_large,.clouds_xlarge,.pagi-nav a,.pagi-nav span{transform:translateY(0)!important;transition:all .25s cubic-bezier(.4,0,.2,1)!important}
form[name="news_set_sort"] ul li,.items-sort li[class]{background:rgba(36,36,36,.8)!important;border-radius:20px!important;border:1px solid rgba(255,107,107,.1)!important;overflow:hidden!important;font-family:GothamProRegular,Tahoma,Geneva,sans-serif!important;font-weight:500!important;padding:8px 16px!important}
form[name="news_set_sort"] ul li a{color:#b0b0b0!important;font-weight:500!important;letter-spacing:.3px!important;transition:color .25s ease!important;font-family:inherit!important;display:block!important}
form[name="news_set_sort"] ul li:hover{background:rgba(42,42,42,.9)!important;border-color:rgba(255,135,135,.3)!important;transform:translateY(-2px)!important;box-shadow:0 4px 12px rgba(255,107,107,.15)!important}
form[name="news_set_sort"] ul li:hover a{color:#ff8787!important}
form[name="news_set_sort"] ul li.asc{background:linear-gradient(135deg,rgba(255,107,107,.2) 0%,rgba(255,135,135,.1) 100%)!important;border-color:rgba(255,107,107,.4)!important}
form[name="news_set_sort"] ul li.asc a{color:#ff8787!important}
.item{background:linear-gradient(135deg,rgba(26,26,26,.95) 0%,rgba(20,20,20,.95) 100%)!important;border:1px solid rgba(255,107,107,.08)!important;border-radius:12px!important;overflow:hidden!important;position:relative!important;backdrop-filter:blur(10px)!important;-webkit-backdrop-filter:blur(10px)!important;transform:translateY(0)!important;transition:all .3s cubic-bezier(.4,0,.2,1)!important}
.item::before{content:''!important;position:absolute!important;top:0!important;left:0!important;right:0!important;height:2px!important;background:linear-gradient(90deg,transparent,#ff6b6b,transparent)!important;opacity:0!important;transition:opacity .3s ease!important}
.item:hover{border-color:rgba(255,107,107,.3)!important;transform:translateY(-4px)!important;box-shadow:0 12px 32px rgba(0,0,0,.5),0 0 0 1px rgba(255,107,107,.1)!important}
.item:hover::before{opacity:1!important}
.item-img{background:#0a0a0a!important;position:relative!important;overflow:hidden!important}
.item-img::after{content:''!important;position:absolute!important;inset:0!important;background:linear-gradient(180deg,transparent 0%,rgba(0,0,0,.4) 100%)!important;opacity:0!important;transition:opacity .3s ease!important;pointer-events:none!important;z-index:5!important}
.item:hover .item-img::after{opacity:1!important}
.item-img img{transform:scale(1)!important;transition:transform .5s cubic-bezier(.34,1.56,.64,1),opacity .3s ease!important}
.item:hover .item-img img{transform:scale(1.08)!important}
.item-title{color:#e0e0e0!important;font-weight:500!important}
.item-title a{color:#e0e0e0!important;transition:color .3s ease!important}
.item-title a:hover{color:#ff8787!important}
.item-title h2{color:#e0e0e0!important;font-weight:500!important}
.item-title h2 i{color:#888!important}
.item-meta{background:linear-gradient(135deg,rgba(255,107,107,.15),rgba(255,135,135,.1))!important;color:#ff8787!important;border-radius:6px!important;font-weight:500!important;backdrop-filter:blur(5px)!important;-webkit-backdrop-filter:blur(5px)!important}
.meta-views{color:#888!important}
.tim{background:rgba(36,36,36,.6)!important;color:#888!important;border-radius:6px!important;backdrop-filter:blur(5px)!important;-webkit-backdrop-filter:blur(5px)!important}
.catmen{background:rgba(42,42,42,.8)!important;color:#b0b0b0!important;border-radius:8px!important;border:1px solid rgba(255,107,107,.1)!important;font-weight:500!important;backdrop-filter:blur(5px)!important;-webkit-backdrop-filter:blur(5px)!important}
.catmen:hover{background:rgba(58,58,58,.9)!important;color:#e0e0e0!important;border-color:rgba(255,135,135,.3)!important;transform:translateY(-2px)!important;box-shadow:0 4px 8px rgba(0,0,0,.3)!important}
.catmen2{background:linear-gradient(135deg,#ff6b6b 0%,#ff5252 100%)!important;color:#fff!important;border-radius:8px!important;font-weight:600!important;box-shadow:0 2px 8px rgba(255,107,107,.3)!important;transform:translateY(0)!important;transition:all .25s cubic-bezier(.4,0,.2,1)!important}
.catmen2:hover{background:linear-gradient(135deg,#ff5252 0%,#ff3838 100%)!important;transform:translateY(-2px)!important;box-shadow:0 4px 12px rgba(255,107,107,.5)!important}
.clouds_xsmall,.clouds_small,.clouds_medium,.clouds_large,.clouds_xlarge{background:rgba(36,36,36,.6)!important;border-radius:16px!important;border:1px solid rgba(255,107,107,.08)!important;opacity:1!important;backdrop-filter:blur(5px)!important;-webkit-backdrop-filter:blur(5px)!important}
.clouds_xsmall a,.clouds_small a,.clouds_medium a,.clouds_large a,.clouds_xlarge a{color:#b0b0b0!important;transition:color .25s ease!important}
.clouds_xsmall:hover,.clouds_small:hover,.clouds_medium:hover,.clouds_large:hover,.clouds_xlarge:hover{background:rgba(42,42,42,.8)!important;border-color:rgba(255,135,135,.2)!important;transform:translateY(-2px)!important}
.clouds_xsmall:hover a,.clouds_small:hover a,.clouds_medium:hover a,.clouds_large:hover a,.clouds_xlarge:hover a{color:#ff8787!important}
.pagi-nav{background:rgba(26,26,26,.8)!important;border:1px solid rgba(255,107,107,.1)!important;border-radius:12px!important;backdrop-filter:blur(10px)!important;-webkit-backdrop-filter:blur(10px)!important}
.pagi-nav a,.pagi-nav span{color:#b0b0b0!important;background:rgba(36,36,36,.6)!important;border-radius:8px!important;font-weight:500!important}
.pagi-nav a:hover{background:rgba(42,42,42,.8)!important;color:#ff8787!important;transform:translateY(-2px)!important;box-shadow:0 4px 8px rgba(255,107,107,.2)!important}
.pagi-nav span{background:linear-gradient(135deg,rgba(255,107,107,.2),rgba(255,135,135,.1))!important;color:#ff8787!important}
.footer a,.footer{color:#888!important}
.search-box input[type="text"],input[type="text"],input[type="password"],input[type="email"],textarea,select{background:rgba(36,36,36,.6)!important;color:#e0e0e0!important;border:1px solid rgba(255,107,107,.1)!important;border-radius:8px!important;backdrop-filter:blur(5px)!important;-webkit-backdrop-filter:blur(5px)!important;transition:all .25s ease!important}
.search-box input[type="text"]{border-radius:12px!important}
.search-box input[type="text"]:focus,input:focus,textarea:focus,select:focus{border-color:rgba(255,107,107,.5)!important;background:rgba(42,42,42,.8)!important;box-shadow:0 0 0 3px rgba(255,107,107,.1)!important;outline:none!important}
.search-box input[type="text"]:focus{box-shadow:0 0 0 3px rgba(255,107,107,.1),0 4px 12px rgba(255,107,107,.2)!important}
.search-box button,.search-box input[type="submit"],button,input[type="submit"],input[type="button"]{background:linear-gradient(135deg,#ff6b6b 0%,#ff5252 100%)!important;color:#fff!important;border:none!important;border-radius:8px!important;font-weight:600!important;box-shadow:0 4px 12px rgba(255,107,107,.3)!important;transform:translateY(0)!important;transition:all .25s cubic-bezier(.4,0,.2,1)!important}
.search-box button,.search-box input[type="submit"]{border-radius:12px!important}
.search-box button:hover,.search-box input[type="submit"]:hover,button:hover,input[type="submit"]:hover,input[type="button"]:hover{background:linear-gradient(135deg,#ff5252 0%,#ff3838 100%)!important;transform:translateY(-2px)!important;box-shadow:0 6px 16px rgba(255,107,107,.5)!important}
.side-panel{background:rgba(26,26,26,.8)!important;border:1px solid rgba(255,107,107,.1)!important;border-radius:12px!important;backdrop-filter:blur(10px)!important;-webkit-backdrop-filter:blur(10px)!important}
h1,h2,h3,h4,h5,h6{color:#e0e0e0!important;font-weight:600!important;letter-spacing:-.3px!important}
p{color:#b0b0b0!important;line-height:1.6!important}
a{color:#b0b0b0!important}
.close-overlay{background:rgba(0,0,0,.98)!important;backdrop-filter:blur(20px)!important;-webkit-backdrop-filter:blur(20px)!important}
::-webkit-scrollbar{width:10px!important}
::-webkit-scrollbar-track{background:rgba(26,26,26,.5)!important}
::-webkit-scrollbar-thumb{background:linear-gradient(180deg,rgba(255,107,107,.5),rgba(255,135,135,.3))!important;border-radius:10px!important;border:2px solid transparent!important}
::-webkit-scrollbar-thumb:hover{background:linear-gradient(180deg,rgba(255,107,107,.8),rgba(255,135,135,.6))!important}
::selection{background:rgba(255,107,107,.3)!important;color:#fff!important}
table{background:rgba(26,26,26,.8)!important;border-color:rgba(255,107,107,.1)!important;border-radius:8px!important;overflow:hidden!important}
th{background:rgba(36,36,36,.8)!important;color:#e0e0e0!important;font-weight:600!important}
td{color:#b0b0b0!important;border-color:rgba(255,107,107,.05)!important}
tr:hover td{background:rgba(36,36,36,.5)!important}
.ad-wrapper{opacity:.5!important;filter:grayscale(.3)!important}
.sect-desc{color:#888!important}
.fluid_controls_container,.fluid_controls_container *{color:#e0e0e0!important}
.fluid_controls_left,.fluid_controls_right{background:rgba(0,0,0,.6)!important}
.fluid_button{background:rgba(255,107,107,.15)!important;border-radius:6px!important;transition:all .2s ease!important}
.fluid_button:hover{background:rgba(255,107,107,.3)!important;transform:scale(1.05)!important}
.fluid_controls_progress_container{background:rgba(255,255,255,.1)!important;border-radius:4px!important}
.fluid_controls_currentpos{background:linear-gradient(90deg,#ff6b6b,#ff8787)!important;color:#fff!important;border-radius:4px!important;font-weight:600!important;text-shadow:0 1px 2px rgba(0,0,0,.8)!important}
.fluid_control_volume_currentpos{background:linear-gradient(90deg,#ff6b6b,#ff8787)!important;border-radius:4px!important}
.fluid_control_duration,.fluid_fluid_control_duration{color:#e0e0e0!important;font-weight:500!important;text-shadow:0 1px 2px rgba(0,0,0,.8)!important}
.fluid_control_volume_container{background:rgba(255,255,255,.1)!important;border-radius:4px!important}
.xd{background:rgba(26,26,26,.8)!important;color:#e0e0e0!important;border:1px solid rgba(255,107,107,.1)!important;border-radius:8px!important;padding:8px!important}
.fm-fav{color:#ff8787!important}
.rating{color:#ff8787!important}
#story{background:rgba(36,36,36,.8)!important;color:#e0e0e0!important;border:1px solid rgba(255,107,107,.2)!important;border-radius:8px!important}
#story:focus{border-color:rgba(255,107,107,.5)!important;box-shadow:0 0 0 3px rgba(255,107,107,.1)!important}
.full-tags a,.full-tags{background:rgba(42,42,42,.8)!important;color:#b0b0b0!important;border:1px solid rgba(255,107,107,.1)!important;border-radius:8px!important;padding:6px 12px!important;display:inline-block!important;margin:3px!important;font-weight:500!important;transition:all .25s ease!important}
.full-tags a:hover{background:rgba(58,58,58,.9)!important;color:#ff8787!important;border-color:rgba(255,135,135,.3)!important;transform:translateY(-2px)!important;box-shadow:0 4px 8px rgba(255,107,107,.2)!important}
.a2a_kit{background:transparent!important}
.a2a_kit a{background:rgba(42,42,42,.8)!important;border:1px solid rgba(255,107,107,.1)!important;border-radius:8px!important;padding:6px 12px!important;transition:all .25s ease!important}
.a2a_kit a:hover{background:rgba(58,58,58,.9)!important;border-color:rgba(255,135,135,.3)!important;transform:translateY(-2px)!important}
.a2a_svg{border-radius:6px!important;transition:transform .2s ease!important}
.a2a_kit a:hover .a2a_svg{transform:scale(1.1)!important}
.full-tags{color:#e0e0e0!important;background:transparent!important;border:none!important;padding:0!important;margin-bottom:10px!important}
.fmeta{background:rgba(26,26,26,.8)!important;border:1px solid rgba(255,107,107,.1)!important;border-radius:12px!important;padding:12px!important;margin:10px 0!important}
.fm-item{background:rgba(36,36,36,.6)!important;color:#b0b0b0!important;border-radius:8px!important;padding:8px 12px!important;margin:4px!important}
.fm-item i{color:#ff8787!important}
.f-desc,.full-text{color:#b0b0b0!important;background:rgba(26,26,26,.8)!important;border:1px solid rgba(255,107,107,.1)!important;border-radius:12px!important;padding:15px!important;margin:10px 0!important}
.f-desc p,.full-text p{color:#b0b0b0!important;line-height:1.6!important}
.fcols{background:transparent!important}
.fleft,.fright{background:transparent!important}
.video-box,.fplayer{background:#0a0a0a!important;border:1px solid rgba(255,107,107,.1)!important;border-radius:12px!important;overflow:hidden!important;margin:10px 0!important}
.item-title p[style*="color"]{color:#888!important}
.item-title p span{color:#b0b0b0!important}
.item-title p a{color:#b0b0b0!important;text-decoration:none!important}
.item-title p a:hover{color:#ff8787!important}
          `;
      } else {
          style.textContent = `
*{transition:background-color .2s ease,color .2s ease,border-color .2s ease!important}
body,.js{background:linear-gradient(135deg,#f8f9fa 0%,#fff 100%)!important;color:#2c3e50!important}
.header,.nav,.footer{background:rgba(255,255,255,.95)!important;backdrop-filter:blur(10px)!important;border-color:rgba(231,76,60,.1)!important}
.header,.nav{box-shadow:0 2px 12px rgba(0,0,0,.08)!important}
.nav-in a:hover{color:#e74c3c!important;background:rgba(231,76,60,.08)!important}
.item{background:rgba(255,255,255,.98)!important;border:1px solid rgba(231,76,60,.08)!important;box-shadow:0 2px 8px rgba(0,0,0,.06)!important;border-radius:12px!important;transform:translateY(0)!important;transition:all .3s cubic-bezier(.4,0,.2,1)!important}
.item:hover{box-shadow:0 12px 32px rgba(0,0,0,.15)!important;border-color:rgba(231,76,60,.3)!important;transform:translateY(-4px)!important}
button,input[type="submit"],input[type="button"]{background:linear-gradient(135deg,#e74c3c 0%,#c0392b 100%)!important;box-shadow:0 4px 12px rgba(231,76,60,.3)!important;border-radius:8px!important;transform:translateY(0)!important;transition:all .25s cubic-bezier(.4,0,.2,1)!important}
button:hover,input[type="submit"]:hover,input[type="button"]:hover{background:linear-gradient(135deg,#c0392b 0%,#a93226 100%)!important;transform:translateY(-2px)!important;box-shadow:0 6px 16px rgba(231,76,60,.5)!important}
.fluid_controls_container,.fluid_controls_container *{color:#2c3e50!important}
.fluid_button{background:rgba(231,76,60,.15)!important}
.fluid_button:hover{background:rgba(231,76,60,.3)!important}
          `;
      }
      document.head.appendChild(style);

      // 2. Video Preview (Integrated with the pack's insertPreviewVideo)
      const videoCache = new Map();
      const preloadQueue = [];
      const MAX_CONCURRENT_PRELOADS = 2;
      let activePreloads = 0;

      function extractVideoUrl(pageUrl) {
          return new Promise((resolve, reject) => {
              if (videoCache.has(pageUrl)) {
                  resolve(videoCache.get(pageUrl));
                  return;
              }
              GM_xmlhttpRequest({
                  method: 'GET',
                  url: pageUrl,
                  onload: function(response) {
                      const parser = new DOMParser();
                      const doc = parser.parseFromString(response.responseText, 'text/html');
                      const videoSource = doc.querySelector('video source');
                      if (videoSource && videoSource.src) {
                          videoCache.set(pageUrl, videoSource.src);
                          resolve(videoSource.src);
                      } else {
                          reject('No video found');
                      }
                  },
                  onerror: reject
              });
          });
      }

      function processQueue() {
          if (activePreloads >= MAX_CONCURRENT_PRELOADS || preloadQueue.length === 0) return;
          const { pageUrl, img } = preloadQueue.shift();
          activePreloads++;

          extractVideoUrl(pageUrl)
              .then(videoUrl => {
                  if (videoUrl) {
                      // Apply pack's native behavior
                      insertPreviewVideo(img, videoUrl);
                  }
              })
              .catch(() => {})
              .finally(() => {
                  activePreloads--;
                  setTimeout(processQueue, 50);
              });
      }

      function initItem(item) {
          if (item.dataset.ypInit) return;
          item.dataset.ypInit = '1';

          const imgContainer = item.querySelector('.item-img');
          const link = item.querySelector('a[href*=".html"]');
          const img = imgContainer ? imgContainer.querySelector('img') : null;

          if (!img || !link) return;

          preloadQueue.push({ pageUrl: link.href, img });
          processQueue();
      }

      const ypFetchObserver = new IntersectionObserver(entries => {
          entries.forEach(entry => {
              if (entry.isIntersecting) {
                  initItem(entry.target);
                  ypFetchObserver.unobserve(entry.target);
              }
          });
      }, { rootMargin: '400px', threshold: 0.01 });

      function watchItems() {
          document.querySelectorAll('.item').forEach(item => {
              if (!item.dataset.ypObserved) {
                  item.dataset.ypObserved = '1';
                  ypFetchObserver.observe(item);
              }
          });
      }

      watchItems();
      new MutationObserver(watchItems).observe(document.body, { childList: true, subtree: true });
      setTimeout(watchItems, 500);
      setInterval(watchItems, 5000);
    },

    "superporn.com": function () {
      const videoCache = new Map();
      const preloadQueue = [];
      const MAX_CONCURRENT_PRELOADS = 2;
      let activePreloads = 0;

      function extractVideoUrl(pageUrl) {
          return new Promise((resolve, reject) => {
              if (videoCache.has(pageUrl)) {
                  resolve(videoCache.get(pageUrl));
                  return;
              }
              GM_xmlhttpRequest({
                  method: 'GET',
                  url: pageUrl,
                  onload: function(response) {
                      const parser = new DOMParser();
                      const doc = parser.parseFromString(response.responseText, 'text/html');
                      const videoSource = doc.querySelector('video source');
                      if (videoSource && videoSource.src) {
                          videoCache.set(pageUrl, videoSource.src);
                          resolve(videoSource.src);
                      } else {
                          reject('No video found');
                      }
                  },
                  onerror: reject
              });
          });
      }

      function processQueue() {
          if (activePreloads >= MAX_CONCURRENT_PRELOADS || preloadQueue.length === 0) return;
          const { pageUrl, img } = preloadQueue.shift();
          activePreloads++;

          extractVideoUrl(pageUrl)
              .then(videoUrl => {
                  if (videoUrl) {
                      insertPreviewVideo(img, videoUrl);
                  }
              })
              .catch(() => {})
              .finally(() => {
                  activePreloads--;
                  setTimeout(processQueue, 50);
              });
      }

      function initItem(item) {
          if (item.dataset.spInit) return;
          item.dataset.spInit = '1';

          const link = item.querySelector('a.thumb-duracion');
          const img = item.querySelector('img');

          if (!img || !link) return;

          preloadQueue.push({ pageUrl: link.href, img });
          processQueue();
      }

      const spFetchObserver = new IntersectionObserver(entries => {
          entries.forEach(entry => {
              if (entry.isIntersecting) {
                  initItem(entry.target);
                  spFetchObserver.unobserve(entry.target);
              }
          });
      }, { rootMargin: '400px', threshold: 0.01 });

      function watchItems() {
          document.querySelectorAll('.thumb-video').forEach(item => {
              if (!item.dataset.spObserved) {
                  item.dataset.spObserved = '1';
                  spFetchObserver.observe(item);
              }
          });
      }

      watchItems();
      new MutationObserver(watchItems).observe(document.body, { childList: true, subtree: true });
      setTimeout(watchItems, 500);
      setInterval(watchItems, 5000);
    }
  };

  // Dispatcher — run immediately AND on DOMContentLoaded as fallback
  function dispatch() {
    for (const domain in siteHandlers) {
      if (hostname.includes(domain)) {
        siteHandlers[domain]();
        break;
      }
    }
  }

  // Run now (for scripts injected after DOM is ready)
  dispatch();

  // Also run on DOMContentLoaded in case we injected before DOM was ready
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', dispatch);
  }

})();