Skip to content

Instantly share code, notes, and snippets.

@guider23
Last active August 25, 2025 02:08
Show Gist options
  • Select an option

  • Save guider23/e9ed427bf8cc116f2407ff49117f2556 to your computer and use it in GitHub Desktop.

Select an option

Save guider23/e9ed427bf8cc116f2407ff49117f2556 to your computer and use it in GitHub Desktop.
Automate Reddit Sharing Button
(function () {
async function redditShareClickerDeep_resilient() {
if (window.redditShareClickerDeepRunning) {
console.log("redditShareClickerDeep already running. Stop with: window.redditShareClickerStop = true");
return;
}
window.redditShareClickerDeepRunning = true;
window.redditShareClickerStop = false;
const sleep = ms => new Promise(res => setTimeout(res, ms));
const rand = (a,b) => a + Math.random()*(b-a);
function querySelectorAllDeep(selector, root = document) {
const results = new Set();
const nodes = [root];
while (nodes.length) {
const node = nodes.shift();
try {
const found = node.querySelectorAll ? node.querySelectorAll(selector) : [];
for (const f of found) results.add(f);
} catch (e) { }
let childElems = [];
try { childElems = node.querySelectorAll ? node.querySelectorAll('*') : []; } catch(e){ childElems = []; }
for (const ch of childElems) {
if (ch.shadowRoot) nodes.push(ch.shadowRoot);
}
}
return Array.from(results);
}
function isSinglePostView() {
try {
const p = location.pathname || '';
if (p.includes('/comments/')) return true;
if (document.querySelector('[data-test-id="post-content"], .Comment, #comments')) return true;
} catch (e) {}
return false;
}
function getPostKey(post) {
try {
const custom = (querySelectorAllDeep('shreddit-post-share-button', post) || [])[0];
if (custom) {
const sid = custom.getAttribute && custom.getAttribute('source-id');
if (sid) return sid;
}
const cA = post.querySelector && post.querySelector('a[data-click-id="comments"], a[href*="/comments/"]');
if (cA) {
const href = cA.href || cA.getAttribute('href') || '';
const m = href.match(/\/comments\/([^\/?#]+)/);
if (m && m[1]) return 'comments:' + m[1];
return 'commentsHref:' + href;
}
const vid = post.getAttribute && (post.getAttribute('id') || post.dataset?.postId || post.dataset?.id);
if (vid) return 'id:' + vid;
const html = (post.outerHTML || '').slice(0,400);
let h = 0;
for (let i=0;i<html.length;i++) h = ((h<<5)-h) + html.charCodeAt(i);
return 'hash:' + (h >>> 0);
} catch (e) { return 'unknown:' + Math.random(); }
}
function findCopyMenuItemsDeep() {
const candidates = querySelectorAllDeep('button, a, [role="menuitem"], [role="button"], li, span, div');
const re = /(copy link|copy permalink|copy post link|copy post permalink|copy url|copy link to post|copy)/i;
return candidates.filter(n => {
try {
const txt = (n.innerText || n.textContent || '').trim();
if (re.test(txt)) return true;
const aria = (n.getAttribute && (n.getAttribute('aria-label') || n.getAttribute('title') || '')) || '';
if (re.test(aria)) return true;
} catch (e) {}
return false;
});
}
function isVisible(el) {
if (!el || !el.getBoundingClientRect) return false;
const r = el.getBoundingClientRect();
if (r.width === 0 || r.height === 0) return false;
if (r.bottom < 0 || r.top > (window.innerHeight || document.documentElement.clientHeight)) return false;
const style = window.getComputedStyle(el);
if (style && (style.visibility === 'hidden' || style.display === 'none' || style.opacity === '0')) return false;
return true;
}
function distanceBetweenRects(a, b) {
const ax = a.left + a.width/2, ay = a.top + a.height/2;
const bx = b.left + b.width/2, by = b.top + b.height/2;
return Math.hypot(ax - bx, ay - by);
}
function robustClickWithShadowFallback(el) {
if (!el) return false;
try {
el.click();
return true;
} catch (e) {}
try {
const evOpts = { bubbles: true, cancelable: true, view: window };
el.dispatchEvent(new MouseEvent('mousedown', evOpts));
el.dispatchEvent(new MouseEvent('mouseup', evOpts));
el.dispatchEvent(new MouseEvent('click', evOpts));
return true;
} catch (e) {
try {
if (el.shadowRoot) {
const btn = el.shadowRoot.querySelector('button, [role="button"], .icon-button');
if (btn) {
btn.click();
return true;
}
}
} catch (err) {}
console.warn('robustClickWithShadowFallback failed:', e);
}
return false;
}
async function attemptReturnToListing(listingUrl) {
try {
history.back();
await sleep(900);
if (!isSinglePostView()) return true;
} catch (e) {}
try {
if (listingUrl && listingUrl !== location.href) {
location.href = listingUrl;
await sleep(1200);
if (!isSinglePostView()) return true;
}
} catch (e) {}
try {
location.href = 'https://www.reddit.com/';
await sleep(1200);
if (!isSinglePostView()) return true;
} catch (e) {}
return !isSinglePostView();
}
console.log("redditShareClickerDeep (resilient) started — Stop with: window.redditShareClickerStop = true");
const processedKeys = new Set();
let touchedCount = 0;
let iteration = 0;
let savedListingUrl = location.href;
try {
while (!window.redditShareClickerStop) {
iteration++;
if (isSinglePostView()) {
console.log('Detected single-post view. Trying to return to listing.');
const ok = await attemptReturnToListing(savedListingUrl);
if (!ok) {
console.warn('Could not return to listing automatically. Stopping script to avoid lock-in.');
break;
} else {
console.log('Returned to listing.');
}
}
if (!isSinglePostView()) savedListingUrl = location.href;
let postCandidates = querySelectorAllDeep('article, [data-testid="post-container"], .Post');
postCandidates = postCandidates.filter(p => p && isVisible(p));
if (postCandidates.length === 0) {
const hosts = querySelectorAllDeep('shreddit-post-share-button');
for (const host of hosts) {
let ancestor = host;
while (ancestor && ancestor.nodeType === 1 && !ancestor.matches?.('article, [data-testid="post-container"], .Post')) {
ancestor = ancestor.parentElement || ancestor.getRootNode()?.host;
}
if (ancestor && !postCandidates.includes(ancestor)) postCandidates.push(ancestor);
}
}
if (postCandidates.length === 0) {
window.scrollBy({ top: window.innerHeight * 0.75, behavior: 'smooth' });
await sleep(rand(800, 1500));
continue;
}
let progress = false;
for (const post of postCandidates) {
if (window.redditShareClickerStop) break;
if (!post) continue;
const key = getPostKey(post);
if (processedKeys.has(key)) continue;
processedKeys.add(key);
progress = true;
if (isSinglePostView()) {
const ok = await attemptReturnToListing(savedListingUrl);
if (!ok) break;
}
try { if (post.scrollIntoView) post.scrollIntoView({ behavior: 'smooth', block: 'center' }); } catch(e){}
await sleep(rand(450, 900));
const shareEl = (function findShareButtonDeepWithin(postRoot) {
try {
const custom = querySelectorAllDeep('shreddit-post-share-button', postRoot).find(x => postRoot.contains(x) || (x.getRootNode && x.getRootNode() === postRoot));
if (custom) return custom;
} catch(e){}
const selectors = [
'button[aria-label="Share"]',
'button[aria-label="share"]',
'a[data-click-id="share"]',
'button[title="Share"]',
'button[aria-label*="share"]',
'div[role="button"][data-click-id="share"]'
];
for (const sel of selectors) {
const found = querySelectorAllDeep(sel, postRoot);
if (found && found.length) {
for (const f of found) if (isVisible(f)) return f;
return found[0];
}
}
const textCandidates = querySelectorAllDeep('button, a, div[role="button"], span', postRoot)
.filter(el => {
try {
const t = (el.innerText || el.textContent || '').trim().toLowerCase();
return t && t.includes('share');
} catch(e){ return false; }
});
if (textCandidates.length) return textCandidates[0];
return null;
})(post);
if (!shareEl) {
console.log('No share button (deep) found for a post — skipping.');
await sleep(rand(200, 500));
continue;
}
const beforeHref = location.href;
robustClickWithShadowFallback(shareEl);
await sleep(rand(350, 900));
if (location.href !== beforeHref || isSinglePostView()) {
console.warn('Click caused navigation or we entered a post — attempting to recover.');
const ok = await attemptReturnToListing(savedListingUrl || beforeHref);
if (!ok) {
console.error('Unable to recover from accidental post navigation. Stopping to avoid lock-in.');
window.redditShareClickerStop = true;
break;
} else {
console.log('Recovered to listing page — marking this post as processed and continuing.');
touchedCount++;
await sleep(rand(700, 1200));
continue;
}
}
const candidates = findCopyMenuItemsDeep();
let chosen = null;
if (candidates.length) {
let shareRect = { left: window.innerWidth/2, top: window.innerHeight/2, width: 0, height: 0 };
try { shareRect = shareEl.getBoundingClientRect(); } catch(e){}
let scored = candidates.map(c => {
try { return { el: c, rect: c.getBoundingClientRect(), txt: (c.innerText||c.textContent||'').trim() }; } catch(e){ return {el:c,rect:shareRect,txt:''}; }
}).map(o => ({ ...o, dist: distanceBetweenRects(shareRect, o.rect) }));
scored.sort((a,b) => a.dist - b.dist);
chosen = scored[0]?.el;
}
if (chosen && isVisible(chosen)) {
try {
chosen.click();
touchedCount++;
console.log(`Clicked Copy item for a post (#${touchedCount}).`);
} catch (e) {
try {
chosen.dispatchEvent(new MouseEvent('mousedown', { bubbles:true }));
chosen.dispatchEvent(new MouseEvent('mouseup', { bubbles:true }));
chosen.dispatchEvent(new MouseEvent('click', { bubbles:true }));
touchedCount++;
console.log(`Clicked Copy item (via dispatched events) for a post (#${touchedCount}).`);
} catch (err) {
console.warn('Failed to click copy item, but share was opened (counted).', err);
touchedCount++;
}
}
} else {
console.log('Copy item not found after opening share, but share clicked (counted as touched).');
touchedCount++;
}
await sleep(rand(400, 1200));
try { document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles:true })); } catch(e){}
await sleep(120);
}
if (!progress) {
window.scrollBy({ top: window.innerHeight * 0.9, behavior: 'smooth' });
await sleep(rand(900, 1500));
} else {
window.scrollBy({ top: window.innerHeight * 0.45, behavior: 'smooth' });
await sleep(rand(700, 1300));
}
if (iteration % 5 === 0) console.log(`Iteration ${iteration} — touchedCount ${touchedCount}`);
}
} catch (err) {
console.error('redditShareClickerDeep encountered an error:', err);
} finally {
console.log('redditShareClickerDeep stopped. total touched:', touchedCount);
window.redditShareClickerDeepRunning = false;
}
}
function _escapeHtml(s) {
return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
const runnableSource = "(" + redditShareClickerDeep_resilient.toString() + ")();";
const host = location.hostname || "";
const isRedditHost = /(^|\.)reddit\.com$/.test(host) || host.endsWith('.reddit.com');
if (isRedditHost) {
try {
(0, eval)(runnableSource);
} catch (e) {
console.error("Failed to eval the redditShareClickerDeep script in this context:", e);
}
return;
}
try {
const newTab = window.open('https://www.reddit.com', '_blank');
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(runnableSource).then(() => {
alert('Opened reddit in a new tab and copied the runnable script to your clipboard.\n\nSwitch to the reddit tab, open the console (F12) and paste (Ctrl+V) + Enter to run.');
}).catch(() => {
const blobHtml = '<!doctype html><meta charset="utf-8"><title>Reddit script — copy</title>' +
'<p>Copy the script below, switch to Reddit tab, open console, paste & Enter:</p>' +
'<textarea style="width:100%;height:70vh;">' + _escapeHtml(runnableSource) + '</textarea>';
const blob = new Blob([blobHtml], { type: 'text/html' });
window.open(URL.createObjectURL(blob), '_blank');
alert('Opened reddit in a new tab. Clipboard copy blocked — a new page with the script has been opened for manual copy.');
});
} else {
const blobHtml = '<!doctype html><meta charset="utf-8"><title>Reddit script — copy</title>' +
'<p>Copy the script below, switch to Reddit tab, open console, paste & Enter:</p>' +
'<textarea style="width:100%;height:70vh;">' + _escapeHtml(runnableSource) + '</textarea>';
const blob = new Blob([blobHtml], { type: 'text/html' });
window.open(URL.createObjectURL(blob), '_blank');
alert('Opened reddit in a new tab. Clipboard unavailable — a new page with the script has been opened for manual copy.');
}
} catch (err) {
console.error('Failed to open reddit or copy script automatically:', err);
alert('Could not open reddit or copy script automatically. The runnable script is available in the variable `runnableSource` in this console. Copy it and paste into reddit console manually.');
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment