Guest User

Untitled

a guest
Jun 17th, 2025
23
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name         RG Tweet Video Remover with Catalog
  3. // @namespace    http://tampermonkey.net/
  4. // @version      2.0
  5. // @description  Remove tweet_video posts, catalog any /status/ URLs (any domain), with copy and collapsible UI
  6. // @author       you
  7. // @match        *://nitter.privacydev.net/*
  8. // @match        *://nitter.poast.org/*
  9. // @match        *://xcancel.com/*
  10. // @match        *://lightbrd.com/*
  11. // @match        *://nitter.net/*
  12. // @grant        GM_setClipboard
  13. // ==/UserScript==
  14.  
  15. (function() {
  16.     'use strict';
  17.  
  18.     let isActive = false;
  19.     let observer = null;
  20.     let deletedUrls = new Set();
  21.  
  22.     function isDarkMode() {
  23.         return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
  24.     }
  25.  
  26.     function getStatusUrls(item) {
  27.         let urls = [];
  28.         let links = item.querySelectorAll('a[href*="/status/"]');
  29.         for (let a of links) {
  30.             // Regex matches any "/status/1234567" style URL
  31.             let match = a.href.match(/.+\/status\/\d+/);
  32.             if (match && !urls.includes(match)) {
  33.                 urls.push(match);
  34.             }
  35.         }
  36.         return urls;
  37.     }
  38.  
  39.     function removeRelevantPosts() {
  40.         const items = document.querySelectorAll('.timeline-item, article, [data-testid="tweet"]');
  41.         items.forEach(function(item) {
  42.             if (
  43.                 item.innerHTML.includes('video.twimg.com%2Ftweet_video%2F') ||
  44.                 item.innerHTML.includes('video.twimg.com/tweet_video/')
  45.             ) {
  46.                 let urls = getStatusUrls(item);
  47.                 urls.forEach(url => {
  48.                     if (!deletedUrls.has(url)) {
  49.                         deletedUrls.add(url);
  50.                         addUrlToCatalog(url);
  51.                     }
  52.                 });
  53.                 item.remove();
  54.             }
  55.         });
  56.     }
  57.  
  58.     // RG Toggle Button
  59.     let fabButton = document.createElement('button');
  60.     fabButton.textContent = "RG ";
  61.     fabButton.setAttribute('aria-label', 'Remove GIF posts');
  62.     fabButton.title = 'RG Inactive: Click to activate';
  63.     fabButton.style.position = 'fixed';
  64.     fabButton.style.bottom = '24px';
  65.     fabButton.style.left = '116px';
  66.     fabButton.style.zIndex = '99999';
  67.     fabButton.style.fontSize = '18px';
  68.     fabButton.style.padding = '10px 18px';
  69.     fabButton.style.borderRadius = '24px';
  70.     fabButton.style.border = '1.5px solid #ccc';
  71.     fabButton.style.boxShadow = '0 4px 24px rgba(0,0,0,0.11)';
  72.     fabButton.style.fontWeight = 'bold';
  73.     fabButton.style.cursor = 'pointer';
  74.     fabButton.style.transition = 'background 0.2s,color 0.2s';
  75.     fabButton.style.background = isDarkMode() ? '#222' : '#fff';
  76.     fabButton.style.color = isDarkMode() ? '#fff' : '#005940';
  77.     fabButton.style.userSelect = 'none';
  78.     document.body.appendChild(fabButton);
  79.  
  80.     // Catalog UI (collapsible)
  81.     let catalogUI = document.createElement('div');
  82.     catalogUI.style.position = 'fixed';
  83.     catalogUI.style.left = '116px';
  84.     catalogUI.style.bottom = '76px';
  85.     catalogUI.style.zIndex = '99999';
  86.     catalogUI.style.minWidth = '272px';
  87.     catalogUI.style.maxWidth = '330px';
  88.     catalogUI.style.maxHeight = '300px';
  89.     catalogUI.style.overflowY = 'auto';
  90.     catalogUI.style.background = isDarkMode() ? '#232629' : '#fbfbfb';
  91.     catalogUI.style.color = isDarkMode() ? '#fff' : '#212121';
  92.     catalogUI.style.border = '1.5px solid #ccc';
  93.     catalogUI.style.borderRadius = '12px';
  94.     catalogUI.style.boxShadow = '0 4px 24px rgba(0,0,0,0.12)';
  95.     catalogUI.style.padding = '10px 10px 8px 12px';
  96.     catalogUI.style.fontSize = '15px';
  97.     catalogUI.style.display = 'flex';
  98.     catalogUI.style.flexDirection = 'column';
  99.     catalogUI.style.gap = '7px';
  100.     catalogUI.style.userSelect = 'text';
  101.  
  102.     // Collapsible header
  103.     const catalogHeader = document.createElement('div');
  104.     catalogHeader.style.display = 'flex';
  105.     catalogHeader.style.justifyContent = 'space-between';
  106.     catalogHeader.style.alignItems = 'center';
  107.     catalogHeader.style.cursor = 'pointer';
  108.     catalogHeader.style.paddingBottom = '6px';
  109.     catalogHeader.style.borderBottom = '1px solid #ccc';
  110.  
  111.     const headerTitle = document.createElement('span');
  112.     headerTitle.textContent = '🗂️ Removed Status URLs';
  113.  
  114.     const collapseBtn = document.createElement('span');
  115.     collapseBtn.textContent = '▾'; // Collapsed: '▸', Expanded: '▾'
  116.     collapseBtn.style.fontSize = '14px';
  117.     collapseBtn.style.marginLeft = '7px';
  118.  
  119.     catalogHeader.appendChild(headerTitle);
  120.     catalogHeader.appendChild(collapseBtn);
  121.  
  122.     // URL List
  123.     const urlList = document.createElement('div');
  124.     urlList.id = 'rg-url-list';
  125.     urlList.style.margin = '7px 0 0 0';
  126.     urlList.style.display = 'block';
  127.  
  128.     // Copy button
  129.     const copyBtn = document.createElement('button');
  130.     copyBtn.textContent = '📋';
  131.     copyBtn.title = 'Copy all URLs';
  132.     copyBtn.style.margin = '3px 0 0 3px';
  133.     copyBtn.style.border = '1px solid #bbb';
  134.     copyBtn.style.borderRadius = '6px';
  135.     copyBtn.style.padding = '3px 7px';
  136.     copyBtn.style.background = isDarkMode() ? '#333' : '#eee';
  137.     copyBtn.style.color = isDarkMode() ? '#fff' : '#222';
  138.     copyBtn.style.fontSize = '15px';
  139.     copyBtn.style.cursor = 'pointer';
  140.     copyBtn.style.alignSelf = 'flex-start';
  141.     copyBtn.style.transition = 'background 0.15s';
  142.  
  143.     copyBtn.addEventListener('click', function () {
  144.         const allUrls = Array.from(deletedUrls).join('\n');
  145.         if (typeof GM_setClipboard !== 'undefined') {
  146.             GM_setClipboard(allUrls, { type: 'text', mimetype: 'text/plain' });
  147.         } else if (navigator.clipboard) {
  148.             navigator.clipboard.writeText(allUrls);
  149.         }
  150.         copyBtn.textContent = '✅';
  151.         setTimeout(() => (copyBtn.textContent = '📋'), 900);
  152.     });
  153.  
  154.     // Collapse functionality
  155.     let collapsed = false;
  156.     catalogHeader.addEventListener('click', function () {
  157.         collapsed = !collapsed;
  158.         urlList.style.display = collapsed ? 'none' : 'block';
  159.         copyBtn.style.display = collapsed ? 'none' : 'inline-block';
  160.         collapseBtn.textContent = collapsed ? '▸' : '▾';
  161.     });
  162.  
  163.     // Add children to catalog UI
  164.     catalogUI.appendChild(catalogHeader);
  165.     catalogUI.appendChild(copyBtn);
  166.     catalogUI.appendChild(urlList);
  167.     document.body.appendChild(catalogUI);
  168.  
  169.     function addUrlToCatalog(url) {
  170.         if (document.getElementById('rg-url-' + btoa(url))) return;
  171.         const urlBox = document.createElement('div');
  172.         urlBox.textContent = url;
  173.         urlBox.style.background = isDarkMode() ? '#181c1f' : '#f2f2f4';
  174.         urlBox.style.borderRadius = '4px';
  175.         urlBox.style.padding = '4px 7px';
  176.         urlBox.style.margin = '2px 0';
  177.         urlBox.style.wordBreak = 'break-all';
  178.         urlBox.id = 'rg-url-' + btoa(url);
  179.         urlList.appendChild(urlBox);
  180.     }
  181.  
  182.     function refreshCatalogTheme() {
  183.         catalogUI.style.background = isDarkMode() ? '#232629' : '#fbfbfb';
  184.         catalogUI.style.color = isDarkMode() ? '#fff' : '#212121';
  185.         copyBtn.style.background = isDarkMode() ? '#333' : '#eee';
  186.         copyBtn.style.color = isDarkMode() ? '#fff' : '#222';
  187.         urlList.querySelectorAll('div').forEach(el => {
  188.             el.style.background = isDarkMode() ? '#181c1f' : '#f2f2f4';
  189.         });
  190.         fabButton.style.background = isDarkMode() ? (isActive ? '#048848':'#222') : (isActive ? '#23be78':'#fff');
  191.         fabButton.style.color = isDarkMode() ? '#fff' : (isActive ? '#fff' : '#005940');
  192.     }
  193.  
  194.     function setButtonActive(active) {
  195.         if(active){
  196.             removeRelevantPosts();
  197.             observer = new MutationObserver(() => {
  198.                 removeRelevantPosts();
  199.             });
  200.             observer.observe(document.body, {childList:true, subtree:true});
  201.             fabButton.style.background = isDarkMode() ? '#048848' : '#23be78';
  202.             fabButton.style.color = '#fff';
  203.             fabButton.title = 'RG Active: Hides tweet_video posts';
  204.         } else {
  205.             if(observer) observer.disconnect();
  206.             observer = null;
  207.             fabButton.style.background = isDarkMode() ? '#222' : '#fff';
  208.             fabButton.style.color = isDarkMode() ? '#fff' : '#005940';
  209.             fabButton.title = 'RG Inactive: Click to activate';
  210.         }
  211.         refreshCatalogTheme();
  212.     }
  213.  
  214.     fabButton.addEventListener('click', function() {
  215.         isActive = !isActive;
  216.         setButtonActive(isActive);
  217.     });
  218.  
  219.     // On page reload
  220.     window.addEventListener("pageshow",function(){
  221.         setButtonActive(isActive);
  222.     });
  223.  
  224.     // Update on dark/light change
  225.     window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', refreshCatalogTheme);
  226.  
  227.     fabButton.style.pointerEvents = 'auto';
  228.     catalogUI.style.pointerEvents = 'auto';
  229.  
  230.     fabButton.id = '__rg_fab_button';
  231.     catalogUI.id = '__rg_catalog_ui';
  232.  
  233. })();
Advertisement
Add Comment
Please, Sign In to add comment