ZeroAd: Poki

Instant, zero-delay Poki SDK bypass with global object scanning

目前為 2026-08-21 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         ZeroAd: Poki
// @namespace    https://greasyfork.org/en/users/1483567-vujohn123
// @version      4.0.5
// @description  Instant, zero-delay Poki SDK bypass with global object scanning
// @author       ZeroAd Team
// @match        *://*.poki.com/*
// @match        *://poki.com/*
// @grant        none
// @run-at       document-start
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    if (window.__zaPokiLoaded) return;
    window.__zaPokiLoaded = true;

    const CONFIG = { DEBUG: true };  // Set false to disable logs
    const METRICS = {
        hooksInstalled: 0,
        interceptedCalls: 0,
        failedHooks: 0,
        rewardsGranted: 0
    };

    const log = (...args) => CONFIG.DEBUG && console.log('[ZeroAd:Poki]', ...args);
    const warn = (...args) => CONFIG.DEBUG && console.warn('[ZeroAd:Poki]', ...args);
    const error = (...args) => console.error('[ZeroAd:Poki]', ...args);

    // --- Core hook functions (mutates the passed object) ---
    function safeDispatchEvent(target, eventName) {
        try { target.dispatchEvent(new CustomEvent(eventName, { bubbles: true })); } catch (e) {}
    }
    function safeCallback(fn, ...args) {
        if (typeof fn === 'function') {
            try { fn(...args); } catch (e) { warn('Callback error:', e); }
        }
    }

    function hookPokiSDK(sdk) {
        if (!sdk || sdk.__zaHooked) return false;
        log('Hooking SDK object...');

        try {
            sdk.__zaHooked = true;

            // --- commercialBreak ---
            if (typeof sdk.commercialBreak === 'function') {
                sdk.commercialBreak = function(...args) {
                    log('🚫 commercialBreak skipped');
                    METRICS.interceptedCalls++;
                    if (args.length && typeof args[0] === 'function') try { args[0](); } catch(e) {}
                    return Promise.resolve();
                };
                log('✅ commercialBreak hooked');
            }

            // --- rewardedBreak ---
            if (typeof sdk.rewardedBreak === 'function') {
                sdk.rewardedBreak = function(callbacks) {
                    log('🎁 rewardedBreak → instant reward');
                    METRICS.interceptedCalls++;
                    let onStart = null, onReward = null, onError = null;
                    if (typeof callbacks === 'function') {
                        onReward = callbacks;
                    } else if (callbacks && typeof callbacks === 'object') {
                        onStart = callbacks.onStart || callbacks.start;
                        onReward = callbacks.adFinished || callbacks.onComplete || callbacks.onReward || callbacks.complete;
                        onError = callbacks.onError || callbacks.error;
                    }
                    safeCallback(onStart);
                    safeCallback(onReward);
                    safeCallback(onError, null);
                    METRICS.rewardsGranted++;
                    safeDispatchEvent(window, 'rewardedComplete');
                    safeDispatchEvent(window, 'rewardGranted');
                    safeDispatchEvent(window, 'adComplete');
                    log('✅ Reward granted instantly');
                    return Promise.resolve(true);
                };
                log('✅ rewardedBreak hooked');
            }

            // --- display ads ---
            if (typeof sdk.hoistDisplayAd === 'function') {
                sdk.hoistDisplayAd = () => { METRICS.interceptedCalls++; return false; };
            }
            if (typeof sdk.destroyDisplayAd === 'function') {
                sdk.destroyDisplayAd = () => { METRICS.interceptedCalls++; };
            }
            if (typeof sdk.displayAd === 'function') {
                sdk.displayAd = (e, t, o, i) => {
                    METRICS.interceptedCalls++;
                    if (i) safeCallback(i, true);
                    if (o) safeCallback(o);
                    return false;
                };
            }
            if (typeof sdk.destroyAd === 'function') {
                sdk.destroyAd = () => { METRICS.interceptedCalls++; };
            }

            // --- playground / platform breaks ---
            ['playgroundCommercialBreak', 'platformCommercialBreak'].forEach(m => {
                if (typeof sdk[m] === 'function') {
                    sdk[m] = () => { log(m + ' skipped'); METRICS.interceptedCalls++; return Promise.resolve(); };
                }
            });

            // --- monetization internals ---
            if (sdk.__monetization) {
                if (typeof sdk.__monetization.requestAd === 'function') sdk.__monetization.requestAd = () => Promise.resolve();
                if (typeof sdk.__monetization.displayAd === 'function') sdk.__monetization.displayAd = () => false;
                if (typeof sdk.__monetization.init === 'function') sdk.__monetization.init = () => Promise.resolve();
            }

            // --- no-op tracking ---
            ['happyTime','gameLoading','gameplayStart','gameplayStop','captureError','sendEvent','track','setDebug','measure','gameLoadingFinished','gameLoadingProgress','gameInteractive','logError','muteAd','roundEnd','roundStart','sendHighscore','setLogging','setPlayerAge','enableEventTracking','openExternalLink'].forEach(m => {
                if (typeof sdk[m] === 'function') {
                    sdk[m] = (...args) => {
                        if (m === 'gameplayStart' || m === 'gameplayStop') log(m + ' tracked (no-op)');
                        else log(m + ' no-op');
                    };
                }
            });

            METRICS.hooksInstalled++;
            log('✅ SDK object fully hooked!');
            return true;
        } catch (e) {
            error('Hook failed:', e);
            METRICS.failedHooks++;
            return false;
        }
    }

    // --- Trap for window.PokiSDK (non-configurable) ---
    function installTrap() {
        let _pokiSDK = window.PokiSDK;
        if (_pokiSDK && !_pokiSDK.__zaHooked) {
            hookPokiSDK(_pokiSDK);
        }
        Object.defineProperty(window, 'PokiSDK', {
            configurable: false,
            enumerable: true,
            get: function() {
                // log('PokiSDK GET'); // optional, can be noisy
                return _pokiSDK;
            },
            set: function(newValue) {
                log('PokiSDK SET (new SDK)');
                _pokiSDK = newValue;
                if (newValue && !newValue.__zaHooked) {
                    hookPokiSDK(newValue);
                }
            }
        });
        log('✅ Non‑configurable trap installed');
    }

    // --- Global scanner: find and hook any object with SDK methods ---
    function scanAndHookAllSDKObjects() {
        let found = 0;
        // Check all properties of window
        for (let key in window) {
            try {
                const val = window[key];
                if (val && typeof val === 'object' && val !== window && !val.__zaHooked) {
                    // Check if it has the typical SDK methods
                    if (typeof val.commercialBreak === 'function' && typeof val.rewardedBreak === 'function') {
                        log('Found SDK object at window.' + key + ' – hooking its methods');
                        hookPokiSDK(val);
                        found++;
                    }
                }
            } catch(e) {}
        }
        // Also check common aliases
        const aliases = ['Poki', 'PokiUnitySDK', 'PokiSDK', 'poki'];
        for (let alias of aliases) {
            try {
                const val = window[alias];
                if (val && typeof val === 'object' && !val.__zaHooked && typeof val.commercialBreak === 'function') {
                    log('Found SDK object at window.' + alias + ' – hooking');
                    hookPokiSDK(val);
                    found++;
                }
            } catch(e) {}
        }
        if (found > 0) {
            log(`✅ Hooked ${found} additional SDK object(s)`);
        }
        return found;
    }

    // --- Observer for script loads (fallback) ---
    function setupObserver() {
        const observer = new MutationObserver(mutations => {
            for (const mutation of mutations) {
                for (const node of mutation.addedNodes) {
                    if (node.tagName === 'SCRIPT') {
                        const src = (node.src || '').toLowerCase();
                        if (src.includes('poki') && (src.includes('sdk') || src.includes('hoist') || src.includes('playground') || src.includes('v2') || src.includes('ay'))) {
                            log('SDK script detected:', src.substring(0, 80));
                            if (node.readyState === 'complete' || node.readyState === 'loaded') {
                                setTimeout(() => { scanAndHookAllSDKObjects(); }, 0);
                            } else {
                                node.addEventListener('load', () => {
                                    setTimeout(() => { scanAndHookAllSDKObjects(); }, 0);
                                });
                            }
                        }
                    }
                }
            }
        });
        if (document.documentElement) {
            observer.observe(document.documentElement, { childList: true, subtree: true });
        }
        log('✅ MutationObserver active');
    }

    // --- Initialization ---
    function initialize() {
        log('🚀 ZeroAd: Poki SDK v4.0.5 – Global scanner');
        installTrap();
        setupObserver();

        // Initial scan after a short delay
        setTimeout(scanAndHookAllSDKObjects, 100);

        // Keep scanning for a few seconds to catch late objects
        let attempts = 0;
        const maxAttempts = 20; // 10 seconds
        const interval = setInterval(() => {
            attempts++;
            const found = scanAndHookAllSDKObjects();
            if (attempts >= maxAttempts || found > 0) {
                // If we found something, we can slow down or stop, but we'll keep going a bit more.
                if (found > 0) {
                    log('Found objects, continuing scan...');
                }
                if (attempts >= maxAttempts) {
                    clearInterval(interval);
                    log('🔍 Scan finished');
                }
            }
        }, 500);

        window._zaMetrics = window._zaMetrics || {};
        window._zaMetrics.poki = METRICS;

        // Status report after 5 seconds
        setTimeout(() => {
            log('📊 Status:', {
                hooksInstalled: METRICS.hooksInstalled,
                interceptedCalls: METRICS.interceptedCalls,
                rewardsGranted: METRICS.rewardsGranted
            });
        }, 5000);
    }

    initialize();

    // Also scan on DOMContentLoaded as a safety net
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => {
            setTimeout(scanAndHookAllSDKObjects, 0);
        });
    }
})();