Avjb VIP Unlock

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

Você precisará instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Você precisará instalar uma extensão como o Tampermonkey para instalar este script.

Você precisará instalar um gerenciador de scripts de usuário para instalar este script.

(Eu já tenho um gerenciador de scripts de usuário, me deixe instalá-lo!)

Advertisement:

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

(Eu já possuo um gerenciador de estilos de usuário, me deixar fazer a instalação!)

Advertisement:

// ==UserScript==
// @name         Avjb VIP Unlock
// @namespace    avjb_vip_unlock
// @version      1.8.0
// @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';

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

    // =============================================
    // SERVERS LIST — add/remove servers here
    // =============================================
    const SERVERS = [
        'https://7senver.jb-aiwei.cc',
        'https://99newline.jb-aiwei.cc',
        'https://88newline.jb-aiwei.cc',
        'https://newbox.jb-aiwei.cc',
        'https://r22.jb-aiwei.cc',
        'https://back.bbmmic2.com',
    ];

    // =============================================
    // 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(`
        img {
            opacity: 1 !important;
            visibility: visible !important;
        }

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

        .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); }
        }

        #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;
        }

        #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;
        }

        #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);
        }

        #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
    // =============================================
    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;

    // =============================================
    // Double Click 10s Seek
    // =============================================
    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;

        if (timeSinceLastClick < 300 && timeSinceLastClick > 30) {
            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;

            if (clickYpercent > 0.9) {
                lastClickTime = 0;
                return;
            }

            e.preventDefault();
            e.stopPropagation();

            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 ⏩`;
            }

            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;
        }
    }

    // =============================================
    // HLS Stream Loader
    // =============================================
    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! 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! Click to play';
                showTipsEl.style.color = '#2ed573';
            });
        }
    }

    // =============================================
    // Try All Servers — use whichever responds first
    // =============================================
    function tryAllServers(folder, videoID) {
        showTipsEl.innerText = '⌛️ Finding best server...';
        let resolved = false;

        SERVERS.map(baseURL => {
            const url = `${baseURL}/videos/${folder}/${videoID}/index.m3u8`;
            return fetch(url, { method: 'HEAD', cache: 'no-store' })
                .then(res => {
                    if (res.ok && !resolved) {
                        resolved = true;
                        showTipsEl.innerText = `⌛️ Server found, loading...`;
                        loadHlsStream(url);
                    }
                })
                .catch(() => {});
        });

        // Fallback after 5s if no server responded
        setTimeout(() => {
            if (!resolved) {
                resolved = true;
                showTipsEl.innerText = '⚠️ Trying fallback server...';
                const url = `${SERVERS[0]}/videos/${folder}/${videoID}/index.m3u8`;
                loadHlsStream(url);
            }
        }, 5000);
    }

    // =============================================
    // Main Loop
    // =============================================
    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) {
                tryAllServers(folder, videoID);
                clearInterval(my_timer);
            }
        }
    }

    let my_timer = setInterval(check_circle_v2, 1500);

})();