Reddit NSFW Unblur

Unblur nsfw in Shreddit

  1. // ==UserScript==
  2. // @name Reddit NSFW Unblur
  3. // @namespace https://greasyfork.org/users/821661
  4. // @match https://www.reddit.com/*
  5. // @match https://sh.reddit.com/*
  6. // @grant GM_addElement
  7. // @grant GM_setValue
  8. // @grant GM_getValue
  9. // @run-at document-body
  10. // @noframes
  11. // @version 2.4.0
  12. // @author hdyzen
  13. // @description Unblur nsfw in Shreddit
  14. // @license MIT
  15. // @homepage https://github.com/zenstorage/Reddit-NSFW-Unblur
  16. // ==/UserScript==
  17. 'use strict';
  18.  
  19. // States for NSFW and Spoiler
  20. let { state = true, nsfw = true, spoiler = false } = GM_getValue('states', false);
  21.  
  22. // Mutation observer
  23. const observer = new MutationObserver(callback);
  24.  
  25. // Styles loaded
  26. let styleLoaded = false;
  27.  
  28. // Styles link
  29. const styleM = (GM_addElement(document.head, 'link', {
  30. rel: 'stylesheet',
  31. href: 'https://zenstorage.github.io/Reddit-NSFW-Unblur/userscript/style.css',
  32. }).onload = () => {
  33. styleLoaded = true;
  34. });
  35.  
  36. // LOG with prefix
  37. const log = (...msg) => console.log('[Unblur]:', ...msg);
  38.  
  39. // Callback for MutationObserver
  40. function callback(mutations) {
  41. const nsfwModal = [...document.getElementsByTagName('shreddit-async-loader')].find(e => e.getAttribute('bundlename').includes('nsfw_blocking_modal')),
  42. prompt = document.getElementsByTagName('xpromo-nsfw-blocking-container')?.[0]?.shadowRoot?.children[1],
  43. blurreds = [...document.getElementsByTagName('shreddit-blurred-container')].filter(e => !e.hasAttribute('clicked') && e?.shadowRoot?.innerHTML && ((e.getAttribute('reason') === 'nsfw' && nsfw) || (e.getAttribute('reason') === 'spoiler' && spoiler))),
  44. menuAdded = document.getElementById('menu-unblur');
  45.  
  46. // Create menu
  47. if (!menuAdded && styleLoaded) initMenu();
  48.  
  49. // Return if unblur off
  50. if (!state) return;
  51.  
  52. // Remove NSFW modal loader
  53. if (nsfwModal) nsfwModal.remove();
  54.  
  55. // Remove prompt
  56. if (prompt) prompt.remove();
  57.  
  58. // Click in blurred
  59. blurreds.forEach(blurred => {
  60. blurred.firstElementChild.click();
  61. blurred.setAttribute('clicked', '');
  62. });
  63. }
  64.  
  65. async function initMenu() {
  66. // Add menu
  67. const menu = GM_addElement(document.querySelector('header.v2 > nav'), 'div', {
  68. id: 'menu-unblur',
  69. });
  70.  
  71. // Add toggle
  72. menu.addEventListener('click', e => {
  73. if (e.target.id === 'menu' || e.target.id === 'popup-toggle') menu.classList.toggle('active');
  74. });
  75.  
  76. // Add popup html
  77. menu.innerHTML = `<div id="popup-toggle">Unblur</div><form id="status-container"><div id="status"></div><div id="container-toggle"><label for="toggle"><input id="toggle" name="toggle" type="checkbox"><svg viewBox="0 0 24 24"><path fill-rule="evenodd" clip-rule="evenodd" d="M13 3C13 2.44772 12.5523 2 12 2C11.4477 2 11 2.44772 11 3V12C11 12.5523 11.4477 13 12 13C12.5523 13 13 12.5523 13 12V3ZM8.6092 5.8744C9.09211 5.60643 9.26636 4.99771 8.99839 4.5148C8.73042 4.03188 8.12171 3.85763 7.63879 4.1256C4.87453 5.65948 3 8.61014 3 12C3 16.9706 7.02944 21 12 21C16.9706 21 21 16.9706 21 12C21 8.66747 19.1882 5.75928 16.5007 4.20465C16.0227 3.92811 15.4109 4.09147 15.1344 4.56953C14.8579 5.04759 15.0212 5.65932 15.4993 5.93586C17.5942 7.14771 19 9.41027 19 12C19 15.866 15.866 19 12 19C8.13401 19 5 15.866 5 12C5 9.3658 6.45462 7.06997 8.6092 5.8744Z"></path></svg></label></div><div id="selected-ops"><label for="toggle-nsfw"><input type="checkbox" name="toggle-nsfw" id="toggle-nsfw"><span class="slider"></span><span class="slider-label">Unblur NSFW</span></label><label for="toggle-spoiler"><input type="checkbox" name="toggle-spoiler" id="toggle-spoiler"><span class="slider"></span><span class="slider-label">Unblur Spoiler</span></label></div></form>`;
  78.  
  79. await menu;
  80. const toggle = document.getElementById('toggle'),
  81. toggleNSFW = document.getElementById('toggle-nsfw'),
  82. toggleSpoiler = document.getElementById('toggle-spoiler'),
  83. form = document.getElementById('status-container');
  84.  
  85. toggle.checked = state;
  86. toggleNSFW.checked = nsfw;
  87. toggleSpoiler.checked = spoiler;
  88.  
  89. form.addEventListener('change', e => {
  90. GM_setValue('states', { state: toggle.checked, nsfw: toggleNSFW.checked, spoiler: toggleSpoiler.checked });
  91. });
  92.  
  93. document.addEventListener('click', e => {
  94. if (!e.target.closest('#menu-unblur') && menu.classList.contains('active')) menu.classList.remove('active'); // Close menu
  95. if (e.target.closest('media-telemetry-observer')) e.preventDefault(); // Prevent open post when clicking on video
  96. });
  97. }
  98.  
  99. // Start observing
  100. observer.observe(document, {
  101. childList: true,
  102. subtree: true,
  103. attributes: true,
  104. });
  105.  
  106. setTimeout(() => {
  107. let isShreddit = document.querySelector('shreddit-app');
  108. // Check if Shreddit
  109. if (!isShreddit) observer.disconnect();
  110. }, 8000);