Guest User

Untitled

a guest
May 13th, 2025
34
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. javascript:(function() {
  2.   console.log('[Reddit BBCode Tool] Activated - Click copy buttons on posts/comments');
  3.   const USE_DATA_URL_FOR_IMAGES = false;
  4.  
  5.   function htmlToBBCode(html) {
  6.     const textarea = document.createElement('textarea');
  7.     textarea.innerHTML = html;
  8.     const decoded = textarea.value;
  9.     return decoded
  10.       .replace(/<h1>([\s\S]+?)<\/h1>/g, '[HEADING=1][b]$1[/b][/HEADING]\n\n')
  11.       .replace(/<h2>([\s\S]+?)<\/h2>/g, '[HEADING=2][b]$1[/b][/HEADING]\n\n')
  12.       .replace(/<h3>([\s\S]+?)<\/h3>/g, '[HEADING=3][b]$1[/b][/HEADING]\n\n')
  13.       .replace(/<a href="([^"]+)"[^>]*>([\s\S]+?)<\/a>/g, (m, url, text) => {
  14.         const cleanUrl = url.replace(/&/g, '&amp;');
  15.         const cleanText = text.replace(/<(?!\/?(?:b|i|s|u)\b)[^>]*>/gi, '');
  16.         return `[u][url='${cleanUrl}']${cleanText}[/url][/u]`;
  17.       })
  18.       .replace(/<img src="([^"]+)"[^>]*>/g, '[img]$1[/img]')
  19.       .replace(/<(b|strong)>([^<]+)<\/(b|strong)>/g, '[b]$2[/b]')
  20.       .replace(/<(i|em)>([^<]+)<\/(i|em)>/g, '[i]$2[/i]')
  21.       .replace(/<s>([^<]+)<\/s>/g, '[s]$1[/s]')
  22.       .replace(/<blockquote>([\s\S]+?)<\/blockquote>/g, '[quote]$1[/quote]')
  23.       .replace(/<pre>([\s\S]+?)<\/pre>/g, '[code]$1[/code]')
  24.       .replace(/<code>([^<]+)<\/code>/g, '[icode]$1[/icode]')
  25.       .replace(/<ol>([\s\S]+?)<\/ol>/g, (match, listContent) => '[LIST=1]\n' + listContent.replace(/<li>([\s\S]+?)<\/li>/g, '[*] $1\n') + '[/LIST]')
  26.       .replace(/<ul>([\s\S]+?)<\/ul>/g, (match, listContent) => '[LIST]\n' + listContent.replace(/<li>([\s\S]+?)<\/li>/g, '[*] $1\n') + '[/LIST]')
  27.       .replace(/<\/p>|<\s*br\s*\/?>/gi, '\n')
  28.       .replace(/<\/?[^>]+>/g, '')
  29.       .replace(/&amp;/g, '&')
  30.       .replace(/\n{3,}/g, '\n\n')
  31.       .replace(/^\s+|\s+$/g, '');
  32.   }
  33.  
  34.   function extractTextWithLinks(html) {
  35.     const parser = new DOMParser();
  36.     const doc = parser.parseFromString(html, 'text/html');
  37.     let text = doc.body.innerText.trim();
  38.     const links = Array.from(doc.body.querySelectorAll('a'));
  39.     const images = Array.from(doc.body.querySelectorAll('img'));
  40.     let reconstructedText = text;
  41.     links.forEach(link => {
  42.       const linkText = link.textContent.trim();
  43.       const linkUrl = link.href;
  44.       reconstructedText = reconstructedText.replace(linkText, `[u][url]${linkUrl}[/url][/u]`);
  45.     });
  46.     images.forEach(image => {
  47.       let src = image.src;
  48.       if (USE_DATA_URL_FOR_IMAGES) {
  49.         src = image.getAttribute('data-url') || src.replace(/preview\\.redd\\.it/, 'i.redd.it');
  50.       }
  51.       reconstructedText += `\n[img]${src}[/img]`;
  52.     });
  53.     return reconstructedText.trim();
  54.   }
  55.  
  56.   function extractPostUrl(element) {
  57.     return element.querySelector('a.bylink[href*="/comments/"]')?.href || element.querySelector('a.title[href*="/comments/"]')?.href || (element.hasAttribute('data-permalink') ? `https://www.reddit.com${element.getAttribute('data-permalink')}` : window.location.href);
  58.   }
  59.  
  60.   function getParentComments(commentElement, maxDepth = 10) {
  61.     const parents = [];
  62.     const seenIds = new Set();
  63.     let currentComment = commentElement.closest('.thing.comment, shreddit-comment');
  64.  
  65.     while (currentComment && parents.length < maxDepth) {
  66.       let parentId = null;
  67.       let parentCommentElement = null;
  68.  
  69.      
  70.       parentId = currentComment.getAttribute('parentid');
  71.       if (parentId && parentId.startsWith('t1_')) {
  72.         parentCommentElement = document.querySelector(`shreddit-comment[thingid="${parentId}"]`);
  73.       }
  74.  
  75.      
  76.       if (!parentCommentElement) {
  77.         const parentLink = currentComment.querySelector('a[data-parent-id]');
  78.         if (parentLink) {
  79.           parentId = parentLink.getAttribute('data-parent-id');
  80.           if (parentId.startsWith('t1_')) {
  81.             parentCommentElement = document.querySelector(`.thing.comment[data-fullname="${parentId}"]`);
  82.           }
  83.         } else {
  84.          
  85.           const parentThing = currentComment.parentElement.closest('.thing.comment');
  86.           if (parentThing) {
  87.             parentId = parentThing.getAttribute('data-fullname') || parentThing.id;
  88.             parentCommentElement = parentThing;
  89.           }
  90.         }
  91.       }
  92.  
  93.       if (!parentCommentElement || !parentId || seenIds.has(parentId)) {
  94.         break;
  95.       }
  96.       seenIds.add(parentId);
  97.  
  98.       const datetime = parentCommentElement.querySelector('time')?.getAttribute('title') || parentCommentElement.querySelector('time')?.getAttribute('datetime') || 'Unknown';
  99.       const contentHtml = parentCommentElement.querySelector('.md, div[slot="comment"]');
  100.       const permalink = parentCommentElement.querySelector('a.bylink')?.href || (parentCommentElement.getAttribute('permalink') ? `https://www.reddit.com${parentCommentElement.getAttribute('permalink')}` : window.location.href);
  101.       const contentText = contentHtml ? extractTextWithLinks(contentHtml.innerHTML) : 'No content';
  102.       const contentBBCode = htmlToBBCode(contentText);
  103.  
  104.       parents.unshift({ permalink, spoilerContent: `[spoiler="text"]\nCommented on ${datetime}\n\n${contentBBCode}\n[/spoiler]` });
  105.       currentComment = parentCommentElement;
  106.     }
  107.     return parents;
  108.   }
  109.  
  110.   function createDepthDropdown(maxDepth, callback, button) {
  111.     const existingDropdown = document.querySelector('.depth-dropdown');
  112.     if (existingDropdown) existingDropdown.remove();
  113.     const dropdown = document.createElement('select');
  114.     dropdown.className = 'depth-dropdown';
  115.     dropdown.style.position = 'absolute';
  116.     dropdown.style.marginLeft = '5px';
  117.     dropdown.style.padding = '2px';
  118.     dropdown.style.fontSize = '12px';
  119.     for (let i = 0; i <= maxDepth; i++) {
  120.       const option = document.createElement('option');
  121.       option.value = i;
  122.       option.textContent = i === 0 ? 'Only this' : `${i} parent${i > 1 ? 's' : ''}`;
  123.       dropdown.appendChild(option);
  124.     }
  125.     dropdown.addEventListener('change', () => {
  126.       callback(parseInt(dropdown.value));
  127.       dropdown.remove();
  128.     });
  129.     dropdown.addEventListener('blur', () => dropdown.remove());
  130.     button.insertAdjacentElement('afterend', dropdown);
  131.     dropdown.focus();
  132.   }
  133.  
  134.   function createCopyButtons(element) {
  135.     const existingButtons = element.querySelectorAll('.copy-btn, .nested-btn');
  136.     existingButtons.forEach(btn => btn.remove());
  137.     const copyButton = document.createElement('button');
  138.     copyButton.textContent = 'πŸ“‹';
  139.     copyButton.title = 'Copy content to BBCode';
  140.     copyButton.className = 'copy-btn';
  141.     copyButton.style.cssText = 'cursor:pointer;background:green;color:white;margin-left:5px;padding:2px 6px;border:none;border-radius:4px;';
  142.     const nestedButton = document.createElement('button');
  143.     nestedButton.textContent = 'πŸ“‹';
  144.     nestedButton.title = 'Copy content with nested parents';
  145.     nestedButton.className = 'nested-btn';
  146.     nestedButton.style.cssText = 'cursor:pointer;background:blue;color:white;margin-left:5px;padding:2px 6px;border:none;border-radius:4px;';
  147.     if (element.tagName.toLowerCase() === 'shreddit-post' || element.classList.contains('thing') && element.classList.contains('link')) {
  148.       const url = extractPostUrl(element);
  149.       let header = '', body = '', images = new Set();
  150.       const title = element.querySelector('h1[slot="title"], .title > a')?.textContent.trim() || '';
  151.       const flair = element.querySelector('.linkflairlabel span')?.textContent.trim() || '';
  152.       const datetime = element.querySelector('time')?.getAttribute('title') || element.querySelector('time')?.getAttribute('datetime') || 'Unknown';
  153.       const videoUrl = element.dataset.url || element.getAttribute('data-url');
  154.       header = `${flair ? `[i][${flair}][/i] ` : ''}[b]${title}[/b]\n\n${url}\n\n`;
  155.       Array.from(element.querySelectorAll('gallery-carousel li img, .media-preview img'))
  156.         .forEach(img => {
  157.           let src = img.src;
  158.           if (USE_DATA_URL_FOR_IMAGES) {
  159.             src = img.getAttribute('data-url') || src.replace(/preview\\.redd\\.it/, 'i.redd.it');
  160.           }
  161.           if (!src.includes('redditstatic.com/video-') && !src.includes('old.reddit.com/static/checkmark.svg')) {
  162.             images.add(src);
  163.           }
  164.         });
  165.       const textBody = element.querySelector('div[slot="text-body"], .md');
  166.       if (textBody) body += htmlToBBCode(extractTextWithLinks(textBody.innerHTML));
  167.       const imgSection = Array.from(images).map(u => `[img]${u}[/img]`).join('\n');
  168.       const mediaContent = [`Posted on ${datetime}`, ...(imgSection ? [imgSection] : []), ...(videoUrl ? [videoUrl] : [])];
  169.       const fullPayload = `${header}[spoiler="text"]\n${mediaContent.join('\n\n')}\n\n${body.trim()}\n[/spoiler]`;
  170.       copyButton.addEventListener('click', (e) => {
  171.         e.preventDefault();
  172.         e.stopPropagation();
  173.         navigator.clipboard.writeText(fullPayload.replace(/\n{3,}/g, '\n\n'))
  174.           .then(() => showToast('Post copied!'))
  175.           .catch(err => console.error('[Reddit BBCode Tool] Copy failed:', err));
  176.       });
  177.       nestedButton.style.display = 'none';
  178.       const target = element.querySelector('div[slot="credit-bar"], .tagline') || element;
  179.       target.appendChild(copyButton);
  180.       target.appendChild(nestedButton);
  181.     } else if (element.tagName.toLowerCase() === 'shreddit-comment' || element.classList.contains('comment')) {
  182.       const permalink = element.getAttribute('permalink') ? `https://www.reddit.com${element.getAttribute('permalink')}` : element.querySelector('a.bylink')?.href || window.location.href;
  183.       const contentHtml = element.querySelector('div[slot="comment"], .md');
  184.       if (!contentHtml) {
  185.         console.log('[Reddit BBCode Tool] No content found for comment');
  186.         return;
  187.       }
  188.       const datetime = element.querySelector('time')?.getAttribute('title') || element.querySelector('time')?.getAttribute('datetime') || 'Unknown';
  189.       const contentText = extractTextWithLinks(contentHtml.innerHTML);
  190.       const contentBBCode = htmlToBBCode(contentText);
  191.       const spoilerContent = `[spoiler="text"]\nCommented on ${datetime}\n\n${contentBBCode}\n[/spoiler]`;
  192.       copyButton.addEventListener('click', (e) => {
  193.         e.preventDefault();
  194.         e.stopPropagation();
  195.         navigator.clipboard.writeText(`${permalink}\n${spoilerContent}`.replace(/\n{3,}/g, '\n\n'))
  196.           .then(() => showToast('Comment copied!'))
  197.           .catch(err => console.error('[Reddit BBCode Tool] Copy failed:', err));
  198.       });
  199.       nestedButton.addEventListener('click', (e) => {
  200.         e.preventDefault();
  201.         e.stopPropagation();
  202.         const parents = getParentComments(element);
  203.         const maxDepth = parents.length;
  204.         createDepthDropdown(maxDepth, (depth) => {
  205.           const items = [...parents.slice(0, depth), { permalink, spoilerContent }];
  206.           const payload = items
  207.             .map((item, index) => {
  208.               const indent = 'β”‚ '.repeat(index);
  209.               const commentLines = `${item.permalink}\n${item.spoilerContent}`.split('\n');
  210.               return commentLines.map(line => `${indent}${line}`).join('\n');
  211.             })
  212.             .join('\n\n').replace(/\n{3,}/g, '\n\n');
  213.           navigator.clipboard.writeText(payload)
  214.             .then(() => showToast(`Comment with ${depth} parent${depth === 1 ? '' : 's'} copied!`))
  215.             .catch(err => console.error('[Reddit BBCode Tool] Nested copy failed:', err));
  216.         }, nestedButton);
  217.       });
  218.       const target = element.querySelector('div[slot="actionRow"], .tagline') || element;
  219.       target.appendChild(copyButton);
  220.       target.appendChild(nestedButton);
  221.     }
  222.   }
  223.  
  224.   function showToast(message) {
  225.     const toast = document.createElement('div');
  226.     toast.textContent = message;
  227.     toast.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);padding:10px;border-radius:5px;background:#fff;color:#000;z-index:1000;box-shadow:0 0 10px rgba(0,0,0,0.2);';
  228.     document.body.appendChild(toast);
  229.     setTimeout(() => toast.remove(), 2000);
  230.   }
  231.  
  232.   document.querySelectorAll('shreddit-post, shreddit-comment, .thing.link, .thing.comment').forEach(createCopyButtons);
  233. })();
Advertisement
Add Comment
Please, Sign In to add comment