Greasy Fork镜像 支持简体中文。

在B站(Bilibili)网页上手动标记已看过的视频

在B站的网页上手动标记哪些视频是已经看过的,直观区分已看和未看的视频,减少多次打开同一视频的操作。暂时只维护了首页、视频观看、历史、稍后再看、up空间、搜索结果,其他页面暂缓维护(B站更新迭代不适配)。

  1. // ==UserScript==
  2. // @name 在B站(Bilibili)网页上手动标记已看过的视频
  3. // @version 3.2.7
  4. // @description 在B站的网页上手动标记哪些视频是已经看过的,直观区分已看和未看的视频,减少多次打开同一视频的操作。暂时只维护了首页、视频观看、历史、稍后再看、up空间、搜索结果,其他页面暂缓维护(B站更新迭代不适配)。
  5. // @author Truazusa
  6. // @namespace BiliSearchViewed
  7. // @match https://search.bilibili.com/*
  8. // @match https://space.bilibili.com/*
  9. // @match https://t.bilibili.com/*
  10. // @match https://www.bilibili.com/*
  11. // 20220607注:域名static.hdslb.com是B站本身的网站
  12. // @require https://static.hdslb.com/js/jquery.min.js
  13. // @grant unsafeWindow
  14. // @grant GM_setValue
  15. // @grant GM_getValue
  16. // @grant GM_deleteValue
  17. // @grant GM_listValues
  18. // ==/UserScript==
  19.  
  20.  
  21. // 透明度设置修改下面三个变量:数值越小越透明,1不透明、0完全透明
  22. // ***********************************************************
  23. // 全局:视频封面(已看):透明度 设定(0.0-1.0)
  24. var opacityIsViewCover = 0.1; // 【idue】0.65
  25. // 全局:未看按钮:透明度 设定(0.0-1.0)
  26. var opacitybtnView = 0.7; // 【idue】0.8
  27. // 全局:已看按钮:透明度 设定(0.0-1.0)
  28. var opacitybtnIsView = 0.3; // 【idue】0.8
  29. // ***********************************************************
  30.  
  31. var GM_addStyle = GM_addStyle || function(css) {
  32. var style = document.createElement("style");
  33. style.type = "text/css";
  34. style.appendChild(document.createTextNode(css));
  35. document.getElementsByTagName("head")[0].appendChild(style);
  36. };
  37.  
  38. // 增加自定义样式
  39. let staticStyle = `
  40. .btnView{opacity:`+opacitybtnView+`;background:#fff;color:#999!important;width:fit-content;line-height:16px;font-size:12px;text-align:center;cursor:pointer;display:inline-block;position:absolute;left:0;top:0;z-index:2;border:1px solid #999;border-radius:3px;padding:3px 5px;}
  41. .btnIsView{opacity:`+opacitybtnIsView+`;background:#fff8;}/*【idue】background:#FF9EB5;color:#aaa;*/
  42. .btnView:hover{opacity:1;background:#aaa;color:#fff!important;}
  43. .btnIsView:hover{background:#fff;opacity:1;color:#999!important;}/*【idue】background:#FF7BA9;*/
  44. .btnSetAllViewed,.btnRefresh{display:inline-block;background:#fff;font-size:14px;border:1px solid #999;border-radius:5px;color:#999;padding:3px 5px;cursor:pointer;word-break:keep-all;}
  45. .btnSetAllViewed:hover,.btnRefresh:hover{background:#aaa;color:#fff;}`;
  46.  
  47. var searchStyle = `
  48. /*搜索结果页*/
  49. /*自定义的数据操作按钮:默认样式*/
  50. .btnList{display:inline-block;background:#fff;border:1px solid #999;border-radius:5px;color:#999;padding:3px 5px;cursor:pointer;}
  51. .btnList:hover{background:#aaa;color:#fff;}
  52. .btnListSave{display:inline-block;display:none;background:#fff;border:1px solid #999;border-radius:5px;color:#999;padding:3px 5px;cursor:pointer;}
  53. .btnListSave:hover{background:#aaa;color:#fff;}
  54. .viewList{width:100%;height:120px;margin:10px 0;display:none;color:#999;padding:3px 5px;}
  55. /*202501版本:按钮位置微调*/
  56. .btnList{position:absolute;top:11px;right:0;}
  57. .btnListSave{position:absolute;top:11px;right:83px;}
  58. /*202504版本:按钮位置微调*/
  59. .search-input .search-input-container .search-input-wrap{margin:0 10px 0 0;}
  60. /*202501版本:番剧搜索结果*/
  61. .media-card-content-footer-btns{height:45px!important;}
  62. .p_relativeSpan{position:relative;padding:0 0 22px;display:inline-block;}
  63. .p_relativeSpan .btnView{left:-1px;top:unset;bottom:0;position:absolute;border:none;}
  64. .media-footerClone{position:absolute;}
  65. .media-footerClone a{margin-right:8px;}
  66. .media-footerClone .media-footer-badge{top:-14px;}
  67. .bangumi-pgc-list .media-item{overflow-y:auto;}
  68. .media-card>.btnView{left:8px;}
  69. .media-card-image-follow[data-v-402c7b9e]{top:22px;}
  70. /*202501版本:综艺搜索结果*/
  71. .selConSpan{position:relative;}
  72. .selConSpan .btnView{top:8px;left:4px;}
  73. .media-footer-select-content-item{padding:0 6px 0 48px!important;}
  74. `;
  75.  
  76. const spaceStyle = `
  77. /*别人的空间页:space.bili*/
  78. .btnRefresh{margin:0 0 0 16px;line-height:20px;}
  79. .n-inner .btnRefresh{top:5px;position:relative;}
  80. /*202503选旧版:【主页】TA的视频、合集·XXXX*/
  81. .small-item .cover{background:none!important;}
  82. .small-item .btnView{top:10px;left:10px;}
  83. /*202503选旧版:【主页】TA的视频*/
  84. #page-index .video .small-item:nth-child(4n+1) .btnView{left:0;}
  85. /*202503选旧版:【主页】合集·XXXX*/
  86. .channel-video .small-item:nth-child(4n+1) .btnView{left:0;}
  87. /*202503选新版or选旧版:【动态】*/
  88. .bili-dyn-content__orig__major{position:relative;}
  89. /*202503选旧版:【投稿】list模式*/
  90. #submit-video-list .list-list .btnView{top:20px;left:0;}
  91. /*202503选旧版:【合集和列表】list模式*/
  92. .series-item .btnView{top:10px;left:10px;}
  93. /*202503选旧版:【合集和列表】某个合集点“更多”*/
  94. .channel-detail .btnView{top:20px;}
  95. /*202503选旧版:【收藏】*/
  96. .fav-video-list .btnView{top:0;left:0;z-index:9;}
  97. `;
  98.  
  99. const historyStyle = `
  100. /*历史页*/
  101. /*202501版本*/
  102. .btnView{left:unset;right:0;}
  103. .btnSetAllViewed,.btnRefresh{line-height:22px;margin-right:16px;}
  104. `;
  105.  
  106. var videoStyle = `
  107. /*视频观看页*/
  108. /*202501版本:主视频-信息栏*/
  109. .video-info-detail-list .pubdate-ip .btnView{position:unset;margin:0 0 0 10px;border:none;width:35px;}
  110. /*202501版本:播放结束后出现的推荐视频*/
  111. .bpx-player-ending-related-itemDiv{position:relative;float:left}
  112. .bpx-player-ending-related-itemDiv .btnView{opacity:0.9;}
  113. .bpx-player-ending-related-itemDiv .btnIsView{opacity:0.7;}
  114. /*202501版本:主视频下方工具栏(“刷新”按钮设置)*/
  115. .video-toolbar-right .btnRefresh{line-height:22px;}
  116. /*202501版本:订阅合集or视频选集(分P视频列表);带封面or纯标题*/
  117. .normal-base-item .cover,.simple-base-item{position:relative;}
  118. .simple-base-item .btnView{top:4px;left:4px;}
  119. .simple-base-item.normal,.simple-base-item.head{padding:0 10px 0 48px;}
  120. .page-list .page-item{padding:0 10px 0 65px;}
  121. .page-list .page-item .btnView{left:20px;}
  122. /*202501版本:视频选集(分P视频列表)grid模式:数字标题*/
  123. .rcmd-tab .video-pod .video-pod__body .video-pod__list.multip.grid>.page{padding-bottom:25px;height:50px;}
  124. .page{position:relative;}
  125. .page .btnView{position:absolute;bottom:0;top:unset;left:6px;width:32px;}
  126. `;
  127.  
  128.  
  129. var festivalVideoStyle = `
  130. /*202303活动视频播放页*/
  131. .video-section-title{z-index:3!important;}
  132. .video-episode-card__cover .btnView{line-height:12px;width:25px;} /*跟视频页重复的*/
  133. .recommend-video-card{position:relative;}
  134. .recommend-video-card .btnView{right:unset;top:6px;line-height:12px;width:25px;}
  135. .video-toolbar-content_right .btnRefresh{position:relative;top:0;right:15px;line-height:21px;border-radius:2px;}
  136. .video-toolbar-content_left .btnView{position:relative;line-height:16px;height:16px;top:9px;}`;
  137.  
  138. var watchlaterStyle = `
  139. /*稍后再看-列表页*/
  140. /*202501版本*/
  141. .btnView{left:unset;right:0;z-index:201;}
  142. .btnSetAllViewed,.btnRefresh{font-size:14px;line-height:22px;}
  143. `;
  144.  
  145. var listPlayStyle = `
  146. /*稍后再看-视频观看页*/
  147. .tip-info .btnRefresh{font-size:12px;position:absolute;right:0;}
  148. .player-auxiliary-playlist-item{position:relative;}
  149. .player-auxiliary-playlist-item .btnView{position:absolute;top:6px;left:65px;}
  150. .player-auxiliary-playlist-item:first-child .btnView{top:0;}
  151. /*稍后再看-视频观看页at202303*/
  152. .main .btnView{left:0;width:25px;line-height:12px;}
  153. .multip-list-item .left-part{position:relative;padding:0 0 0 40px;}
  154. .multip-list .multip-list-item-active[data-v-079b367a]{padding:0 10px;}
  155. .multip-list-item .btnView{left:0;width:25px;line-height:12px;}
  156. .video-info-detail-list .btnView{position:unset;margin:0;border:none;width:35px;}
  157. .video-toolbar-right .btnRefresh{right:0;top:0;position:relative;}
  158. /*202501版本*/
  159. .video-info-detail-list .pubdate-ip .btnView{position:unset;margin:0 0 0 10px;border:none;width:35px;}
  160. `;
  161.  
  162. var popularStyle = `
  163. /*综合热门、每周必看、入站必刷*/
  164. .popular-video-container .btnView{width:40px}
  165. .weekly-list .weekly-header .panel{z-index:2;}
  166. /*排行榜*/
  167. .popular-container .rank-container .rank-list .rank-item .btnView{font-size:14px;width:45px;height:24px;}
  168. /*全站音乐榜*/
  169. ._card_1kuml_6 .btnView{top:unset;left:12px;bottom:72px;border:1px solid #999;font-size:12px;}
  170. /*短剧榜*/
  171. .drama-board-listClone{justify-content:space-between;flex-wrap:wrap;display:flex;height:0;}
  172. .board-item-wrapDiv{margin-bottom:30px;position:relative;float:left;}
  173. .board-item-wrapDiv .btnView{right:unset;top:16px;left:182px;}`;
  174.  
  175. var indexStyle = `
  176. /*主站首页*/
  177. /*202501版本*/
  178. `;
  179.  
  180. var channelStyle = `
  181. /*频道*/
  182. .card-list .btnView{left:unset;top:0;right:0;width:40px;}`;
  183.  
  184. var bangumiStyle = `
  185. /*bangumi视频观看页*/
  186. .toolbar_toolbar__NJCNy .btnRefresh{right:0;cursor:pointer;}
  187. /*202403版本*/
  188. .toolbar .btnRefresh{right:0;top:14px;cursor:pointer;}
  189.  
  190. /*主视频*/
  191. .toolbar_toolbar__NJCNy .btnView{right:unset;width:36px;top:20px;border:none;}
  192. /*202403版本*/
  193. .toolbar .btnView{right:60px;width:36px;top:19px;border:none;}
  194.  
  195. /*右侧上 正片列表 list模式*/
  196. .longListItem_wrap__9OsZi .btnView{right:unset;position:relative;width:36px;margin:0 7px 0 0;}
  197. /*右侧上 正片列表 cube模式*/
  198. .numberListItem_number_list_item__wszA4 a{height:18px;}
  199. .numberListItem_number_list_item__wszA4 .btnView{width:32px;padding:0;border-radius:1px;right:unset;left:0;border:none;}
  200. /*右侧中 PV&其他*/
  201. .epitem_ep_item__CPdZy .btnView{width:36px;height:24px;position:relative;float:left;margin:3px 5px 0 0;text-align:center;color:#aaa;}
  202. .epitem_ep_item__CPdZy .btnView:hover{color:#fff;background:#aaa;}
  203. /*右侧下 系列*/
  204. .seasonlist_ss_info__Yc7YV{width:130px;}
  205. .seasonlist_ss_item__czhHy .btnView{height:24px;width:40px;position:relative;right:280px;}
  206. /*右侧下 相关推荐*/
  207. .RecommendItem_wrap__pJmXL{position:relative;}
  208. .RecommendItem_wrap__pJmXL .btnView{height:22px;width:40px;position:absolute;right:unset;}
  209. .RecommendItem_wrap__pJmXL .RecommendItem_cover__Rc3y2{background:none;}`;
  210.  
  211. var cheeseStyle = `
  212. /*课堂分区首页*/
  213. .block-list-item{position:relative;}
  214. .rank dd{position:relative;}
  215. .rank dd .btnView{right:unset;left:28px;line-height:12px;width:25px;}
  216. .common-lazy-img{background:none;}
  217. /*课程分类查找页*/
  218. .big-card .btnView{right:unset;left:0;}`;
  219.  
  220. var cheesePlayStyle =`
  221. /*课程视频观看页*/
  222. .section-item .btnView{line-height:12px;width:25px;left:2px;bottom:7px;top:unset;border:none;}
  223. .layout-r .btnRefresh{position:relative;top:0;right:0;cursor:pointer;line-height:24px;margin:0 0 0 10px;}
  224. .layout-l .btnView{position:relative;border:none;}
  225. /*右侧下 相关推荐*/
  226. .season-recommend-card{position:relative;}
  227. .season-recommend-card .btnView{right:unset;line-height:12px;width:25px;}`
  228.  
  229. var areaStyle = `
  230. /*各分区首页or首页右侧的排行榜*/
  231. .bili-rank-list-video__item--wrap{position:relative;}
  232. .bili-rank-list-video__item--wrap .btnView{right:-8px;color:#aaa;border:1px solid #aaa;}
  233. .bili-rank-list-cheese__item--wrap .btnView{color:#aaa;border:1px solid #aaa;}
  234. .bili-rank-list-ogv__item--wrap .btnView{color:#aaa;border:1px solid #aaa;}`;
  235.  
  236. var varietyStyle = `
  237. /*综艺分区首页*/
  238. .side-item{position:relative;}
  239. .side-item .btnView{width:25px;line-height:12px;}
  240. .hot-item{position:relative;}
  241. .column-itemDiv{-webkit-box-flex:1;flex:1;margin:0 16px 0 0;border-radius:8px;overflow:hidden;position:relative;}
  242. .column-itemDiv .btnView{right:unset;left:0;}
  243. .hover-item .btnView{right:unset;z-index:3;}
  244. .web_rank_v2 .hover-item .btnView{right:0;}
  245. /*综艺索引*/
  246. .bangumi-item{position:relative;}
  247. .bangumi-item .btnView{right:unset;left:0;}`;
  248.  
  249. var guochangStyle = `
  250. /*国创*/
  251. .progress-bar-content .btnView{top:4px;right:4px;border-radius:7px;}
  252. .timeline-weekday-hover-item .btnView{z-index:10;right:unset;}
  253. .ranking-ratio-item-container .btnView{z-index:10;right:unset;}
  254. /*国创:二级分区*/
  255. .spread-module .lazy-img{background:none;}
  256. .spread-module .btnView{width:25px;line-height:12px;}
  257. .sec-rank .rank-item .btnView{width:25px;line-height:12px;right:unset;}
  258. .rank-list .rank-item.show-detail .ri-detail{padding:0 0 0 40px;}
  259. .rank-list .rank-item.show-detail.highlight .ri-detail{padding:0;}
  260. .rank-list .rank-item.show-detail a:hover .ri-detail{padding:0;}
  261. /*国创:索引*/
  262. .bangumi-item{position:relative;}
  263. .bangumi-item .btnView{right:unset;}
  264. .bangumi-item .common-lazy-img{background:none;}
  265. .rank-item .lazy-img{background:none;}`;
  266.  
  267. let setMethod = null;
  268. let timer = null;
  269. let viewVideoList = null;
  270. const btnRefresh = $("<a class='btnRefresh' title='如果列表没出现已看/未看标识,请手动点击这个按钮进行刷新'>刷新</a>");
  271. let btnSetAllViewed = null;
  272. // 增加全局样式设置
  273. GM_addStyle(staticStyle);
  274. // 页面加载后分类处理
  275. $(document).ready(function(){
  276. var oldList = GM_getValue("BiliViewed",null);
  277. if(oldList != null){
  278. // 对原已看数据列表进行分组
  279. groupGMVideoList(oldList);
  280. }
  281. // 获取页面高度:用于滚动条监听
  282. pageHeight = $(window).height() * 0.66;
  283. var domain = location.href;
  284. var askIndex = domain.indexOf("?");
  285. if(askIndex > -1){
  286. domain = domain.substring(0,askIndex);
  287. }
  288. domain = domain.toLowerCase();
  289. if(domain.indexOf("search.") > -1){
  290. // 搜索页
  291. GM_addStyle(searchStyle);
  292. setMethod = setSearchPage;
  293. }else if(domain.indexOf("space.") > -1){
  294. // up主页空间
  295. GM_addStyle(spaceStyle);
  296. setMethod = setSpacePage;
  297. }else if(domain.indexOf("t.") > -1){
  298. // 登录(不可用)后的动态
  299. GM_addStyle(spaceStyle);
  300. setMethod = setSpacePage;
  301. // 滚动条下拉响应
  302. setPageScrollMethod();
  303. // up主头像点击响应
  304. if($(".bili-dyn-up-list__item").length == 0){
  305. // 头像未加载出来,等2秒后重新绑定
  306. setTimeout(function(){
  307. $(".bili-dyn-up-list__item").unbind("click").click(function(){
  308. prePageScrollTop = 0;
  309. setTimeout(setPageRefreshMethod,2000);
  310. })
  311. },2000);
  312. }
  313. }else if(domain.indexOf("www.") > -1){
  314. // 主站
  315. var href = location.href;
  316. href = href.toLowerCase();
  317. if(href.indexOf("/bangumi/play/") > -1){
  318. // 节目-视频观看页
  319. GM_addStyle(bangumiStyle);
  320. setMethod = setBangumiPage;
  321. }else if(href.indexOf("/cheese/play/") > -1){
  322. // 课程-视频观看页
  323. GM_addStyle(cheesePlayStyle);
  324. setMethod = setCheesePlayPage;
  325. }else if(href.indexOf("/cheese/") > -1){
  326. // 课程-分区首页
  327. GM_addStyle(cheeseStyle);
  328. setMethod = setCheesePage;
  329. }else if(href.indexOf("/guochuang") > -1 || href.indexOf("/anime") > -1){
  330. // 番剧、国创-分区
  331. GM_addStyle(guochangStyle);
  332. setMethod = setGuochuangPage;
  333. // 滚动条下拉监听
  334. setPageScrollMethod();
  335. }else if(href.indexOf("/v/musicplus") > -1){
  336. // 新歌热榜-分区
  337. GM_addStyle(indexStyle);
  338. setMethod = setMusicplusPage;
  339. }else if(href.indexOf("/play/watchlater") > -1){
  340. // 稍后再看-视频观看页 (202303注:貌似已经自动跳转到/list/watchlater了)
  341. return;
  342. }else if(href.indexOf("/list/") > -1){
  343. // 列表-视频观看页 (202303增加)
  344. // 稍后再看-播放全部 按钮点击进入 /list/watchlater
  345. // 个人收藏-播放全部 按钮点击进入 /list/mlxxxxx
  346. GM_addStyle(listPlayStyle);
  347. setMethod = setListPlayPage;
  348. // 右侧 稍后再看 滚动条下拉监听(局部)
  349. $("#playlist-video-action-list").scroll(function(){
  350. var curScrollTop = $("#playlist-video-action-list").scrollTop();
  351. if(Math.abs(curScrollTop - preScrollTop) > 300){
  352. preScrollTop = curScrollTop;
  353. setTimeout(function(){setMethod();},1000)
  354. }
  355. })
  356. // 右侧下 推荐视频 滚动条下拉监听
  357. setPageScrollMethod();
  358. // 右侧下 推荐视频 展开按钮点击响应
  359. $(".rec-footer").click(function(){
  360. setTimeout(function(){setMethod();},1000)
  361. });
  362. }else if(href.indexOf("/watchlater") > -1){
  363. // 稍后再看(列表页) :顶部收藏-稍后再看-查看全部
  364. GM_addStyle(watchlaterStyle);
  365. // 设置一键已看相关功能
  366. setAllViewedMethod();
  367. // 设置页面
  368. setMethod = setWatchlaterPage;
  369. // 滚动条下拉监听
  370. setPageScrollMethod();
  371. }else if(href.indexOf("/video/") > -1){
  372. // 视频观看页
  373. GM_addStyle(videoStyle);
  374. setMethod = setVideoPage;
  375. // 右侧下 推荐视频 滚动条下拉监听
  376. setPageScrollMethod();
  377. }else if(href.indexOf("/festival/") > -1){
  378. // 活动视频观看页
  379. GM_addStyle(festivalVideoStyle);
  380. setMethod = setFestivalVideoPage;
  381. // 右侧下 推荐视频 滚动条下拉监听
  382. setPageScrollMethod();
  383. }else if(href.indexOf("/popular/") > -1){
  384. // 2023新增:综合热门、每周必看、入站必刷、排行榜、全站音乐榜
  385. GM_addStyle(popularStyle);
  386. setMethod = setPopularPage;
  387. // tab点击监听
  388. $(".nav-tabs__item").click(function(e){
  389. setTimeout(function(){setMethod();},3000)
  390. })
  391. // 滚动条下拉监听(主要用于:综合热门)
  392. setPageScrollMethod();
  393. }else if(href.indexOf("/history") > -1 ){
  394. // 历史页
  395. GM_addStyle(historyStyle);
  396. // 设置一键已看相关功能
  397. setAllViewedMethod();
  398. // 设置页面
  399. setMethod = setHistoryPage;
  400. // 滚动条下拉监听
  401. setPageScrollMethod();
  402. // 设置一键已看
  403. }else if(href.indexOf("/v/channel/") > -1 ){
  404. // 频道页
  405. GM_addStyle(channelStyle);
  406. setMethod = setChannelPage;
  407. setTimeout(function(e){
  408. // 左侧 发现频道 按钮点击响应
  409. $(".discovery-panel__title").click(function(e){
  410. setTimeout(setMethod,2000);
  411. })
  412. // 左侧 分类 点击响应
  413. $(".content-item").click(function(e){
  414. setTimeout(setMethod,4000);
  415. })
  416. // 左侧 我的订阅 Item点击响应
  417. $(".subscribe-item").click(function(e){
  418. setTimeout(setMethod,4000);
  419. })
  420. },2000);
  421. }else if(href.indexOf("/variety/") > -1 || href.indexOf("/movie/") > -1 || href.indexOf("/tv/") > -1 || href.indexOf("/documentary/") > -1){
  422. // 2023新增:分区:综艺、电影、电视剧、纪录片
  423. GM_addStyle(varietyStyle);
  424. setMethod = setVarietyPage;
  425. // 滚动条下拉监听
  426. setPageScrollMethod();
  427. }else if(href.endsWith(".com/") || href.indexOf(".com/?") > -1 || href.indexOf(".com/index.html") > -1){
  428. // 主站首页
  429. GM_addStyle(indexStyle);
  430. setMethod = setIndexPage;
  431. // 滚动条下拉监听
  432. setPageScrollMethod();
  433. setTimeout(function(){
  434. // 202501版本:(左上)白色“换一换”按钮 点击响应
  435. $(".feed-roll-btn").click(function(e){
  436. setTimeout(setMethod,2000);
  437. })
  438. // 202501版本:(左下)蓝色“刷新内容”按钮 点击响应
  439. $(".flexible-roll-btn").unbind("click").click(function(){
  440. setTimeout(setMethod,2000);
  441. })
  442. },2000);
  443. }else{
  444. // 主站其他页面,如分区主页:鬼畜、舞蹈、娱乐、科技、美食、游戏、音乐、影视、知识、资讯、更多
  445. GM_addStyle(areaStyle);
  446. setMethod = setAreaPage;
  447. // 滚动条下拉监听
  448. setPageScrollMethod();
  449. // 子分区按钮点击响应
  450. $(".channel-nav-sub-item").click(function(e){
  451. setTimeout(function(){setMethod();},1000)
  452. })
  453. }
  454. }
  455. // 刷新按钮 点击响应
  456. btnRefresh.click(function(){
  457. setPageRefreshMethod();
  458. })
  459. // 检查执行结果(每3秒执行检查一次,最多执行5次)
  460. if(setMethod != null){
  461. timer = setInterval(checkBtnViewLoad,3000);
  462. }
  463. });
  464.  
  465. // 局部模块滚动条响应
  466. var preScrollTop = 0;// 上一次局部模块滚动条到达的高度
  467. // 设置页面滚动条响应
  468. var pageHeight = 600; // 设置页面高度的三分二自动刷新一次
  469. var curPageScrollTop = 0; // 当前页面滚动条的高度
  470. var prePageScrollTop = 0; // 上一次页面滚动条到达的高度
  471. var setPageScrollMethod = function(){
  472. $(window).scroll(function(){
  473. var curPageScrollTop = $(document).scrollTop();
  474. if(Math.abs(curPageScrollTop - prePageScrollTop) > pageHeight){
  475. prePageScrollTop = curPageScrollTop;
  476. setTimeout(setMethod,1000);
  477. }
  478. })
  479. }
  480.  
  481. // 设置刷新功能
  482. var setPageRefreshMethod = function(){
  483. $(".btnView").remove();
  484. viewVideoJson = {};
  485. setMethod();
  486. setTimeout(function(e){
  487. setMethod();
  488. },3000);
  489. }
  490.  
  491. // 设置一键已看相关功能
  492. const setAllViewedMethod = function(){
  493. btnSetAllViewed = $("<a class='btnSetAllViewed' title='一键设置未看视频为已看。只针对当前页面已加载出来的视频(带未看按钮的)。可以拉到页面底部加载出更多的视频再点这个。执行该操作后不可进行撤销,可根据个人情况进行使用。'>一键已看</a>")
  494. // 一键已看 点击响应
  495. btnSetAllViewed.click(function(){
  496. if(!confirm($(this).attr("title"))){
  497. return;
  498. }
  499. $(".btnNotView").each(function(idx){
  500. saveGMVideoList($(this).data("av"),true);
  501. });
  502. setPageRefreshMethod();
  503. })
  504. }
  505.  
  506. // 202303新增:课程视频播放页
  507. var setCheesePlayPage = function(){
  508. var refreshObj = $(".btnRefresh");
  509. if(refreshObj.size() == 0){
  510. $(".layout-r").append("<a class='btnRefresh' title='如果列表没出现已看/未看标识,请手动点击这个按钮进行刷新'>刷新↗</a>");
  511. $(".btnRefresh").click(function(){
  512. setPageRefreshMethod();
  513. })
  514. }
  515. var indexJson = document.getElementById("app")._vnode.appContext.config.globalProperties.$pinia.state._rawValue.index;
  516. if(indexJson == null){
  517. return;
  518. }
  519. // 主视频
  520. setVideoIsViewed($(".archive-tool-box"),".layout-l",0,"ep"+indexJson.currentEp.id,true);
  521. // 右侧上 课程目录Item
  522. var epoArr = indexJson.epList;
  523. $(".section-item").each(function(idx){
  524. setVideoIsViewed($(this),".season-info",0,"ep"+epoArr[idx].id,true,true);
  525. })
  526. // 右侧下 相关推荐Item
  527. var rEpoArr = indexJson.viewInfo.recommend_seasons;
  528. $(".season-recommend-card").each(function(idx){
  529. setVideoIsViewed($(this),coverItemClass,0,"ss"+rEpoArr[idx].id);
  530. })
  531. // 点击视频自动刷新
  532. $(".section-item").unbind("click").click(function(e){
  533. setTimeout(setPageRefreshMethod,5000);
  534. })
  535. // 已看/未看按钮响应
  536. setBtnView();
  537. }
  538.  
  539. // 202303新增:课堂 分区首页
  540. var setCheesePage = function(){
  541. // 普通Item
  542. $(".block-list-item").each(function(){
  543. setVideoIsViewed($(this),coverItemClass);
  544. });
  545. // 排行榜Item
  546. $(".rank dd").each(function(){
  547. setVideoIsViewed($(this),coverItemClass);
  548. });
  549. // 分类查找Item:大卡模式
  550. $(".big-card").each(function(){
  551. setVideoIsViewed($(this),coverItemClass);
  552. });
  553. // 分类查找Item:小卡模式
  554. $(".small-card").each(function(){
  555. setVideoIsViewed($(this),coverItemClass);
  556. });
  557. // 各筛选按钮点击
  558. $(".radio-button-box .item").unbind("click").click(function(e){
  559. setTimeout(setPageRefreshMethod,2000);
  560. })
  561. // 大小卡点击响应
  562. $(".mode-trigger span").unbind("click").click(function(e){
  563. setTimeout(setPageRefreshMethod,2000);
  564. })
  565. // 分页按钮点击响应
  566. $(".page-item").unbind("click").click(function(e){
  567. setTimeout(setPageRefreshMethod,2000);
  568. })
  569. // 分页跳转到、搜索框回车响应
  570. // 回车响应
  571. $(document).unbind('keyup').keyup(function(event){
  572. if(event.keyCode ==13){
  573. setTimeout(setPageRefreshMethod,2000);
  574. }
  575. });
  576. // 已看/未看按钮响应
  577. setBtnView();
  578. }
  579.  
  580. // 202303新增:国创 分区
  581. var setGuochuangPage = function(){
  582. // 滚动推荐Item
  583. $(".progress-bar-content").each(function(){
  584. setVideoIsViewed($(this),coverItemClass);
  585. });
  586. // 横向封面Item
  587. $(".horizontal-ratio-item-inner").each(function(){
  588. setVideoIsViewed($(this),coverItemClass);
  589. });
  590. // 新番时间表Item
  591. $(".timeline-weekday-hover-item").each(function(){
  592. setVideoIsViewed($(this),coverItemClass);
  593. });
  594. // 国创热播榜单Item
  595. $(".ranking-ratio-item-container").each(function(){
  596. setVideoIsViewed($(this),coverItemClass);
  597. });
  598. // 新热推荐Item
  599. $(".item-wrap").each(function(idx){
  600. var epid = $(this).children("a")[0].__vue__.$parent.item.episode_id;
  601. setVideoIsViewed($(this),coverItemClass,0,"ep"+epid,false,false);
  602. });
  603. // 二级分区:最新动态Item、普通Item
  604. $(".spread-module").each(function(){
  605. setVideoIsViewed($(this),coverItemClass);
  606. });
  607. // 二级分区:热门Item
  608. $(".rank-item").each(function(){
  609. setVideoIsViewed($(this),coverItemClass);
  610. });
  611. // tab点击响应
  612. $(".tabs-item").unbind("click").click(function(e){
  613. setTimeout(setPageRefreshMethod,3000);
  614. })
  615. // 最近更新、周一、周二...周日 按钮点击响应
  616. $(".week-day-item").unbind("click").click(function(e){
  617. setTimeout(setPageRefreshMethod,1000);
  618. })
  619. // 下一页按钮点击响应
  620. $(".next-page").unbind("click").click(function(e){
  621. setTimeout(setPageRefreshMethod,1000);
  622. })
  623. // 上一页按钮点击响应
  624. $(".prev-page").unbind("click").click(function(e){
  625. setTimeout(setPageRefreshMethod,1000);
  626. })
  627. // 索引查找Item
  628. $(".bangumi-item").each(function(){
  629. setVideoIsViewed($(this),coverItemClass);
  630. });
  631. // 索引查找 排序方式按钮点击响应
  632. $(".sort-item").unbind("click").click(function(e){
  633. setTimeout(setPageRefreshMethod,2000);
  634. })
  635. // 索引查找 筛选按钮点击响应
  636. $(".filter-item").unbind("click").click(function(e){
  637. setTimeout(setPageRefreshMethod,2000);
  638. })
  639. // 二级分区:热门标签 按钮点击响应
  640. $(".tag-item").unbind("click").click(function(e){
  641. setTimeout(setMethod,1000);
  642. })
  643. // 二级分区:换一换 按钮点击响应
  644. $(".read-push").unbind("click").click(function(e){
  645. setTimeout(setMethod,1000);
  646. })
  647. // 二级分区:投稿时间排序、视频热度排序、全部、原创、查看模式 点击响应
  648. $(".tab-list li").unbind("click").click(function(e){
  649. setTimeout(setPageRefreshMethod,2000);
  650. })
  651. // 二级分区:播放数 下拉菜单 点击响应
  652. $(".dropdown-item").unbind("click").click(function(e){
  653. setTimeout(setPageRefreshMethod,2000);
  654. })
  655. // 二级分区:分页按钮点击响应
  656. $(".page-item").unbind("click").click(function(e){
  657. setTimeout(setPageRefreshMethod,2000);
  658. })
  659. // 索引查找、二级分区:分页跳转到 回车响应
  660. $(document).unbind('keyup').keyup(function(event){
  661. if(event.keyCode ==13){
  662. setTimeout(setPageRefreshMethod,1000);
  663. }
  664. });
  665. // 已看/未看按钮响应
  666. setBtnView();
  667. }
  668.  
  669. // 202303新增:新歌热榜 分区
  670. var setMusicplusPage = function(){
  671. // 头部1+6个Item
  672. $(".video-card-reco").each(function(){
  673. setVideoIsViewed($(this),coverItemClass);
  674. });
  675. // 热门推荐Item
  676. $(".card-pic").each(function(){
  677. setVideoIsViewed($(this),coverItemClass);
  678. });
  679. // tabs 按钮点击响应
  680. $(".tabs a").unbind("click").click(function(e){
  681. setTimeout(setPageRefreshMethod,1000);
  682. })
  683. // 更多 按钮点击响应
  684. $(".more").unbind("click").click(function(e){
  685. setTimeout(setPageRefreshMethod,1000);
  686. })
  687. // 筛选 各按钮点击响应
  688. $(".type-group li").unbind("click").click(function(e){
  689. setTimeout(setPageRefreshMethod,1000);
  690. })
  691. // 搜索结果页 上面的 音乐首页 点击响应
  692. $(".main-menu a").unbind("click").click(function(e){
  693. setTimeout(setPageRefreshMethod,1000);
  694. })
  695. // 分页按钮点击响应
  696. $(".pager a").unbind("click").click(function(e){
  697. setTimeout(setPageRefreshMethod,1000);
  698. })
  699. // 搜索框回车响应
  700. $(document).unbind('keyup').keyup(function(event){
  701. if(event.keyCode ==13){
  702. setTimeout(setPageRefreshMethod,1000);
  703. }
  704. });
  705. // 已看/未看按钮响应
  706. setBtnView();
  707. }
  708.  
  709. // 202303新增:番剧视频播放页
  710. var setBangumiPage = function(){
  711. // 主视频
  712. var linkArr = $("link");
  713. var linkRel = "";
  714. var linkHref = "";
  715. for(var i = 0 ; i < linkArr.length ;i++){
  716. linkRel = $(linkArr[i]).attr("rel");
  717. if(linkRel != "canonical"){
  718. continue;
  719. }
  720. linkHref = $(linkArr[i]).attr("href");
  721. if($(".toolbar").length > 0){
  722. // 202403版本
  723. setVideoIsViewed($(".player-left-components"),".toolbar",2,linkHref,true);
  724. }else{
  725. setVideoIsViewed($(".player-left-components"),".toolbar_toolbar__NJCNy",2,linkHref,true);
  726. }
  727. break;
  728. }
  729. // 刷新按钮
  730. var refreshObj = $(".btnRefresh");
  731. if(refreshObj.size() == 0){
  732. if($(".toolbar").length > 0){
  733. // 202403版本
  734. $(".toolbar").append("<a class='btnRefresh' title='如果列表没出现已看/未看标识,请手动点击这个按钮进行刷新'>刷新→</a>");
  735. }else{
  736. $(".toolbar_toolbar__NJCNy").append("<a class='btnRefresh' title='如果列表没出现已看/未看标识,请手动点击这个按钮进行刷新'>刷新→</a>");
  737. }
  738. $(".btnRefresh").click(function(){
  739. setPageRefreshMethod();
  740. })
  741. }
  742. if($(".toolbar").length > 0){
  743. // 202403版本
  744. // 下次更新。。
  745. }else{
  746. // 右侧上 正片(list模式)Item
  747. $(".longListItem_wrap__9OsZi").each(function(){
  748. var pArr = Object.getOwnPropertyNames(this);
  749. if(pArr.length == 0){
  750. return;
  751. }
  752. var epId = eval("this."+pArr[0]+".return.key");
  753. setVideoIsViewed($(this),".longListItem_title__Xziqq",0,"ep"+epId,true,true);
  754. // 点击响应
  755. $(this).children("a:eq(1)").unbind("click").click(function(e){
  756. setTimeout(setPageRefreshMethod,2000);
  757. })
  758. })
  759. // 右侧上 正片(cube模式)Item
  760. $(".numberListItem_number_list_item__wszA4").each(function(){
  761. setVideoIsViewed($(this),"a",0,null,true,true);
  762. // 点击响应
  763. $(this).children("a:eq(1)").unbind("click").click(function(e){
  764. setTimeout(setPageRefreshMethod,2000);
  765. })
  766. })
  767. // 右侧上 正片查看模式切换点击响应
  768. $(".modeChangeBtn_wrap__NOGS3").unbind("click").click(function(e){
  769. setTimeout(setPageRefreshMethod,1000);
  770. })
  771. // 右侧中 系列Item
  772. $(".seasonlist_ss_item__czhHy").each(function(){
  773. setVideoIsViewed($(this),coverItemClass);
  774. })
  775. // 展开 按钮点击响应
  776. $(".seasonlist_expand_more__VcTha").unbind("click").click(function(e){
  777. setTimeout(setPageRefreshMethod,2000);
  778. })
  779. // 右侧中 PV&其他Item
  780. $(".epitem_ep_item__CPdZy").each(function(){
  781. setVideoIsViewed($(this),"a",0,null,true,true);
  782. // 点击响应
  783. $(this).children("a:eq(1)").unbind("click").click(function(e){
  784. setTimeout(setPageRefreshMethod,2000);
  785. })
  786. })
  787. // 右侧下 相关推荐Item
  788. $(".RecommendItem_wrap__pJmXL").each(function(){
  789. setVideoIsViewed($(this),coverItemClass);
  790. // 点击响应
  791. $(this).children("a:first").unbind("click").click(function(e){
  792. setTimeout(setPageRefreshMethod,3000);
  793. })
  794. // 视频播放结束后没有出现推荐视频
  795. })
  796. }
  797. // 已看/未看按钮响应
  798. setBtnView();
  799. }
  800.  
  801. // 202303新增:频道页
  802. var setChannelPage = function(){
  803. // 普通Item
  804. $(".video-card__content").each(function(){
  805. setVideoIsViewed($(this),coverItemClass,0,null,false,false,false,true); // 注意排行1、2、3数字的图片
  806. });
  807. // 右侧“进入频道”按钮点击响应
  808. $(".go-channel-btn").unbind("click").click(function(e){
  809. setTimeout(setMethod,2000);
  810. })
  811. // 滚动条下拉监听(右侧局部)
  812. $("#container").unbind("scroll").scroll(function(){
  813. var curScrollTop = $("#container").scrollTop();
  814. if(Math.abs(curScrollTop - preScrollTop) > pageHeight){
  815. preScrollTop = curScrollTop;
  816. setTimeout(setMethod,2000);
  817. }
  818. })
  819. // 精选、综合 按钮点击响应
  820. $(".van-tabs-tab").unbind("click").click(function(e){
  821. setTimeout(setMethod,2000);
  822. })
  823. // 年份 按钮点击响应
  824. $(".year-selector__item").unbind("click").click(function(e){
  825. setTimeout(setMethod,2000);
  826. })
  827. // 近期热门、播放最多、最新投稿 按钮点击响应
  828. $(".play-selector__item").unbind("click").click(function(e){
  829. setTimeout(setMethod,2000);
  830. })
  831. // 相关tag 点击响应
  832. $(".relative-tags div a").unbind("click").click(function(e){
  833. setTimeout(setMethod,2000);
  834. })
  835. // 已看/未看按钮响应
  836. setBtnView();
  837. }
  838.  
  839. // 202303新增:分区:综艺、电影、电视剧、纪录片
  840. var setVarietyPage = function(){
  841. // 头部滚动
  842. $(".side-item").each(function(){
  843. setVideoIsViewed($(this),".title",0,null,false,false);
  844. });
  845. // 综艺Item:封面是横的
  846. $(".hot-item").each(function(){
  847. setVideoIsViewed($(this),coverItemClass);
  848. });
  849. // 综艺Item:封面是竖的
  850. $(".hover-item").each(function(){
  851. setVideoIsViewed($(this),coverItemClass);
  852. });
  853. // 综艺Item:封面是方的(打一层包装)
  854. var itemDivArr = $(".column-itemDiv");
  855. if(itemDivArr.length == 0){
  856. var itemArr = $(".column-item");
  857. for(var i = 0 ; i < itemArr.length ;i++){
  858. var divObj = $("<div class='column-itemDiv'></div>");
  859. divObj.append(itemArr[i]);
  860. $(".module-column").append(divObj);
  861. }
  862. }
  863. // 综艺Item:封面是方的(.column-item → .column-itemDiv)
  864. $(".column-itemDiv").each(function(){
  865. setVideoIsViewed($(this),coverItemClass);
  866. });
  867. // 索引查找Item
  868. $(".bangumi-item").each(function(){
  869. setVideoIsViewed($(this),coverItemClass);
  870. });
  871. // 索引查找 排序方式按钮点击响应
  872. $(".sort-item").unbind("click").click(function(e){
  873. setTimeout(setPageRefreshMethod,2000);
  874. })
  875. // 索引查找 筛选按钮点击响应
  876. $(".filter-item").unbind("click").click(function(e){
  877. setTimeout(setPageRefreshMethod,2000);
  878. })
  879. // 已看/未看按钮响应
  880. setBtnView();
  881. }
  882.  
  883. // 202303新增:分区:其他
  884. var setAreaPage = function(){
  885. // 普通Item
  886. $(".bili-video-card__wrap").each(function(){
  887. setVideoIsViewed($(this),coverItemClass);
  888. });
  889. // 热门Item
  890. $(".bili-rank-list-video__item--wrap").each(function(){
  891. setVideoIsViewed($(this),".rank-video-card");
  892. });
  893. // 换一换按钮点击响应
  894. $(".roll-btn").unbind("click").click(function(e){
  895. setTimeout(setPageRefreshMethod,3000);
  896. })
  897. // 换一换旁边的查看更多进入:
  898. // tag按钮点击响应
  899. $(".tags-item").unbind("click").click(function(e){
  900. setTimeout(setPageRefreshMethod,3000);
  901. })
  902. // 排序下拉菜单按钮点击响应
  903. $(".channel-select-content-item").unbind("click").click(function(e){
  904. setTimeout(setPageRefreshMethod,3000);
  905. })
  906. // 已看/未看按钮响应
  907. setBtnView();
  908. }
  909.  
  910. // 202303新增:设置热门页的视频
  911. var setPopularPage = function(){
  912. // 综合热门Item
  913. $(".video-card__content").each(function(){
  914. setVideoIsViewed($(this),coverItemClass);
  915. });
  916. // 排行榜Item
  917. $(".img").each(function(){
  918. setVideoIsViewed($(this),coverItemClass);
  919. });
  920. // 全站音乐榜Item
  921. $("._card_1kuml_6").each(function(){
  922. setVideoIsViewed($(this),coverItemClass,0,null,false,false,true,true);
  923. });
  924. // 短剧榜Item(打一层包装)
  925. var itemListArr = $(".drama-board-listClone");
  926. if(itemListArr.length == 0){
  927. $(".drama-board-list").each(function(idx){
  928. var objOffset = $(this).offset();
  929. var cloneObj = $(this).clone();
  930. $(cloneObj).addClass("drama-board-listClone");
  931. $(cloneObj).addClass("drama-board-listClone_"+idx);
  932. $(cloneObj).removeClass("drama-board-list");
  933. $(this).parent().append(cloneObj);
  934. // 对克隆体里面的元素进行外层包装
  935. var itemArr = $(".drama-board-listClone_"+idx+" .board-item-wrap");
  936. for(var i = 0; i < itemArr.length;i++){
  937. var divObj = $("<div class='board-item-wrapDiv'></div>");
  938. divObj.append(itemArr[i]);
  939. $(".drama-board-listClone_"+idx).append(divObj);
  940. }
  941. // 对齐被克隆的对象
  942. $(cloneObj).offset(objOffset);
  943. $(this).attr("style","opacity:0;");
  944. })
  945. }
  946. $(".board-item-wrapDiv").each(function(){
  947. setVideoIsViewed($(this),coverItemClass);
  948. })
  949. // 每周必看:切换第N期监听
  950. $(".panel .select-item").click(function(e){
  951. setTimeout(setPageRefreshMethod,5000);
  952. })
  953. // 排行榜:分类 点击监听
  954. $(".rank-tab li").click(function(e){
  955. $(".btnView").remove();
  956. setTimeout(setMethod,3000);
  957. })
  958. // 全站音乐版:切换第N期 点击响应
  959. // 修正原网页“看MV”按钮连接不正确的问题
  960. $(".periodShow").unbind("click").click(function(e){
  961. setTimeout(function(){
  962. $(".periodList .periodItem").unbind("click").click(function(e){
  963. $(".btnView").remove();
  964. setTimeout(setMethod,3000);
  965. })
  966. },500)
  967. })
  968. // 短剧榜:切换第N期 点击响应
  969. $(".dropdown-item").unbind("click").click(function(e){
  970. $(".drama-board-listClone").remove();
  971. $(".drama-board-list").removeAttr("style");
  972. setTimeout(setMethod,2000);
  973. })
  974. // 短剧榜:热榜榜单、编辑精选 点击响应
  975. $(".switch-tabs .tab").unbind("click").click(function(e){
  976. var tabIndex = $(this).index();
  977. var objOffset = $(".drama-board-list:eq("+tabIndex+")").offset();
  978. $(".drama-board-listClone_"+tabIndex).offset(objOffset);
  979. })
  980. // 已看/未看按钮响应
  981. setBtnView();
  982. }
  983.  
  984. // 设置主站首页
  985. var setIndexPage = function(){
  986. // 202501版本:推荐视频Item
  987. $(".bili-video-card").each(function(){
  988. setVideoIsViewed($(this),coverItemClass);
  989. });
  990. // 已看/未看按钮响应
  991. setBtnView();
  992. // 按钮点击响应设置在上层方法调用
  993. }
  994.  
  995. // 设置视频观看页
  996. var setVideoPage = function(){
  997. var refreshObj = $(".btnRefresh");
  998. if(refreshObj.size() == 0){
  999. // 202501版本:在记笔记按钮右边的三点的右边 添加刷新按钮
  1000. $(".video-toolbar-right").append(btnRefresh);
  1001. btnRefresh.text("刷新↗");
  1002. }
  1003. var initState = unsafeWindow.__INITIAL_STATE__;
  1004. if(!initState){
  1005. return;
  1006. }
  1007. // 主视频bv:如果是分P则显示为分P已看状态
  1008. var bvid = initState.bvid;
  1009. var videos = initState.videoData.videos; // 总分P数
  1010. if(videos > 1){
  1011. bvid = bvid + "-"+initState.p;
  1012. }
  1013. // 202501版本:主视频已看/未看设置
  1014. setVideoIsViewed($(".video-info-meta"),".pubdate-ip",0,bvid,true);
  1015. // 下箭头悬浮框(如果有)
  1016. setVideoIsViewed($(".overflow-panel"),".pubdate-ip",0,bvid,true);
  1017. // 202501版本:右侧上 订阅合集Item
  1018. $(".pod-item").each(function(){
  1019. var targetObj = $(this).find(".cover:first");
  1020. var bvNum = $(this).data("key");
  1021. if(targetObj.length > 0){
  1022. // 有视频封面
  1023. setVideoIsViewed(targetObj,coverItemClass,0,bvNum);
  1024. }else{
  1025. // 没视频封面
  1026. setVideoIsViewed($(this),".title",0,bvNum,true,true);
  1027. }
  1028. // 有分P列表
  1029. var multiPObj = $(this).children(".multi-p");
  1030. if(multiPObj.length > 0){
  1031. multiPObj.children(".page-list").children(".page-item").each(function(idx){
  1032. setVideoIsViewed($(this),".title",0,bvNum+"-"+(idx+1),true,true);
  1033. });
  1034. }
  1035. })
  1036. // 202501版本:右侧上 视频选集(分P视频)Item
  1037. $(".multip .video-pod__item").each(function(idx){
  1038. // 没视频封面
  1039. setVideoIsViewed($(this),".title",0,initState.bvid+"-"+(idx+1),true,true);
  1040. })
  1041. // 202501版本:右侧上 视频选集(分P视频)grid模式Item
  1042. $(".multip.grid .page").each(function(idx){
  1043. // 没视频封面
  1044. if($(this).children("span").length == 0){
  1045. $(this).append("<span></span>");
  1046. }
  1047. setVideoIsViewed($(this),"span",0,initState.bvid+"-"+(idx+1),true,true);
  1048. })
  1049. // 202501版本:右侧下 后台推荐视频or通用推荐视频Item
  1050. $(".card-box .pic").each(function(){
  1051. setVideoIsViewed($(this),coverItemClass);
  1052. })
  1053. var relatedArr = initState.related;
  1054. if(relatedArr && relatedArr.length > 0){
  1055. // 202501版本:视频窗口播放视频结束后出现的推荐视频Item
  1056. $(".bpx-player-ending-related-itemDiv").each(function(idx){
  1057. setVideoIsViewed($(this),".bpx-player-ending-related-item",0,relatedArr[idx].bvid,true,true); // 封面是div
  1058. // 点击视频自动刷新
  1059. $(".bpx-player-ending-related-item").unbind("click").click(function(e){
  1060. setTimeout(setPageRefreshMethod,3000);
  1061. })
  1062. });
  1063. // 202501版本:视频窗口播放视频结束后出现的推荐视频Item
  1064. $(".bpx-player-video-wrap video").unbind("ended").bind("ended",function(e){
  1065. setTimeout(function(){
  1066. var itemDivArr = $(".bpx-player-ending-related-itemDiv");
  1067. if(itemDivArr.length == 0){
  1068. var itemArr = $(".bpx-player-ending-related-item");
  1069. for(var i = 0 ; i < itemArr.length ;i++){
  1070. var divObj = $("<div class='bpx-player-ending-related-itemDiv'></div>");
  1071. divObj.append(itemArr[i]);
  1072. $(".bpx-player-ending-related").append(divObj);
  1073. }
  1074. }
  1075. $(".bpx-player-ending-related-itemDiv").each(function(idx){
  1076. setVideoIsViewed($(this),".bpx-player-ending-related-item",0,relatedArr[idx].bvid,true,true); // 封面是div
  1077. // 点击视频自动刷新
  1078. $(".bpx-player-ending-related-item").unbind("click").click(function(e){
  1079. setTimeout(setPageRefreshMethod,3000);
  1080. })
  1081. });
  1082. },2000);
  1083. })
  1084. }
  1085. // 已看/未看按钮响应
  1086. setBtnView();
  1087. // 202510版本:(右上)合集视频or视频选集(分P视频)Item 点击响应
  1088. $(".video-pod__item").unbind("click").click(function(e){
  1089. setTimeout(setPageRefreshMethod,3000);
  1090. })
  1091. // 202510版本:(右上)合集视频-分类(横向+下拉列表) Item 点击响应
  1092. $(".slide-item").unbind("click").click(function(e){
  1093. setTimeout(setPageRefreshMethod,3000);
  1094. })
  1095. // 202510版本:(右上)视频选集(分P视频) list、grid模式切换 点击响应
  1096. $(".view-mode").unbind("click").click(function(){
  1097. setTimeout(setPageRefreshMethod,2000);
  1098. })
  1099. // 202501版本:(右下)后台推荐视频or通用推荐视频 点击响应
  1100. $(".card-box").unbind("click").click(function(){
  1101. setTimeout(setPageRefreshMethod,2000);
  1102. })
  1103. // 202501版本:(右下)按钮点击响应
  1104. $(".rec-footer").unbind("click").click(function(){
  1105. setTimeout(setMethod,2000);
  1106. })
  1107. }
  1108.  
  1109. // 设置活动视频观看页
  1110. var setFestivalVideoPage = function(){
  1111. var refreshObj = $(".btnRefresh");
  1112. if(refreshObj.size() == 0){
  1113. // 202303:在记笔记按钮右边的三点的右边 添加刷新按钮
  1114. $(".video-toolbar-content_right").append("<a class='btnRefresh' title='如果列表没出现已看/未看标识,请手动点击这个按钮进行刷新'>刷新↗</a>");
  1115. $(".btnRefresh").click(function(){
  1116. setPageRefreshMethod();
  1117. })
  1118. }
  1119. var initState = unsafeWindow.__INITIAL_STATE__;
  1120. if(!initState){
  1121. return;
  1122. }
  1123. // 主视频
  1124. var videoInfo = initState.videoInfo;
  1125. if(videoInfo){
  1126. var bvid = initState.videoInfo.bvid;
  1127. setVideoIsViewed($(".video-toolbar-content"),".video-toolbar-content_left",0,bvid,true);
  1128. }
  1129. // 202303:右侧上 合集Item
  1130. var sectionArr = initState.videoSections;
  1131. if(sectionArr && sectionArr.length > 0){
  1132. var epoArr = sectionArr[0].episodes;
  1133. for(var i = 1 ; i < sectionArr.length;i++){
  1134. epoArr = epoArr.concat(sectionArr[i].episodes);
  1135. }
  1136. $(".video-episode-card").each(function(idx){
  1137. var targetObj = $(this).find(".video-episode-card__cover:first");
  1138. if(targetObj.length > 0){
  1139. // 有视频封面
  1140. setVideoIsViewed(targetObj,".activity-image-card__image",0,epoArr[idx].bvid);// 封面图片用div
  1141. }else{
  1142. // 没视频封面
  1143. setVideoIsViewed($(this),".video-episode-card__info-title",0,epoArr[idx].bvid,true,true);
  1144. }
  1145. })
  1146. // 点击视频自动刷新
  1147. $(".video-episode-card").unbind("click").click(function(e){
  1148. setTimeout(setPageRefreshMethod,3000);
  1149. })
  1150. }
  1151. // 202303:右侧下 推荐视频Item
  1152. var recommendArr = initState.recommendList.relate_video;
  1153. if(recommendArr){
  1154. $(".recommend-video-card").each(function(idx){
  1155. setVideoIsViewed($(this),".activity-image-card__image",0,recommendArr[idx].bvid); // 封面图片用div
  1156. });
  1157. // 视频播放结束后没有出现推荐视频
  1158. }
  1159. // 已看/未看按钮响应
  1160. setBtnView();
  1161. }
  1162.  
  1163. // 设置历史页
  1164. var setHistoryPage = function(){
  1165. var refreshObj = $(".btnRefresh");
  1166. if(refreshObj.size() == 0){
  1167. // 202504版本
  1168. $(".breadcrumbs__top .right").prepend(btnRefresh);
  1169. $(".breadcrumbs__top .right").prepend(btnSetAllViewed);
  1170. }
  1171. // 202501版本:视频Item
  1172. $(".bili-video-card__cover").each(function(){
  1173. setVideoIsViewed($(this),coverItemClass);
  1174. });
  1175. // 已看/未看按钮响应
  1176. setBtnView();
  1177. // 202501版本:搜索框 回车响应
  1178. $(document).unbind('keyup').keyup(function(event){
  1179. if(event.keyCode ==13){
  1180. setTimeout(setPageRefreshMethod,2000);
  1181. }
  1182. });
  1183. // 202501版本:导航按钮 点击响应(全部、视频、直播、专栏)
  1184. $(".radio-filter__item").unbind("click").click(function(){
  1185. setTimeout(setPageRefreshMethod,2000);
  1186. })
  1187. // 202501版本:(右上)切换grid/list按钮 点击响应
  1188. $(".lists-view-mode").unbind("click").click(function(){
  1189. setTimeout(setPageRefreshMethod,2000);
  1190. })
  1191. // 202501版本:搜索图标按钮 点击响应
  1192. $(".search-btn").unbind("click").click(function(){
  1193. setTimeout(setPageRefreshMethod,2000);
  1194. })
  1195. // 202501版本:退出管理按钮 点击响应
  1196. $(".batch-manage-btn").unbind("click").click(function(){
  1197. setTimeout(setPageRefreshMethod,2000);
  1198. })
  1199. }
  1200.  
  1201. // 稍后再看-视频观看页
  1202. var setListPlayPage = function(){
  1203. var refreshObj = $(".btnRefresh");
  1204. if(refreshObj.size() == 0){
  1205. // 202501版本:在记笔记按钮右边的三点的右边 添加刷新按钮
  1206. $(".video-toolbar-right").append(btnRefresh);
  1207. btnRefresh.text("刷新↗");
  1208. }
  1209. var initState = unsafeWindow.__INITIAL_STATE__;
  1210. if(!initState){
  1211. return;
  1212. }
  1213. // 主视频bv:如果是分P则显示为分P已看状态
  1214. var bvid = initState.bvid;
  1215. var videos = initState.videoData.videos; // 总分P数
  1216. if(videos > 1){
  1217. bvid = bvid + "-"+initState.p;
  1218. }
  1219. // 202504版本:主视频已看/未看设置
  1220. setVideoIsViewed($(".video-info-meta"),".pubdate-ip",0,bvid,true);
  1221. // 下箭头悬浮框(如果有)
  1222. setVideoIsViewed($(".overflow-panel"),".pubdate-ip",0,bvid,true);
  1223. // 右侧 稍后再看Item
  1224. var epoArr = initState.resourceList;
  1225. let eachBvid = null;
  1226. $(".actionlist-item-inner .main").each(function(idx){
  1227. if(typeof epoArr[idx].bv_id == "undefined"){
  1228. // 202503版本用bvid
  1229. eachBvid = epoArr[idx].bvid;
  1230. }else{
  1231. // 202503前用bv_id(不知其他人更新到新版没有,暂保留,日后删)
  1232. eachBvid = epoArr[idx].bv_id;
  1233. }
  1234. setVideoIsViewed($(this),coverItemClass,0,eachBvid);
  1235. var multipObj = $(this).parent().children(".multip-list:first");
  1236. if(multipObj.length > 0){
  1237. // 有分P视频列表
  1238. $(multipObj[0]).children(".multip-list-item").each(function(idx2){
  1239. if(epoArr[idx].pages[idx2].p){
  1240. // 202504版本分P用.p
  1241. setVideoIsViewed($(this),".left-part",0,eachBvid+"-"+epoArr[idx].pages[idx2].p,true);
  1242. }else{
  1243. // 202504前的版本分P用.page(日后可删)
  1244. setVideoIsViewed($(this),".left-part",0,eachBvid+"-"+epoArr[idx].pages[idx2].page,true);
  1245. }
  1246. // 视频点击响应
  1247. $(this).unbind("click").click(function(){
  1248. setTimeout(setPageRefreshMethod,2000);
  1249. })
  1250. })
  1251. }
  1252. // 视频点击响应
  1253. $(this).unbind("click").click(function(){
  1254. setTimeout(setPageRefreshMethod,2000);
  1255. })
  1256. })
  1257. // 右侧下 推荐视频Item
  1258. $(".pic-box").each(function(){
  1259. setVideoIsViewed($(this),coverItemClass);
  1260. });
  1261. // 右侧 稍后再看 删除按钮点击响应
  1262. $(".del-btn").unbind("click").click(function(){
  1263. setTimeout(setPageRefreshMethod,2000);
  1264. })
  1265. // 已看/未看按钮响应
  1266. setBtnView();
  1267. }
  1268.  
  1269. // 设置稍后再看页(列表页)
  1270. const setWatchlaterPage = function(){
  1271. let refreshObj = $(".btnRefresh");
  1272. if(refreshObj.size() == 0){
  1273. // 202501版本
  1274. $(".list-header-options").prepend(btnRefresh);
  1275. $(".list-header-options").prepend(btnSetAllViewed);
  1276. }
  1277. // 202501版本:视频Item
  1278. $(".bili-video-card__cover").each(function(){
  1279. setVideoIsViewed($(this),coverItemClass,3);
  1280. });
  1281. // 已看/未看按钮响应
  1282. setBtnView();
  1283. // 202501版本:搜索框 回车响应
  1284. $(document).unbind('keyup').keyup(function(event){
  1285. if(event.keyCode ==13){
  1286. setTimeout(setPageRefreshMethod,2000);
  1287. }
  1288. });
  1289. // 202501版本:导航按钮 点击响应(全部进度、未看完)
  1290. $(".list-header-filter__btn").unbind("click").click(function(){
  1291. setTimeout(setPageRefreshMethod,2000);
  1292. })
  1293. // 202501版本:(右上)切换grid/list按钮 点击响应
  1294. $(".watchlater-list-title-sort").unbind("click").click(function(){
  1295. setTimeout(setPageRefreshMethod,2000);
  1296. })
  1297. // 202501版本:搜索图标按钮 点击响应
  1298. $(".search-btn").unbind("click").click(function(){
  1299. setTimeout(setPageRefreshMethod,2000);
  1300. })
  1301. // 202501版本:最近添加/最早添加按钮 点击响应
  1302. $(".menu-popover__panel-item").unbind("click").click(function(){
  1303. setTimeout(setPageRefreshMethod,2000);
  1304. })
  1305. // 202501版本:退出管理按钮 点击响应
  1306. $(".action-btn").unbind("click").click(function(){
  1307. setTimeout(setPageRefreshMethod,2000);
  1308. })
  1309. }
  1310.  
  1311. // 设置空间页:https://space.bilibili.com/xxxx
  1312. const setSpacePage = function(){
  1313. let refreshObj = $(".btnRefresh");
  1314. if(refreshObj.size() == 0){
  1315. // 202503选新版
  1316. $(".nav-bar__main-left").append(btnRefresh);
  1317. // 202503选旧版
  1318. $(".n-inner").append(btnRefresh);
  1319. }
  1320. // 202503选旧版:置顶视频Item
  1321. $(".i-pin-part .i-pin-has-content").each(function(){
  1322. setVideoIsViewed($(this),coverItemClass);
  1323. });
  1324. // 【首页】代表作(3个)、置顶视频(1个)、TA的视频、最近投币的视频、合集·XXXX、最近点赞的视频
  1325. // 【投稿】TA的视频
  1326. // 202503选旧版:普通Item(cube模式)
  1327. $(".small-item").each(function(){
  1328. setVideoIsViewed($(this),coverItemClass);
  1329. });
  1330. // 202503选新版
  1331. $(".bili-video-card__cover").each(function(){
  1332. setVideoIsViewed($(this),coverItemClass);
  1333. });
  1334. // 202503选新版or旧版:【动态】
  1335. // 用户登录(不可用)后的动态:https://t.bilibili.com/?spm_id_from=
  1336. // up空间的动态:https://space.bilibili.com/xxxx/dynamic
  1337. $(".bili-dyn-content__orig__major").each(function(){
  1338. var coverObj = $(this).find(".bili-awesome-img:first");// 202303选新版、页面用的<div/>
  1339. if(coverObj.length > 0){
  1340. setVideoIsViewed($(this),".bili-awesome-img");
  1341. }else{
  1342. setVideoIsViewed($(this),coverItemClass);// 202303选旧版、t.bili
  1343. }
  1344. });
  1345. // 普通Item(list模式):.small-item切换为list模式
  1346. $(".list-item").each(function(){
  1347. setVideoIsViewed($(this),coverItemClass);
  1348. });
  1349. // 202503选旧版:【合集和列表】点击“查看更多”后的Item
  1350. $(".video-card").each(function(){
  1351. setVideoIsViewed($(this),coverItemClass);
  1352. });
  1353. // 已看/未看按钮响应
  1354. setBtnView();
  1355. // 点击up主头像响应
  1356. $(".bili-dyn-up-list__item").unbind("click").click(function(){
  1357. prePageScrollTop = 0;
  1358. setTimeout(setPageRefreshMethod,2000);
  1359. })
  1360. // 分页按钮响应
  1361. $(".be-pager li").unbind('click').click(function(){
  1362. setTimeout(setPageRefreshMethod,2000);
  1363. })
  1364. // 搜索视频按钮响应
  1365. $(".search-btn").unbind('click').click(function(){
  1366. setTimeout(setPageRefreshMethod,2000);
  1367. })
  1368. // 回车响应
  1369. $(document).unbind('keyup').keyup(function(event){
  1370. if(event.keyCode ==13){
  1371. setTimeout(setPageRefreshMethod,2000);
  1372. }
  1373. });
  1374. // 导航栏响应
  1375. $(".n-tab-links a").unbind('click').click(function(){
  1376. setTimeout(setPageRefreshMethod,2000);
  1377. })
  1378. // 侧栏按钮响应
  1379. $(".contribution-item").unbind('click').click(function(){
  1380. setTimeout(setPageRefreshMethod,2000);
  1381. })
  1382. // 排序按钮响应
  1383. $(".be-tab-item").unbind('click').click(function(){
  1384. setTimeout(setPageRefreshMethod,2000);
  1385. })
  1386. // Tag点击响应
  1387. $("#submit-video-type-filter a").unbind('click').click(function(){
  1388. setTimeout(setPageRefreshMethod,2000);
  1389. })
  1390. // 收藏列表响应
  1391. $(".fav-item a").unbind('click').click(function(){
  1392. setTimeout(setPageRefreshMethod,2000);
  1393. })
  1394. // up空间主页:点击“更多”按钮 响应
  1395. $(".more").unbind('click').click(function(){
  1396. setTimeout(setPageRefreshMethod,2000);
  1397. })
  1398. // 合集和列表:点击“更多”按钮 响应
  1399. $(".more-btn").unbind('click').click(function(){
  1400. setTimeout(setPageRefreshMethod,2000);
  1401. })
  1402. // 合集和列表:查看模式 点击响应
  1403. $(".list-style span").unbind('click').click(function(){
  1404. setTimeout(setPageRefreshMethod,2000);
  1405. })
  1406. // 202501版本:导航链接 点击响应(主页、动态、投稿、合集)
  1407. $(".nav-tab__item").unbind('click').click(function(){
  1408. setTimeout(setPageRefreshMethod,2000);
  1409. })
  1410. // 202501版本:(多栏目公用)排序方式 点击响应(最新发布、最多播放、最多收藏、更多筛选下面的按钮)
  1411. $(".radio-filter__item").unbind('click').click(function(){
  1412. setTimeout(setPageRefreshMethod,2000);
  1413. })
  1414. // 202501版本:(多栏目公用)查看更多 点击响应
  1415. $(".vui_button").unbind('click').click(function(){
  1416. setTimeout(setPageRefreshMethod,2000);
  1417. })
  1418. // 202501版本:投稿(TA的视频)左侧栏 点击响应
  1419. $(".side-nav__item").unbind('click').click(function(){
  1420. setTimeout(setPageRefreshMethod,2000);
  1421. })
  1422. // 202501版本:投稿(TA的视频)查看模式(cube或list) 点击响应
  1423. $(".lists-view-mode").unbind('click').click(function(){
  1424. setTimeout(setPageRefreshMethod,2000);
  1425. })
  1426. // 202501版本:合集列表 查看更多 左上角返回“<” 点击响应
  1427. $(".back").unbind('click').click(function(){
  1428. setTimeout(setPageRefreshMethod,2000);
  1429. })
  1430. // 202501版本:合集列表 查看更多 右上角排序 点击响应(最早添加、最新添加)
  1431. $(".menu-popover__panel-item").unbind('click').click(function(){
  1432. setTimeout(setPageRefreshMethod,2000);
  1433. })
  1434. // 202501版本:收藏夹 左侧自定义分类 点击响应
  1435. $(".fav-sidebar-item").unbind('click').click(function(){
  1436. setTimeout(setPageRefreshMethod,2000);
  1437. })
  1438. }
  1439.  
  1440. // 设置已看/未看按钮响应
  1441. var coverItemClass = "img";
  1442. var setBtnView = function(){
  1443. $(".btnView").unbind("click").click(function(e){
  1444. var avId = $(this).data("av");
  1445. var view = $(this).data("view");
  1446. // 先读再存(跨页操作)
  1447. // not:类.block-list-item-info-player--img为课堂分区封面上面的播放小图标
  1448. // not:类.cover为热门-全站排行榜的唱片封面
  1449. var coverObjs = $(this).parent().find(coverItemClass+":not(.block-list-item-info-player--img):not(.cover):first");
  1450. var setIsViewed = false;
  1451. if(view == 0){
  1452. // 未看 -> 已看
  1453. setIsViewed = true;
  1454. $(this).text("已看");
  1455. $(this).removeClass("btnNotView");
  1456. $(this).addClass("btnIsView");
  1457. $(this).data("view","1");
  1458. coverObjs.css("opacity",opacityIsViewCover);
  1459. }else{
  1460. // 已看 -> 未看
  1461. $(this).text("未看");
  1462. $(this).removeClass("btnIsView");
  1463. $(this).addClass("btnNotView");
  1464. $(this).data("view","0");
  1465. coverObjs.css("opacity","1");
  1466. }
  1467. // 删除所有按钮
  1468. $(".btnView").remove();
  1469. // 即时存储
  1470. saveGMVideoList(avId,setIsViewed);
  1471. // 重新读取
  1472. setMethod();
  1473. return false;
  1474. });
  1475. }
  1476.  
  1477.  
  1478. // (多域名共用)检测按钮是否已加载,8次内有效
  1479. var isCheck = true;
  1480. var btnCount = 0;
  1481. var checkCount = 0;
  1482. var checkBtnViewLoad = function(){
  1483. if(!isCheck){
  1484. clearInterval(timer);
  1485. timer = null;
  1486. return;
  1487. }
  1488. btnCount = $(".btnView").size();
  1489. if(btnCount > 0 || checkCount > 5){
  1490. clearInterval(timer);
  1491. timer = null;
  1492. }else{
  1493. setMethod();
  1494. }
  1495. checkCount++;
  1496. }
  1497.  
  1498. // 设置搜索页面
  1499. var isView = 0;
  1500.  
  1501. var videoArr = null;
  1502. var isTextAreaHidden = true;
  1503. var setSearchPage = function(){
  1504. var refreshObj = $(".btnRefresh");
  1505. if(refreshObj.size() == 0){
  1506. // 202501版本
  1507. $(".vui_tabs--navbar").append("<a class='btnList' title='显示/隐藏已看ID的数据列表,建议定期复制到其他地方进行保存,避免因事故造成丢失'>显示/隐藏</a>");
  1508. $(".vui_tabs--navbar").append("<a class='btnListSave' title='如果文本框内容有修改,请点击这个按钮进行保存。'>保存列表</a>");
  1509. $(".vui_tabs--navbar").append("<textarea class='viewList'></textarea>");
  1510. $(".search-input-container .flex_center").append(btnRefresh);
  1511. // 显示列表按钮 点击响应
  1512. $(".btnList").click(function(){
  1513. if(isTextAreaHidden){
  1514. var keyList = GM_listValues();
  1515. var key = "";
  1516. var str = "";
  1517. for(var i = 0 ; i < keyList.length;i++){
  1518. key = keyList[i];
  1519. if(key.indexOf("BiliViewed_") == 0){
  1520. str += GM_getValue(key,"")+",";
  1521. }
  1522. }
  1523. $(".viewList").val(str);
  1524. }
  1525. isTextAreaHidden = !isTextAreaHidden;
  1526. $(".viewList").toggle();
  1527. $(".btnListSave").toggle();
  1528. })
  1529. // 刷新按钮 点击响应
  1530. $(".btnRefresh").click(function(){
  1531. setPageRefreshMethod();
  1532. })
  1533. // 保存列表 点击响应
  1534. $(".btnListSave").click(function(){
  1535. viewVideoList = $(".viewList").val();
  1536. saveTextAreaVideoList(viewVideoList);
  1537. isTextAreaHidden = !isTextAreaHidden;
  1538. $(".viewList").toggle();
  1539. $(".btnListSave").toggle();
  1540. })
  1541. }
  1542. // 202501版本:番剧搜索结果
  1543. // 番剧封面视频
  1544. $(".media-card").each(function(){
  1545. setVideoIsViewed($(this),coverItemClass);
  1546. });
  1547. // 番剧集数列表
  1548. var itemSpanArr = $(".media-footerClone .p_relativeSpan");
  1549. if(itemSpanArr.length == 0){
  1550. // 克隆一个.media-footer
  1551. $(".media-card-content-footer").each(function(idx){
  1552. var mFooter = $(this).find(".media-footer:first");
  1553. if(mFooter.length == 0){
  1554. return;
  1555. }
  1556. var objOffset = mFooter.offset();
  1557. var cloneObj = $(mFooter).clone();
  1558. $(cloneObj).addClass("media-footerClone");
  1559. $(cloneObj).addClass("media-footerClone_"+idx);
  1560. $(cloneObj).removeClass("media-footer");
  1561. $(this).append(cloneObj);
  1562. // 对克隆体里面的元素进行外层包装
  1563. var itemArr = $(".media-footerClone_"+idx+" .p_relative");
  1564. for(var i = 0 ; i < itemArr.length ;i++){
  1565. var spanObj = $("<span class='p_relativeSpan'></span>");
  1566. spanObj.append(itemArr[i]);
  1567. $(".media-footerClone_"+idx).append(spanObj);
  1568. }
  1569. // 克隆层对齐被克隆层
  1570. $(".media-footerClone_"+idx).offset(objOffset);
  1571. })
  1572. $(".media-footer").attr("style","opacity:0");//原来那层变透明
  1573. // 窗口大小改变时进行监听:自动删除克隆层
  1574. $(window).unbind("resize").resize(function(){
  1575. $(".media-footer").removeAttr("style");
  1576. $(".media-footerClone").remove();
  1577. setTimeout(setMethod,2000);
  1578. })
  1579. }
  1580. $(".p_relativeSpan").each(function(){
  1581. setVideoIsViewed($(this),".vui_button");
  1582. });
  1583. // 202501版本:综艺节目搜索结果
  1584. // 综艺集数列表
  1585. $(".seleced-ep").unbind("mouseenter").bind("mouseenter",function(){
  1586. setTimeout(setMethod,500);
  1587. })
  1588. var itemArr = $(".media-footer-select-content-item");
  1589. itemSpanArr = $(".selConSpan");
  1590. var newLength = itemArr.length - itemSpanArr.length;
  1591. if(itemSpanArr.length == 0 || newLength > 0){
  1592. for(var i = itemSpanArr.length ; i < itemArr.length ;i++){
  1593. var spanObj = $("<div class='selConSpan'></div>");
  1594. spanObj.append(itemArr[i]);
  1595. $(".media-footer-select-content").append(spanObj);
  1596. }
  1597. }
  1598. $(".selConSpan").each(function(){
  1599. setVideoIsViewed($(this),".media-footer-select-content-item",0,null,true,true);
  1600. });
  1601. // 查看更多 按钮调回到列表最后面
  1602. $(".media-footer-select-content-more").each(function(){
  1603. $(this).appendTo($(this).parent());
  1604. })
  1605. // 202501版本:up主的视频Item、普通搜索结果Item
  1606. $(".bili-video-card__wrap").each(function(){
  1607. setVideoIsViewed($(this),coverItemClass);
  1608. });
  1609. // 已看/未看按钮响应
  1610. setBtnView();
  1611. // 回车响应(搜索框)
  1612. $(document).unbind('keyup').keyup(function(event){
  1613. if(event.keyCode ==13){
  1614. setTimeout(setPageRefreshMethod,2000);
  1615. }
  1616. });
  1617. // 202501版本:分类菜单点击响应
  1618. $(".vui_tabs--nav-item").unbind('click').click(function(){
  1619. setTimeout(setPageRefreshMethod,2000);
  1620. })
  1621. // 202501版本:页面上的按钮 点击响应(搜索、分页、排序、筛选 等按钮)
  1622. $(".vui_button").unbind('click').click(function(){
  1623. setTimeout(setPageRefreshMethod,2000);
  1624. })
  1625. }
  1626.  
  1627. // 获取视频链接上的bv号(不含开头bv)
  1628. // 设置每个视频是否已看/未看
  1629. // targetAppend:获取视频链接的目标对象(子元素有<a/>),追加已看/未看按钮的那个对象
  1630. // coverClass:视频封面的对象(用来设置透明度)
  1631. // playType:播放类型(链接处理不同) 0普通视频/节目视频(版权视频)、1稍后观看视频、2节目视频(视频链接作为videoid传入)、3稍后再看视频202412(/list/watchlater?bvid=BVxxxxx&oid=xxxxx)
  1632. // videoid:直接传入视频号(如果传入这个,则跳过对targetAppend的视频链接提取处理)
  1633. // noAppendTarget:传入true时,则不追加按钮到targetAppend对象下,而是追加到coverClass对象下面,也不会设置封面透明度(主要用于对视频观看页的特殊处理)
  1634. // isBefore:传入true时,按钮插入到指定对象(同层)的前面,否则追加指定对象(内部)的最后
  1635. // findALast:传入true时,查找targetAppend的最后一个a标签,否则查找第一个a标签
  1636. // findCoverClassLast:传入true时,查找coverClass对应的的最后一个对象元素,否则查找对应的第一个对象元素
  1637. // 返回:去掉开头bv两个字符的视频号,如果中途处理失败,则返回null
  1638. var bvid = null;
  1639. var setVideoIsViewed = function(targetAppend,coverClass,playType,videoid,noAppendTarget,isBefore,findALast,findCoverClassLast){
  1640. // 获取封面
  1641. var coverObj = null;
  1642. if(findCoverClassLast){
  1643. coverObj = targetAppend.find(coverClass+":last");
  1644. }else{
  1645. coverObj = targetAppend.find(coverClass+":first");
  1646. }
  1647. if(coverObj.length == 0){
  1648. return null;
  1649. }
  1650. // 判断是否已设置按钮和封面
  1651. var btnView = null;
  1652. if(noAppendTarget){
  1653. if(isBefore){
  1654. btnView = coverObj.parent().children(".btnView:first");
  1655. }else{
  1656. btnView = coverObj.children(".btnView:first");
  1657. }
  1658. }else{
  1659. btnView = targetAppend.children(".btnView:first");
  1660. }
  1661. if(btnView.length > 0){
  1662. return null;
  1663. }
  1664. if(videoid != null && playType != 2){
  1665. bvid = videoid;
  1666. }else{
  1667. // 获取视频链接和封面
  1668. if(playType == 2){
  1669. // videoid作为链接处理
  1670. bvid = videoid;
  1671. // 然后作为普通视频处理
  1672. playType = 0;
  1673. }else{
  1674. var aObj = null;
  1675. if(findALast){
  1676. aObj = targetAppend.find("a:last");
  1677. }else{
  1678. aObj = targetAppend.find("a:first");
  1679. }
  1680. if(aObj.length == 0){
  1681. return null;
  1682. }
  1683. bvid = aObj.attr("href");
  1684. }
  1685. if(bvid == null){
  1686. return null;
  1687. }
  1688. // 提取视频链接上面的bv号
  1689. if(playType == 1){
  1690. // 稍后观看视频
  1691. bvid = bvid.replace("//www.bilibili.com/medialist/play/watchlater/","");
  1692. }else if(playType == 3){
  1693. // 202412稍后再看列表的视频:https://www.bilibili.com/list/watchlater?bvid=BVxxxxxxx&oid=xxxxxxx
  1694. bvid = getBvidFromUrl(bvid);
  1695. if(!bvid){
  1696. return;
  1697. }
  1698. }else{
  1699. // 短地址
  1700. bvid = bvid.replace("//b23.tv/","");
  1701. // 课程手机视频(首页的课堂Item用的)
  1702. bvid = bvid.replace("//m.bilibili.com/cheese/play/","");
  1703. // 普通视频
  1704. bvid = bvid.replace("//www.bilibili.com/video/","").replace("/video/","");
  1705. // 节目视频
  1706. bvid = bvid.replace("//www.bilibili.com/bangumi/play/","").replace("/bangumi/play/","");
  1707. // 课程视频
  1708. bvid = bvid.replace("//www.bilibili.com/cheese/play/","").replace("/cheese/play/","");
  1709. }
  1710. bvid = bvid.replace("https:","");
  1711. var slashIndex = bvid.indexOf("/");
  1712. if(slashIndex > -1){
  1713. bvid = bvid.substring(0,slashIndex);
  1714. }
  1715. if(bvid.length == 0){
  1716. return null;
  1717. }
  1718. slashIndex = bvid.indexOf("?");
  1719. if(slashIndex > -1){
  1720. bvid = bvid.substring(0,slashIndex);
  1721. }
  1722. bvid = bvid.replace("/","");
  1723. }
  1724. if(bvid.startsWith("av")){
  1725. // av号转bv号
  1726. bvid = bvid.substr(2);
  1727. bvid = avToBv.encode(bvid);
  1728. bvid = bvid.substr(2);
  1729. }else if(bvid.startsWith("BV") || bvid.startsWith("bv")){
  1730. bvid = bvid.replace("BV","").replace("bv","");
  1731. }else if(bvid.startsWith("ep") || bvid.startsWith("ss")){
  1732. // 节目视频原样保留
  1733. }else{
  1734. return null;
  1735. }
  1736. if(noAppendTarget){
  1737. targetAppend = coverObj;
  1738. }
  1739. // 添加已看/未看按钮、设置封面透明度
  1740. if(getBvIsViewed(bvid)){
  1741. // 已看
  1742. if(isBefore){
  1743. targetAppend.before("<a class='btnView btnIsView' data-view='1' data-av='"+bvid+"'>已看</a>");
  1744. }else{
  1745. targetAppend.append("<a class='btnView btnIsView' data-view='1' data-av='"+bvid+"'>已看</a>");
  1746. }
  1747. if(!noAppendTarget){
  1748. coverObj.css("opacity",opacityIsViewCover);
  1749. }
  1750. }else{
  1751. // 未看
  1752. if(isBefore){
  1753. targetAppend.before("<a class='btnView btnNotView' data-view='0' data-av='"+bvid+"'>未看</a>");
  1754. }else{
  1755. targetAppend.append("<a class='btnView btnNotView' data-view='0' data-av='"+bvid+"'>未看</a>");
  1756. }
  1757. if(!noAppendTarget){
  1758. coverObj.css("opacity","1");
  1759. }
  1760. }
  1761. return bvid;
  1762. }
  1763.  
  1764. var getBvidFromUrl = function(url) {
  1765. // 使用正则表达式匹配 bvid 的值
  1766. const regex = /bvid=([^&]+)/;
  1767. const match = url.match(regex);
  1768. // 如果匹配成功,返回 bvid 的值,否则返回 null
  1769. return match ? match[1] : null;
  1770. }
  1771.  
  1772. // 判断视频是否已看
  1773. var viewVideoJson = {};
  1774. var viewGroupArr = null;
  1775. var getBvIsViewed = function(bvid){
  1776. bvid = bvid + "";
  1777. if(bvid.length < 5){ // 暂时发现最短是ss100
  1778. return false;
  1779. }
  1780. var groupId = "";
  1781. if(bvid.startsWith("ep")){
  1782. // 节目视频(ep数字):ep+最后一个数字作为分组名称
  1783. groupId = "ep"+bvid.substr(bvid.length-1,1);
  1784. }else if(bvid.startsWith("ss")){
  1785. // 节目合集(ss数字):ss+最后一个数字作为分组名称
  1786. groupId = "ss"+bvid.substr(bvid.length-1,1);
  1787. }else if(bvid.length == 10){
  1788. // 普通视频bv号:取第二个字符作为分组
  1789. groupId = bvid.substr(1,1);
  1790. }else if(bvid.length > 10 && bvid.indexOf("-") == 10){
  1791. // 分P存储bv-N,N为第N P:取第二个字符作为分组
  1792. groupId = bvid.substr(1,1);
  1793. }else{
  1794. return false;
  1795. }
  1796. viewGroupArr = viewVideoJson[groupId];
  1797. if(!viewGroupArr){
  1798. viewGroupArr = GM_getValue("BiliViewed_"+groupId,null);
  1799. if(viewGroupArr == null){
  1800. // 该分组未建立
  1801. return false;
  1802. }
  1803. viewVideoJson[groupId] = viewGroupArr;
  1804. }
  1805. for(var i = 0 ; i < viewGroupArr.length;i++){
  1806. if(bvid == viewGroupArr[i]){
  1807. return true;
  1808. }
  1809. }
  1810. return false;
  1811. }
  1812.  
  1813. // 更新和保存GM本地存储的列表
  1814. var saveGMVideoList = function(bvid,isViewed){
  1815. bvid = bvid + "";
  1816. if(bvid.length < 5){
  1817. return false;
  1818. }
  1819. var groupId = "";
  1820. if(bvid.startsWith("ep")){
  1821. // 节目视频(ep数字):ep+最后一个数字作为分组名称
  1822. groupId = "ep"+bvid.substr(bvid.length-1,1);
  1823. }else if(bvid.startsWith("ss")){
  1824. // 节目合集(ss数字):ss+最后一个数字作为分组名称
  1825. groupId = "ss"+bvid.substr(bvid.length-1,1);
  1826. }else if(bvid.length == 10){
  1827. // 普通视频bv号:取第二个字符作为分组
  1828. groupId = bvid.substr(1,1);
  1829. }else if(bvid.length > 10 && bvid.indexOf("-") == 10){
  1830. // 分P存储bv-N,N为第N P:取第二个字符作为分组
  1831. groupId = bvid.substr(1,1);
  1832. }else{
  1833. return false;
  1834. }
  1835. viewGroupArr = viewVideoJson[groupId];
  1836. if(!viewGroupArr){
  1837. viewGroupArr = GM_getValue("BiliViewed_"+groupId,null);
  1838. if(viewGroupArr == null){
  1839. // 该分组未建立
  1840. if(!isViewed){
  1841. return;
  1842. }
  1843. viewVideoJson[groupId] = [];
  1844. }
  1845. }
  1846. if(isViewed){
  1847. // 防止没刷新重复插入
  1848. for(var i = 0 ; i < viewVideoJson[groupId].length && i < 10;i++){
  1849. if(viewVideoJson[groupId][i] == bvid){
  1850. return;
  1851. }
  1852. }
  1853. viewVideoJson[groupId].unshift(bvid); // 添加新的bv号到数组中
  1854. }else{
  1855. for(var i = 0 ; i < viewVideoJson[groupId].length;i++){
  1856. if(viewVideoJson[groupId][i] == bvid){
  1857. viewVideoJson[groupId].splice(i,1); // 删除数组上指定位置的数据
  1858. }
  1859. }
  1860. }
  1861. // 存储到GM
  1862. GM_setValue("BiliViewed_"+groupId,viewVideoJson[groupId]);
  1863. }
  1864.  
  1865. // 对原已看视频数据列表进行分组(按第二个字母)
  1866. var groupGMVideoList = function(viewVideoList){
  1867. if(viewVideoList.length == 0){
  1868. GM_deleteValue("BiliViewed");
  1869. return;
  1870. }
  1871. var videoArr = viewVideoList.split("\n");
  1872. var gid = "";
  1873. var groupJson = {};
  1874. for(var i = 0 ; i < videoArr.length;i++){
  1875. if(videoArr[i].length < 6){
  1876. continue;
  1877. }
  1878. if(videoArr[i].startsWith("ep")){
  1879. // 节目视频(ep数字):ep+最后一个数字作为分组名称
  1880. gid = "ep"+videoArr[i].substr(videoArr[i].length-1,1);
  1881. }else if(videoArr[i].startsWith("ss")){
  1882. // 节目合集(ss数字):ss+最后一个数字作为分组名称
  1883. gid = "ss"+videoArr[i].substr(videoArr[i].length-1,1);
  1884. }else if(videoArr[i].length == 10){
  1885. // 普通视频bv号:取第二个字符作为分组
  1886. gid = videoArr[i].substr(1,1);
  1887. }else if(videoArr[i].length > 10 && videoArr[i].indexOf("-") == 10){
  1888. // 分P存储bv-N,N为第N P:取第二个字符作为分组
  1889. gid = videoArr[i].substr(1,1);
  1890. }else{
  1891. continue;
  1892. }
  1893. if(!groupJson[gid]){
  1894. groupJson[gid] = [];
  1895. }
  1896. groupJson[gid].unshift(videoArr[i]);
  1897. }
  1898. // 存储各分表
  1899. for(var key in groupJson){
  1900. GM_setValue("BiliViewed_"+key,groupJson[key]);
  1901. }
  1902. // 删除原列表
  1903. GM_deleteValue("BiliViewed");
  1904. }
  1905.  
  1906. // 对文本框的视频数据列表进行分组(按第二个字母)
  1907. var saveTextAreaVideoList = function(viewVideoList){
  1908. viewVideoList = viewVideoList.replaceAll("\n",",");
  1909. var videoArr = viewVideoList.split(",");
  1910. var gid = "";
  1911. var groupJson = {};
  1912. for(var i = 0 ; i < videoArr.length;i++){
  1913. if(videoArr[i].length < 6){
  1914. continue;
  1915. }
  1916. if(videoArr[i].startsWith("ep")){
  1917. // 节目视频(ep数字):ep+最后一个数字作为分组名称
  1918. gid = "ep"+videoArr[i].substr(videoArr[i].length-1,1);
  1919. }else if(videoArr[i].startsWith("ss")){
  1920. // 节目合集(ss数字):ss+最后一个数字作为分组名称
  1921. gid = "ss"+videoArr[i].substr(videoArr[i].length-1,1);
  1922. }else if(videoArr[i].length == 10){
  1923. // 普通视频bv号:取第二个字符作为分组
  1924. gid = videoArr[i].substr(1,1);
  1925. }else if(videoArr[i].length > 10 && videoArr[i].indexOf("-") == 10){
  1926. // 分P存储bv-N,N为第N P:取第二个字符作为分组
  1927. gid = videoArr[i].substr(1,1);
  1928. }else{
  1929. continue;
  1930. }
  1931. if(!groupJson[gid]){
  1932. groupJson[gid] = [];
  1933. }
  1934. groupJson[gid].unshift(videoArr[i]);
  1935. }
  1936. // 清空原来GM存储的所有数据
  1937. var keyList = GM_listValues();
  1938. var key = "";
  1939. for(var i = 0 ; i < keyList.length;i++){
  1940. key = keyList[i];
  1941. if(key.indexOf("BiliViewed_") == 0){
  1942. GM_deleteValue(key);
  1943. }
  1944. }
  1945. // 存储各分表
  1946. for(var key in groupJson){
  1947. GM_setValue("BiliViewed_"+key,groupJson[key]);
  1948. }
  1949. }
  1950.  
  1951. // av转bv,参考来源:https://github.com/Coxxs/bvid/blob/master/bvid.js
  1952. var avToBv = (function () {
  1953. var table = 'fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF'
  1954. var tr = {}
  1955. for (var i = 0; i < 58; i++) {
  1956. tr[table[i]] = i
  1957. }
  1958. var s = [11, 10, 3, 8, 4, 6]
  1959. var r = ['B', 'V', '1', '', '', '4', '', '1', '', '7', '', '']
  1960. var xor = 177451812
  1961. var add = 8728348608
  1962.  
  1963. function encode(x) {
  1964. if (x <= 0 || x >= 1e9) {
  1965. return null
  1966. }
  1967. x = (x ^ xor) + add
  1968. var result = r.slice()
  1969. for (var i = 0; i < 6; i++) {
  1970. result[s[i]] = table[Math.floor(x / 58 ** i) % 58]
  1971. }
  1972. return result.join('')
  1973. }
  1974. return { encode }
  1975. })()

QingJ © 2025

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