Revive mod.reddit.com
// ==UserScript==
// @name mod.reddit.com revived
// @namespace https://greatest.deepsurf.us/en/users/1574555-littux
// @version 1.3
// @description Revive mod.reddit.com
// @author littux
// @match https://mod-reddit-com.netlify.app/*
// @match http://localhost:44444/*
// @match https://*.reddit.com/mail/*
// @connect www.reddit.com
// @connect sh.reddit.com
// @connect gql-fed.reddit.com
// @icon https://www.redditstatic.com/modmail/favicon/android-icon-192x192.png
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_xmlhttpRequest
// @grant GM_cookie
// @grant GM_registerMenuCommand
// @run-at document-start
// @license MIT
// ==/UserScript==
const defaultConfig = { useLocalhost: false, loadTrophyData: false };
const configData = GM_getValue("config");
if (!configData) {
GM_setValue("config", defaultConfig)
}
let { useLocalhost, loadTrophyData } = configData ?? defaultConfig;
if (location.hostname.endsWith("reddit.com")) {
window.stop();
location.replace((useLocalhost ? "http://localhost:44444" : "https://mod-reddit-com.netlify.app") + location.pathname + location.search + location.hash);
return;
};
(async function() {
GM_registerMenuCommand(`[${useLocalhost ? 'YES' : 'NO'}] Use localhost`, () => {
useLocalhost = !useLocalhost;
GM_setValue("config", { useLocalhost, loadTrophyData });
location.reload();
});
GM_registerMenuCommand(`[${loadTrophyData ? 'YES' : 'NO'}] Load trophy data (not recommended; delays user pane load)`, () => {
loadTrophyData = !loadTrophyData;
GM_setValue("config", { useLocalhost, loadTrophyData });
location.reload();
});
const gmFetch = (options) => {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
...options,
onload: (res) => resolve(res),
onerror: (err) => reject(err)
});
});
}
const getExternalCookie = (name, url) => {
return new Promise((resolve, reject) => {
if (typeof window.GM_cookie !== 'undefined') {
GM_cookie.list({ name, url }, (cookies, error) => {
if (error) reject(error);
else resolve(cookies.length > 0 ? cookies[0].value : null);
});
} else {
reject("GM_cookie not supported. Ensure you are using Tampermonkey.");
}
});
};
unsafeWindow.tokenCache = null, pendingTokenPromise = null;
const _getToken = async () => {
try {
const loid = await getExternalCookie("loid", "https://www.reddit.com/mail/");
if (!loid) {
throw new Error("loid cookie missing");
}
const tokenKey = `rAPI:accessToken~${loid}`;
const expiryKey = `rAPI:accessTokenExpiry~${loid}`;
const cachedToken = GM_getValue(tokenKey);
const cachedExpiry = GM_getValue(expiryKey);
if (cachedToken && cachedExpiry > Date.now()) {
unsafeWindow.tokenCache = { token: cachedToken, expires: cachedExpiry };
return cachedToken;
}
let csrf = await getExternalCookie("csrf_token", "https://sh.reddit.com/mail/");
if (!csrf) {
await gmFetch({
method: "HEAD",
url: "https://sh.reddit.com/404",
withCredentials: true
});
csrf = await getExternalCookie("csrf_token", "https://sh.reddit.com/mail/");
};
try {
const response = await gmFetch({
method: "POST",
url: "https://www.reddit.com/svc/shreddit/token",
withCredentials: true,
headers: {
"Content-Type": "application/json",
"Origin": "https://www.reddit.com",
"Referer": "https://www.reddit.com/"
},
data: JSON.stringify({ csrf_token: csrf })
});
if (response.status === 200) {
const data = JSON.parse(response.responseText);
GM_setValue(tokenKey, data.token);
GM_setValue(expiryKey, data.expires);
unsafeWindow.tokenCache = data;
return data.token;
}
} catch (e) {
throw new Error("Token fetch failed: " + e);
}
} catch (e) {
throw new Error("Error getting token: " + e);
} finally {
pendingTokenPromise = null
}
};
const getToken = () => {
if (unsafeWindow.tokenCache?.expires > Date.now()) return unsafeWindow.tokenCache.token;
if (!pendingTokenPromise) pendingTokenPromise = _getToken();
return pendingTokenPromise;
};
unsafeWindow.gmFetch = gmFetch;
unsafeWindow.getToken = getToken;
const eventData = {
detail: { accessToken: await getToken() }
};
console.log("rAPI access token ready.");
unsafeWindow.__MODREDDITCOM_REVIVED__ = {
version: 1,
useLocalhost,
loadTrophyData,
event: eventData
};
const event = new CustomEvent('rAPI-accessToken-ready', eventData);
window.dispatchEvent(event);
})();