ZhihuOneKeyReport-JavaScript

2022/9/3 15:00:00

  1. // ==UserScript==
  2. // @name ZhihuOneKeyReport-JavaScript
  3. // @namespace Violentmonkey Scripts
  4. // @match https://www.zhihu.com/people/*
  5. // @require https://cdn.staticfile.org/jquery/3.4.1/jquery.min.js
  6. // @grant window.open
  7. // @grant window.focus
  8. // @version 1.1
  9. // @author 尼尼尼@知乎
  10. // @author 备份公众号:尼尼尼不打拳
  11. // @description 2022/9/3 15:00:00
  12. // @license GPL3
  13. // ==/UserScript==
  14.  
  15.  
  16. // 用于举报“不友善内容”时简化操作步骤的Javascript脚本。
  17. // 请勿滥用
  18.  
  19. // 简要操作说明:
  20. // 1.在浏览器扩展商店中搜索“暴力猴“、”油猴“之类扩展插件,安装并启用。下面以”暴力猴“为例。
  21. // 2.在暴力猴插件中点击”+“号,新建JS脚本,将此脚本内容全部复制粘贴进去并保存。
  22. // 3.进入知乎主页,登录(不可用)知乎账户。在暴力猴插件控制台中启用上面保存的脚本。注意不能与单页回答检查脚本同时启用。
  23. // 4.刷新页面,右侧滚动条旁边会出多一个蓝色按钮(备用按钮,不是必须点击)
  24. // 5.进入要举报内容的个人主页, 点击回答、文章、想法等模块后,注意需要手工刷新一次页面。
  25. // 在每条内容后就会多出一个“一键举报”按钮。
  26. // 6.知乎的文章、回答等模块是部分动态加载的,所以有时候出现只有一半内容加上按钮的情况,
  27. // 这时点击一下右侧的蓝色按钮手工添加即可。
  28.  
  29.  
  30. (function () {
  31. 'use strict';
  32.  
  33. // 开始对Modal窗口的变化监视,及提交处理。
  34. function handleModalSubmit(target){
  35. // Firefox和Chrome早期版本中带有前缀
  36. var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
  37. // 创建Modal窗口的观察者对象
  38. var modalObserver = new MutationObserver(function (mutations) {
  39. try {
  40. mutations.forEach(function (mutation) {
  41. switch (mutation.type) {
  42. case 'childList':
  43. quickReport(modalObserver);
  44. throw new Error("模态窗口变化已检测到,抛出异常中止。")
  45. }
  46. });
  47. }catch (e){
  48. console.log(e);
  49. }
  50. });
  51. // 配置观察选项
  52. var config = {
  53. childList: true //观察目标子节点的变化,添加或者删除
  54. }
  55. // 传入目标节点和观察选项
  56. modalObserver.observe(target, config);
  57. }
  58.  
  59. function handlePopMenuObserver(observer) {
  60. // 终止对pop menu的observer监控
  61. observer.disconnect();
  62.  
  63. // 开始处理Modal窗口的提交
  64. var target = document.querySelector('div[class="Modal-content"]');
  65. handleModalSubmit(target)
  66.  
  67. }
  68.  
  69. function handleNormalReport(reportBtn){
  70. var originalReportBtn = reportBtn.previousElementSibling;
  71. if(originalReportBtn === null ){
  72. console.log('错误: 未查找到原始举报按钮');
  73. }
  74.  
  75. originalReportBtn.click();
  76. var target = document.querySelector('div[class="Modal-content"]');
  77. handleModalSubmit(target);
  78. }
  79.  
  80. function handlePopMenuReport(reportBtn) {
  81. // 先点击pop menu,这里要注意选择button元素,才能click。不要选到外层的div.
  82. console.log('点击pop menu');
  83. var popMenu = reportBtn.previousElementSibling.firstChild;
  84.  
  85. // 使用mutation observer监视点击pop menu后生成的原始举报按钮
  86. var docBody = document.querySelector('body');
  87. // Firefox和Chrome早期版本中带有前缀
  88. var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
  89. var btn = null;
  90. // 创建pop menu的观察者对象
  91. var popMenuObserver = new MutationObserver(function (mutations) {
  92. try{
  93. mutations.forEach(function (mutation) {
  94. switch (mutation.type) {
  95. case 'childList':
  96. var selfMenu = document.querySelector('div[class="Menu AnswerItem-selfMenu"]');
  97. var nsl = selfMenu.childNodes;
  98. // console.log(nsl);
  99. for(let n of nsl){
  100. if(n.innerHTML === '举报'){
  101. btn = n;
  102. // console.log(btn);
  103. }
  104. }
  105. btn.click();
  106. handlePopMenuObserver(popMenuObserver);
  107. throw new Error("回答模块按钮栏的pop menu变化已检测到,抛出异常中止。")
  108. }
  109. });
  110. }
  111. catch(e) {
  112. console.log(e);
  113. }
  114. });
  115.  
  116. var config = {
  117. childList: true //观察目标子节点的变化,添加或者删除
  118. }
  119. // 传入目标节点和观察选项
  120. popMenuObserver.observe(docBody, config);
  121.  
  122. // 建立观察者后再点击下拉菜单
  123. popMenu.click();
  124. }
  125.  
  126. function quickReport(observer) {
  127. var spanList = document.querySelectorAll('div[class="Modal-content"] span');
  128. // console.log(spanList);
  129. var reason = null;
  130.  
  131. for (let i = 0; i < spanList.length; ++i) {
  132. let span = spanList[i]
  133. if (span.innerHTML === '辱骂、人身攻击等不友善行为') {
  134. reason = span.parentElement;
  135. }
  136. }
  137.  
  138. // 终止对Modal窗口的变化监控
  139. observer.disconnect();
  140. reason.click();
  141.  
  142. var dialog = document.querySelector('textarea[class="Input"]');
  143. dialog.innerHTML = '不友善,引发情绪对立';
  144.  
  145. var btnArea = document.querySelector('textarea[class="Input"]').parentElement.nextSibling;
  146. var btnList = btnArea.childNodes;
  147.  
  148. var btnOnDialog = null;
  149.  
  150. for (let i = 0; i < btnList.length; ++i) {
  151. //console.log(btnList[i]);
  152. if (btnList[i].innerHTML === "举报") {
  153. btnOnDialog = btnList[i];
  154. break;
  155. }
  156. }
  157. console.log('准备点击');
  158. btnOnDialog.click();
  159. }
  160.  
  161. // 一键举报按钮的关联事件
  162. function watchReasonLoad(e) {
  163. var reportBtn = e.target;
  164. //对于带弹出菜单和不带菜单的页面,需要作分别处理。
  165. var url = window.location.href;
  166. if(url.includes('answers')){
  167. console.log('回答页面有pop菜单,需要单独处理');
  168. handlePopMenuReport(reportBtn);
  169. }else{
  170. console.log('回答以外的页面通用处理');
  171. handleNormalReport(reportBtn);
  172. }
  173. }
  174.  
  175. // 监听“回答”模块的内容框架中的加载情况。即等待回答的内容动态加载完成。
  176. function monitorAnswerTab() {
  177. // var answerBody = document.querySelector('div[class="ListShortcut"]');
  178. var answerBody = document.getElementById('Profile-answers');
  179.  
  180. // Firefox和Chrome早期版本中带有前缀
  181. var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
  182.  
  183. var answerObserver = new MutationObserver(function (mutations) {
  184. try {
  185. mutations.forEach(function (mutation) {
  186. switch (mutation.type) {
  187. case 'childList':
  188. console.log("进到这里说明内容是异步加载的,已加载完成")
  189. handlerContentObserver(answerObserver);
  190. // 这里有多个ChildList的变动,所以这里执行一次之后,要跳出foreach。
  191. // 不然会将堆栈中记录的所有变化遍历一次,重复执行。
  192. throw new Error('内容模块已加载,抛出异常中止多余的遍历');
  193. }
  194. });
  195. }catch(e){
  196. console.log(e);
  197. }
  198. });
  199.  
  200. var config = {
  201. childList: true,
  202. subtree: true
  203. }
  204. // 传入目标节点和观察选项
  205. answerObserver.observe(answerBody, config);
  206. }
  207.  
  208. // 处理回答的obeserver的回调函数
  209. function handlerContentObserver(answerObserver) {
  210. //终止监视
  211. answerObserver.disconnect();
  212. // 内容加载后,执行初始化
  213. console.log("内容加载后,执行初始化")
  214. init();
  215. }
  216.  
  217. // 在每个"举报"按钮后添加"一键举报"按钮。
  218. // 想法和文章模块,是一部分随请求返回,另一部分异步加载。不保证每次都能全部添加上。
  219. function addReportButton() {
  220.  
  221. var btnBarList = document.querySelectorAll('div[class="ContentItem-actions"]');
  222. //btnBarList = document.getElementsByClassName('ContentItem-actions');
  223.  
  224. console.log("开始添加按钮")
  225.  
  226. // 如果该Tab下一条内容都没有,直接return
  227. if (btnBarList.length === 0 ) {
  228. console.log("发生错误: 内容尚未加载,需手动点击右侧按钮注入");
  229. return;
  230. }
  231.  
  232. for (let item of btnBarList) {
  233.  
  234. // 视频模块的内容操作栏的结果与其它不同,多套了两层div, 需要单独处理。
  235. var url = window.location.href;
  236. if(url.includes('/zvideos')){
  237. let newItem = item.firstChild.firstChild;
  238. // console.log(newItem);
  239. newItem.insertAdjacentHTML('beforeend', '<button id="OneKeyReport" type="button" class="one-key-report" style="color:blue"> 【一键举报】</button>');
  240. }else{
  241. // 其它模块正常处理
  242. //$(item).append('<button id="OneKeyReport" type="button" class="one-key-report"> 【一键举报】</button>');
  243. item.insertAdjacentHTML('beforeend', '<button id="OneKeyReport" type="button" class="one-key-report" style="color:blue"> 【一键举报】</button>');
  244. }
  245. }
  246.  
  247. // 遍历,给所有新增按钮注册(不可用)事件
  248. var oneKeyReportList = document.querySelectorAll('button[class="one-key-report"]');
  249.  
  250. for (let item of oneKeyReportList) {
  251. item.addEventListener("click", watchReasonLoad, false);
  252. }
  253. console.log('添加新按钮完毕');
  254. }
  255.  
  256. // 在每个翻页按钮中绑定刷新页面的event listener
  257. function addPageBtnEvent() {
  258. var pageBtnList = document.querySelectorAll('div[class="Pagination"] > button');
  259. //console.log(pageBtnList);
  260. //如果没有翻页栏,直接return
  261. if(pageBtnList === null){
  262. return;
  263. }
  264. for (let item of pageBtnList) {
  265. //item.addEventListener("click", addReportButton, false);
  266. item.addEventListener("click", refreshPage, false);
  267. }
  268. console.log('翻页按钮添加事件完成');
  269. }
  270.  
  271. // 翻页后一次刷新,保证显示新增按钮
  272. function refreshPage(e){
  273. console.log(e.target)
  274. console.log("自动刷新页面");
  275. e.target.click();
  276. window.location.reload();
  277. }
  278.  
  279. // 监视翻页栏的的翻页变化, 发布变化时则执行添加按钮和刷新的操作
  280. // function observePageBar() {
  281. // // Firefox和Chrome早期版本中带有前缀
  282. // var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
  283. //
  284. // // 创建翻页栏的观察者对象
  285. // var targetPageBar = document.querySelector('div[class="Pagination"]');
  286. // console.log("找翻页栏");
  287. // console.log(targetPageBar);
  288. // //如果当前Tab没有翻页栏,直接return,不用监视了
  289. // if(targetPageBar === null){
  290. // console.log("本页没有翻页栏");
  291. // return;
  292. // }
  293. // var pageObserver = new MutationObserver(function (mutations) {
  294. // mutations.forEach(function (mutation) {
  295. // switch (mutation.type) {
  296. // case 'childList':
  297. // console.log(mutation);
  298. // console.log("发生翻页了===========");
  299. // addReportButton();
  300. // addPageBtnEvent(); // 因为页码元素会发生变化,所以每次都重新绑定
  301. // break;
  302. // }
  303. // });
  304. // });
  305. // // 配置观察选项,翻页栏监听子元素的变化
  306. // var config = {
  307. // childList: true,
  308. // subtree: true,
  309. // attributes:true
  310. // }
  311. // // 传入目标节点和观察选项
  312. // pageObserver.observe(targetPageBar, config);
  313. // }
  314.  
  315. function init(){
  316. // 先开始监听个人主页中回答模块内容的动态加载。
  317. // 知乎的回答模块的内容全部是动态加载, 还好办。
  318. // 想法和文章模块,则是一部分内容随请求返回,另一部分又是异步加载,这种处理起来很麻烦,靠手动按钮弥补。
  319. var url = window.location.href;
  320. if(url.includes('/answers')){
  321. console.log("当前为回答模块, 单独处理");
  322. // 如果目标内容没有加载,则开始监听;如果已经加载,则直接在下面作普通初始化
  323. var answerContent = document.querySelectorAll('div[class="ContentItem-actions"]');
  324. if(answerContent.length === 0){
  325. console.log("回答模块的内容还没有加载,开始监听");
  326. monitorAnswerTab();
  327. }
  328. }
  329.  
  330. //回答之外的模块作普通初始化处理
  331. // 添加一键举报按钮
  332. addReportButton();
  333. // 在每个翻页按钮中绑定 listener
  334. addPageBtnEvent();
  335.  
  336. // 取消监视翻页栏的的翻页变化, 通过每次翻页时重新加载页面,来重新绑定事件,不然容易循环调用。
  337. // observePageBar();
  338. }
  339.  
  340. // 添加手动插入举报按钮
  341. function addFloatButton() {
  342. $('body').append('<div id="FloatButton">点<br>击<br>添<br>加<br>一<br>键<br>举<br>报</div>')
  343. $('#FloatButton').css('width', '20px')
  344. $('#FloatButton').css('position', 'fixed')
  345. $('#FloatButton').css('top', '150px')
  346. $('#FloatButton').css('right', '3px')
  347. $('#FloatButton').css('background-color', '#2F4F4F')
  348. $('#FloatButton').css('color', 'white')
  349. $('#FloatButton').css('font-size', 'small')
  350. $('#FloatButton').css('z-index', 100)
  351. $('#FloatButton').css('border-radius', '25px')
  352. $('#FloatButton').css('text-align', 'center')
  353. $('#FloatButton').css('cursor', 'default')
  354. $('#FloatButton').click(function () {
  355. init();
  356. });
  357. }
  358.  
  359. document.onreadystatechange = function () {
  360. if (document.readyState === "complete") {
  361.  
  362. console.log('添加手动插入举报按钮');
  363. addFloatButton();
  364.  
  365. // 进行初始化
  366. init();
  367. }
  368. }
  369. }
  370.  
  371. )();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址