Note
-
This Doesn't Work In-Browser For Non-Video, And Non-Activity Quests!
-
For Stream/Play Quests, Use The Desktop App!
-
When Doing Stream Quests, You REQUIRE AT LEAST 1 Other Account In Voice Chat With You!
How To Use The Script:
- Accept A Quest Under User Settings -> Gift Inventory
- Press Ctrl+Shift+I To Open DevTools
- Go To The Console Tab
- Paste The Following Code And Hit Enter:
Click To View Code
delete window.$;
let wpRequire;
window.webpackChunkdiscord_app.push([[ Math.random() ], {}, (req) => { wpRequire = req; }]);
let ApplicationStreamingStore = Object.values(wpRequire.c).find(x => x?.exports?.Z?.getStreamerActiveStreamMetadata).exports.Z;
let RunningGameStore = Object.values(wpRequire.c).find(x => x?.exports?.ZP?.getRunningGames).exports.ZP;
let QuestsStore = Object.values(wpRequire.c).find(x => x?.exports?.Z?.getQuest).exports.Z;
let ChannelStore = Object.values(wpRequire.c).find(x => x?.exports?.Z?.getAllThreadsForParent).exports.Z;
let GuildChannelStore = Object.values(wpRequire.c).find(x => x?.exports?.ZP?.getSFWDefaultChannel).exports.ZP;
let FluxDispatcher = Object.values(wpRequire.c).find(x => x?.exports?.Z?.flushWaitQueue).exports.Z;
let api = Object.values(wpRequire.c).find(x => x?.exports?.tn?.get).exports.tn;
let quest = [...QuestsStore.quests.values()].find(x => x.id !== "1248385850622869556" && x.userStatus?.enrolledAt && !x.userStatus?.completedAt && new Date(x.config.expiresAt).getTime() > Date.now())
let isApp = navigator.userAgent.includes("Electron/")
if(!quest) {
console.log("No Available Quests Detected!")
} else {
const pid = Math.floor(Math.random() * 30000) + 1000
const applicationId = quest.config.application.id
const applicationName = quest.config.application.name
const taskName = ["WATCH_VIDEO", "PLAY_ON_DESKTOP", "STREAM_ON_DESKTOP", "PLAY_ACTIVITY"].find(x => quest.config.taskConfig.tasks[x] != null)
const secondsNeeded = quest.config.taskConfig.tasks[taskName].target
const secondsDone = quest.userStatus?.progress?.[taskName]?.value ?? 0
if(taskName === "WATCH_VIDEO") {
const tolerance = 2, speed = 10
const diff = Math.floor((Date.now() - new Date(quest.userStatus.enrolledAt).getTime())/1000)
const startingPoint = Math.min(Math.max(Math.ceil(secondsDone), diff), secondsNeeded)
let fn = async () => {
for(let i=startingPoint;i<=secondsNeeded;i+=speed) {
try {
await api.post({url: `/quests/${quest.id}/video-progress`, body: {timestamp: Math.min(secondsNeeded, i + Math.random())}})
} catch(ex) {
console.log("Failed To Send Increment Of", i, ex.message)
}
await new Promise(resolve => setTimeout(resolve, tolerance * 1000))
}
if((secondsNeeded-secondsDone)%speed !== 0) {
await api.post({url: `/quests/${quest.id}/video-progress`, body: {timestamp: secondsNeeded}})
}
console.log("Quest Completed!")
}
fn()
console.log(`Spoofing video for ${applicationName}. Wait for ${Math.ceil((secondsNeeded - startingPoint)/speed*tolerance)} more seconds.`)
} else if(taskName === "PLAY_ON_DESKTOP") {
if(!isApp) {
console.log("Unfortunately, This No Longer Works On The Browser Version Of Discord For Non-Video Quests. Use Discord Desktop To Complete The", applicationName, "Quest!")
}
api.get({url: `/applications/public?application_ids=${applicationId}`}).then(res => {
const appData = res.body[0]
const exeName = appData.executables.find(x => x.os === "win32").name.replace(">","")
const games = RunningGameStore.getRunningGames()
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: pid,
pidPath: [pid],
processName: appData.name,
start: Date.now(),
}
games.push(fakeGame)
FluxDispatcher.dispatch({type: "RUNNING_GAMES_CHANGE", removed: [], added: [fakeGame], games: games})
let fn = data => {
let progress = quest.config.configVersion === 1 ? data.userStatus.streamProgressSeconds : Math.floor(data.userStatus.progress.PLAY_ON_DESKTOP.value)
console.log(`Quest Progress: ${progress}/${secondsNeeded}`)
if(progress >= secondsNeeded) {
console.log("Quest Completed!")
const idx = games.indexOf(fakeGame)
if(idx > -1) {
games.splice(idx, 1)
FluxDispatcher.dispatch({type: "RUNNING_GAMES_CHANGE", removed: [fakeGame], added: [], games: []})
}
FluxDispatcher.unsubscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn)
}
}
FluxDispatcher.subscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn)
console.log(`Spoofed Your Game & Discord Rich Presence To: ${applicationName}. Please, Wait ${Math.ceil((secondsNeeded - secondsDone) / 60)} Minutes.`)
})
} else if(taskName === "STREAM_ON_DESKTOP") {
if(!isApp) {
console.log("Unfortunately, This No Longer Works On The Browser Version Of Discord For Non-Video Quests. Use Discord Desktop To Complete The", applicationName, "Quest!")
}
let realFunc = ApplicationStreamingStore.getStreamerActiveStreamMetadata
ApplicationStreamingStore.getStreamerActiveStreamMetadata = () => ({
id: applicationId,
pid,
sourceName: null
})
let fn = data => {
let progress = quest.config.configVersion === 1 ? data.userStatus.streamProgressSeconds : Math.floor(data.userStatus.progress.STREAM_ON_DESKTOP.value)
console.log(`Quest Progress: ${progress}/${secondsNeeded}`)
if(progress >= secondsNeeded) {
console.log("Quest Completed!")
ApplicationStreamingStore.getStreamerActiveStreamMetadata = realFunc
FluxDispatcher.unsubscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn)
}
}
FluxDispatcher.subscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn)
console.log(`Spoofed your stream to ${applicationName}. Stream Any Window In Voice Chat For ${Math.ceil((secondsNeeded - secondsDone) / 60)} Minutes.`)
console.log("REMINDER: You need AT LEAST 1 OTHER Person In Voice Chat")
} 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 () => {
console.log("Completing Quest", applicationName, "-", quest.config.messages.questName)
while(true) {
const res = await api.post({url: `/quests/${quest.id}/heartbeat`, body: {stream_key: streamKey, terminal: false}})
const progress = res.body.progress.PLAY_ACTIVITY.value
console.log(`Quest Progress: ${progress}/${secondsNeeded}`)
await new Promise(resolve => setTimeout(resolve, 20 * 1000))
if(progress >= secondsNeeded) {
await api.post({url: `/quests/${quest.id}/heartbeat`, body: {stream_key: streamKey, terminal: true}})
break
}
}
console.log("Quest Completed!")
}
fn()
}
}Note
5. Follow On The Instructions Based On The Type Of Quest
- If The Quest Says "play", You Can Just Wait And Do Nothing
- If The Quest Says "stream", Join A Voice Chat With A Friend Or Alt
- Wait For The Quest To Complete
- Claim Your Reward In User Settings -> Gift Inventory!
You Can Monitor The Quest Progress By Checking The Quest Progress: Entries In The Console Tab Or By Revisiting User Settings -> Gift Inventory.
-
Q: Ctrl + Shift + I (DevTools) Doesn't Work
-
A: Download Discord Canary, Or The Discord Public Test Build.
-
Alternatively, You Can Enable DevTools On The Stable (Main) Build.
-
Q: I'm Getting An Unauthorized Error
-
A: Discord Has Implemented An Update That Prevents The Script From Properly Functioning In Browsers. To Resolve This, Please Use The Discord Desktop Application, Or Alternatively, You Can Use An Extension To Modify Your User-Agent To Append Electron/ To It.
-
Q: I'm Getting SyntaxError(s)/Unexpected TokenError(s)
-
A: Ensure that your browser is not automatically translating the webpage before copying the script. Disable any translation extensions and attempt the process again.
-
Q: I'm Getting A Cannot read properties of undefined (reading 'nativeModules') Error
-
A: This Error Typically Occurs When Using A Modified Client, Such As A Browser Wrapper (E.g., Vesktop). To Resolve This Issue, Please Use The Official Discord Desktop Application.
-
Q: I'm Encountering A Different Error
-
A: Please Ensure That You're Copying & Pasting The Script Completely, And That You've Followed All The Steps Correctly.
-
Q: Is It Possible To Automate The Acceptance Of The Quest/Reward?
-
A: While It Is Technically Possible To Automate The Acceptance Of The Quest And Reward, Doing So Can Lead To Abuse And Potential Account Issues. Both Actions May Trigger A CAPTCHA, And Automating Them Could Result In Unintended Consequences. It Is Therefore Advised To Manually Complete These Steps To Ensure Compliance And Avoid Any Potential Risk To Your Account.
Please Refrain From Posting Any "Fixed" Or "Improved" Versions Of This Script In The Comments. Such Actions Can Lead To Unnecessary Confusion, Often Fail To Resolve Issues, And In Some Cases, May Expose Other Users To Security Risks. Unauthorized Modifications Can Also Lead To Account Compromise, As They May Interfere With The Intended Functionality Or Introduce Vulnerabilities. Any Such Comments May Be Redacted Or Deleted Without Prior Notice To Ensure The Security And Integrity Of The Community. Thank You For Your Understanding And Cooperation.