Avjb VIP Unlock

Unlock all VIP videos, perfect mobile support, fixes lazy loaded thumbnails. Added double click 10s seek. No ads, no popups.

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Avjb VIP Unlock
// @namespace    avjb_vip_unlock
// @version      1.7.2
// @description  Unlock all VIP videos, perfect mobile support, fixes lazy loaded thumbnails. Added double click 10s seek. No ads, no popups.
// @author       codegeasse
// @match        https://avjb.com/*
// @match        https://avjb.cc/*
// @grant        GM_addStyle
// @license      MIT
// @require      https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.1.5/hls.min.js

// ==/UserScript==

(function() {
    'use strict';

    // Based on original script by w2f, heavily modified and improved
    // Added double click seek feature

    const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || window.innerWidth <= 768;

    // =============================================
    // Original thumbnail fix logic
    // =============================================
    function fixThumbnails() {

        document.querySelectorAll('.thumb, .video-thumb, .videos-list a, .list-videos a, .card a').forEach(el => {

            if (el.dataset.thumbFixed) return;
            el.dataset.thumbFixed = 'true';

            el.dispatchEvent(new PointerEvent('pointerover', {bubbles: true, cancelable: true}));
            el.dispatchEvent(new TouchEvent('touchstart', {bubbles: true, cancelable: true}));
            el.dispatchEvent(new MouseEvent('mouseover', {bubbles: true, cancelable: true}));

            setTimeout(() => {
                el.dispatchEvent(new PointerEvent('pointermove', {bubbles: true}));
            }, 50);
        });

        document.querySelectorAll('a[href^="/video/"] img').forEach(img => {
            if (img.src && !img.src.includes('placeholder') && !img.src.includes('blank')) return;

            const link = img.closest('a[href^="/video/"]');
            if (!link) return;

            const videoId = link.href.split('/video/')[1].split('/')[0];
            if (!videoId) return;

            const folder = Math.floor(parseInt(videoId) / 1000) * 1000;
            img.src = `https://stat.avstatic.com/cdn1/contents/videos_screenshots/${folder}/${videoId}/385x233/1.jpg`;
        });

        document.querySelectorAll('img').forEach(img => {
            img.style.opacity = '1';
            img.style.visibility = 'visible';
            img.loading = 'eager';
            img.classList.remove('lazy', 'lazyload', 'b-lazy');
        });

    }

    function startThumbnailFixer() {
        fixThumbnails();

        setInterval(fixThumbnails, 700);

        let scrollTimeout;
        window.addEventListener('scroll', () => {
            clearTimeout(scrollTimeout);
            scrollTimeout = setTimeout(fixThumbnails, 150);
        }, { passive: true });

        const observer = new MutationObserver(() => {
            setTimeout(fixThumbnails, 100);
        });

        observer.observe(document.body, { childList: true, subtree: true });
    }

    startThumbnailFixer();


    GM_addStyle(`
        /* Force thumbnails to show no matter what */
        img {
            opacity: 1 !important;
            visibility: visible !important;
        }

        .thumb, .video-thumb {
            background: none !important;
        }

        /* Double click seek feedback */
        .seek-indicator {
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            font-size: 42px;
            font-weight: bold;
            color: white;
            background: rgba(0,0,0,0.6);
            padding: 16px 20px;
            border-radius: 50%;
            z-index: 500;
            pointer-events: none;
            animation: seekFadeOut 0.7s ease-out forwards;
        }

        @keyframes seekFadeOut {
            0% { opacity: 1; transform: translateY(-50%) scale(0.7); }
            30% { opacity: 1; transform: translateY(-50%) scale(1.1); }
            100% { opacity: 0; transform: translateY(-50%) scale(1); }
        }

        /* ===== INLINE MODE (Mobile) — replaces original player ===== */
        #hlsPlayer.inline-mode {
            position: relative !important;
            width: 100% !important;
            max-width: 100vw !important;
            background: #000;
            border-radius: 0;
            box-shadow: none;
            border: none;
            padding: 0;
            margin: 0;
            z-index: 100;
        }

        #hlsPlayer.inline-mode .player-content {
            display: flex;
            flex-direction: column;
            width: 100%;
            position: relative;
        }

        #hlsPlayer.inline-mode #videoElement {
            width: 100%;
            max-height: 56.25vw;
            aspect-ratio: 16 / 9;
            background: #000;
            border-radius: 0;
            display: block;
        }

        #hlsPlayer.inline-mode .player-footer {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 8px 12px;
            background: #1a1a1a;
            font-size: 13px;
            font-family: Arial, sans-serif;
        }

        /* ===== FLOATING MODE (Desktop) ===== */
        #hlsPlayer.floating-mode {
            position: fixed;
            bottom: 20px;
            right: 20px;
            width: 480px;
            max-width: 40vw;
            background: #141414;
            border-radius: 12px;
            box-shadow: 0 10px 40px rgba(0,0,0,0.6);
            z-index: 2147483647;
            overflow: hidden;
            border: 2px solid #ff4757;
            padding: 8px;
            display: none;
        }

        #hlsPlayer.floating-mode.open {
            display: block;
        }

        #hlsPlayer.floating-mode .player-content {
            display: flex;
            flex-direction: column;
            width: 100%;
            position: relative;
        }

        #hlsPlayer.floating-mode #videoElement {
            width: 100%;
            aspect-ratio: 16 / 9;
            background: #000;
            border-radius: 8px;
            display: block;
        }

        #hlsPlayer.floating-mode .player-footer {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 8px 5px 4px;
            font-size: 13px;
            font-family: Arial, sans-serif;
        }

        /* ===== TOGGLE BUTTON (Desktop floating) ===== */
        #hlsToggleBtn {
            position: fixed;
            bottom: 20px;
            right: 20px;
            width: 50px;
            height: 50px;
            background: #1a1a1a;
            border: 2px solid #ff4757;
            border-radius: 50%;
            box-shadow: 0 6px 20px rgba(0,0,0,0.5);
            z-index: 2147483647;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 24px;
            cursor: pointer;
            transition: transform 0.2s, box-shadow 0.2s;
            user-select: none;
        }

        #hlsToggleBtn:hover {
            transform: scale(1.1);
            box-shadow: 0 8px 25px rgba(255,71,87,0.4);
        }

        #hlsToggleBtn:active {
            transform: scale(0.95);
        }

        /* ===== SHARED STYLES ===== */
        #showTips {
            color: #ccc;
        }

        #download {
            color: #ff4757;
            text-decoration: none;
            font-weight: bold;
            font-size: 13px;
            white-space: nowrap;
        }

        #download:hover {
            color: #ff6b81;
            text-decoration: underline;
        }

        .player-holder .no-access,
        .player-holder .premium-only,
        .player-holder .vip-lock {
            display: none !important;
        }
    `);

    // =============================================
    // VIDEO PLAYER LOGIC
    // =============================================

    const playerDiv = document.createElement('div');
    playerDiv.id = 'hlsPlayer';
    playerDiv.innerHTML = `
        <div class="player-content">
            <video id="videoElement" controls preload="none" playsinline webkit-playsinline></video>
            <div class="player-footer">
                <span id="showTips">⌛️ Unlocking...</span>
                <a id="download" href="" target="_blank">⏬ 1-Click Download</a>
            </div>
        </div>
    `;

    const toggleBtn = document.createElement('div');
    toggleBtn.id = 'hlsToggleBtn';
    toggleBtn.innerText = '📺';

    const video = playerDiv.querySelector('#videoElement');
    const downloadEl = playerDiv.querySelector('#download');
    const showTipsEl = playerDiv.querySelector('#showTips');
    let hls = null;

    // ==============================
    // ✨ NEW: Double Click 10sec Seek Feature
    // ==============================
    const SEEK_SECONDS = 10;
    let lastClickTime = 0;

    video.addEventListener('click', handleDoubleClick);
    video.addEventListener('touchend', handleDoubleClick, { passive: false });

    function handleDoubleClick(e) {
        const now = Date.now();
        const timeSinceLastClick = now - lastClickTime;

        // Standard 300ms double click window
        if (timeSinceLastClick < 300 && timeSinceLastClick > 30) {

            // Get correct coordinates for both mouse and touch events
            let clientX, clientY;
            if (e.type.startsWith('touch')) {
                clientX = e.changedTouches[0].clientX;
                clientY = e.changedTouches[0].clientY;
            } else {
                clientX = e.clientX;
                clientY = e.clientY;
            }

            const rect = video.getBoundingClientRect();
            const offsetX = clientX - rect.left;
            const offsetY = clientY - rect.top;

            const clickXpercent = offsetX / rect.width;
            const clickYpercent = offsetY / rect.height;

            // ❗ Important: Ignore clicks on the bottom native control bar
            if (clickYpercent > 0.9) {
                lastClickTime = 0;
                return;
            }

            // Cancel default play/pause action
            e.preventDefault();
            e.stopPropagation();

            // Left half = backward, Right half = forward
            let indicator;

            if (clickXpercent < 0.5) {
                video.currentTime = Math.max(0, video.currentTime - SEEK_SECONDS);
                indicator = `⏪ -${SEEK_SECONDS}s`;
            } else {
                video.currentTime = Math.min(video.duration, video.currentTime + SEEK_SECONDS);
                indicator = `+${SEEK_SECONDS}s ⏩`;
            }

            // Show animation feedback
            const popup = document.createElement('div');
            popup.className = 'seek-indicator';
            popup.innerText = indicator;
            popup.style.left = clickXpercent < 0.5 ? '15%' : '65%';
            video.parentElement.appendChild(popup);
            setTimeout(() => popup.remove(), 700);

            lastClickTime = 0;
        } else {
            lastClickTime = now;
        }
    }


    function loadHlsStream(url) {
        downloadEl.href = `https://tools.thatwind.com/tool/m3u8downloader#m3u8=${url}&referer=${window.location.href}&filename=${encodeURIComponent(document.title)}`;

        if (Hls.isSupported()) {
            if (hls) hls.destroy();
            hls = new Hls();
            hls.loadSource(url);
            hls.attachMedia(video);
            hls.on(Hls.Events.MANIFEST_PARSED, () => {
                showTipsEl.innerText = '✅ Unlocked successfully! Click to play';
                showTipsEl.style.color = '#2ed573';
            });
            hls.on(Hls.Events.ERROR, (event, data) => {
                if (data.fatal) {
                    showTipsEl.innerText = '❌ Load failed, please refresh and try again';
                    showTipsEl.style.color = '#ff4757';
                }
            });
        } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
            video.src = url;
            video.addEventListener('loadedmetadata', () => {
                showTipsEl.innerText = '✅ Unlocked successfully! Click to play';
                showTipsEl.style.color = '#2ed573';
            });
        }
    }

    let savedImgSrc = null;

    function earlyGrab() {
        if (!savedImgSrc) {
            const img = document.querySelector('.player-holder img[src*="videos_screenshots"]');
            const meta = document.querySelector('meta[property="og:image"]');
            if (img) savedImgSrc = img.src;
            else if (meta) savedImgSrc = meta.content;
        }
    }

    function check_circle_v2() {
        if (!document.body) return;

        const playerHolder = document.querySelector('.player-holder');
        if (!playerHolder) return;

        earlyGrab();

        if (isMobile && !document.getElementById('hlsPlayer')) {
            playerDiv.className = 'inline-mode';
            playerHolder.innerHTML = '';
            playerHolder.style.cssText = 'padding:0;margin:0;overflow:visible;';
            playerHolder.appendChild(playerDiv);
        } else if (!isMobile && !document.getElementById('hlsPlayer')) {
            playerDiv.className = 'floating-mode';
            document.body.appendChild(playerDiv);
            document.body.appendChild(toggleBtn);
            toggleBtn.addEventListener('click', () => {
                const isOpen = playerDiv.classList.toggle('open');
                toggleBtn.style.display = isOpen ? 'none' : 'flex';
            });
        }

        if (!savedImgSrc) {
            const meta = document.querySelector('meta[property="og:image"]');
            if (meta) savedImgSrc = meta.content;
        }

        if (savedImgSrc) {
            const tmp = savedImgSrc.split('/');
            let folder = null, videoID = null;

            for (let i = 0; i < tmp.length - 1; i++) {
                if (/^\d+000$/.test(tmp[i]) && /^\d+$/.test(tmp[i + 1])) {
                    folder = tmp[i];
                    videoID = parseInt(tmp[i + 1]);
                    break;
                }
            }

            if (folder && videoID) {
                let baseURL = 'https://99newline.jb-aiwei.cc';
                if (videoID >= 92803) {
                    baseURL = 'https://88newline.jb-aiwei.cc';
                }

                const url = `${baseURL}/videos/${folder}/${videoID}/index.m3u8`;
                loadHlsStream(url);
                clearInterval(my_timer);
            }
        }
    }

    let my_timer = setInterval(check_circle_v2, 1500);

})();