Last active
March 14, 2019 06:27
-
-
Save heptal/622859d8aea612132ad8d2029c65df8e to your computer and use it in GitHub Desktop.
Pattern (regex) based mass deletion of discord messages, with UI button!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// enable developer tools (aka chrome inspector) in discord app | |
// in dev tools get user token from Application > Local Storage (or google how) | |
// then go to Sources, open Snippets, add and save this code (replacing token with your own) | |
// use play button in the bottom right to enable, creating a new 'Purge' widget | |
// discord search in a server/dm (example - from: you, before: jan 2019) and get a postid | |
// paste in the appropriate input box to delete older/newer messages | |
const token = "sUp3R-s3kR1t"; //replace with your own | |
const api = async (uri, opts = {}) => await fetch(GLOBAL_ENV.API_ENDPOINT + uri, {headers: {authorization: token}, method: "GET", ...opts}); | |
const channel = async (id) => await api(`/channels/${id}`).then(r => r.json()); | |
const user = async (id) => await api(`/users/${id}`).then(r => r.json()); | |
user("@me").then(o => window.author_id = o.id); | |
const snowflake_from_date = (date) => String(BigInt(new Date(date).valueOf() - 1420070400000) << 22n); | |
const date_from_snowflake = (snowflake) => new Date(Number((BigInt(snowflake) >> 22n) + 1420070400000n)); | |
const sleep = (time) => new Promise((resolve) => setTimeout(resolve, time)); | |
const focused = () => location.href.split("/").pop(); | |
const filter_messages = (msgs, content) => { | |
const filtered = msgs.filter(msg => msg && msg.type == 0 && msg.author.id == author_id); | |
const regex = RegExp(`\\b${content}\\b`, "i"); | |
return content ? filtered.filter(msg => regex.test(msg.content)) : filtered; | |
} | |
const channel_messages = async (chan_id = focused()) => { | |
const url = `/channels/${chan_id}/messages?limit=100`; | |
const msgs = await api(url).then(r => r.json()); | |
while (true) { | |
const prior = await api(`${url}&before=${msgs[msgs.length - 1].id}`).then(r => r.json()); | |
if (prior.length == 0) break; | |
msgs.push(...prior); | |
} | |
return msgs; | |
} | |
const search_messages = async (content, max_id, min_id, chan_id = focused()) => { | |
const chan = await channel(chan_id); | |
let url = `/v6` + (chan.type ? `/channels/${chan.id}` : `/guilds/${chan.guild_id}`) + `/messages/search?`; | |
url += String(new URLSearchParams(Object.entries({include_nsfw: true, author_id, content, max_id, min_id}).filter(i => i[1]))); | |
let res = await api(url).then(o => o.json()); | |
if (res.code && res.code == 110000) { await sleep(res.retry_after); res = await api(url).then(o => o.json()); } | |
const flatten = (r) => r.messages.map(grp => grp.filter(msg => msg.hit).pop()); | |
const msgs = flatten(res); | |
for (let p = 1; p < Math.ceil(res.total_results / 25); p++) { | |
let next = await api(url + `&offset=${p * 25}`).then(o => o.json()); | |
msgs.push(...flatten(next)); | |
} | |
return filter_messages(msgs, content); | |
} | |
const delete_messages = async (msgs) => { | |
const total = msgs.length; | |
while (msgs.length) { | |
const msg = msgs.shift(); | |
const resp = await api(`/channels/${msg.channel_id}/messages/${msg.id}`, {method: "DELETE"}); | |
if (resp.status == 429) msgs.unshift(msg); | |
console.log(`${((total - msgs.length) / total * 100).toFixed(2)}%, ${(msgs.length / 120).toFixed(2)}mins left`); | |
await sleep(500); | |
} | |
} | |
document.body.insertAdjacentHTML("afterbegin", `<style>form>div{display: flex} input{width: 100%} input[type=submit]{width:30%}</style>`) | |
$(`[class^="chan"]`).insertAdjacentHTML("afterbegin",`<style>input{width: 100%}</style><form id="purge"> | |
<div style="display:flex"><input type="text" placeholder="regex filter: either|or"><input type="submit" value="Purge"></div> | |
<input type="text" placeholder="before id: 526593342650449240"><input type="text" placeholder="after id: 426593342650449240"></form>`); | |
$("#purge").onsubmit = async (e) => { e.preventDefault(); delete_messages(await search_messages(e.target[0].value, e.target[2].value, e.target[3].value)) }; | |
$(`[class^="chan"]`).insertAdjacentHTML("afterbegin",`<form id="user"><div><input type="text" placeholder="userid (ex: 585387035561951133)"> | |
<input type="submit" value="Lookup User"></div><input type="text" placeholder="username#discriminator"><img></form>`); | |
$("#user").onsubmit = async (e) => { | |
e.preventDefault(); | |
const u = await user(e.target[0].value); console.log(u); | |
e.target[2].value = `${u.username}#${u.discriminator}`; | |
e.target.lastChild.src = `https://cdn.discordapp.com/avatars/${u.id}/${u.avatar}?size=64`; | |
} | |
const repeater = async (content, chan_id = focused(), interval = 1000) => { | |
while (true) { | |
await api(`/channels/${chan_id}/messages`, {method: "POST", headers: {authorization: token, "Content-Type": "application/json"}, body: JSON.stringify({content})}); | |
await sleep(interval); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment