CompleteDiscordQuest.md

翻译

Discord Quest Auto-Completer

Modulo di automazione lato client per il completamento delle Discord Quests (Video, Desktop Game, Streaming, Attività) tramite iniezione nel runtime Webpack di Discord.

Caution

Violazione dei Termini di Servizio (ToS)

L'automazione di chiamate API e l'esecuzione di script arbitrari nel client costituiscono una violazione dei Termini di Servizio di Discord. Questo software è fornito esclusivamente a scopo di ricerca e analisi tecnica. L'utilizzo avviene a totale rischio dell'utente.

Note

Funzionalità e Task Supportati

    WATCH_VIDEO / WATCH_VIDEO_ON_MOBILE: Avanzamento temporale tramite payload API sintetici.

    PLAY_ON_DESKTOP: Registrazione dinamica di falsi processi nel RunningGameStore.

    STREAM_ON_DESKTOP: Override dei metadati del flusso video attivo in ApplicationStreamingStore.

    PLAY_ACTIVITY: Invio sequenziale di pacchetti heartbeat su canali vocali attivi.

Dettagli Tecnici

Integrazione UI: Iniezione nativa tramite i moduli ExpressiveModal e Button estratti direttamente dal bundle Webpack.

Indicatori di Stato: Rendering di un elemento visivo nel DOM (toolbar) con avanzamento percentuale e gestione dell'interruzione manuale.

Ripristino dello Stato: Gestione della pulizia dei listener FluxDispatcher e ripristino delle funzioni modificate al termine dell'esecuzione o in caso di stop forzato.

Guida all'Esecuzione

Important

È necessario aver già accettato e riscattato le Quest all'interno del client Discord prima di avviare lo script.

Apertura Strumenti per Sviluppatori:

    Windows / Linux: Ctrl + Shift + I

    macOS: Cmd + Option + I

Accesso alla Console: Selezionare il tab Console negli strumenti per sviluppatori.

Esecuzione dello Script: Incollare il codice sorgente riportato di seguito e premere Invio.

Conferma: Interagire con la finestra modale a schermo cliccando su Continua.
(async () => {
    if (window.__orbsQuestRunner?.active) {
        window.__orbsQuestRunner.stop();
    }

    let wreq = webpackChunkdiscord_app.push([[Symbol()], {}, (r) => r]);
    webpackChunkdiscord_app.pop();

    let _mods = webpackChunkdiscord_app.push([[Symbol()], {}, (r) => r.c]);
    webpackChunkdiscord_app.pop();

    let WebpackFind = (...filters) => {
        for (let m of Object.values(_mods)) {
            try {
                if (!m.exports || m.exports === window) continue;
                if (filters.every((fn) => fn(m.exports))) return m.exports;
                for (let ex in m.exports) {
                    const target = m.exports[ex];
                    if (target && filters.every((fn) => fn(target)) && target[Symbol.toStringTag] !== 'IntlMessagesProxy') {
                        return target;
                    }
                }
            } catch {}
        }
    };

    let findByProps = (...props) => WebpackFind((m) => props.every((x) => typeof m === 'object' && x in (m || {})));

    const Components = {
        ...findByProps('openModal', 'closeModal')
    };

    Components.ExpressiveModal = WebpackFind((e) => {
        if (typeof e !== 'function') return false;
        const code = e?.toString?.();
        return code.match(/gradientColor:[a-z-A-Z0-9$_]+="purple"/) && code.includes('paddingSize:"lg"');
    });

    Components.Button = WebpackFind((e) => {
        if (typeof e !== 'function') return false;
        return e.toString().includes('"data-mana-component":"button"');
    });

    const jsxModule = findByProps('jsx', 'jsxs');
    const jsx = jsxModule?.jsx || jsxModule?.jsxs;
    const jsxs = jsxModule?.jsxs || jsx;

    if (!Components.ExpressiveModal || !jsx) return;

    let ApplicationStreamingStore = Object.values(_mods).find(x => x?.exports?.A?.__proto__?.getStreamerActiveStreamMetadata)?.exports?.A;
    let RunningGameStore = Object.values(_mods).find(x => x?.exports?.Ay?.getRunningGames)?.exports?.Ay;
    let QuestsStore = Object.values(_mods).find(x => x?.exports?.A?.__proto__?.getQuest)?.exports?.A;
    let ChannelStore = Object.values(_mods).find(x => x?.exports?.A?.__proto__?.getAllThreadsForParent)?.exports?.A;
    let GuildChannelStore = Object.values(_mods).find(x => x?.exports?.Ay?.getSFWDefaultChannel)?.exports?.Ay;
    let FluxDispatcher = Object.values(_mods).find(x => x?.exports?.h?.__proto__?.flushWaitQueue)?.exports?.h;
    let api = Object.values(_mods).find(x => x?.exports?.Bo?.get)?.exports?.Bo;

    const supportedTasks = ["WATCH_VIDEO", "PLAY_ON_DESKTOP", "STREAM_ON_DESKTOP", "PLAY_ACTIVITY", "WATCH_VIDEO_ON_MOBILE"];

    window.__orbsQuestRunner = {
        active: false,
        cleanups: [],
        addCleanup(fn) {
            this.cleanups.push(fn);
        },
        stop() {
            this.active = false;
            this.cleanups.forEach(fn => { try { fn(); } catch(e){} });
            this.cleanups = [];
            removeStatusText(true);
        }
    };

    function updateStatusText(questName, currentSec, totalSec) {
        if (!window.__orbsQuestRunner.active) return;

        let el = document.getElementById("orbs-quest-text");
        const safeCurrent = Math.min(Math.floor(currentSec), totalSec);
        const percent = Math.min(100, Math.floor((safeCurrent / totalSec) * 100)) || 0;

        if (!el) {
            el = document.createElement("div");
            el.id = "orbs-quest-text";
            el.title = "Clicca per disattivare l'auto-completer";
            el.style.cssText = `
                color: var(--text-positive, #23a55a);
                font-size: 12px;
                font-weight: 600;
                margin-right: 12px;
                display: inline-flex;
                align-items: center;
                gap: 6px;
                white-space: nowrap;
                font-family: var(--font-primary, 'gg sans', sans-serif);
                cursor: pointer;
                background: rgba(35, 165, 90, 0.1);
                border: 1px solid rgba(35, 165, 90, 0.3);
                padding: 2px 8px;
                border-radius: 6px;
                transition: background 0.2s ease;
            `;

            el.onmouseenter = () => el.style.background = "rgba(237, 66, 69, 0.15)";
            el.onmouseleave = () => el.style.background = "rgba(35, 165, 90, 0.1)";

            el.onclick = () => {
                window.__orbsQuestRunner.stop();
            };
        }

        const toolbar = document.querySelector('[class*="toolbar_"]') || 
                        document.querySelector('[class*="toolbar"]') || 
                        document.querySelector('header');

        if (toolbar && !toolbar.contains(el)) {
            toolbar.insertBefore(el, toolbar.firstChild);
        } else if (!el.parentNode) {
            el.style.position = "fixed";
            el.style.top = "12px";
            el.style.right = "240px";
            el.style.zIndex = "99999";
            document.body.appendChild(el);
        }

        el.innerHTML = `[Quest: ${questName} - ${percent}%] ✕`;
    }

    function removeStatusText(wasStopped = false) {
        let el = document.getElementById("orbs-quest-text");
        if (el) {
            el.style.background = wasStopped ? "rgba(237, 66, 69, 0.1)" : "rgba(35, 165, 90, 0.1)";
            el.style.borderColor = wasStopped ? "rgba(237, 66, 69, 0.3)" : "rgba(35, 165, 90, 0.3)";
            el.style.color = wasStopped ? "#ed4245" : "#23a55a";
            el.innerHTML = wasStopped ? "[Quest Disattivate]" : "[Quest Completate!]";
            setTimeout(() => { el.remove(); }, 3000);
        }
    }

    function startOrbsQuests() {
        window.__orbsQuestRunner.active = true;

        let quests = [...QuestsStore.quests.values()].filter(x => 
            x.userStatus?.enrolledAt && 
            !x.userStatus?.completedAt && 
            new Date(x.config.expiresAt).getTime() > Date.now() && 
            supportedTasks.some(y => Object.keys((x.config.taskConfig ?? x.config.taskConfigV2).tasks).includes(y))
        );

        let isApp = typeof DiscordNative !== "undefined";

        if (quests.length === 0) {
            removeStatusText(false);
            window.__orbsQuestRunner.active = false;
            return;
        }

        let doJob = function() {
            if (!window.__orbsQuestRunner.active) return;

            const quest = quests.pop();
            if (!quest) {
                removeStatusText(false);
                window.__orbsQuestRunner.active = false;
                return;
            }

            const questTitle = quest.config.messages?.questName ?? quest.config.application?.name ?? "Discord Quest";
            const pid = Math.floor(Math.random() * 30000) + 1000;
            const taskConfig = quest.config.taskConfig ?? quest.config.taskConfigV2;
            const taskName = supportedTasks.find(x => taskConfig.tasks[x] != null);
            const taskData = taskConfig.tasks[taskName];
            const applicationId = quest.config.application?.id ?? taskData.applications?.[0]?.id;
            const secondsNeeded = taskData.target;
            let secondsDone = quest.userStatus?.progress?.[taskName]?.value ?? 0;

            updateStatusText(questTitle, secondsDone, secondsNeeded);

            if (taskName === "WATCH_VIDEO" || taskName === "WATCH_VIDEO_ON_MOBILE") {
                const speed = 7;
                let fn = async () => {
                    while (window.__orbsQuestRunner.active) {
                        const remaining = Math.min(speed, secondsNeeded - secondsDone);
                        await new Promise(resolve => setTimeout(resolve, remaining * 1000));

                        if (!window.__orbsQuestRunner.active) break;

                        const timestamp = secondsDone + speed;
                        const res = await api.post({
                            url: `/quests/${quest.id}/video-progress`, 
                            body: { timestamp: Math.min(secondsNeeded, timestamp + Math.random()) }
                        });

                        secondsDone = Math.min(secondsNeeded, timestamp);
                        updateStatusText(questTitle, secondsDone, secondsNeeded);

                        if (timestamp >= secondsNeeded || res.body?.completed_at != null) {
                            break;
                        }
                    }
                    
                    if (window.__orbsQuestRunner.active) {
                        await api.post({
                            url: `/quests/${quest.id}/video-progress`, 
                            body: { timestamp: secondsNeeded }
                        });
                        doJob();
                    }
                };
                fn();

            } else if (taskName === "PLAY_ON_DESKTOP" && isApp) {
                api.get({ url: `/applications/public?application_ids=${applicationId}` }).then(res => {
                    if (!window.__orbsQuestRunner.active) return;

                    const appData = res.body[0];
                    const exeName = appData.executables?.find(x => x.os === "win32")?.name?.replace(">", "") ?? appData.name.replace(/[\/\\:*?"<>|]/g, "");

                    const fakeGame = {
                        cmdLine: `C:\\Program Files\\${appData.name}\\${exeName}`,
                        exeName,
                        exePath: `c:/program files/${appData.name.toLowerCase()}/${exeName}`,
                        hidden: false,
                        isLauncher: false,
                        id: applicationId,
                        name: appData.name,
                        pid,
                        pidPath: [pid],
                        processName: appData.name,
                        start: Date.now()
                    };

                    const realGames = RunningGameStore.getRunningGames();
                    const fakeGames = [fakeGame];
                    const realGetRunningGames = RunningGameStore.getRunningGames;
                    const realGetGameForPID = RunningGameStore.getGameForPID;

                    RunningGameStore.getRunningGames = () => fakeGames;
                    RunningGameStore.getGameForPID = p => fakeGames.find(x => x.pid === p);
                    
                    const cleanupGame = () => {
                        RunningGameStore.getRunningGames = realGetRunningGames;
                        RunningGameStore.getGameForPID = realGetGameForPID;
                        FluxDispatcher.dispatch({ type: "RUNNING_GAMES_CHANGE", removed: [fakeGame], added: [], games: [] });
                        FluxDispatcher.unsubscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn);
                    };
                    window.__orbsQuestRunner.addCleanup(cleanupGame);

                    FluxDispatcher.dispatch({ type: "RUNNING_GAMES_CHANGE", removed: realGames, added: [fakeGame], games: fakeGames });

                    let fn = data => {
                        if (!window.__orbsQuestRunner.active) return;
                        let progress = quest.config.configVersion === 1 ? data.userStatus.streamProgressSeconds : Math.floor(data.userStatus.progress.PLAY_ON_DESKTOP.value);
                        updateStatusText(questTitle, progress, secondsNeeded);

                        if (progress >= secondsNeeded) {
                            cleanupGame();
                            doJob();
                        }
                    };
                    FluxDispatcher.subscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn);
                });

            } else if (taskName === "STREAM_ON_DESKTOP" && isApp) {
                let realFunc = ApplicationStreamingStore.getStreamerActiveStreamMetadata;
                ApplicationStreamingStore.getStreamerActiveStreamMetadata = () => ({
                    id: applicationId,
                    pid,
                    sourceName: null
                });

                const cleanupStream = () => {
                    ApplicationStreamingStore.getStreamerActiveStreamMetadata = realFunc;
                    FluxDispatcher.unsubscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn);
                };
                window.__orbsQuestRunner.addCleanup(cleanupStream);

                let fn = data => {
                    if (!window.__orbsQuestRunner.active) return;
                    let progress = quest.config.configVersion === 1 ? data.userStatus.streamProgressSeconds : Math.floor(data.userStatus.progress.STREAM_ON_DESKTOP.value);
                    updateStatusText(questTitle, progress, secondsNeeded);

                    if (progress >= secondsNeeded) {
                        cleanupStream();
                        doJob();
                    }
                };
                FluxDispatcher.subscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn);

            } else if (taskName === "PLAY_ACTIVITY") {
                const channelId = ChannelStore.getSortedPrivateChannels()[0]?.id ?? Object.values(GuildChannelStore.getAllGuilds()).find(x => x != null && x.VOCAL?.length > 0)?.VOCAL[0]?.channel?.id;
                const streamKey = `call:${channelId}:1`;

                let fn = async () => {
                    while (window.__orbsQuestRunner.active) {
                        const res = await api.post({ url: `/quests/${quest.id}/heartbeat`, body: { stream_key: streamKey, terminal: false } });
                        const progress = res.body.progress.PLAY_ACTIVITY.value;
                        updateStatusText(questTitle, progress, secondsNeeded);

                        await new Promise(resolve => setTimeout(resolve, 20000));

                        if (progress >= secondsNeeded || !window.__orbsQuestRunner.active) {
                            if (window.__orbsQuestRunner.active) {
                                await api.post({ url: `/quests/${quest.id}/heartbeat`, body: { stream_key: streamKey, terminal: true } });
                            }
                            break;
                        }
                    }
                    if (window.__orbsQuestRunner.active) doJob();
                };
                fn();
            } else {
                doJob();
            }
        };
        doJob();
    }

    const OrbsModal = (props) => {
        const isRunning = window.__orbsQuestRunner?.active;

        const handleConfirm = () => {
            Components.closeModal(modalId);
            startOrbsQuests();
        };

        const handleStop = () => {
            Components.closeModal(modalId);
            window.__orbsQuestRunner.stop();
        };

        return jsx(Components.ExpressiveModal, {
            title: 'Orbs Quest Auto-Completer',
            onCancel: () => Components.closeModal(modalId),
            ...props,
            children: jsxs('div', {
                style: {
                    display: 'flex',
                    flexDirection: 'column',
                    gap: '16px',
                    padding: '16px',
                    backgroundColor: '#ffffff',
                    borderRadius: '8px',
                    boxShadow: '0 4px 12px rgba(0,0,0,0.1)'
                },
                children: [
                    jsxs('div', {
                        style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center' },
                        children: [
                            jsx('span', {
                                style: { 
                                    fontSize: '12px', 
                                    fontWeight: 'bold', 
                                    color: isRunning ? '#ed4245' : '#23a55a', 
                                    background: isRunning ? '#fef2f2' : '#e8f8ee', 
                                    padding: '2px 8px', 
                                    borderRadius: '4px' 
                                },
                                children: isRunning ? 'IN ESECUZIONE' : 'ORBS TOOL'
                            }),
                            jsx('span', {
                                style: { fontSize: '12px', color: '#5c5e66', fontWeight: '600' },
                                children: 'Autore: Ctrl24'
                            })
                        ]
                    }),
                    jsx('div', {
                        style: { color: '#2e3338', fontSize: '14px', lineHeight: '1.5' },
                        children: isRunning 
                            ? 'L\'auto-completer è attualmente attivo in background. Puoi interromperlo in qualsiasi momento cliccando sul bottone sottostante.' 
                            : 'Questo script simula l\'attività necessaria a completare automaticamente tutte le Discord Quests attive sul tuo account.'
                    }),
                    jsx('div', {
                        style: {
                            background: '#fee2e2',
                            borderLeft: '4px solid #dc2626',
                            padding: '12px',
                            borderRadius: '4px'
                        },
                        children: jsxs('div', {
                            children: [
                                jsx('strong', {
                                    style: { color: '#dc2626', display: 'block', marginBottom: '4px', fontSize: '14px' },
                                    children: 'Violazione dei Termini di Servizio (ToS)'
                                }),
                                jsx('span', {
                                    style: { fontSize: '13px', color: '#1f2937' },
                                    children: 'L\'utilizzo di script personalizzati o l\'automazione delle chiamate API viola i ToS di Discord. Utilizza questo strumento a tuo rischio e pericolo.'
                                })
                            ]
                        })
                    }),
                    isRunning 
                        ? jsx(Components.Button, {
                            size: 'md',
                            onClick: handleStop,
                            text: 'Disattiva / Interrompi',
                            children: 'Disattiva / Interrompi',
                            style: { width: '100%', marginTop: '4px', backgroundColor: '#dc2626', color: '#ffffff' }
                        })
                        : jsx(Components.Button, {
                            size: 'md',
                            onClick: handleConfirm,
                            text: 'Continua',
                            children: 'Continua',
                            style: { width: '100%', marginTop: '4px' }
                        })
                ]
            })
        });
    };

    const modalId = Components.openModal((props) => jsx(OrbsModal, props));
})();
添加评论
点赞收藏
点踩分享查看原文
评论
?
参与讨论