知乎取消关注

知乎快速取消关注

  1. // ==UserScript==
  2. // @name 知乎取消关注
  3. // @namespace https://gf.qytechs.cn/users/831154
  4. // @version 1.0.2
  5. // @author percy
  6. // @description 知乎快速取消关注
  7. // @match *://www.zhihu.com/people/*/following*
  8. // @match https://www.zhihu.com/question/following
  9. // @icon https://static.zhihu.com/heifetz/favicon.ico
  10. // @grant GM_xmlhttpRequest
  11. // @grant GM_registerMenuCommand
  12. // @grant GM_unregisterMenuCommand
  13. // @grant GM_openInTab
  14. // @grant GM_getValue
  15. // @grant GM_setValue
  16. // @grant GM_notification
  17. // @grant GM_info
  18. // @grant window.onurlchange
  19. // @license GPL-3.0 License
  20. // @run-at document-end
  21. // ==/UserScript==
  22.  
  23. 'use strict';
  24. let menu_ALL = [
  25. ['unfollow_members', '取消关注人', '取消关注人', true],
  26. ['unfollow_columns', '取消关注专栏', '取消关注专栏', true],
  27. ['unfollow_topics', '取消关注话题', '取消关注话题', true],
  28. ['unfollow_questions', '取消关注问题', '取消关注问题', true]
  29. ];
  30. let menu_ID = [];
  31. for (let i = 0; i < menu_ALL.length; i++) { // 如果读取到的值为 null 就写入默认值
  32. if (GM_getValue(menu_ALL[i][0]) == null) {
  33. GM_setValue(menu_ALL[i][0], menu_ALL[i][3])
  34. }
  35. ;
  36. }
  37. registerMenuCommand();
  38.  
  39. // 注册(不可用)脚本菜单
  40. function registerMenuCommand() {
  41. if (menu_ID.length > menu_ALL.length) { // 如果菜单ID数组多于菜单数组,说明不是首次添加菜单,需要卸载所有脚本菜单
  42. for (let i = 0; i < menu_ID.length; i++) {
  43. GM_unregisterMenuCommand(menu_ID[i]);
  44. }
  45. }
  46. for (let i = 0; i < menu_ALL.length; i++) { // 循环注册(不可用)脚本菜单
  47. menu_ALL[i][3] = GM_getValue(menu_ALL[i][0]);
  48. if (menu_ALL[i][0] === 'menu_customBlockUsers') {
  49. if (menu_value('menu_blockUsers')) menu_ID[i] = GM_registerMenuCommand(`#️⃣ ${menu_ALL[i][1]}`, function () {
  50. customBlockUsers()
  51. });
  52. } else if (menu_ALL[i][0] === 'menu_customBlockKeywords') {
  53. if (menu_value('menu_blockKeywords')) menu_ID[i] = GM_registerMenuCommand(`#️⃣ ${menu_ALL[i][1]}`, function () {
  54. customBlockKeywords()
  55. });
  56. } else if (menu_ALL[i][0] === 'menu_blockType') {
  57. menu_ID[i] = GM_registerMenuCommand(`#️⃣ ${menu_ALL[i][1]}`, function () {
  58. menu_setting('checkbox', menu_ALL[i][1], menu_ALL[i][2], true, [menu_ALL[i + 1], menu_ALL[i + 2], menu_ALL[i + 3], menu_ALL[i + 4], menu_ALL[i + 5]])
  59. });
  60. } else if (menu_ALL[i][0] != 'menu_blockTypeVideo' && menu_ALL[i][0] != 'menu_blockTypeArticle' && menu_ALL[i][0] != 'menu_blockTypeTopic' && menu_ALL[i][0] != 'menu_blockTypeSearch' && menu_ALL[i][0] != 'menu_blockYanXuan') {
  61. menu_ID[i] = GM_registerMenuCommand(`${menu_ALL[i][3] ? '✅' : '❌'} ${menu_ALL[i][1]}`, function () {
  62. menu_switch(`${menu_ALL[i][3]}`, `${menu_ALL[i][0]}`, `${menu_ALL[i][2]}`)
  63. });
  64. }
  65. }
  66. menu_ID[menu_ID.length] = GM_registerMenuCommand('💬 反馈 & 建议', function () {
  67. window.GM_openInTab('https://gf.qytechs.cn/zh-CN/scripts/457969/feedback', {
  68. active: true,
  69. insert: true,
  70. setParent: true
  71. });
  72. window.GM_openInTab('https://gf.qytechs.cn/zh-CN/scripts/457969/feedback', {
  73. active: true,
  74. insert: true,
  75. setParent: true
  76. });
  77. });
  78. }
  79.  
  80. // 菜单开关
  81. function menu_switch(menu_status, Name, Tips) {
  82. if (menu_status == 'true') {
  83. GM_setValue(`${Name}`, false);
  84. GM_notification({
  85. text: `已关闭 [${Tips}] 功能\n(点击刷新网页后生效)`, timeout: 3500, onclick: function () {
  86. location.reload();
  87. }
  88. });
  89. } else {
  90. GM_setValue(`${Name}`, true);
  91. GM_notification({
  92. text: `已开启 [${Tips}] 功能\n(点击刷新网页后生效)`, timeout: 3500, onclick: function () {
  93. location.reload();
  94. }
  95. });
  96. }
  97. registerMenuCommand(); // 重新注册(不可用)脚本菜单
  98. };
  99.  
  100. // 返回菜单值
  101. function menu_value(menuName) {
  102. for (let menu of menu_ALL) {
  103. if (menu[0] == menuName) {
  104. return menu[3]
  105. }
  106. }
  107. }
  108.  
  109. // 脚本设置
  110. function menu_setting(type, title, tips, line, menu) {
  111. let _br = '', _html = `<style class="zhihuE_SettingStyle">.zhihuE_SettingRoot {position: absolute;top: 50%;left: 50%;-webkit-transform: translate(-50%, -50%);-moz-transform: translate(-50%, -50%);-ms-transform: translate(-50%, -50%);-o-transform: translate(-50%, -50%);transform: translate(-50%, -50%);width: auto;min-width: 400px;max-width: 600px;height: auto;min-height: 150px;max-height: 400px;color: #535353;background-color: #fff;border-radius: 3px;}
  112. .zhihuE_SettingBackdrop_1 {position: fixed;top: 0;right: 0;bottom: 0;left: 0;z-index: 203;display: -webkit-box;display: -ms-flexbox;display: flex;-webkit-box-orient: vertical;-webkit-box-direction: normal;-ms-flex-direction: column;flex-direction: column;-webkit-box-pack: center;-ms-flex-pack: center;justify-content: center;overflow-x: hidden;overflow-y: auto;-webkit-transition: opacity .3s ease-out;transition: opacity .3s ease-out;}
  113. .zhihuE_SettingBackdrop_2 {position: absolute;top: 0;right: 0;bottom: 0;left: 0;z-index: 0;background-color: rgba(18,18,18,.65);-webkit-transition: background-color .3s ease-out;transition: background-color .3s ease-out;}
  114. .zhihuE_SettingRoot .zhihuE_SettingHeader {padding: 10px 20px;color: #fff;font-weight: bold;background-color: #3994ff;border-radius: 3px 3px 0 0;}
  115. .zhihuE_SettingRoot .zhihuE_SettingMain {padding: 10px 20px;border-radius: 0 0 3px 3px;}
  116. .zhihuE_SettingHeader span {float: right;cursor: pointer;}
  117. .zhihuE_SettingMain input {margin: 10px 6px 10px 0;cursor: pointer;vertical-align:middle}
  118. .zhihuE_SettingMain label {margin-right: 20px;user-select: none;cursor: pointer;vertical-align:middle}
  119. .zhihuE_SettingMain hr {border: 0.5px solid #f4f4f4;}
  120. [data-theme="dark"] .zhihuE_SettingRoot {color: #adbac7;background-color: #343A44;}
  121. [data-theme="dark"] .zhihuE_SettingHeader {color: #d0d0d0;background-color: #2D333B;}
  122. [data-theme="dark"] .zhihuE_SettingMain hr {border: 0.5px solid #2d333b;}</style>
  123. <div class="zhihuE_SettingBackdrop_1"><div class="zhihuE_SettingBackdrop_2"></div><div class="zhihuE_SettingRoot">
  124. <div class="zhihuE_SettingHeader">${title}<span class="zhihuE_SettingClose" title="点击关闭"><svg class="Zi Zi--Close Modal-closeIcon" fill="currentColor" viewBox="0 0 24 24" width="24" height="24"><path d="M13.486 12l5.208-5.207a1.048 1.048 0 0 0-.006-1.483 1.046 1.046 0 0 0-1.482-.005L12 10.514 6.793 5.305a1.048 1.048 0 0 0-1.483.005 1.046 1.046 0 0 0-.005 1.483L10.514 12l-5.208 5.207a1.048 1.048 0 0 0 .006 1.483 1.046 1.046 0 0 0 1.482.005L12 13.486l5.207 5.208a1.048 1.048 0 0 0 1.483-.006 1.046 1.046 0 0 0 .005-1.482L13.486 12z" fill-rule="evenodd"></path></svg></span></div>
  125. <div class="zhihuE_SettingMain"><p>${tips}</p><hr>`
  126. if (line) _br = '<br>'
  127. for (let i = 0; i < menu.length; i++) {
  128. if (GM_getValue(menu[i][0])) {
  129. _html += `<label><input name="zhihuE_Setting" type="checkbox" value="${menu[i][0]}" checked="checked">${menu[i][1]}</label>${_br}`
  130. } else {
  131. _html += `<label><input name="zhihuE_Setting" type="checkbox" value="${menu[i][0]}">${menu[i][1]}</label>${_br}`
  132. }
  133. }
  134. _html += `</div></div></div>`
  135. document.body.insertAdjacentHTML('beforeend', _html); // 插入网页末尾
  136. setTimeout(function () { // 延迟 100 毫秒,避免太快
  137. // 关闭按钮 点击事件
  138. document.querySelector('.zhihuE_SettingClose').onclick = function () {
  139. this.parentElement.parentElement.parentElement.remove();
  140. document.querySelector('.zhihuE_SettingStyle').remove();
  141. }
  142. // 点击周围空白处 = 点击关闭按钮
  143. document.querySelector('.zhihuE_SettingBackdrop_2').onclick = function (event) {
  144. if (event.target == this) {
  145. document.querySelector('.zhihuE_SettingClose').click();
  146. }
  147. ;
  148. }
  149. // 复选框 点击事件
  150. document.getElementsByName('zhihuE_Setting').forEach(function (checkBox) {
  151. checkBox.addEventListener('click', function () {
  152. if (this.checked) {
  153. GM_setValue(this.value, true);
  154. } else {
  155. GM_setValue(this.value, false);
  156. }
  157. });
  158. })
  159. }, 100)
  160. }
  161.  
  162. //sleep
  163. function sleep(time) {
  164. return new Promise((resolve) => setTimeout(resolve, time));
  165. }
  166.  
  167. //取消关注的人
  168. async function unfollow_members() {
  169. if (!menu_value('unfollow_members')) return;
  170. //users
  171. let elements = document.querySelectorAll('.ContentItem .ContentItem-main');
  172. for (let e of elements) {
  173. try {
  174. let user = e.querySelector('.ContentItem-image .UserLink-link');
  175. let userUrl = user.getAttribute("href");
  176. let userId = userUrl.substring(userUrl.lastIndexOf('/') + 1);
  177. let userName = user.querySelector('img').getAttribute('alt');
  178. console.log("user:%s,id:%s,http:%s", userName, userId, userUrl);
  179.  
  180. let result = await createDialogue("取消关注的人", userName);
  181. if (result === -1) {
  182. // 关闭
  183. return;
  184. } else if (result === 0) {
  185. // 取消
  186. continue;
  187. } else if (result === 2) {
  188. // 查看
  189. window.open(userUrl);
  190. continue;
  191. }
  192.  
  193. let button = e.querySelector('.ContentItem-extra button');
  194. if (button.innerText === '已关注') {
  195. button.click();
  196. await sleep(20);
  197. }
  198. } catch (e) {
  199. debugger
  200. console.error('parse user err:', e);
  201. }
  202. }
  203. }
  204.  
  205. // 取消关注的话题
  206. async function unfollow_topics() {
  207. if (!menu_value('unfollow_topics')) return;
  208. // topics
  209. let topics = document.querySelectorAll('.TopicLink');
  210. for (let topic of topics) {
  211. try {
  212. let topicUrl = topic.getAttribute('href');
  213. let topicId = topicUrl.substring(topicUrl.lastIndexOf('/') + 1);
  214. let topicText = topic.children[0].innerText;
  215. console.log("topic:%s,id:%s,http:%s", topicText, topicId, topicUrl);
  216.  
  217. let result = await createDialogue("取消关注话题", topicText);
  218. if (result === -1) {
  219. // 关闭
  220. return;
  221. } else if (result === 0) {
  222. // 取消
  223. continue;
  224. } else if (result === 2) {
  225. // 查看
  226. window.open(topicUrl);
  227. continue;
  228. }
  229. fetch(`https://www.zhihu.com/api/v4/topics/${topicId}/followers`, {
  230. "headers": {
  231. "accept": "*/*",
  232. "accept-language": "zh-CN,zh;q=0.9",
  233. "sec-ch-ua-mobile": "?0",
  234. "sec-ch-ua-platform": "\"Windows\"",
  235. "sec-fetch-dest": "empty",
  236. "sec-fetch-mode": "cors"
  237. },
  238. "referrer": window.location.href,
  239. "referrerPolicy": "no-referrer-when-downgrade",
  240. "body": null,
  241. "method": "DELETE",
  242. "mode": "cors",
  243. "credentials": "include"
  244. }).then(response => {
  245. let status = response.status;
  246. console.log("topicId:%s,api operate ret:%s", topicId, status);
  247. });
  248. } catch (e) {
  249. debugger
  250. console.error('parse topic err:', e);
  251. }
  252. }
  253.  
  254. // page
  255. let pageElement = document.querySelector('.Pagination');
  256. let pageChildren = pageElement.children;
  257. // let innerText = pageChildren[pageChildren.length-2].innerText;
  258. // console.log("totalPage text:", innerText);
  259.  
  260. let nextPageElement = pageChildren[pageChildren.length - 1];
  261. let nextText = nextPageElement.innerText;
  262. if (nextText === '下一页') {
  263. nextPageElement.click();
  264. }
  265. }
  266.  
  267. let qustion_div_refresh = false;
  268.  
  269. let moreQuestionResolve = function () {
  270. };
  271.  
  272. // 取消关注的问题
  273. async function unfollow_questions() {
  274. if (!menu_value('unfollow_questions')) return;
  275. debugger
  276. if (window.location.href !== ('https://www.zhihu.com/question/following')) {
  277. let result = await createDialogue('批量取消关注问题', '即将打开新页面');
  278. if (result === -1 || result === 0) {
  279. return;
  280. }
  281. window.open('https://www.zhihu.com/question/following');
  282. return;
  283. }
  284.  
  285. // window.scrollTo(0, 0);
  286.  
  287. // 监听 [更多] 这个a标签
  288. let moreQuestionButton = document.querySelector('.zu-button-more');
  289. const config = {attributes: true, attributeOldValue: true};
  290. const callback = function (mutationsList, observer) {
  291. // Use traditional 'for loops' for IE 11
  292. for (let mutation of mutationsList) {
  293. if (mutation.type === 'childList') {
  294. console.log('A child node has been added or removed.');
  295. } else if (mutation.type === 'attributes') {
  296. console.log('The ' + mutation.attributeName + ' attribute was modified. oldValue:' + mutation.oldValue);
  297. if (mutation.oldValue === 'zg-btn-white zu-button-more' || moreQuestionButton.getAttribute("class") === 'zg-btn-white zu-button-more') {
  298. moreQuestionResolve();
  299. qustion_div_refresh = true;
  300. console.log('qustion_div_refresh:',qustion_div_refresh);
  301. // followedQuesions = document.querySelectorAll('.zg-unfollow');
  302. } else if (mutation.oldValue === 'zg-btn-white zu-button-more') {
  303. console.log("更多数据加载中...." + new Date().toLocaleString());
  304. }
  305. }
  306. }
  307. };
  308. // 创建一个观察器实例并传入回调函数
  309. const observer = new MutationObserver(callback);
  310. // 以上述配置开始观察目标节点
  311. observer.observe(moreQuestionButton, config);
  312.  
  313.  
  314. let i = 0;
  315. let first = true;
  316. let followedQuesions = document.querySelectorAll('.zg-unfollow');
  317. async function do_unfollow_questions() {
  318. while (i < followedQuesions.length) {
  319. let question = followedQuesions[i];
  320. let qustionTop = question.getBoundingClientRect().top;
  321. i++;
  322. if (qustionTop < 80) {
  323. continue;
  324. }
  325. if (i === 1) {
  326. window.scrollTo(0, 10);
  327. }
  328. if (followedQuesions.length - i <= 2) {
  329. console.log("点击[更多]按钮,获取数据...");
  330. moreQuestionButton.click();
  331. await new Promise((resolve) => moreQuestionResolve = resolve);
  332. console.log("after click,data:{}",document.querySelectorAll('.zg-unfollow').length)
  333. }
  334. if (i % 10 === 0 || qustion_div_refresh) {
  335. console.log('qustion_div_refresh---->:',qustion_div_refresh);
  336. qustion_div_refresh = false;
  337. followedQuesions = document.querySelectorAll('.zg-unfollow');
  338. }
  339. let quesionLink = question.parentNode.parentNode.querySelector('.question_link');
  340. let questionText = quesionLink.innerText;
  341. let href = quesionLink.getAttribute('href');
  342. let quesionId = href.substring(href.lastIndexOf('/') + 1);
  343. let quesionUrl = `https://www.zhihu.com${href}`;
  344. let scrollHeight = window.scrollY + qustionTop;
  345. console.log("i:%s/%s,qustion:%s,id:%s,%s", i, followedQuesions.length, questionText, quesionId, quesionUrl);
  346. let onCreate = !first ? undefined : function () {
  347. console.log("scrollHeight:", scrollHeight);
  348. document.getElementById("percyMsgBox").children[0].style.top = scrollHeight + 150 + "px";
  349. first = false;
  350. };
  351. let result = await createDialogue('取消关注问题', questionText, false, onCreate);
  352. console.log("scrollHeight:",scrollHeight);
  353. document.getElementById("percyMsgBox").children[0].style.top = scrollHeight + 200 + "px";
  354. window.scrollTo(0, scrollHeight);
  355. if (result === -1) {
  356. // 关闭
  357. return;
  358. } else if (result === 0) {
  359. // 取消
  360. continue;
  361. } else if (result === 2) {
  362. // 查看
  363. window.open(quesionUrl);
  364. continue;
  365. }
  366. question.click();
  367. }
  368. }
  369. await do_unfollow_questions();
  370. console.log('取消关注问题结束....');
  371. observer.disconnect();
  372. }
  373.  
  374. // 自定义 urlchange 事件(用来监听 URL 变化)
  375. function addUrlChangeEvent() {
  376. history.pushState = (f => function pushState() {
  377. let ret = f.apply(this, arguments);
  378. window.dispatchEvent(new Event('pushstate'));
  379. window.dispatchEvent(new Event('urlchange'));
  380. return ret;
  381. })(history.pushState);
  382.  
  383. history.replaceState = (f => function replaceState() {
  384. var ret = f.apply(this, arguments);
  385. window.dispatchEvent(new Event('replacestate'));
  386. window.dispatchEvent(new Event('urlchange'));
  387. return ret;
  388. })(history.replaceState);
  389.  
  390. window.addEventListener('popstate', () => {
  391. window.dispatchEvent(new Event('urlchange'))
  392. });
  393. }
  394.  
  395.  
  396. //region 对话框组件
  397. /**
  398. * 初始化对话框
  399. */
  400. function initDialogueBox() {
  401. let percyMsgBoxDiv = document.getElementById("percyMsgBox");
  402. if (percyMsgBoxDiv != null) {
  403. return;
  404. }
  405.  
  406. percyMsgBoxDiv = document.createElement("div");
  407. percyMsgBoxDiv.id = "percyMsgBox";
  408.  
  409. percyMsgBoxDiv.style.display = 'none';
  410.  
  411. let oDiv = document.createElement("div");
  412.  
  413. /*div样式设置*/
  414. oDiv.style.backgroundColor = "#F0F0F0";
  415. oDiv.style.position = "absolute";
  416. oDiv.style.borderColor = "#AEC7E1";
  417. oDiv.style.borderWidth = "4px";
  418. oDiv.style.borderTopWidth = "30px";
  419. oDiv.style.borderStyle = "solid";
  420. oDiv.style.width = "250px";
  421. oDiv.style.height = "120px";
  422.  
  423. /*根据网页宽度 和窗口大小 来调整左边和顶边,使其居中显示*/
  424. let w = parseInt(document.documentElement.scrollWidth || document.body.scrollWidth);
  425. let h = parseInt(document.documentElement.scrollHeight || document.body.scrollHeight);
  426. // oDiv.style.left = (w - parseInt(oDiv.style.width)) / 5 * 2 + "px";
  427. // oDiv.style.top = (h - parseInt(oDiv.style.height)) / 5 * 2 + "px";
  428.  
  429. oDiv.style.left = (w - parseInt(oDiv.style.width)) / 5 * 2 + "px";
  430. oDiv.style.top = window.screen.availWidth / 6 + 'px';
  431.  
  432. //region 创建子元素
  433. /*创建标题*/
  434. let titleDiv = document.createElement("div");
  435. titleDiv.style = "text-align: center;position: relative;top: -26px;";
  436. let titleSpan = document.createElement("span");
  437. titleSpan.id = 'percyMsgBoxTitle';
  438. titleSpan.innerHTML = "title";
  439. titleSpan.style = "color:red";
  440. titleDiv.appendChild(titleSpan);
  441. oDiv.appendChild(titleDiv);
  442.  
  443. /*创建关闭按钮*/
  444. let closeSpan = document.createElement('span');
  445. closeSpan.innerHTML = 'X';
  446. let span1style = "background-color:red;position:absolute;top:-27px;right:3px;color:#FFFFFF;";
  447. span1style += "width:26px;border-radius:3px;text-align:center;line-height:26px;cursor:pointer;position:absolute;";
  448. closeSpan.style = span1style;
  449. closeSpan.onclick = function () {
  450. percyMsgBoxDiv.style.display = "none";
  451. dialogueResolve(-1);
  452. };
  453. oDiv.appendChild(closeSpan);
  454.  
  455. /*创建消息*/
  456. let msgDiv = document.createElement("div");
  457. msgDiv.style = "text-align:center";
  458. let msgSpan = document.createElement("span");
  459. msgSpan.id = 'percyMsg';
  460. msgSpan.innerHTML = 'message';
  461. msgSpan.style = "color:red";
  462. msgDiv.appendChild(msgSpan);
  463. oDiv.appendChild(msgDiv);
  464.  
  465. /*创建确定按钮*/
  466. let confirmButton = document.createElement("input");
  467. confirmButton.style = "left:30px;bottom:20px;position:absolute;";
  468. confirmButton.type = "button";
  469. confirmButton.value = "确定";
  470. confirmButton.onclick = function () {
  471. document.getElementById("percyMsgBox").style.display = "none";
  472. dialogueResolve(1);
  473. };
  474. oDiv.appendChild(confirmButton);
  475.  
  476. /*取消按钮*/
  477. let cancelButton = document.createElement("input");
  478. cancelButton.style = "right:30px;bottom:20px;position:absolute;";
  479. cancelButton.type = "button";
  480. cancelButton.value = "取消";
  481. cancelButton.onclick = function () {
  482. document.getElementById("percyMsgBox").style.display = "none";
  483. dialogueResolve(0);
  484. };
  485. oDiv.appendChild(cancelButton);
  486.  
  487. /*查看按钮*/
  488. let detailButton = document.createElement("input");
  489.  
  490. detailButton.style = "left:104px;bottom:20px;position:absolute;";
  491. detailButton.type = "button";
  492. detailButton.value = "查看";
  493. detailButton.onclick = function () {
  494. document.getElementById("percyMsgBox").style.display = "none";
  495. dialogueResolve(2);
  496. };
  497. oDiv.appendChild(detailButton);
  498. //endregion
  499.  
  500. percyMsgBoxDiv.appendChild(oDiv);
  501. document.body.appendChild(percyMsgBoxDiv);
  502.  
  503. /*拖动事件处理*/
  504. oDiv.onmousedown = function (ev) {/*鼠标按下*/
  505. let disX = ev.clientX - oDiv.offsetLeft;
  506. let disY = ev.clientY - oDiv.offsetTop;
  507. // console.log(disY);
  508. if (disY > 30) {/*使其只拖动标题栏有效*/
  509. return;
  510. }
  511. document.onmousemove = function (ev) {
  512. let l = ev.clientX - disX;
  513. let t = ev.clientY - disY;
  514.  
  515. oDiv.style.left = l + 'px';
  516. oDiv.style.top = t + 'px';
  517. };
  518. document.onmouseup = function () {/*鼠标松开*/
  519. document.onmousemove = null;
  520. document.onmouseup = null
  521. }
  522. };
  523. }
  524.  
  525.  
  526. let dialogueResolve = function () {
  527. };
  528.  
  529. /**
  530. * 创建对话框
  531. * @param title
  532. * @param message
  533. * @param isTop 是否有遮罩
  534. * @param onCreate 对话框创建完成回调函数
  535. * @returns {Promise<int>} 返回 -1:关闭 0:取消 1:确定
  536. */
  537. let initialWidth = null;
  538. let initialHeight = null;
  539.  
  540. async function createDialogue(title, message, shade, onCreate) {
  541. if (shade === undefined) {
  542. shade = true;
  543. }
  544. initDialogueBox();
  545. let percyMsgBoxDiv = document.getElementById("percyMsgBox");
  546. percyMsgBoxDiv.style.display = "block";
  547. let div = percyMsgBoxDiv.children[0];
  548. if (shade) {
  549. percyMsgBoxDiv.style = "width:100%;height:100%;position:absolute;left:0;top:0;z-index:99;";
  550. percyMsgBoxDiv.style.height = document.body.clientHeight + "px";
  551. } else {
  552. percyMsgBoxDiv.style = "";
  553. div.style.zIndex = "99";
  554. }
  555. if (initialWidth == null || initialHeight == null) {
  556. initialWidth = parseInt(div.style.width.replace("px", ""));
  557. initialHeight = parseInt(div.style.height.replace("px", ""));
  558. }
  559.  
  560. document.getElementById("percyMsgBoxTitle").innerText = title;
  561. document.getElementById("percyMsg").innerText = message;
  562.  
  563. let q = Math.pow(message.length / 18, 1 / 5);
  564. if (q < 1) {
  565. q = 1;
  566. }
  567.  
  568. div.style.width = initialWidth * q + "px";
  569. div.style.height = initialHeight * q + "px";
  570.  
  571. console.log('q:%s,w:%,h:%s', q, div.style.width, div.style.height);
  572.  
  573. // 调整查看按钮的位置
  574. let buttons = percyMsgBoxDiv.querySelectorAll('input[type=button]');
  575. let a = buttons[0].getClientRects()[0].x;
  576. let b = buttons[1].getClientRects()[0].x;
  577.  
  578. let a_left = buttons[0].style.left;
  579. a_left = parseInt(a_left.replace("px", ''));
  580. a_left += ((b - a) / 2);
  581.  
  582. // 查看按钮
  583. buttons[2].style.left = a_left + "px";
  584.  
  585. if (onCreate !== null && onCreate !== undefined) {
  586. onCreate();
  587. }
  588.  
  589. return new Promise(function (resolve) {
  590. dialogueResolve = resolve;
  591. });
  592. }
  593.  
  594. //endregion
  595.  
  596. (function () {
  597. if (window.onurlchange === undefined) {
  598. addUrlChangeEvent();
  599. } // Tampermonkey v4.11 版本添加的 onurlchange 事件 grant,可以监控 pjax 等网页的 URL 变化
  600. window.addEventListener('urlchange', function () { // 针对的是从单个回答页跳转到完整回答页时
  601. // Violentmonkey 比 Tampermonkey 加载更早,会导致一些元素还没加载,因此需要延迟一会儿
  602. // Tampermonkey 4.18.0 版本可能需要延迟一会执行
  603. if (GM_info.scriptHandler === 'Violentmonkey' || (GM_info.scriptHandler === 'Tampermonkey' && parseFloat(GM_info.version.slice(0, 4)) >= 4.18)) {
  604. setTimeout(start, 300);
  605. } else {
  606. start();
  607. }
  608. });
  609.  
  610. // Violentmonkey 比 Tampermonkey 加载更早,会导致一些元素还没加载,因此需要延迟一会儿
  611. // Tampermonkey 4.18.0 版本可能需要延迟一会执行
  612. if (GM_info.scriptHandler === 'Violentmonkey' || (GM_info.scriptHandler === 'Tampermonkey' && parseFloat(GM_info.version.slice(0, 4)) >= 4.18)) {
  613. setTimeout(start, 300);
  614. } else {
  615. start();
  616. }
  617.  
  618. function start() {
  619. debugger
  620. let flag = location.pathname.startsWith('/people/');
  621. if (flag && (location.pathname.endsWith('/following') || location.pathname.includes('/following?page'))) { // 关注的人
  622. console.log('取消关注的人');
  623. unfollow_members().then(r => console.log(r)); //取消关注的人
  624. return;
  625. }
  626. if (flag && location.pathname.includes('/following/columns')) { // 关注的专栏
  627. console.log('取消关注的专栏');
  628. // unfollow_columns(); // 取消关注的专栏
  629. return;
  630. }
  631. if (flag && location.pathname.includes('/following/topics')) { // 关注的话题
  632. console.log('取消关注的话题');
  633. unfollow_topics().then(r => console.log(r)); // 取消关注的话题
  634. return;
  635. }
  636. if ((flag && location.pathname.includes('/following/questions')) || window.location.href === 'https://www.zhihu.com/question/following') { // 关注的问题
  637. console.log('取消关注的问题');
  638. unfollow_questions().then(r => console.log(r)); // 取消关注的问题
  639. return;
  640. }
  641. }
  642. })();

QingJ © 2025

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