[Bilibili] MarkAsRead

Mark all sessions as read with one click!

  1. // ==UserScript==
  2. // @name [Bilibili] MarkAsRead
  3. // @name:zh-CN [Bilibili] 一键已读
  4. // @namespace ckylin-script-bilibili-mark-as-read
  5. // @version 0.6
  6. // @description Mark all sessions as read with one click!
  7. // @description:zh-CN 一键设置所有会话已读!
  8. // @author CKylinMC
  9. // @match https://message.bilibili.com/*
  10. // @grant unsafeWindow
  11. // @supportURL https://github.com/CKylinMC/UserJS
  12. // @license GPL-3.0-only
  13. // ==/UserScript==
  14.  
  15. if (typeof (unsafeWindow) === "undefined") var unsafeWindow = window;
  16. (function () {
  17. 'use strict';
  18. const blacklist_elTitle = ["我的应援团","未关注人消息","疑似不良消息"];
  19. const wait = t => new Promise(r => setTimeout(r, t));
  20. const inBlacklist = el=>{
  21. for(let titleItem of blacklist_elTitle){
  22. if(el.querySelector(`[title='${titleItem}']`)) return true;
  23. }
  24. return false;
  25. }
  26. const touch = async el => {
  27. el.click();
  28. await wait(100)
  29. };
  30. const touchList = async div => {
  31. let active = div.querySelector(".active");
  32. for (let el of [...div.children].splice(1)) {
  33. if (el.classList.contains("list-item") && el.querySelector(".notify") && !inBlacklist(el)) await touch(el)
  34. }
  35. if (active) await touch(active)
  36. else location.hash = "#/whisper";
  37. };
  38. const msgList = () => document.querySelector("div.list");
  39. const asRead = async () => await touchList(msgList());
  40. const settingList = () => document.querySelector("ul.list");
  41. const intervalLog = {
  42. intervalId: null,
  43. lastHash: location.hash,
  44. lastState: false
  45. };
  46. const intervalHashChecker = ()=>{
  47. if(location.hash!==intervalLog.lastHash) {
  48. hashChecker();
  49. intervalLog.lastHash = location.hash;
  50. }
  51. }
  52. const hashChecker = ()=>{
  53. if(location.hash.startsWith("#/whisper")) {
  54. if(!intervalLog.lastState) {
  55. injectBtn();
  56. intervalLog.lastState = true;
  57. }
  58. }
  59. else{
  60. if(!intervalLog.lastState) return;
  61. let old;
  62. if (old = document.querySelector("#CKMARKREAD-BTN")) {
  63. old.style.transition = "margin .3s .2s, opacity .5s";
  64. old.style.opacity = "0";
  65. old.style.margin = "0px 0px";
  66. setTimeout(()=>old.remove(),300);
  67. }
  68. intervalLog.lastState = false;
  69. }
  70. };
  71. const waitFor = async (func, waitt = 100, retries = 100) => {
  72. while (--retries > 0) {
  73. try {
  74. const val = await func();
  75. if (val) return val;
  76. await wait(waitt);
  77. } catch (e) {
  78. console.log(e);
  79. await wait(100);
  80. }
  81. }
  82. return false;
  83. };
  84. const injectBtn = async () => {
  85. if (await waitFor(() => settingList())) {
  86. let old;
  87. if (old = document.querySelector("#CKMARKREAD-BTN")) old.remove();
  88. const a = document.createElement("a");
  89. a.href = "javascript:void(0)";
  90. a.innerHTML = "💬 全部标为已读";
  91. a.onclick = async (e) => {
  92. e.target.innerHTML = "🕓 请稍等...";
  93. await waitFor(() => msgList());
  94. await asRead();
  95. e.target.innerHTML = "✔ 已标为已读";
  96. e.target.onclick = e => e.target.innerHTML = "✔ 无需操作";
  97. setTimeout(()=>{
  98. e.target.parentElement.style.transition = "margin .3s .2s, opacity .5s";
  99. e.target.parentElement.style.opacity = "0";
  100. e.target.parentElement.style.margin = "0px 0px";
  101. setTimeout(()=>e.target.parentElement.remove(),300);
  102. },3000);
  103. };
  104. const item = document.createElement("li");
  105. item.classList.add("item");
  106. item.id = "CKMARKREAD-BTN";
  107. item.style.opacity = "0";
  108. item.style.margin = "0px 0";
  109. item.style.transition = "all .3s";
  110. item.appendChild(a);
  111. settingList().appendChild(item);
  112. setTimeout(()=>{
  113. if(item){
  114. item.style.margin = "15px 0";
  115. item.style.opacity = "1";
  116. }
  117. },50)
  118. }
  119. };
  120. const delayedInjectTask = async () => {
  121. await wait(1000);
  122. hashChecker();
  123. if(intervalLog.intervalId)clearInterval(intervalLog.intervalId);
  124. intervalLog.intervalId = setInterval(intervalHashChecker,300);
  125. };
  126. delayedInjectTask();
  127. })();

QingJ © 2025

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