GreasyFork 一键回报垃圾评论

在 Greasy Fork 一键回报垃圾评论

目前为 2023-09-19 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name GreasyFork: One Click Report Spam
  3. // @name:zh-TW GreasyFork 一鍵回報垃圾評論
  4. // @name:zh-CN GreasyFork 一键回报垃圾评论
  5. // @namespace UserScripts
  6. // @match https://greasyfork.org/*
  7. // @grant none
  8. // @version 1.4
  9. // @author CY Fung
  10. // @license MIT
  11. // @description To report spam comments in Greasy Fork with one click
  12. // @description:zh-TW 在 Greasy Fork 一鍵回報垃圾評論
  13. // @description:zh-CN 在 Greasy Fork 一键回报垃圾评论
  14. // ==/UserScript==
  15.  
  16. (() => {
  17.  
  18. const TEST_MODE = 0;
  19. let skipMode = false;
  20.  
  21. const onIframeLoad = async (evt) => {
  22. const iframe = evt.target;
  23. if (!(iframe instanceof HTMLIFrameElement)) return;
  24.  
  25. if (skipMode) return;
  26.  
  27.  
  28. const onNewUrl = async () => {
  29. skipMode = true;
  30.  
  31. alert('reported');
  32. await new Promise(requestAnimationFrame);
  33. iframe.remove();
  34. skipMode = false;
  35.  
  36. }
  37. const onAbort = async () => {
  38. skipMode = true;
  39.  
  40. await new Promise(requestAnimationFrame);
  41. iframe.remove();
  42. skipMode = false;
  43. }
  44.  
  45. iframe.removeEventListener('load', onIframeLoad, false);
  46.  
  47. if (!iframe.contentDocument) {
  48. alert('Iframe Access Error. Action aborted.');
  49. onAbort();
  50. return;
  51. }
  52.  
  53.  
  54. const reportReasonRadio = iframe.contentDocument.querySelector('input[name="report[reason]"]');
  55. if (reportReasonRadio) {
  56. reportReasonRadio.scrollIntoView();
  57. await new Promise(requestAnimationFrame);
  58. reportReasonRadio.click();
  59. const form = reportReasonRadio.closest('form');
  60. let currentUrl = iframe.contentWindow.location.pathname;
  61. skipMode = true;
  62. if (TEST_MODE) {
  63.  
  64. iframe.contentWindow.location.href = 'https://greasyfork.org/'
  65. } else {
  66. form.submit();
  67. }
  68. let cid = setInterval(() => {
  69. if (!cid) return;
  70. let nextUrl = iframe.contentWindow.location.pathname;
  71. if (nextUrl !== currentUrl) {
  72. clearInterval(cid)
  73. cid = 0;
  74. setTimeout(onNewUrl, 300);
  75. }
  76. }, 100)
  77.  
  78. } else if (iframe.contentDocument.querySelector('#open-report-:not(:empty)')) {
  79. alert("The spam report is already submitted for moderator's review. Action aborted.");
  80. onAbort();
  81.  
  82. } else {
  83. alert('Cannot find the report[reason] radio button. Action aborted.');
  84. onAbort();
  85. }
  86.  
  87. };
  88. const clickHandler = (evt) => {
  89. evt.preventDefault();
  90. if (!(evt.target instanceof HTMLElement)) return;
  91. let url = evt.target.getAttribute('ohref');
  92. if (!url) return;
  93. let userid = /id=(\d+)\b/.exec(url);
  94. if (userid) userid = userid[1];
  95. let r = window.confirm(`Confirm to report user#${userid || "------"} ?`);
  96. if (!r) return;
  97. const iframe = document.createElement('iframe');
  98. skipMode = false;
  99. iframe.addEventListener('load', onIframeLoad, false);
  100. iframe.name = "u423323";
  101. iframe.src = url;
  102. Object.assign(iframe.style, {
  103. display: 'block',
  104. position: 'fixed',
  105. top: '0px',
  106. left: '0px',
  107. width: '300px',
  108. height: '300px',
  109. 'contain': 'strict',
  110. });
  111. document.body.appendChild(iframe);
  112. }
  113.  
  114.  
  115. for (const anchor of document.querySelectorAll('a[href*="/reports/new?item_class=comment&item_id="],a[href*="/reports/new?item_class=discussion&item_id="]')) {
  116.  
  117. let anchorNode = anchor;
  118. if (anchor.parentNode.firstElementChild === anchor.parentNode.lastElementChild) {
  119. anchorNode = anchorNode.parentNode;
  120. }
  121. let newAnchorNode = anchorNode.cloneNode(true);
  122. let newAnchor = newAnchorNode.querySelector('a[href]') || newAnchorNode;
  123. newAnchor.classList.add('report-spam-btn');
  124. newAnchor.setAttribute('ohref', newAnchor.getAttribute('href'));
  125. newAnchor.setAttribute('href', '#');
  126. newAnchor.addEventListener('click', clickHandler, false)
  127. newAnchor.textContent = 'Report Spam';
  128. anchorNode.parentNode.insertBefore(newAnchorNode, anchorNode.nextSibling);
  129.  
  130.  
  131. }
  132.  
  133. document.head.appendChild(document.createElement('style')).textContent=`
  134. .discussion-list-container{
  135. display:flex;
  136. flex-direction: row;
  137. flex-wrap: nowrap;
  138. }
  139. .discussion-list-container > .discussion-list-item {
  140. flex-grow:1;
  141. width:0;
  142. }
  143. .discussion-list-container > .discussion-list-item ~ .report-spam-btn {
  144. align-self: center;
  145. }
  146. `
  147.  
  148. setTimeout(()=>{
  149.  
  150. for(const li of document.querySelectorAll('.discussion-list-item')){
  151.  
  152. let a = li.querySelector('a[href*="/discussions/"].discussion-title');
  153. if(!a) continue;
  154. let href = a.getAttribute('href');
  155. let idx = href.lastIndexOf('/discussions/');
  156. let discussionId = parseInt(href.substring(idx+'/discussions/'.length)||0);
  157. if(isNaN(discussionId) || discussionId < 0)continue;
  158.  
  159. let btn = document.createElement('a');
  160. btn.classList.add('report-spam-btn');
  161. btn.setAttribute('ohref', 'https://greasyfork.org/en/reports/new?item_class=discussion&item_id='+discussionId)
  162. btn.setAttribute('href','#')
  163. btn.textContent='Report Spam';
  164. btn.addEventListener('click', clickHandler, false)
  165. li.parentNode.insertBefore(btn, li.nextSibling);
  166.  
  167.  
  168. }
  169.  
  170. }, 270);
  171.  
  172. })();