BiliBili+

在B站个人动态的视频列表里直接加入稍后看按钮

  1. // ==UserScript==
  2. // @name BiliBili+
  3. // @namespace BiliBili+@Byzod.user.js
  4. // @include /https?:\/\/www\.bilibili\.com\/account\/dynamic/
  5. // @version 2017-6-21b
  6. // @grant none
  7. // jshint esversion:6
  8. // @description 在B站个人动态的视频列表里直接加入稍后看按钮
  9. // ==/UserScript==
  10.  
  11. const WATCH_LATER_TEXT = " 【稍候再看】 ";
  12. const REMOVE_WATCH_LATER_TEXT = " 【移除稍候再看】 ";
  13. const WATCH_LATER_BG_COLOR = "#1672A4";
  14.  
  15. // 观察者,执行“添加稍后看按钮”
  16. let observer = new MutationObserver(AddWatchLaterButton);
  17. // 视频列表
  18. let vidsList = document.querySelector(".stm-lst");
  19. if(vidsList){
  20. observer.observe( vidsList, { childList: true } );
  21. } else {
  22. alert("[Bili+]: Vids list not exist");
  23. }
  24.  
  25. // 添加稍候看按钮
  26. async function AddWatchLaterButton(recs){
  27. // console.log("[Bili+]: recs %o", recs); // DEBUG
  28. // 先获取稍后看列表
  29. let addedVids = await GettingAddedWatchList();
  30. // console.log("[Bili+]: addedVids %o", addedVids); // DEBUG
  31. for(let rec of recs){
  32. rec.addedNodes.forEach(vidRow => {
  33. // 如果是视频,加个按钮
  34. if(vidRow.className == "stm-lst-item"){
  35. let vid = vidRow.querySelector(".hint>a");
  36. let av = vid.href;
  37. av = av.match(/\d+/)[0];
  38. // console.log("[Bili+]: av " + av); // DEBUG
  39. if(!vid.parentNode.querySelector(".watch-later-btn")){
  40. let watchLaterBtn = document.createElement("button");
  41. watchLaterBtn.className = "watch-later-btn";
  42. watchLaterBtn.style.trasition = "0.5s";
  43. if(!addedVids.includes(parseInt(av))){
  44. // 不在稍后看里,只改提示
  45. watchLaterBtn.innerText = WATCH_LATER_TEXT;
  46. } else {
  47. // 已在稍后看里,改为移除按钮样式
  48. watchLaterBtn.innerText = REMOVE_WATCH_LATER_TEXT;
  49. watchLaterBtn.style.backgroundColor = WATCH_LATER_BG_COLOR;
  50. }
  51. // 挂添加/移除事件处理
  52. watchLaterBtn.onclick = ()=>{ ToggleWatchLater(av, watchLaterBtn); };
  53. // 加在链接后面
  54. vid.parentNode.appendChild(document.createElement("br"));
  55. vid.parentNode.appendChild(watchLaterBtn);
  56. }
  57. }
  58. });
  59. }
  60. }
  61.  
  62. // 获取稍后看列表
  63. async function GettingAddedWatchList(){
  64. return new Promise(async (resolve, reject)=>{
  65. let r = null;
  66. let url = new URL(location.protocol + "//api.bilibili.com/x/v2/history/toview/web");
  67. let params = {
  68. jsonp: "jsonp",
  69. sid: GetCookieValue('sid'), // 大概是用户id
  70. csrf: GetCookieValue('bili_jct') // 并不清楚这是啥
  71. }
  72. Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
  73. try{
  74. r = await (await fetch(url, {method: "GET", credentials: "include"})).json();
  75. } catch (ex) {
  76. r = null;
  77. }
  78. // console.log("[Bili+]: fetch result %o", r); // DEBUG
  79. if(r && r.data && r.data.list){
  80. resolve(r.data.list.map(vid=>vid.aid));
  81. } else {
  82. reject([])
  83. }
  84. });
  85. }
  86.  
  87. // 切换稍后看状态
  88. async function ToggleWatchLater(av, btn){
  89. // console.log("[Bili+]: Toggle av %o", av); // DEBUG
  90. // 先获取稍后看列表
  91. let addedVids = await GettingAddedWatchList();
  92. let isWatchLater = addedVids.includes(parseInt(av));
  93. // console.log("[Bili+]: " + (isWatchLater ? "Removing from watch later" : "Adding to watch later")); // DEBUG
  94. let result = null;
  95. let url = new URL(location.protocol + "//api.bilibili.com/x/v2/history/toview/" + (isWatchLater ? "del" : "add"));
  96.  
  97. let params = {
  98. aid: av,
  99. jsonp: "jsonp",
  100. csrf: GetCookieValue('bili_jct') // 并不清楚这是啥
  101. }
  102. Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
  103. try{
  104. result = await (await fetch(url, {method: "POST", credentials: "include"})).json();
  105. } catch (ex) {
  106. // 一般来说是网络错误
  107. result = ex;
  108. btn.innerText = " 【操作失败,请重试】 ";
  109. }
  110. if(result.code == "0"){
  111. // 添加/移除成功
  112. btn.innerText = (isWatchLater ? WATCH_LATER_TEXT : REMOVE_WATCH_LATER_TEXT);
  113. btn.style.backgroundColor = (isWatchLater ? "" : WATCH_LATER_BG_COLOR);
  114. if(MessageBox){(new MessageBox).show(btn, "已" + (isWatchLater ? "移除" : "添加"), 700, "info")};
  115. } else {
  116. // 服务器返回失败
  117. if(MessageBox){(new MessageBox).show(btn, "粗错啦:\n" + result.message, 3000, "error")};
  118. btn.innerText = result.message;
  119. }
  120. }
  121.  
  122. // 获取cookie
  123. function GetCookieValue(name) {
  124. var valueMatch = document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]+)');
  125. return valueMatch ? valueMatch.pop() : '';
  126. }

QingJ © 2025

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