Reddit Restore

Restores deleted Reddit posts, comments, usernames, images, videos, and media using Arctic Shift with PullPush fallback.

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

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

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

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

Advertisement:

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

Advertisement:

// ==UserScript==
// @name        Reddit Restore
// @namespace   reddit-restore
// @version     1.4
// @description Restores deleted Reddit posts, comments, usernames, images, videos, and media using Arctic Shift with PullPush fallback.
// @author      brainbaker
// @license     MIT
// @icon        data:image/png;base64,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
// @match       https://www.reddit.com/r/*/comments/*
// @match       https://old.reddit.com/r/*/comments/*
// @match       https://new.reddit.com/r/*/comments/*
// @match       https://sh.reddit.com/r/*/comments/*
// @connect     arctic-shift.photon-reddit.com
// @connect     api.pullpush.io
// @connect     i.redd.it
// @connect     preview.redd.it
// @connect     v.redd.it
// @connect     media.giphy.com
// @connect     www.redgifs.com
// @connect     api.redgifs.com
// @connect     media.redgifs.com
// @grant       GM_xmlhttpRequest
// @run-at      document-end
// ==/UserScript==
(function RedditUncensoredEnhancedV3() {
    "use strict";
    const CFG = {
        arctic: "https://arctic-shift.photon-reddit.com",
        pullpush: "https://api.pullpush.io",
        batchSize: 100,
        observeDebounce: 500,
        maxObserverPasses: 24,
        cacheTTL: 6 * 60 * 60 * 1e3
    };
    const REMOVED_RE = /^\s*\[(?:deleted|removed)\]\s*$|deleted by user|removed by (?:moderator|reddit)|sorry, this post (?:was|has been) removed|content is no longer available|this comment (?:has been|was) removed|this comment (?:has been|was) deleted|this post (?:has been|was) removed|awaiting moderator approval/i;
    const IMAGE_RE = /\.(?:png|jpe?g|gif|webp|avif)(?:[?#].*)?$/i;
    const VIDEO_RE = /\.(?:mp4|webm|mov)(?:[?#].*)?$/i;
    const state = {
        postId: null,
        running: false,
        observerPasses: 0,
        doneComments: new Set,
        lastStats: null,
        originalView: false,
        threadComments: null,
        redgifsToken: null,
        observer: null
    };
    function esc(str) {
        return String(str ?? "").replace(/[&<>"']/g, ch => ({
            "&": "&amp;",
            "<": "&lt;",
            ">": "&gt;",
            '"': "&quot;",
            "'": "&#39;"
        }[ch]));
    }
    function unhtml(str) {
        return String(str ?? "").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'");
    }
    function normId(id) {
        return String(id || "").replace(/^t[13]_/, "").trim();
    }
    function looksRemoved(text) {
        return REMOVED_RE.test(String(text || "").trim());
    }
    function isDeletedAuthor(text) {
        return /^\s*\[?deleted\]?\s*$/i.test(String(text || "").trim());
    }
    function currentPostId() {
        return (location.pathname.match(/\/comments\/([a-z0-9]+)(?:\/|$)/i) || [])[1] || null;
    }
    function unique(a) {
        return [ ...new Set(a.filter(Boolean)) ];
    }
    function log(...a) {
        console.debug("[RU Enhanced]", ...a);
    }
    function status(sign, detail) {
        let el = document.getElementById("ru-enhanced-status");
        if (!el) {
            el = document.createElement("button");
            el.id = "ru-enhanced-status";
            el.type = "button";
            el.addEventListener("click", ev => {
                if (ev.shiftKey) run(true); else toggleOriginalView();
            });
            document.documentElement.appendChild(el);
        }
        el.textContent = sign;
        el.title = detail;
        el.setAttribute("aria-label", detail);
    }
    function restoredTotal() {
        const st = state.lastStats;
        return st ? st.postText + st.postMedia + st.authors + st.commentAuthors + st.commentBodies : 0;
    }
    function setOriginalView(on) {
        state.originalView = !!on;
        document.querySelectorAll("[data-ru-kind], [data-ru-comment]").forEach(el => {
            el.style.display = on ? "none" : "";
        });
        document.querySelectorAll("[data-ru-author-link]").forEach(el => {
            el.style.display = on ? "none" : "";
        });
        document.querySelectorAll("[data-ru-hidden-deleted-author]").forEach(el => {
            el.style.display = on ? "" : "none";
        });
        document.querySelectorAll('[data-ru-title-modified="true"]').forEach(el => {
            if (on) {
                if (!el.hasAttribute("data-ru-restored-text")) el.setAttribute("data-ru-restored-text", el.textContent || "");
                el.textContent = el.getAttribute("data-ru-orig-text") || "[removed]";
            } else {
                el.textContent = el.getAttribute("data-ru-restored-text") || el.textContent || "";
            }
        });
        document.querySelectorAll('a[data-ru-author-modified="true"]').forEach(el => {
            if (on) {
                if (!el.hasAttribute("data-ru-restored-text")) el.setAttribute("data-ru-restored-text", el.textContent || "");
                if (!el.hasAttribute("data-ru-restored-href")) el.setAttribute("data-ru-restored-href", el.getAttribute("href") || "");
                el.textContent = el.getAttribute("data-ru-orig-text") || "[deleted]";
                el.setAttribute("href", el.getAttribute("data-ru-orig-href") || "#");
            } else {
                el.textContent = el.getAttribute("data-ru-restored-text") || el.textContent || "";
                el.setAttribute("href", el.getAttribute("data-ru-restored-href") || el.getAttribute("href") || "#");
            }
        });
        if (on) status("O", "Original view: showing Reddit deleted/removed placeholders. Click to show restored content. Shift-click rescans archives."); else if (restoredTotal()) status("✓", `Restored view: showing recovered content (${restoredTotal()} item(s)). Click to show original deleted/removed placeholders. Shift-click rescans.`);
    }
    function toggleOriginalView() {
        if (!restoredTotal() && !document.querySelector("[data-ru-kind], [data-ru-comment], [data-ru-author-link], [data-ru-title-modified], [data-ru-author-modified]")) {
            run(true);
            return;
        }
        setOriginalView(!state.originalView);
    }
    function ensureStyle() {
        if (document.getElementById("ru-enhanced-style")) return;
        const st = document.createElement("style");
        st.id = "ru-enhanced-style";
        st.textContent = `\n      #ru-enhanced-status{position:fixed!important;right:12px!important;bottom:12px!important;z-index:2147483647!important;width:32px!important;height:32px!important;min-width:32px!important;min-height:32px!important;border-radius:50%!important;border:3px solid #ff8700!important;background:#fff!important;color:#128a13!important;font:700 18px/26px Arial,sans-serif!important;box-shadow:0 2px 8px #0006!important;cursor:pointer!important;padding:0!important;margin:0!important;text-align:center!important;appearance:none!important;-webkit-appearance:none!important;box-sizing:border-box!important;overflow:hidden!important;display:flex!important;align-items:center!important;justify-content:center!important}\n      .ru-enhanced-selftext,.ru-enhanced-media,.ru-enhanced-comment-body{display:block!important;clear:both!important;width:auto!important;max-width:min(860px,100%)!important;border-left:4px solid #ff8700;margin:8px 0!important;padding:10px!important;background:rgba(255,135,0,.08);border-radius:8px;box-sizing:border-box;white-space:normal!important;word-break:normal!important;overflow-wrap:break-word!important;line-height:1.45!important}
      .ru-enhanced-comment-body .md,.ru-enhanced-comment-body p,.ru-enhanced-selftext .md,.ru-enhanced-selftext p{white-space:normal!important;word-break:normal!important;overflow-wrap:break-word!important;display:block!important;width:auto!important;max-width:100%!important}
      .ru-enhanced-comment-body img,.ru-enhanced-comment-body video{max-width:min(520px,100%)!important;height:auto!important;border-radius:8px;display:block!important;margin:6px 0!important}
      .ru-enhanced-comment-body{position:relative!important}.ru-enhanced-comment-body a.ru-enhanced-author{color:#7dd3fc!important}
      .ru-enhanced-author{color:#24a0ed!important;text-decoration:none!important;font-weight:600}.ru-enhanced-author:hover{text-decoration:underline!important}
      .ru-enhanced-meta{font:12px/1.35 system-ui,-apple-system,Segoe UI,sans-serif;opacity:.75;margin-bottom:6px}.ru-enhanced-grid{display:flex!important;flex-wrap:wrap!important;gap:10px!important;align-items:flex-start!important;align-content:flex-start!important}.ru-enhanced-grid figure{display:inline-block!important;vertical-align:top!important;margin:0!important;padding:0!important;width:auto!important;max-width:min(260px,100%)!important}.ru-enhanced-grid img,.ru-enhanced-grid video{display:block!important;width:auto!important;max-width:min(260px,100%)!important;max-height:320px!important;height:auto!important;border-radius:8px;background:#000;object-fit:contain!important}.ru-enhanced-grid iframe{display:block!important;width:min(360px,100%)!important;height:300px!important;border:0!important;border-radius:8px!important;background:#000}.ru-enhanced-redgifs-fallback,.rr-redgifs-link{display:block!important;margin-top:5px!important;font:12px/1.3 system-ui!important;color:#7dd3fc!important}.rr-redgifs-video-wrap{margin-top:8px!important}.rr-redgifs-status{margin-top:8px!important}.rr-redgifs-thumb{position:relative!important;display:block!important;max-width:min(420px,100%)!important;background:#111!important;border-radius:8px!important;overflow:hidden!important}.rr-redgifs-thumb img{display:block!important;width:100%!important;height:auto!important}.rr-redgifs-play{position:absolute!important;left:50%!important;top:50%!important;transform:translate(-50%,-50%)!important;background:rgba(0,0,0,.68)!important;color:#fff!important;border-radius:999px!important;width:54px!important;height:54px!important;text-align:center!important;font:700 24px/54px Arial!important}.ru-enhanced-redgifs-thumb{position:relative!important;display:block!important;max-width:min(360px,100%)!important;background:#111!important;border-radius:8px!important;overflow:hidden!important}.ru-enhanced-redgifs-thumb img{display:block!important;width:100%!important;max-width:100%!important;height:auto!important}.ru-enhanced-redgifs-play{position:absolute!important;left:50%!important;top:50%!important;transform:translate(-50%,-50%)!important;background:rgba(0,0,0,.65)!important;color:#fff!important;border-radius:999px!important;width:54px!important;height:54px!important;line-height:54px!important;text-align:center!important;font:700 24px/54px Arial!important}.rr-media-status,.ru-enhanced-redgifs-unavailable,.ru-enhanced-media-unavailable{padding:10px!important;border-radius:8px!important;background:#111!important;color:#ddd!important;font:12px/1.4 system-ui!important;max-width:360px!important;box-sizing:border-box!important}.ru-enhanced-media-unavailable a{color:#7dd3fc!important}.ru-enhanced-grid figcaption{font:12px/1.3 system-ui;word-break:break-word;opacity:.75;margin-top:4px!important}.ru-enhanced-links{font-size:12px;margin-top:6px;word-break:break-all}.ru-enhanced-selftext+.ru-enhanced-media,.ru-enhanced-media+.ru-enhanced-selftext{margin-top:6px!important}.ru-enhanced-media{min-width:0!important}`;
        document.head.appendChild(st);
    }
    function cacheKey(type, id) {
        return `reddit-restore:${type}:${id}`;
    }
    function cacheRead(type, id) {
        try {
            const raw = localStorage.getItem(cacheKey(type, id));
            if (!raw) return null;
            const item = JSON.parse(raw);
            if (!item || Date.now() - item.t > CFG.cacheTTL) {
                localStorage.removeItem(cacheKey(type, id));
                return null;
            }
            const v = item.v;
            if (v == null) return null;
            if (Array.isArray(v) && v.length === 0) return null;
            if (typeof v === 'object' && !Array.isArray(v) && !v.id && !v.name && !v.author) return null;
            return v;
        } catch (_e) {
            return null;
        }
    }
    function cacheWrite(type, id, value) {
        if (!id || value == null) return;
        if (Array.isArray(value) && value.length === 0) return;
        if (typeof value === 'object' && !Array.isArray(value) && !value.id && !value.name && !value.author) return;
        try {
            localStorage.setItem(cacheKey(type, id), JSON.stringify({
                t: Date.now(),
                v: value
            }));
        } catch (_e) {}
    }
    function restoredCommentPresent(el, id) {
        return !!el.querySelector(`[data-ru-comment="${id}"]`);
    }

    function xhrJSON(url) {
        return new Promise((resolve, reject) => {
            const finish = (code, text) => {
                if (code < 200 || code >= 300) return reject(new Error(`HTTP ${code}`));
                try {
                    resolve(JSON.parse(text));
                } catch (e) {
                    reject(e);
                }
            };
            const fn = typeof GM !== "undefined" && GM.xmlHttpRequest ? GM.xmlHttpRequest.bind(GM) : typeof GM_xmlhttpRequest !== "undefined" ? GM_xmlhttpRequest : null;
            if (fn) fn({
                method: "GET",
                url: url,
                headers: {
                    Accept: "application/json"
                },
                timeout: 3e4,
                onload: r => finish(r.status, r.responseText),
                onerror: reject,
                ontimeout: () => reject(new Error("timeout"))
            }); else fetch(url, {
                credentials: "omit",
                headers: {
                    Accept: "application/json"
                }
            }).then(async r => finish(r.status, await r.text())).catch(reject);
        });
    }
    async function getFirst(urls) {
        let last;
        for (const u of urls) {
            try {
                const j = await xhrJSON(u);
                const item = j?.data?.[0] || null;
                if (item) return item;
            } catch (e) {
                last = e;
                log("source failed", u, e);
            }
        }
        if (last) throw last;
        return null;
    }
    async function fetchPost(id) {
        return getFirst([ `${CFG.arctic}/api/posts/ids?ids=${encodeURIComponent(id)}&md2html=true`, `${CFG.pullpush}/reddit/search/submission/?ids=${encodeURIComponent(id)}&size=1` ]);
    }
    async function fetchCommentsByIds(ids) {
        const map = new Map;
        for (let i = 0; i < ids.length; i += CFG.batchSize) {
            const chunk = ids.slice(i, i + CFG.batchSize).map(normId);
            let got = [];
            try {
                got = (await xhrJSON(`${CFG.arctic}/api/comments/ids?ids=${encodeURIComponent(chunk.join(","))}&md2html=true`)).data || [];
            } catch (e) {
                log("arctic comments failed", e);
            }
            const found = new Set(got.map(c => normId(c.id || c.name)));
            const missing = chunk.filter(x => !found.has(x));
            if (missing.length) {
                const maxUrlLen = 4000;
                const baseUrl = `${CFG.pullpush}/reddit/search/comment/?ids=`;
                let batch = [];
                for (const mid of missing) {
                    const testUrl = baseUrl + encodeURIComponent([...batch, mid].join(",")) + `&size=${batch.length + 1}`;
                    if (testUrl.length > maxUrlLen && batch.length > 0) {
                        try {
                            got = got.concat((await xhrJSON(`${baseUrl}${encodeURIComponent(batch.join(","))}&size=${batch.length}`)).data || []);
                        } catch (e) {
                            log("pullpush comments batch failed", e);
                        }
                        batch = [mid];
                    } else {
                        batch.push(mid);
                    }
                }
                if (batch.length) {
                    try {
                        got = got.concat((await xhrJSON(`${baseUrl}${encodeURIComponent(batch.join(","))}&size=${batch.length}`)).data || []);
                    } catch (e) {
                        log("pullpush comments failed", e);
                    }
                }
            }
            got.forEach(c => map.set(normId(c.id || c.name), c));
        }
        return map;
    }
    async function fetchThreadComments(postId) {
        const cached = cacheRead("thread", postId);
        if (cached) return cached;
        try {
            const pageSize = 500;
            let allComments = [];
            let after = "";
            let pages = 0;
            const maxPages = 20;
            do {
                const afterParam = after ? `&after=${encodeURIComponent(after)}` : "";
                const j = await xhrJSON(`${CFG.arctic}/api/comments/search?link_id=${encodeURIComponent(postId)}&limit=${pageSize}&md2html=true${afterParam}`);
                const arr = j?.data || [];
                allComments = allComments.concat(arr);
                after = arr.length >= pageSize && arr.length > 0 ? normId(arr[arr.length - 1].id || arr[arr.length - 1].name || "") : "";
                pages++;
            } while (after && pages < maxPages);
            cacheWrite("thread", postId, allComments);
            return allComments;
        } catch (e) {
            log("thread comments failed", e);
            return [];
        }
    }
    function threadMap(arr) {
        const byId = new Map, children = new Map;
        (arr || []).forEach(c => {
            const id = normId(c.id || c.name);
            if (!id) return;
            byId.set(id, c);
            const p = normId(c.parent_id || "");
            if (p) {
                if (!children.has(p)) children.set(p, []);
                children.get(p).push(c);
            }
        });
        return { byId, children };
    }

    function urlWithoutEscapedAmp(url) {
        return String(url || "").replace(/&amp;/g, "&");
    }
    function mediaTypeFromURL(url) {
        url = urlWithoutEscapedAmp(url);
        if (/\.(?:png|jpe?g|gif|webp|avif)(?:[?#].*)?$/i.test(url)) return "image";
        if (/\.(?:mp4|webm|mov)(?:[?#].*)?$/i.test(url)) return "video";
        if (/\/preview\.redd\.it\//i.test(url) || /\/i\.redd\.it\//i.test(url) || /format=(?:pjpg|jpg|png|webp)/i.test(url)) return "image";
        if (/\/v\.redd\.it\//i.test(url)) return "video-link";
        return "";
    }
    function mediaPreviewHTML(url, label = "media preview") {
        const type = mediaTypeFromURL(url);
        url = esc(urlWithoutEscapedAmp(url));
        if (type === "image") return `<a href="${url}" target="_blank" rel="noopener noreferrer"><img src="${url}" alt="${esc(label)}" loading="lazy" referrerpolicy="no-referrer"></a>`;
        if (type === "video") return `<video controls preload="metadata" src="${url}"></video>`;
        if (type === "video-link") return `<div class="ru-enhanced-links"><a href="${url}" target="_blank" rel="noopener noreferrer">🎞️ open archived video/media</a></div>`;
        return "";
    }
    function addLinkMediaPreviews(html) {
        const seen = new Set;
        let previews = "";
        String(html || "").replace(/<a\b[^>]*href=(['"])(.*?)\1[^>]*>/gi, (_m, _q, href) => {
            const url = urlWithoutEscapedAmp(href);
            if (!seen.has(url) && mediaTypeFromURL(url)) {
                seen.add(url);
                previews += mediaPreviewHTML(url, "comment media");
            }
            return _m;
        });
        String(html || "").replace(/https?:\/\/[^\s<>'"]+/gi, url => {
            url = url.replace(/[),.;]+$/g, "");
            if (!seen.has(url) && mediaTypeFromURL(url)) {
                seen.add(url);
                previews += mediaPreviewHTML(url, "comment media");
            }
            return url;
        });
        return previews ? `${html}<div class="ru-enhanced-comment-media">${previews}</div>` : html;
    }
    function fixArchivedInlineMedia(html, fallbackText = "") {
        let out = String(html || "");
        out = out.replace(/src=(['"])(?:giphy%7C|giphy\|)([A-Za-z0-9_-]+)\1/gi, "src=$1https://media.giphy.com/media/$2/giphy.gif$1");
        out = out.replace(/data-media-id=(['"])(?:giphy\|)([A-Za-z0-9_-]+)\1/gi, 'data-media-id=$1giphy|$2$1 data-ru-giphy="https://media.giphy.com/media/$2/giphy.gif"');
        if (!/<img\b|<video\b/i.test(out) && fallbackText) {
            out = out.replace(/!\[([^\]]*)\]\((https?:\/\/[^\s)]+)\)/gi, '<img src="$2" alt="$1" loading="lazy" referrerpolicy="no-referrer">');
            out = out.replace(/!\[([^\]]*)\]\(giphy\|([A-Za-z0-9_-]+)\)/gi, '<img src="https://media.giphy.com/media/$2/giphy.gif" alt="$1" loading="lazy" referrerpolicy="no-referrer">');
        }
        return addLinkMediaPreviews(out);
    }
    function htmlFrom(obj, field) {
        const html = obj?.[`${field}_html`];
        if (html && !looksRemoved(html)) return fixArchivedInlineMedia(unhtml(html), obj?.[field] || "");
        const text = obj?.[field];
        if (!text || looksRemoved(text)) return "";
        const withMedia = fixArchivedInlineMedia(esc(text), text);
        return `<div class="md"><p>${withMedia.replace(/\n{2,}/g, "</p><p>").replace(/\n/g, "<br>")}</p></div>`;
    }
    function isSelfOrPermalinkURL(p, url) {
        url = unhtml(url || "");
        if (!url) return true;
        const pid = currentPostId();
        if (p?.is_self || /^self\./i.test(p?.domain || "")) return true;
        if (/reddit\.com\/r\/[^/]+\/comments\//i.test(url)) return true;
        if (pid && new RegExp(`/comments/${pid}(?:/|$)`, "i").test(url)) return true;
        return false;
    }
    function redgifsSlug(url) {
        url = unhtml(url || "");
        const m = url.match(/(?:www\.|v3\.)?redgifs\.com\/(?:watch|ifr)\/([a-z0-9-]+)/i);
        return m ? m[1] : "";
    }
    function redgifsEmbedURL(url) {
        const slug = redgifsSlug(url);
        return slug ? `https://www.redgifs.com/ifr/${slug}` : "";
    }
    function redgifsWatchURL(slugOrUrl) {
        const slug = redgifsSlug(slugOrUrl) || slugOrUrl;
        return slug ? `https://www.redgifs.com/watch/${slug}` : "";
    }

    function postContentTarget(root) {
        if (isOldReddit() && root.matches?.('.thing.link, .link')) {
            const entry = root.querySelector(':scope > .entry') || root.querySelector('.entry') || root;
            let expando = entry.querySelector(':scope > .expando') || root.querySelector(':scope > .expando');
            if (!expando) {
                expando = document.createElement('div');
                expando.className = 'expando ru-enhanced-old-post-target';
                const buttons = entry.querySelector(':scope > .flat-list.buttons, :scope > ul.buttons');
                if (buttons) buttons.insertAdjacentElement('beforebegin', expando); else entry.appendChild(expando);
            }
            return expando;
        }
        return root.querySelector?.(".entry, .expando") || root;
    }

    function oembedURL(p) {
        const html = p?.secure_media?.oembed?.html || p?.media?.oembed?.html || "";
        const m = unhtml(html).match(/<iframe[^>]+src=["']([^"']+)["']/i);
        return m ? m[1] : "";
    }

    function mediaCandidates(p) {
        const out = [];
        const norm = url => unhtml(url || "").replace(/^http:\/\//i, "https://").replace(/[?#].*$/, "").toLowerCase();
        const add = (url, label, type, original = "", poster = "") => {
            url = unhtml(url || "");
            original = unhtml(original || "");
            poster = unhtml(poster || "");
            if (!/^https?:\/\//i.test(url)) return;
            const slug = redgifsSlug(url);
            const key = slug ? `redgifs:${slug.toLowerCase()}` : `${type}:${norm(url)}`;
            if (!out.some(x => x.key === key)) out.push({ url, label, type, original, poster, key });
        };
        const sourceURL = unhtml(p?.url || "");
        const oe = p?.secure_media?.oembed || p?.media?.oembed || {};
        const oeURL = oembedURL(p);
        const rg = redgifsEmbedURL(sourceURL) || redgifsEmbedURL(oeURL);
        if (rg) {
            add(rg, "Redgifs", "redgifs", sourceURL || oeURL || rg, oe.thumbnail_url || "");
            return out;
        }
        const hasRealMediaObject = !!(p?.secure_media?.reddit_video || p?.media?.reddit_video || p?.is_gallery || p?.gallery_data?.items?.length || Object.keys(p?.media_metadata || {}).length || oeURL);
        if (isSelfOrPermalinkURL(p, sourceURL) && !hasRealMediaObject) return out;
        const rv = p?.secure_media?.reddit_video || p?.media?.reddit_video;
        if (rv) {
            add(rv.fallback_url, "video", "video", "", rv.scrubber_media_url || "");
            add(rv.hls_url, "hls stream", "link");
            add(rv.dash_url, "dash stream", "link");
        }
        const md = p?.media_metadata || {};
        const gallery = p?.gallery_data?.items || Object.keys(md).map(media_id => ({ media_id }));
        gallery.forEach(it => {
            const m = md[it.media_id] || {};
            add(m.s?.u || m.s?.gif || m.p?.slice?.(-1)?.[0]?.u, it.caption || "gallery image", "image");
        });
        if (oeURL) add(oeURL, oe.provider_name || "embed", "embed", sourceURL || oeURL, oe.thumbnail_url || "");
        if (!isSelfOrPermalinkURL(p, sourceURL)) add(sourceURL, p?.domain || "source", IMAGE_RE.test(sourceURL) ? "image" : VIDEO_RE.test(sourceURL) ? "video" : "link");
        const videoLike = p?.is_video || VIDEO_RE.test(sourceURL) || /video|gif/i.test(p?.post_hint || "") || !!rv || !!oeURL;
        if (videoLike && !out.some(x => ["image","video","embed","redgifs"].includes(x.type))) {
            const preview = p?.preview?.images?.[0];
            add(preview?.source?.url || preview?.resolutions?.slice?.(-1)?.[0]?.url, "video preview", "image");
        }
        return out;
    }
    function mediaHTML(p) {
        const c = mediaCandidates(p);
        if (!c.length) return "";
        const embeds = c.filter(x => x.type === "image" || x.type === "video" || x.type === "embed" || x.type === "redgifs" || IMAGE_RE.test(x.url) || VIDEO_RE.test(x.url)).slice(0, 12).map(x => {
            const u = esc(x.url), cap = esc(x.label || x.url);
            if (x.type === "redgifs") {
                const slug = redgifsSlug(x.url);
                const open = esc(x.original || redgifsWatchURL(slug) || x.url);
                const poster = esc(x.poster || "");
                const thumb = poster ? `<div class="rr-redgifs-thumb"><img src="${poster}" loading="lazy" referrerpolicy="no-referrer"><span class="rr-redgifs-play">▶</span></div>` : `<div class="rr-media-status">Loading Redgifs…</div>`;
                return `<figure><div class="rr-redgifs-box" data-rr-redgifs-id="${esc(slug)}" data-rr-redgifs-url="${open}">${thumb}<a class="rr-redgifs-link" href="${open}" target="_blank" rel="noopener noreferrer">open Redgifs</a></div><figcaption>${cap}</figcaption></figure>`;
            }
            if (x.type === "embed") return `<figure><iframe src="${u}" allow="autoplay; fullscreen; encrypted-media" loading="lazy"></iframe><a class="rr-redgifs-link" href="${u}" target="_blank" rel="noopener noreferrer">open media</a><figcaption>${cap}</figcaption></figure>`;
            if (x.type === "video" || VIDEO_RE.test(x.url)) return `<figure><video controls loop playsinline preload="metadata" ${x.poster ? `poster="${esc(x.poster)}"` : ""} src="${u}"></video><figcaption>${cap}</figcaption></figure>`;
            return `<figure><a href="${u}" target="_blank" rel="noopener noreferrer"><img loading="lazy" referrerpolicy="no-referrer" src="${u}"></a><figcaption>${cap}</figcaption></figure>`;
        }).join("");
        const links = c.map(x => `<li><a href="${esc(x.original || x.url)}" target="_blank" rel="noopener noreferrer">${esc(x.label || "url")}</a></li>`).join("");
        return `<div class="ru-enhanced-media" data-ru-kind="media"><div class="ru-enhanced-meta">↺ restored deleted media/source</div>${embeds ? `<div class="ru-enhanced-grid">${embeds}</div>` : ""}<details class="ru-enhanced-links" open><summary>source links</summary><ul>${links}</ul></details></div>`;
    }
    async function redgifsToken() {
        if (state.redgifsToken) return state.redgifsToken;
        const j = await xhrJSON('https://api.redgifs.com/v2/auth/temporary');
        state.redgifsToken = j?.token || "";
        return state.redgifsToken;
    }
    function setRedgifsStatus(box, message, link) {
        let st = box.querySelector('.rr-redgifs-status');
        if (!st) {
            st = document.createElement('div');
            st.className = 'rr-media-status rr-redgifs-status';
            box.appendChild(st);
        }
        st.innerHTML = `${esc(message)}${link ? `<br><a href="${esc(link)}" target="_blank" rel="noopener noreferrer">open Redgifs link</a>` : ""}`;
    }
    async function resolveRedgifsVideos(root = document) {
        const all = [...root.querySelectorAll('[data-rr-redgifs-id]')];
        const seen = new Set;
        all.forEach(el => {
            const id = (el.getAttribute('data-rr-redgifs-id') || '').toLowerCase();
            if (!id) return;
            if (seen.has(id)) el.closest('figure')?.remove(); else seen.add(id);
        });
        const boxes = [...root.querySelectorAll('[data-rr-redgifs-id]')].filter(el => !el.getAttribute('data-rr-redgifs-done'));
        if (!boxes.length) return;
        let token = "";
        try { token = await redgifsToken(); } catch (_e) {}
        for (const box of boxes) {
            const id = box.getAttribute('data-rr-redgifs-id');
            if (!id) continue;
            box.setAttribute('data-rr-redgifs-done', '1');
            const fallback = box.getAttribute('data-rr-redgifs-url') || redgifsWatchURL(id);
            try {
                const j = await new Promise((resolve, reject) => {
                    const fn = typeof GM !== "undefined" && GM.xmlHttpRequest ? GM.xmlHttpRequest.bind(GM) : typeof GM_xmlhttpRequest !== "undefined" ? GM_xmlhttpRequest : null;
                    const url = `https://api.redgifs.com/v2/gifs/${encodeURIComponent(id)}`;
                    if (fn) fn({ method: 'GET', url, headers: { Accept: 'application/json', Authorization: `Bearer ${token}` }, onload: r => { try { resolve(JSON.parse(r.responseText || '{}')); } catch (e) { reject(e); } }, onerror: reject, ontimeout: reject });
                    else fetch(url, { headers: { Authorization: `Bearer ${token}` } }).then(r => r.json()).then(resolve).catch(reject);
                });
                const urls = j?.gif?.urls || {};
                const src = urls.hd || urls.sd;
                const poster = urls.poster || urls.thumbnail || "";
                const open = urls.html || fallback;
                if (src) {
                    box.querySelector('.rr-redgifs-status')?.remove();
                    let wrap = box.querySelector('.rr-redgifs-video-wrap');
                    if (!wrap) {
                        wrap = document.createElement('div');
                        wrap.className = 'rr-redgifs-video-wrap';
                        box.appendChild(wrap);
                    }
                    wrap.innerHTML = `<video controls autoplay muted loop playsinline preload="metadata" ${poster ? `poster="${esc(poster)}"` : ''} src="${esc(src)}"></video>`;
                    const link = box.querySelector('.rr-redgifs-link');
                    if (link) link.href = open;
                    attachMediaFailureHandlers(wrap);
                } else {
                    const gone = /GifDeleted|deleted|410/i.test(String(j?.error?.code || j?.error?.description || ""));
                    setRedgifsStatus(box, gone ? 'Redgifs media is deleted at source.' : 'Could not load Redgifs video here.', fallback);
                }
            } catch (_e) {
                setRedgifsStatus(box, 'Could not load Redgifs video here.', fallback);
            }
        }
    }

    function unavailableMediaBox(url, kind = "image") {
        const msg = kind === "video" ? "Video/media is probably deleted or unavailable." : "Image/media is probably deleted or unavailable.";
        return `<div class="rr-media-status">${msg}${url ? `<br><a href="${esc(url)}" target="_blank" rel="noopener noreferrer">open media link</a>` : ""}</div>`;
    }
    function attachMediaFailureHandlers(root = document) {
        root.querySelectorAll('.ru-enhanced-media img, .ru-enhanced-comment-body img').forEach(img => {
            if (img.getAttribute('data-ru-fallback-bound')) return;
            img.setAttribute('data-ru-fallback-bound', '1');
            const fail = () => {
                const url = img.closest('a')?.href || img.src || "";
                const fig = img.closest('figure');
                if (fig) fig.innerHTML = unavailableMediaBox(url, "image");
                else img.replaceWith(document.createRange().createContextualFragment(unavailableMediaBox(url, "image")));
            };
            img.addEventListener('error', fail, { once: true });
            if (img.complete && img.naturalWidth === 0) fail();
            setTimeout(() => { if (img.isConnected && img.complete && img.naturalWidth === 0) fail(); }, 3500);
        });
        root.querySelectorAll('.ru-enhanced-media video, .ru-enhanced-comment-body video').forEach(video => {
            if (video.getAttribute('data-ru-fallback-bound')) return;
            video.setAttribute('data-ru-fallback-bound', '1');
            const fail = () => {
                const url = video.currentSrc || video.src || "";
                const rgBox = video.closest('[data-rr-redgifs-id]');
                if (rgBox) {
                    video.closest('.rr-redgifs-video-wrap')?.remove();
                    setRedgifsStatus(rgBox, 'Could not play Redgifs video here.', rgBox.getAttribute('data-rr-redgifs-url') || url);
                    return;
                }
                const fig = video.closest('figure');
                if (fig) fig.innerHTML = unavailableMediaBox(url, "video");
                else video.replaceWith(document.createRange().createContextualFragment(unavailableMediaBox(url, "video")));
            };
            video.addEventListener('error', fail, { once: true });
        });
    }

    function postNode() {
        return document.querySelector('shreddit-post, .thing.link:not(.comment), .sitetable > .link, [data-testid="post-container"], article[aria-label], article') || null;
    }
    function postDeletedParts() {
        const p = postNode();
        if (!p) return {
            any: false
        };
        const txt = (p.innerText || p.textContent || "").slice(0, 5e3);
        const authorEls = [ ...p.querySelectorAll('a.author, span.author, .tagline .author, .tagline [href^="/user/"], .tagline [href^="/u/"], a[href^="/user/"], a[href^="/u/"], [slot="authorName"], shreddit-post-author') ];
        const titleEls = [ ...p.querySelectorAll('a.title, h1, [slot="title"], [data-testid="post-title"]') ];
        const bodyEls = [ ...p.querySelectorAll('.expando .usertext-body .md, .usertext-body .md, [slot="text-body"], [data-testid="post-content"], .md') ];
        const author = authorEls.filter(e => !e.hasAttribute?.("data-ru-hidden-deleted-author")).some(e => isDeletedAuthor(e.textContent) || /\/user\/\[deleted\]/i.test(e.getAttribute("href") || "")) || /Posted by\s+u\/\[deleted\]/i.test(txt);
        const title = titleEls.some(e => looksRemoved(e.textContent));
        const body = bodyEls.some(e => looksRemoved(e.textContent)) || /\b(post|content)\b.{0,30}\bremoved\b/i.test(txt);
        const oldRedditDeleted = p.classList?.contains("deleted") || p.querySelector('.entry .buttons .removed, .entry .tagline .deleted, .expando .error, .expando .md')?.textContent?.match(/removed|deleted/i);
        const oldRedditMissingExpando = location.hostname === 'old.reddit.com' && p.matches?.('.thing.link') && (p.getAttribute('data-url') || '').includes('/removed_by_reddit/');
        const urlRemoved = oldRedditDeleted || oldRedditMissingExpando || (p.getAttribute("data-url") || "").includes("/removed_by_reddit/") || (p.getAttribute("data-permalink") || "").includes("/removed_by_reddit/");
        const mediaGone = urlRemoved || (body && !hasVisibleMedia(p));
        return {
            any: author || title || body || urlRemoved,
            author: author,
            title: title,
            body: body || urlRemoved,
            media: mediaGone
        };
    }
    function profileHref(author) {
        return `/user/${encodeURIComponent(author)}/`;
    }
    function makeAuthorClickable(el, author) {
        const href = profileHref(author);
        if (el.tagName === "A") {
            if (!el.hasAttribute("data-ru-author-modified")) {
                el.setAttribute("data-ru-orig-text", el.textContent || "[deleted]");
                el.setAttribute("data-ru-orig-href", el.getAttribute("href") || "");
            }
            el.textContent = author;
            el.setAttribute("href", href);
            el.setAttribute("data-ru-author-modified", "true");
            el.classList.add("ru-enhanced-author");
            return;
        }
        const a = document.createElement("a");
        a.href = href;
        a.textContent = author;
        a.className = "ru-enhanced-author";
        a.setAttribute("data-ru-author-link", author);
        el.insertAdjacentElement("beforebegin", a);
        el.setAttribute("data-ru-hidden-deleted-author", "true");
        el.style.display = "none";
    }
    function replaceAuthor(root, author) {
        if (!author || isDeletedAuthor(author)) return 0;
        let n = 0;
        const authorSel = 'a.author, a[href^="/user/"], a[href^="/u/"], [slot="authorName"], shreddit-post-author, shreddit-comment-author';
        const nodes = root.matches?.(COMMENT_ROOT_SEL) ? directQuery(root, authorSel) : [ ...root.querySelectorAll(authorSel) ];
        nodes.forEach(el => {
            if (el.closest?.("[data-ru-author-link]") || el.hasAttribute?.("data-ru-hidden-deleted-author") || el.previousElementSibling?.hasAttribute?.("data-ru-author-link")) return;
            if (isDeletedAuthor(el.textContent) || /\/user\/\[deleted\]/i.test(el.getAttribute?.("href") || "")) {
                makeAuthorClickable(el, author);
                n++;
            }
        });
        return n;
    }
    function compactText(x) {
        return String(x || "").replace(/\s+/g, " ").trim().toLowerCase();
    }
    function replaceOldRedditPostAuthor(root, author) {
        if (!author || isDeletedAuthor(author) || !isOldReddit()) return 0;
        if (root.querySelector('[data-ru-old-author-replaced]')) return 0;
        const entry = root.querySelector?.(':scope > .entry') || root.querySelector?.('.entry') || root;
        const tagline = entry.querySelector?.(':scope > .tagline, :scope > p.tagline, .tagline');
        if (!tagline || !/\[deleted\]/i.test(tagline.textContent || "")) return 0;
        const walker = document.createTreeWalker(tagline, NodeFilter.SHOW_TEXT, null, false);
        let node;
        while ((node = walker.nextNode())) {
            if (/\[deleted\]/i.test(node.nodeValue || "")) {
                const parts = node.nodeValue.split(/\[deleted\]/i);
                const frag = document.createDocumentFragment();
                parts.forEach((part, i) => {
                    if (i > 0) {
                        const a = document.createElement('a');
                        a.className = 'ru-enhanced-author';
                        a.setAttribute('data-ru-author-link', author);
                        a.href = profileHref(author);
                        a.textContent = author;
                        frag.appendChild(a);
                    }
                    if (part) frag.appendChild(document.createTextNode(part));
                });
                node.parentNode.replaceChild(frag, node);
                root.setAttribute('data-ru-old-author-replaced', 'true');
                return 1;
            }
        }
        return 0;
    }

    function archivedBodyAlreadyVisible(root, p) {
        const archived = compactText(p?.selftext || "");
        if (!archived) return true;
        const page = compactText(root.innerText || root.textContent || "");
        return page.includes(archived.slice(0, Math.min(80, archived.length)));
    }
    function hasVisiblePostBody(root) {
        const bodyNodes = [ ...root.querySelectorAll('.expando .usertext-body .md, .entry > .usertext .usertext-body .md, .entry > form.usertext .usertext-body .md, [slot="text-body"], [data-testid="post-content"], [id*="post-rtjson-content"]') ];
        return bodyNodes.some(n => {
            const t = compactText(n.innerText || n.textContent || "");
            return t && !looksRemoved(t) && t.length > 12;
        });
    }
    function hasVisibleMedia(root) {
        if (isOldReddit()) return !!root.querySelector('.expando img[src*="redd.it"], .expando img[src*="redditmedia"], .expando video, .expando iframe, .expando object, .expando embed');
        return !!root.querySelector('[slot="media"] img, [slot="media"] video, [data-testid*="media"] img, [data-testid*="media"] video, shreddit-player, gallery-carousel, video');
    }
    function archiveSaysPostRemoved(p) {
        const m = p?._meta || {};
        return !!(p?.removed_by_category || m.removal_type || m.was_deleted_later || m.was_initially_deleted || m.was_initially_removed);
    }

    function restorePost(p, parts) {
        const root = postNode();
        if (!root) return {
            postText: 0,
            postMedia: 0,
            authors: 0
        };
        let postText = 0, postMedia = 0, authors = 0;
        authors += replaceAuthor(root, p.author);
        if (!authors) authors += replaceOldRedditPostAuthor(root, p.author);
        if (p.title) {
            const titles = [ ...root.querySelectorAll('a.title, h1, [slot="title"], [data-testid="post-title"]') ];
            titles.forEach(t => {
                if (looksRemoved(t.textContent)) {
                    if (!t.hasAttribute("data-ru-title-modified")) t.setAttribute("data-ru-orig-text", t.textContent || "[removed]");
                    t.textContent = p.title;
                    t.setAttribute("data-ru-title-modified", "true");
                    postText++;
                }
            });
        }
        const body = htmlFrom(p, "selftext");
        const mh = mediaHTML(p);
        if (!mh) root.querySelectorAll('[data-ru-kind="media"]').forEach(n => n.remove());
        const shouldRestoreBody = body && !root.querySelector('[data-ru-kind="selftext"]') && (parts.body || !hasVisiblePostBody(root)) && !archivedBodyAlreadyVisible(root, p);
        if (shouldRestoreBody) {
            const marker = [ ...root.querySelectorAll('.expando .usertext-body .md, .usertext-body .md, [slot="text-body"], [data-testid="post-content"], [id*="post-rtjson-content"], .md, p, div') ].find(e => looksRemoved(e.textContent));
            const html = `<div class="ru-enhanced-selftext" data-ru-kind="selftext"><div class="ru-enhanced-meta">↺ restored deleted/missing post text</div>${body}</div>`;
            const target = postContentTarget(root);
            const existingMedia = target.querySelector('[data-ru-kind="media"]');
            if (isOldReddit()) {
                if (existingMedia) existingMedia.insertAdjacentHTML("beforebegin", html); else target.insertAdjacentHTML("afterbegin", html);
            } else if (marker) marker.insertAdjacentHTML("afterend", html); else {
                if (existingMedia) existingMedia.insertAdjacentHTML("beforebegin", html); else target.insertAdjacentHTML("afterbegin", html);
            }
            postText++;
        }
        const shouldRestoreMedia = mh && !root.querySelector('[data-ru-kind="media"]') && !hasVisibleMedia(root) && (parts.media || archiveSaysPostRemoved(p));
        if (shouldRestoreMedia) {
            const target = postContentTarget(root);
            target.insertAdjacentHTML("beforeend", mh);
            resolveRedgifsVideos(target);
            attachMediaFailureHandlers(target);
            postMedia++;
        }
        return {
            postText: postText,
            postMedia: postMedia,
            authors: authors
        };
    }
    const COMMENT_ROOT_SEL = 'shreddit-comment, .comment[id], .comment[data-fullname], .thing.comment, [thingid*="t1_"], [data-testid="comment"]';
    const COMMENT_BODY_SEL = '.usertext-body, .usertext-body .md, [slot="comment"], [id$="-comment-rtjson-content"], [data-testid="comment-content"], [data-testid="comment"] .md';
    const COMMENT_AUTHOR_SEL = 'a.author, span.author, .tagline .author, a[href^="/user/"], a[href^="/u/"], [slot="authorName"], shreddit-comment-author';
    function isOldReddit() {
        return location.hostname === "old.reddit.com" || !!document.querySelector("body.listing-page, .commentarea .nestedlisting, .sitetable.nestedlisting");
    }
    function oldThingId(el) {
        const node = el?.matches?.('.thing.comment[id^="thing_t1_"], .comment[id^="thing_t1_"]') ? el : null;
        const id = node?.id || '';
        const m = id.match(/^thing_t1_([a-z0-9]{5,15})$/i);
        return m ? m[1] : null;
    }
    function oldDomParentCommentId(el) {
        const parent = el?.parentElement?.closest?.('.thing.comment[id^="thing_t1_"], .comment[id^="thing_t1_"]');
        return parent ? oldThingId(parent) : null;
    }
    function archiveMatchesOldCommentPosition(el, c, id) {
        if (!isOldReddit()) return true;
        const archiveId = normId(c?.id || c?.name || "");
        if (archiveId && archiveId !== normId(id)) return false;
        const domParent = oldDomParentCommentId(el);
        if (!domParent) return true;
        const archiveParent = normId(c?.parent_id || "");
        return !archiveParent || archiveParent === normId(domParent);
    }

    function oldEntryRoot(el) {
        return el?.querySelector?.(':scope > .entry') || el?.querySelector?.('.entry') || el;
    }
    function oldDirectBodies(el) {
        const entry = oldEntryRoot(el);
        return [...entry.querySelectorAll(':scope > form.usertext .usertext-body .md, :scope > .usertext .usertext-body .md, :scope > .md, :scope > div.md')];
    }
    function oldDirectAuthors(el) {
        const entry = oldEntryRoot(el);
        return [...entry.querySelectorAll(':scope > .tagline a.author, :scope > .tagline span.author, :scope > p.tagline a.author, :scope > p.tagline span.author')];
    }

  function closestCommentRoot(node) {
        if (!node?.closest && !node?.matches) return null;
        return node.matches?.(COMMENT_ROOT_SEL) ? node : node.closest?.(COMMENT_ROOT_SEL);
    }
    function isSameCommentScope(root, node) {
        const c = closestCommentRoot(node);
        return c === root || !c && root.contains(node);
    }
    function directQuery(root, selector) {
        if (isOldReddit() && root.matches?.('.thing.comment, .comment')) {
            if (selector === COMMENT_BODY_SEL || selector.includes('usertext-body') || selector.includes('[slot="comment"]')) return oldDirectBodies(root);
            if (selector === COMMENT_AUTHOR_SEL || selector.includes('a.author') || selector.includes('span.author')) return oldDirectAuthors(root);
        }
        return [ ...root.querySelectorAll(selector) ].filter(n => isSameCommentScope(root, n));
    }
    function commentOwnText(root) {
        if (isOldReddit() && root.matches?.('.thing.comment, .comment')) {
            const entry = oldEntryRoot(root);
            const clone = entry.cloneNode(true);
            clone.querySelectorAll("[data-ru-kind], [data-ru-comment], [data-ru-author-link]").forEach(n => n.remove());
            return (clone.innerText || clone.textContent || "").slice(0, 2500);
        }
        const clone = root.cloneNode(true);
        clone.querySelectorAll(COMMENT_ROOT_SEL).forEach(n => {
            if (n !== clone) n.remove();
        });
        clone.querySelectorAll("[data-ru-kind], [data-ru-comment], [data-ru-author-link]").forEach(n => n.remove());
        return (clone.innerText || clone.textContent || "").slice(0, 2500);
    }
    function oldDirectChildCommentIds(el) {
        if (!isOldReddit()) return [];
        const child = el.querySelector?.(':scope > .child');
        if (!child) return [];
        return [...child.querySelectorAll('.thing.comment[id^="thing_t1_"], .comment[id^="thing_t1_"]')]
            .filter(n => n.parentElement?.closest?.('.thing.comment[id^="thing_t1_"], .comment[id^="thing_t1_"]') === el || n.closest('.child') === child)
            .map(n => oldThingId(n)).filter(Boolean);
    }
    function oldVisibleCommentIds() {
        return new Set([...document.querySelectorAll('.thing.comment[id^="thing_t1_"], .comment[id^="thing_t1_"]')].map(n => oldThingId(n)).filter(Boolean));
    }
    function oldNoIdDeletedNodes() {
        if (!isOldReddit()) return [];
        return [...document.querySelectorAll('.thing.comment, .comment')].filter(el => !oldThingId(el) && commentParts(el).body);
    }
    function inferOldNoIdArchive(el, maps) {
        const visible = oldVisibleCommentIds();
        for (const childId of oldDirectChildCommentIds(el)) {
            const child = maps.byId.get(normId(childId));
            const parentId = normId(child?.parent_id || "");
            if (parentId && !visible.has(parentId) && maps.byId.has(parentId)) return maps.byId.get(parentId);
        }
        const domParent = oldDomParentCommentId(el);
        if (domParent) {
            const missing = (maps.children.get(normId(domParent)) || []).filter(c => {
                const id = normId(c.id || c.name);
                return id && !visible.has(id) && !document.querySelector(`[data-ru-comment="${id}"]`) && c.body && !looksRemoved(c.body);
            });
            if (missing.length === 1) return missing[0];
        }
        return null;
    }
    async function processOldNoIdComments() {
        if (!isOldReddit()) return { commentAuthors: 0, commentBodies: 0, looked: 0 };
        const nodes = oldNoIdDeletedNodes().filter(el => !el.querySelector('[data-ru-comment]'));
        if (!nodes.length) return { commentAuthors: 0, commentBodies: 0, looked: 0 };
        const arr = state.threadComments || await fetchThreadComments(currentPostId());
        state.threadComments = arr;
        const maps = threadMap(arr);
        let commentAuthors = 0, commentBodies = 0, looked = 0;
        nodes.forEach(el => {
            const c = inferOldNoIdArchive(el, maps);
            if (!c) return;
            const id = normId(c.id || c.name);
            if (!id || el.querySelector(`[data-ru-comment="${id}"]`)) return;
            const r = restoreComment(el, c, { any: true, author: true, body: true });
            commentAuthors += r.authors; commentBodies += r.bodies; looked++;
        });
        return { commentAuthors, commentBodies, looked };
    }

    function commentNodes() {
        const roots = [];
        document.querySelectorAll(COMMENT_ROOT_SEL).forEach(n => {
            const r = closestCommentRoot(n);
            if (r && commentId(r) && !roots.includes(r)) roots.push(r);
        });
        return roots;
    }
    function commentId(el) {
        const oldId = oldThingId(el);
        if (oldId) return oldId;
        if (isOldReddit() && el.matches?.('.thing.comment, .comment')) return null;
        for (const a of [ "thingid", "data-fullname", "fullname", "id", "data-id", "data-name" ]) {
            const v = String(el.getAttribute?.(a) || "");
            let m = v.match(/(?:thing_)?t1_([a-z0-9]{5,15})/i);
            if (m) return m[1];
            if ((a === "thingid" || a === "data-id") && /^([a-z0-9]{5,15})$/i.test(v)) return v;
        }
        const inner = el.querySelector?.('[thingid*="t1_"],[data-fullname*="t1_"],[id*="t1_"]');
        return inner && inner !== el ? commentId(inner) : null;
    }
    function commentParts(el) {
        const ownText = commentOwnText(el);
        const bodyEls = directQuery(el, COMMENT_BODY_SEL);
        const bodyText = bodyEls.length ? bodyEls.map(n => n.innerText || n.textContent || "").join("\n") : ownText;
        const author = directQuery(el, COMMENT_AUTHOR_SEL).filter(a => !a.hasAttribute?.("data-ru-hidden-deleted-author")).some(a => isDeletedAuthor(a.textContent) || /\/user\/\[deleted\]/i.test(a.getAttribute?.("href") || "")) || /u\/\[deleted\]/i.test(ownText);
        const body = looksRemoved(bodyText) || /^\s*(?:comment (?:deleted|removed)|removed by moderator|removed by reddit)\s*$/im.test(bodyText);
        return {
            any: author || body,
            author: author,
            body: body
        };
    }
    function commentInsertTarget(el) {
        if (isOldReddit() && el.matches?.('.thing.comment, .comment')) return oldEntryRoot(el);
        return directQuery(el, '.usertext-body, [slot="comment"], [id$="-comment-rtjson-content"], [data-testid="comment-content"]').find(Boolean) || el;
    }
    function commentPermalink(c, id) {
        if (c?.permalink) return `https://www.reddit.com${c.permalink}`;
        const pid = currentPostId();
        return pid ? `https://www.reddit.com/comments/${pid}/_/${id}/` : `https://www.reddit.com/comment/${id}/`;
    }
    function restoredCommentHeader(c, id, authorsChanged) {
        const author = c?.author && !isDeletedAuthor(c.author) ? c.author : "";
        const authorHTML = author ? `<a class="ru-enhanced-author" href="/user/${encodeURIComponent(author)}/" target="_self">u/${esc(author)}</a>` : "unknown author";
        const link = esc(commentPermalink(c, id));
        return `<div class="ru-enhanced-meta">↺ restored deleted comment · ${authorHTML} · <a href="${link}" target="_blank" rel="noopener noreferrer">t1_${esc(id)}</a></div>`;
    }
    function restoreComment(el, c, parts) {
        const id = normId(c.id || c.name || commentId(el));
        if (!archiveMatchesOldCommentPosition(el, c, id)) return {
            authors: 0,
            bodies: 0
        };
        let authors = 0, bodies = 0;
        if (parts.author) authors += replaceAuthor(el, c.author);
        if (parts.body && !el.querySelector(`[data-ru-comment="${id}"]`)) {
            const body = htmlFrom(c, "body");
            if (body) {
                el.setAttribute?.("data-ru-restored-comment-id", id);
                const marker = directQuery(el, '.usertext-body .md, [slot="comment"], [id$="-comment-rtjson-content"], .md').find(e => looksRemoved(e.textContent));
                const html = `<div class="ru-enhanced-comment-body" data-ru-comment="${esc(id)}">${restoredCommentHeader(c, id, authors > 0)}${body}</div>`;
                if (marker) marker.insertAdjacentHTML("afterend", html); else {
                    const target = commentInsertTarget(el);
                    if (isOldReddit() && el.matches?.('.thing.comment, .comment')) target.insertAdjacentHTML("beforeend", html); else if (target !== el && target.matches?.('[slot="comment"], [id$="-comment-rtjson-content"]')) target.insertAdjacentHTML("afterend", html); else target.insertAdjacentHTML("beforeend", html);
                }
                attachMediaFailureHandlers(el);
                bodies++;
            }
        }
        if (bodies) state.doneComments.add(id);
        return {
            authors: authors,
            bodies: bodies
        };
    }
    async function processComments() {
        const candidates = commentNodes().map(el => ({
            el: el,
            id: commentId(el),
            parts: commentParts(el)
        })).filter(x => x.id && x.parts.any && (!state.doneComments.has(x.id) || !restoredCommentPresent(x.el, x.id)));
        if (!candidates.length) return await processOldNoIdComments();
        const map = await fetchCommentsByIds(candidates.map(x => x.id));
        let commentAuthors = 0, commentBodies = 0;
        candidates.forEach(x => {
            const c = map.get(normId(x.id));
            if (!c) return;
            const r = restoreComment(x.el, c, x.parts);
            commentAuthors += r.authors;
            commentBodies += r.bodies;
        });
        const extra = await processOldNoIdComments();
        commentAuthors += extra.commentAuthors;
        commentBodies += extra.commentBodies;
        return {
            commentAuthors: commentAuthors,
            commentBodies: commentBodies,
            looked: candidates.length + extra.looked
        };
    }
    async function run(force = false) {
        const pid = currentPostId();
        if (!pid || state.running) return;
        const parts = postDeletedParts();
        const cands = commentNodes().map(el => ({
            el: el,
            id: commentId(el),
            parts: commentParts(el)
        })).filter(x => x.id && x.parts.any && (!state.doneComments.has(x.id) || !restoredCommentPresent(x.el, x.id)));
        const previousTotal = state.lastStats ? state.lastStats.postText + state.lastStats.postMedia + state.lastStats.authors + state.lastStats.commentAuthors + state.lastStats.commentBodies : 0;
        const oldNoIdMayNeedCheck = isOldReddit() && oldNoIdDeletedNodes().length > 0;
        if (!force && !parts.any && !cands.length && !oldNoIdMayNeedCheck) {
            if (previousTotal) status("✓", `Visible scan: previously restored ${previousTotal} item(s). Expand/scroll for more; Shift-click rescans.`); else status("·", "Idle: no deleted post/comment text or author detected. Click to rescan.");
            return;
        }
        state.running = true;
        disconnectObserver();
        ensureStyle();
        status("…", `In progress: checking archives for ${parts.any ? "post" : ""}${parts.any && cands.length ? " and " : ""}${cands.length ? cands.length + " comment(s)" : ""}.`);
        const stats = {
            postText: 0,
            postMedia: 0,
            authors: 0,
            commentAuthors: 0,
            commentBodies: 0,
            failures: []
        };
        try {
            try {
                if (parts.any) {
                    const post = await fetchPost(pid);
                    if (post) Object.assign(stats, {
                        ...stats,
                        ...restorePost(post, parts)
                    }); else if (parts.any) stats.failures.push("post not found in archives");
                }
            } catch (e) {
                stats.failures.push(`post lookup failed: ${e.message || e}`);
            }
            try {
                const cr = await processComments();
                stats.commentAuthors = cr.commentAuthors;
                stats.commentBodies = cr.commentBodies;
            } catch (e) {
                stats.failures.push(`comment lookup failed: ${e.message || e}`);
            }
            const total = stats.postText + stats.postMedia + stats.authors + stats.commentAuthors + stats.commentBodies;
            if (total || !previousTotal) state.lastStats = stats;
            if (stats.failures.length && total) status("!", `Partial: restored ${total}; ${stats.failures.join("; ")}. Click toggles original/restored; Shift-click rescans.`); else if (stats.failures.length) status("×", `Failed: ${stats.failures.join("; ")}. Click rescans.`); else if (total) status("✓", `Visible scan: restored ${stats.postText} post text, ${stats.postMedia} media, ${stats.authors + stats.commentAuthors} username(s), ${stats.commentBodies} comment body/bodies. Expand/scroll for more; Shift-click rescans.`); else if (previousTotal) status("✓", `Visible scan: already restored ${previousTotal} item(s). Expand/scroll for more; Shift-click rescans.`); else status("Ø", "Done: deleted-looking content was detected, but no matching archived replacement was found or DOM replacement was not possible. Shift-click rescans.");
        } finally {
            state.running = false;
            reconnectObserver();
        }
    }
    function disconnectObserver() {
        if (state.observer) state.observer.disconnect();
    }
    function reconnectObserver() {
        if (state.observer) {
            state.observer.observe(document.documentElement, {
                childList: true,
                subtree: true
            });
        }
    }
    function watch() {
        let t;
        state.observer = new MutationObserver(() => {
            clearTimeout(t);
            t = setTimeout(() => {
                const pid = currentPostId();
                if (pid !== state.postId) {
                    state.postId = pid;
                    state.doneComments.clear();
                    state.observerPasses = 0;
                }
                state.observerPasses++;
                run(false).catch(e => {
                    state.running = false;
                    status("×", `Failed: ${e.message || e}`);
                });
            }, 1500);
        });
        state.observer.observe(document.documentElement, {
            childList: true,
            subtree: true
        });
        window.addEventListener("popstate", () => setTimeout(() => {
            state.postId = null;
            run(true);
        }, 700));
    }
    if (/\/comments\/[a-z0-9]+/i.test(location.pathname)) {
        ensureStyle();
        status("…", "Starting: waiting for Reddit content.");
        state.postId = currentPostId();
        setTimeout(() => run(false), 700);
        setTimeout(() => run(false), 2200);
        watch();
    }
})();