🏠 Home 

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