Avjb VIP Unlock

Unlock all VIP videos, nuke paywall, fix thumbnails. Raw Source Fetch API Bypass, CORS fix, and native Playerjs hooking.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Avjb VIP Unlock
// @namespace    avjb_vip_unlock
// @version      2.11.0
// @description  Unlock all VIP videos, nuke paywall, fix thumbnails. Raw Source Fetch API Bypass, CORS fix, and native Playerjs hooking.
// @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
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    // ==========================================
    // Server Fallbacks (Prioritized Legacy Servers)
    // ==========================================
    const SERVERS = [
        'https://99newline.jb-aiwei.cc',
        'https://88newline.jb-aiwei.cc',
        'https://7senver.jb-aiwei.cc',
        'https://newbox.jb-aiwei.cc',
        'https://r22.jb-aiwei.cc',
        'https://bmc2.imgclh.com',
        'https://cdn1.bmc2.imgclh.com',
        'https://cdn2.bmc2.imgclh.com',
        'https://v.bmc2.imgclh.com',
        'https://hls.bmc2.imgclh.com',
        'https://stream.bmc2.imgclh.com',
        'https://back.bbmmic2.com',
        'https://lvb.rsso2.com'
    ];

    let capturedMasterUrl = null;
    let my_timer;
    let videoLoaded = false;
    let isChecking = false;

    // ====== NATIVE PLAYER HOOK (CRASH PREVENTION & URL THEFT) ======
    if (!window.__avjb_hooked) {
        window.__avjb_hooked = true;
        window.Playerjs = function(config) {
            console.log('[Avjb Unlock] Intercepted native Playerjs config:', config);
            if (config && config.file && !videoLoaded) {
                console.log('[Avjb Unlock] 🚀 Stolen secure URL from native player:', config.file);
                if (my_timer) { clearInterval(my_timer); my_timer = null; }
                loadHlsStream(config.file);
            }

            // Provide dummy API methods so the native scripts don't crash
            this.api = function(cmd, val) {
                const vid = document.getElementById('videoElement');
                if (cmd === 'time' && vid) return vid.currentTime || 0;
                if (cmd === 'duration' && vid) return vid.duration || 0;
                return 0;
            };
        };
    }

    // Hook fetch/xhr to capture master URLs (IGNORING OUR OWN PROBES)
    const originalFetch = window.fetch;
    window.fetch = function(input, init) {
        try {
            if (init && init.method && init.method.toUpperCase() === 'HEAD') return originalFetch.apply(this, arguments);
            const url = typeof input === 'string' ? input : input?.url;
            if (url && /\.m3u8(\?|$)/i.test(url) && !capturedMasterUrl) {
                const isBasicProbe = SERVERS.some(s => url.startsWith(s)) && !url.includes('md5=') && !url.match(/[a-zA-Z0-9_-]{30,}/);
                if (!isBasicProbe) {
                    capturedMasterUrl = url;
                    console.log('[Avjb Unlock] Captured master via Fetch:', url);
                }
            }
        } catch (e) {}
        return originalFetch.apply(this, arguments);
    };

    const originalXHROpen = XMLHttpRequest.prototype.open;
    XMLHttpRequest.prototype.open = function(method, url, ...rest) {
        try {
            if (method && method.toUpperCase() === 'HEAD') return originalXHROpen.call(this, method, url, ...rest);
            if (url && /\.m3u8(\?|$)/i.test(url) && !capturedMasterUrl) {
                const isBasicProbe = SERVERS.some(s => url.startsWith(s)) && !url.includes('md5=') && !url.match(/[a-zA-Z0-9_-]{30,}/);
                if (!isBasicProbe) {
                    capturedMasterUrl = url;
                    console.log('[Avjb Unlock] Captured master via XHR:', url);
                }
            }
        } catch (e) {}
        return originalXHROpen.call(this, method, url, ...rest);
    };

    // ====== VIDEO PLAYER DOM ======
    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">⌛️ Initializing...</span>
                <a id="download" href="" target="_blank">⏬ 1-Click Download</a>
            </div>
        </div>
    `;
    const video = playerDiv.querySelector('#videoElement');
    const downloadEl = playerDiv.querySelector('#download');
    const showTipsEl = playerDiv.querySelector('#showTips');
    let hls = null;

    // ====== DOUBLE CLICK 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 t = now - lastClickTime;
        if (t < 300 && t > 30) {
            let cx, cy;
            if (e.type.startsWith('touch')) {
                cx = e.changedTouches[0].clientX; cy = e.changedTouches[0].clientY;
            } else { cx = e.clientX; cy = e.clientY; }
            const rect = video.getBoundingClientRect();
            const xp = (cx - rect.left) / rect.width;
            const yp = (cy - rect.top) / rect.height;
            if (yp > 0.9) { lastClickTime = 0; return; }
            e.preventDefault(); e.stopPropagation();
            if (xp < 0.5) {
                video.currentTime = Math.max(0, video.currentTime - SEEK_SECONDS);
                showIndicator(`⏪ -${SEEK_SECONDS}s`, '15%');
            } else {
                video.currentTime = Math.min(video.duration, video.currentTime + SEEK_SECONDS);
                showIndicator(`+${SEEK_SECONDS}s ⏩`, '65%');
            }
            lastClickTime = 0;
        } else { lastClickTime = now; }
    }
    function showIndicator(text, left) {
        const popup = document.createElement('div');
        popup.className = 'seek-indicator';
        popup.innerText = text;
        popup.style.left = left;
        video.parentElement.appendChild(popup);
        setTimeout(() => popup.remove(), 700);
    }

    // ====== HLS LOADER ======
    function loadHlsStream(url) {
        if (videoLoaded) { return; }

        console.log('[Avjb Unlock] Loading HLS stream:', 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({
                manifestLoadingTimeOut: 20000,
                manifestLoadingMaxRetry: 4,
                levelLoadingTimeOut: 20000,
                levelLoadingMaxRetry: 4,
                xhrSetup: (xhr) => {
                    xhr.withCredentials = false;
                },
                enableWorker: true,
                lowLatencyMode: false,
            });

            hls.on(Hls.Events.MANIFEST_LOADING, () => {
                showTipsEl.innerText = '⌛️ Loading manifest...';
            });

            hls.loadSource(url);
            hls.attachMedia(video);
            hls.on(Hls.Events.MANIFEST_PARSED, () => {
                videoLoaded = true;
                showTipsEl.innerText = '✅ Unlocked! Click to play';
                showTipsEl.style.color = '#2ed573';
                if (my_timer) { clearInterval(my_timer); my_timer = null; }
            });
            hls.on(Hls.Events.ERROR, (event, data) => {
                if (data.fatal) {
                    if (data.type === Hls.ErrorTypes.MEDIA_ERROR) {
                        hls.recoverMediaError();
                        return;
                    }
                    showTipsEl.innerText = '❌ Load failed: ' + (data.details || data.type);
                    showTipsEl.style.color = '#ff4757';
                }
            });
        } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
            video.src = url;
            video.addEventListener('loadedmetadata', () => {
                videoLoaded = true;
                showTipsEl.innerText = '✅ Unlocked! Click to play';
                showTipsEl.style.color = '#2ed573';
                if (my_timer) { clearInterval(my_timer); my_timer = null; }
            });
        }
    }

    // ====== TRY ALL SERVERS ======
    function tryAllServers(folder, videoID) {
        if (videoLoaded || isChecking) return;

        isChecking = true;
        console.log('[Avjb Unlock] Starting legacy server probe for video:', videoID, 'folder:', folder);
        if (!videoID || isNaN(videoID) || videoID <= 0) {
            showTipsEl.innerText = '❌ Invalid video ID';
            isChecking = false;
            return;
        }

        showTipsEl.innerText = '⌛️ Finding legacy server...';
        let resolved = false;
        const cacheKey = `bbmmic2_date_${videoID}`;
        const cachedDate = localStorage.getItem(cacheKey);

        const tasks = [];
        SERVERS.forEach(baseURL => {
            let urlsToTry = [];

            if (baseURL.includes('bbmmic2.com')) {
                if (cachedDate) urlsToTry.push(`${baseURL}/data/${cachedDate}/${videoID}/hls/index.m3u8`);
                const probeDates = ['20220101','20220301','20220530','20220615','20220801','20221001','20221201','20230201','20230501','20230801','20240101','20240601','20250101','20250501','20250901'];
                probeDates.forEach(d => { if (d !== cachedDate) urlsToTry.push(`${baseURL}/data/${d}/${videoID}/hls/index.m3u8`); });
            } else if (baseURL.includes('imgclh.com')) {
                urlsToTry.push(
                    `${baseURL}/contents/videos/${folder}/${videoID}/index.m3u8`,
                    `${baseURL}/contents/videos/${folder}/${videoID}/master.m3u8`,
                    `${baseURL}/contents/videos_hls/${folder}/${videoID}/index.m3u8`,
                    `${baseURL}/contents/hls/${folder}/${videoID}/index.m3u8`,
                    `${baseURL}/videos/${folder}/${videoID}/index.m3u8`,
                    `${baseURL}/hls/${folder}/${videoID}/index.m3u8`,
                    `${baseURL}/contents/videos/${folder}/${videoID}/playlist.m3u8`
                );
            } else {
                urlsToTry.push(`${baseURL}/videos/${folder}/${videoID}/index.m3u8`);
            }

            urlsToTry.forEach(url => {
                tasks.push(
                    fetch(url, { method: 'HEAD', cache: 'no-store' })
                        .then(res => {
                            if (res.ok && !resolved && !videoLoaded) {
                                resolved = true;
                                console.log('[Avjb Unlock] ✅ Found working legacy server:', url);
                                const match = url.match(/\/data\/(\d{8})\//);
                                if (match) try { localStorage.setItem(cacheKey, match[1]); } catch (e) {}
                                showTipsEl.innerText = '⌛️ Server found, loading...';
                                loadHlsStream(url);
                            }
                        }).catch(() => {})
                );
            });
        });

        Promise.all(tasks);
        setTimeout(() => {
            if (!resolved && !videoLoaded) {
                resolved = true;
                showTipsEl.innerText = '⚠️ Limit hit & no legacy fallback found. Use VPN.';
                if (capturedMasterUrl) loadHlsStream(capturedMasterUrl);
            }
            isChecking = false;
        }, 20000);
    }

    // ====== THUMBNAILS ======
    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') && !img.src.includes('lazy')) 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://bmc2.imgclh.com/contents/videos_screenshots/${folder}/${videoId}/preview.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 });
    }

    function safeObserve(callback) {
        if (document.body) {
            callback();
        } else {
            const wait = setInterval(() => {
                if (document.body) { clearInterval(wait); callback(); }
            }, 10);
        }
    }

    safeObserve(() => {
        new MutationObserver(() => setTimeout(fixThumbnails, 100))
            .observe(document.body, { childList: true, subtree: true });
    });

    startThumbnailFixer();

    // ====== PAYWALL KILLER ======
    function nukePaywallAggressive(context) {
        context = context || document;
        try {
            const layer2 = context.getElementById ? context.getElementById('layer2') : (context.querySelector && context.querySelector('#layer2'));
            if (layer2 && layer2.remove) layer2.remove();

            const classQuery = context.querySelectorAll ? context.querySelectorAll(
                '.paywall-guest, .paywall-v2, .no-player, .pw-headline, ' +
                '.pw-guest-actions, .pw-btn-primary, .pw-btn-secondary, .pw-title, .message'
            ) : [];
            classQuery.forEach(el => el.remove());

            const allEls = context.querySelectorAll ? context.querySelectorAll('*') : [];
            allEls.forEach(el => {
                if (el.id === 'hlsPlayer' || (el.closest && el.closest('#hlsPlayer'))) return;
                if (el.children.length === 0) {
                    const text = (el.textContent || '').trim();
                    if (text === 'Sign Up to Watch' || text === 'Register Free Now' ||
                        text === 'Already a member? Log In' || text === 'Full video' ||
                        text.includes('Get 5 Free Watches')) {
                        let target = el;
                        for (let i = 0; i < 6 && target.parentElement; i++) {
                            if (target.className && typeof target.className === 'string' &&
                                (target.className.includes('paywall') ||
                                 target.className.includes('no-player') ||
                                 target.className.includes('message'))) {
                                target.remove();
                                break;
                            }
                            target = target.parentElement;
                        }
                    }
                }
            });

            const iframes = context.querySelectorAll ? context.querySelectorAll('iframe') : [];
            iframes.forEach(f => {
                try {
                    const idoc = f.contentDocument || (f.contentWindow && f.contentWindow.document);
                    if (idoc) nukePaywallAggressive(idoc);
                } catch (e) {}
            });

            const allWithShadow = context.querySelectorAll ? context.querySelectorAll('*') : [];
            allWithShadow.forEach(el => {
                if (el.shadowRoot) nukePaywallAggressive(el.shadowRoot);
            });

        } catch (e) {}

        if (context === document) {
            const holder = document.querySelector('.player-holder');
            if (holder && !holder.querySelector('#hlsPlayer')) {
                playerDiv.className = 'inline-mode';
                holder.innerHTML = '';
                holder.style.cssText = 'padding:0;margin:0;overflow:visible;position:relative;background:#000;min-height:200px;';
                holder.appendChild(playerDiv);
            }
        }
    }

    function setupPaywallKiller() {
        if (window.__paywallKillerInstalled) return;
        window.__paywallKillerInstalled = true;

        new MutationObserver(() => nukePaywallAggressive(document)).observe(document.body, { childList: true, subtree: true });
        setInterval(() => nukePaywallAggressive(document), 500);

        document.addEventListener('click', (e) => {
            const t = e.target;
            if (t.closest && (t.closest('.paywall-v2') || t.closest('.paywall-guest') ||
                t.closest('.no-player') || t.closest('.pw-btn-primary') ||
                t.closest('.pw-btn-secondary') || t.closest('.pw-guest-actions'))) {
                e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation();
            }
        }, true);
    }

    // ====== STYLE ======
    GM_addStyle(`
        img { opacity: 1 !important; visibility: visible !important; }
        .thumb, .video-thumb { background: none !important; }

        .paywall-guest, .paywall-v2, .no-player, .pw-headline, .pw-guest-actions,
        .pw-btn-primary, .pw-btn-secondary, .pw-title, .message {
            display: none !important; visibility: hidden !important; opacity: 0 !important;
            pointer-events: none !important; height: 0 !important; width: 0 !important;
            position: absolute !important; left: -99999px !important; top: -99999px !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: 999999; 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: 999999; display: block !important;
            visibility: visible !important; opacity: 1 !important;
        }
        #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; }

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

    function getVideoIdFromUrl() {
        const m = window.location.pathname.match(/\/video\/(\d+)/);
        return m ? parseInt(m[1]) : null;
    }

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

    // ====== SECURE API BYPASS ======
    async function fetchSecureVIPLink() {
        showTipsEl.innerText = '⌛️ Extracting API token...';

        let rawHTML = "";
        try {
            // Bulletproof method: Fetch the raw page source directly so site scripts can't hide the token
            const pageRes = await fetch(window.location.href);
            rawHTML = await pageRes.text();
        } catch (e) {
            // Fallback to DOM if fetch fails
            rawHTML = document.documentElement.innerHTML;
        }

        const scriptMatch = rawHTML.match(/var\s+PLAYER_CSRF\s*=\s*"([^"]+)"/);

        if (!scriptMatch || !scriptMatch[1]) {
            console.warn('[Avjb Unlock] ❌ No CSRF token found in raw source. Strict IP-Ban active.');
            return false;
        }

        const csrfToken = scriptMatch[1];
        console.log('[Avjb Unlock] ✅ Found CSRF Token in raw source, requesting secure links...');
        showTipsEl.innerText = '⌛️ Requesting secure links...';

        try {
            const apiUrl = `/player/spped.php?csrf=${encodeURIComponent(csrfToken)}`;
            const response = await fetch(apiUrl, { credentials: 'same-origin' });

            if (!response.ok) throw new Error("HTTP " + response.status);

            const data = await response.json();

            if (data && data.sources && data.sources.length > 0) {
                const bestSource = data.sources.find(s => s.key === data.defaultKey) || data.sources[0];
                if (bestSource && bestSource.url) {
                    console.log('[Avjb Unlock] 🚀 API Success! Authorized URL:', bestSource.url);
                    if (my_timer) { clearInterval(my_timer); my_timer = null; }
                    loadHlsStream(bestSource.url);
                    return true;
                }
            }

            if (data && data.direct) {
                 const mp4Match = rawHTML.match(/this\.currentVideoURL\s*=\s*"([^"]+)"/);
                 if (mp4Match && mp4Match[1]) {
                     // Clean up weird 'function/0/' prefixes if they exist
                     const cleanUrl = mp4Match[1].replace('function/0/', '');
                     console.log('[Avjb Unlock] ⚠️ Falling back to direct proxy:', cleanUrl);
                     if (my_timer) { clearInterval(my_timer); my_timer = null; }
                     loadHlsStream(cleanUrl);
                     return true;
                 }
            }
        } catch (error) {
            console.error('[Avjb Unlock] ❌ API fetch failed:', error);
        }

        return false;
    }

    async function check_circle_v2() {
        if (videoLoaded || isChecking) return;
        if (!document.body) return;

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

        earlyGrab();
        setupPaywallKiller();

        if (!document.getElementById('hlsPlayer')) {
            playerDiv.className = 'inline-mode';
            playerHolder.innerHTML = '';
            playerHolder.style.cssText = 'padding:0;margin:0;overflow:visible;position:relative;background:#000;min-height:200px;';
            playerHolder.appendChild(playerDiv);
        }

        if (capturedMasterUrl) {
            console.log('[Avjb Unlock] Using captured URL:', capturedMasterUrl);
            showTipsEl.innerText = '⌛️ Using site request...';
            loadHlsStream(capturedMasterUrl);
            if (my_timer) { clearInterval(my_timer); my_timer = null; }
            return;
        }

        isChecking = true;
        const apiSuccess = await fetchSecureVIPLink();

        if (!apiSuccess && !videoLoaded) {
            let videoID = getVideoIdFromUrl();
            let folder = null;
            if (!videoID && savedImgSrc) {
                const tmp = savedImgSrc.split('/');
                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 (!videoID) {
                const meta = document.querySelector('meta[property="og:image"]');
                if (meta) {
                    const tmp = meta.content.split('/');
                    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 (videoID) {
                if (!folder) folder = Math.floor(videoID / 1000) * 1000;
                console.log('[Avjb Unlock] API Failed/Limit Hit. Checking Legacy Servers. Video ID:', videoID, 'Folder:', folder);
                isChecking = false;
                tryAllServers(folder, videoID);
            } else {
                isChecking = false;
            }
        }

        if (videoLoaded && my_timer) {
            clearInterval(my_timer);
            my_timer = null;
        }
    }

    safeObserve(() => {
        console.log('[Avjb Unlock] Body ready, setting up paywall killer');
        setupPaywallKiller();
        check_circle_v2();
    });

    my_timer = setInterval(check_circle_v2, 1500);
})();