From 04384dbbbec88e07b21e39dc87647dc557c84314 Mon Sep 17 00:00:00 2001 From: festoney8 Date: Sat, 15 Jun 2024 04:25:57 +0800 Subject: [PATCH 01/10] refactor: url cleaner, bv2av --- CHANGELOG.md | 6 ++ src/main.ts | 10 --- src/rules/common.ts | 128 ++++++++++++++++++++------------------- src/rules/video.ts | 75 ++++++++++++----------- src/utils/url-cleaner.ts | 73 ++++++++++++++++++++++ vite.config.ts | 2 +- 6 files changed, 187 insertions(+), 107 deletions(-) create mode 100644 src/utils/url-cleaner.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 783e8e0d..61dfe8ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## 3.7.1 + +- 重构:URL净化、BV号转AV号 +- 优化:去除播放页网址跳变问题 +- 优化:减少URL变化对浏览器历史记录的影响 + ## 3.7.0 - 新增:播放页 播放设定板块 diff --git a/src/main.ts b/src/main.ts index 560da648..7fccd6f6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -69,16 +69,6 @@ const main = async () => { const COMMENT_FILTER_GROUPS = [...videoPageCommentFilterGroupList, ...dynamicPageCommentFilterGroupList] COMMENT_FILTER_GROUPS.forEach((e) => e.enableGroup()) - // 监听各种形式的URL变化 (普通监听无法检测到切换视频) - let lastURL = location.href - setInterval(() => { - const currURL = location.href - if (currURL !== lastURL) { - RULE_GROUPS.forEach((e) => e.reloadGroup()) - lastURL = currURL - } - }, 500) - // 全局启动/关闭快捷键 chrome: Alt+B,firefox: Ctrl+Alt+B let isGroupEnable = true document.addEventListener('keydown', (event) => { diff --git a/src/rules/common.ts b/src/rules/common.ts index d4f67c34..7dabd69f 100644 --- a/src/rules/common.ts +++ b/src/rules/common.ts @@ -12,6 +12,7 @@ import { isPageSearch, isPageVideo, } from '../utils/page-type' +import URLCleanerInstance from '../utils/url-cleaner' // Grouplist const commonGroupList: Group[] = [] @@ -337,76 +338,79 @@ const basicItems = [ itemID: 'url-cleaner', description: 'URL参数净化 (充电时需关闭)', defaultStatus: true, - isItemFuncReload: true, /** * URL净化,移除query string中的跟踪参数/无用参数 * 净化掉vd_source参数会导致充电窗口载入失败 */ itemFunc: () => { - // 直播域名各种iframe页面(天选、抽奖)和活动页特殊处理 - if (location.href.match(/live\.bilibili\.com\/(p\/html|activity|blackboard)/)) { - return - } - const keysToRemove = new Set([ - 'from_source', - 'spm_id_from', - 'search_source', - 'vd_source', - 'unique_k', - 'is_story_h5', - 'from_spmid', - 'share_plat', - 'share_medium', - 'share_from', - 'share_source', - 'share_tag', - 'up_id', - 'timestamp', - 'mid', - 'live_from', - 'launch_id', - 'session_id', - 'share_session_id', - 'broadcast_type', - 'is_room_feed', - 'spmid', - 'plat_id', - 'goto', - 'report_flow_data', - 'trackid', - 'live_form', - 'track_id', - 'from', - 'visit_id', - 'extra_jump_from', - ]) - if (isPageSearch()) { - keysToRemove.add('vt') - } - if (isPageLiveRoom()) { - keysToRemove.add('bbid') - keysToRemove.add('ts') - } - const url = location.href - const urlObj = new URL(url) - const params = new URLSearchParams(urlObj.search) + const cleanParams = (url: string): string => { + try { + // 直播域名各种iframe页面(天选、抽奖)和活动页特殊处理 + if (url.match(/live\.bilibili\.com\/(p\/html|activity|blackboard)/)) { + return url + } + const keysToRemove = new Set([ + 'from_source', + 'spm_id_from', + 'search_source', + 'vd_source', + 'unique_k', + 'is_story_h5', + 'from_spmid', + 'share_plat', + 'share_medium', + 'share_from', + 'share_source', + 'share_tag', + 'up_id', + 'timestamp', + 'mid', + 'live_from', + 'launch_id', + 'session_id', + 'share_session_id', + 'broadcast_type', + 'is_room_feed', + 'spmid', + 'plat_id', + 'goto', + 'report_flow_data', + 'trackid', + 'live_form', + 'track_id', + 'from', + 'visit_id', + 'extra_jump_from', + ]) + if (isPageSearch()) { + keysToRemove.add('vt') + } + if (isPageLiveRoom()) { + keysToRemove.add('bbid') + keysToRemove.add('ts') + } + const urlObj = new URL(url) + const params = new URLSearchParams(urlObj.search) - const temp = [] - for (const k of params.keys()) { - keysToRemove.has(k) && temp.push(k) - } - for (const k of temp) { - params.delete(k) - } - if (params.get('p') === '1') { - params.delete('p') - } + const temp = [] + for (const k of params.keys()) { + keysToRemove.has(k) && temp.push(k) + } + for (const k of temp) { + params.delete(k) + } + if (params.get('p') === '1') { + params.delete('p') + } - urlObj.search = params.toString() - const newURL = urlObj.toString().replace(/\/$/, '') - if (newURL !== url) { - history.replaceState(null, '', newURL) + urlObj.search = params.toString() + return urlObj.toString() + } catch (err) { + return url + } } + URLCleanerInstance.cleanFnArr.push(cleanParams) + URLCleanerInstance.clean() }, }), // 隐藏页底 footer diff --git a/src/rules/video.ts b/src/rules/video.ts index 52826302..67a895c7 100644 --- a/src/rules/video.ts +++ b/src/rules/video.ts @@ -4,6 +4,7 @@ import { debugRules as debug, error } from '../utils/logger' import { matchAvidBvid, matchBvid, waitForEle } from '../utils/tool' import { isPageFestival, isPagePlaylist, isPageVideo } from '../utils/page-type' import { GM_getValue, GM_setValue, unsafeWindow } from '$' +import URLCleanerInstance from '../utils/url-cleaner' /** 宽屏模式监听 */ let _isWide = unsafeWindow.isWide @@ -90,45 +91,51 @@ if (isPageVideo() || isPagePlaylist()) { itemID: 'video-page-bv2av', description: 'BV号转AV号', itemFunc: () => { - /** - * algo by bilibili-API-collect - * @see https://www.zhihu.com/question/381784377/answer/1099438784 - * @see https://github.com/SocialSisterYi/bilibili-API-collect/issues/740 - * @see https://socialsisteryi.github.io/bilibili-API-collect/docs/misc/bvid_desc.html - * @param bvid 输入BV号 - * @returns 输出纯数字av号 - */ - const XOR_CODE = 23442827791579n - const MASK_CODE = 2251799813685247n - const BASE = 58n - const data = 'FcwAPNKTMug3GV5Lj7EJnHpWsx4tb8haYeviqBz6rkCy12mUSDQX9RdoZf' - const dec = (bvid: string): number => { - const bvidArr = Array.from(bvid) - ;[bvidArr[3], bvidArr[9]] = [bvidArr[9], bvidArr[3]] - ;[bvidArr[4], bvidArr[7]] = [bvidArr[7], bvidArr[4]] - bvidArr.splice(0, 3) - const tmp = bvidArr.reduce((pre, bvidChar) => pre * BASE + BigInt(data.indexOf(bvidChar)), 0n) - return Number((tmp & MASK_CODE) ^ XOR_CODE) - } + const bv2av = (url: string): string => { + /** + * algo by bilibili-API-collect + * @see https://www.zhihu.com/question/381784377/answer/1099438784 + * @see https://github.com/SocialSisterYi/bilibili-API-collect/issues/740 + * @see https://socialsisteryi.github.io/bilibili-API-collect/docs/misc/bvid_desc.html + * @param bvid 输入BV号 + * @returns 输出纯数字av号 + */ + const XOR_CODE = 23442827791579n + const MASK_CODE = 2251799813685247n + const BASE = 58n + const data = 'FcwAPNKTMug3GV5Lj7EJnHpWsx4tb8haYeviqBz6rkCy12mUSDQX9RdoZf' + const dec = (bvid: string): number => { + const bvidArr = Array.from(bvid) + ;[bvidArr[3], bvidArr[9]] = [bvidArr[9], bvidArr[3]] + ;[bvidArr[4], bvidArr[7]] = [bvidArr[7], bvidArr[4]] + bvidArr.splice(0, 3) + const tmp = bvidArr.reduce((pre, bvidChar) => pre * BASE + BigInt(data.indexOf(bvidChar)), 0n) + return Number((tmp & MASK_CODE) ^ XOR_CODE) + } - try { - if (location.href.includes('bilibili.com/video/BV')) { - const bvid = matchBvid(location.href) - if (bvid) { - // 保留query string中分P参数, anchor中reply定位 - let partNum = '' - const params = new URLSearchParams(location.search) - if (params.has('p')) { - partNum += `?p=${params.get('p')}` + try { + if (url.includes('bilibili.com/video/BV')) { + const bvid = matchBvid(url) + if (bvid) { + // 保留query string中分P参数, anchor中reply定位 + const urlObj = new URL(url) + const params = new URLSearchParams(urlObj.search) + let partNum = '' + if (params.has('p')) { + partNum += `?p=${params.get('p')}` + } + const aid = dec(bvid) + return `https://www.bilibili.com/video/av${aid}/${partNum}${urlObj.hash}` } - const aid = dec(bvid) - const newURL = `https://www.bilibili.com/video/av${aid}${partNum}${location.hash}` - history.replaceState(null, '', newURL) } + return url + } catch (err) { + return url } - } catch (err) {} + } + URLCleanerInstance.cleanFnArr.push(bv2av) + URLCleanerInstance.clean() }, - isItemFuncReload: true, }), // 净化分享, 默认开启, 关闭功能需刷新 new CheckboxItem({ diff --git a/src/utils/url-cleaner.ts b/src/utils/url-cleaner.ts new file mode 100644 index 00000000..8436a4d1 --- /dev/null +++ b/src/utils/url-cleaner.ts @@ -0,0 +1,73 @@ +import { unsafeWindow } from '$' +import { error } from './logger' + +class URLCleaner { + origReplaceState = unsafeWindow.history.replaceState + origPushState = unsafeWindow.history.pushState + + // URL清理函数 + cleanFnArr: ((url: string) => string)[] = [] + + constructor() { + try { + this.hijack() + } catch (err) { + error('init URLCleaner error', err) + } + } + + hijack() { + unsafeWindow.history.replaceState = (data: any, unused: string, url?: string | URL | null): void => { + try { + if (typeof url === 'string') { + // 修补url + if (!url.startsWith(location.origin) && !url.startsWith(location.hostname)) { + url = `${location.origin}${url.startsWith('/') ? '' : '/'}${url}` + } + const cleanURL = this.cleanFnArr.reduce((curr, fn) => fn(curr), url) + if (location.href.endsWith(cleanURL)) { + return + } + return this.origReplaceState.apply(unsafeWindow.history, [data, unused, cleanURL]) + } + return this.origReplaceState.apply(unsafeWindow.history, [data, unused, url]) + } catch (err) { + error('URLCleaner replaceState error', err) + return this.origReplaceState.apply(unsafeWindow.history, [data, unused, url]) + } + } + unsafeWindow.history.pushState = (data: any, unused: string, url?: string | URL | null): void => { + try { + if (typeof url === 'string') { + if (!url.startsWith(location.origin) && !url.startsWith(location.hostname)) { + url = `${location.origin}${url.startsWith('/') ? '' : '/'}${url}` + } + const cleanURL = this.cleanFnArr.reduce((curr, fn) => fn(curr), url) + if (location.href.endsWith(cleanURL)) { + return + } + return this.origPushState.apply(unsafeWindow.history, [data, unused, cleanURL]) + } + return this.origPushState.apply(unsafeWindow.history, [data, unused, url]) + } catch (err) { + error('URLCleaner pushState error', err) + return this.origReplaceState.apply(unsafeWindow.history, [data, unused, url]) + } + } + } + + clean() { + try { + const cleanURL = this.cleanFnArr.reduce((curr, fn) => fn(curr), location.href) + if (location.href !== cleanURL) { + this.origReplaceState.apply(unsafeWindow.history, [null, '', cleanURL]) + } + } catch (err) { + error('init URLCleaner error', err) + } + } +} + +// 单例 +const URLCleanerInstance = new URLCleaner() +export default URLCleanerInstance diff --git a/vite.config.ts b/vite.config.ts index 1b40ef0c..d510cdf1 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -8,7 +8,7 @@ export default defineConfig({ userscript: { name: 'bilibili 页面净化大师', namespace: 'http://tampermonkey.net/', - version: '3.7.0', + version: '3.7.1', description: '净化 B站/哔哩哔哩 页面,支持「精简功能、播放器净化、过滤视频、过滤评论、全站黑白名单」,提供 300+ 功能,定制自己的 B 站', author: 'festoney8', From f929a05e13f8ad7a55d4e3990753f5e3ee1f3f71 Mon Sep 17 00:00:00 2001 From: festoney8 Date: Sat, 15 Jun 2024 21:52:09 +0800 Subject: [PATCH 02/10] update: bangumi page common header items --- CHANGELOG.md | 1 + src/rules/common.ts | 40 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61dfe8ad..e0d63755 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - 重构:URL净化、BV号转AV号 - 优化:去除播放页网址跳变问题 - 优化:减少URL变化对浏览器历史记录的影响 +- 优化:顶栏净化对版权视频页优化 ## 3.7.0 diff --git a/src/rules/common.ts b/src/rules/common.ts index 7dabd69f..4f3aeca6 100644 --- a/src/rules/common.ts +++ b/src/rules/common.ts @@ -442,6 +442,10 @@ if (!isPageLiveHome()) { } #biliMainHeader .left-entry .v-popover-wrap a[href="https://www.bilibili.com/"]>svg { display: none !important; + } + /* 番剧页 */ + [class^="BiliHeaderV3_leftEntryTitle__"] > svg { + display: none !important; }`, }), // 隐藏 首页 @@ -469,6 +473,10 @@ if (!isPageLiveHome()) { } #biliMainHeader .bili-header .left-entry__title .mini-header__logo { margin-right: 0 !important; + } + /* 番剧页 */ + [class^="BiliHeaderV3_leftEntryTitle__"] > div { + display: none !important; }`, }), // 隐藏 分区弹出框 @@ -491,6 +499,10 @@ if (!isPageLiveHome()) { } #biliMainHeader .left-entry .v-popover-wrap:has(>a[href*="bilibili.com/anime"]) { display: none !important; + } + /* 番剧页 */ + [class^="BiliHeaderV3_leftEntry__"] li:has(a[href*="bilibili.com/anime"]){ + display: none !important; }`, }), // 隐藏 番剧弹出框 @@ -514,6 +526,10 @@ if (!isPageLiveHome()) { } #biliMainHeader .left-entry .v-popover-wrap:has(>a[href*="live.bilibili.com"]) { display: none !important; + } + /* 番剧页 */ + [class^="BiliHeaderV3_leftEntry__"] li:has(a[href*="live.bilibili.com"]){ + display: none !important; }`, }), // 隐藏 直播弹出框 @@ -537,6 +553,10 @@ if (!isPageLiveHome()) { } #biliMainHeader .left-entry .v-popover-wrap:has(>a[href*="game.bilibili.com"]) { display: none !important; + } + /* 番剧页 */ + [class^="BiliHeaderV3_leftEntry__"] li:has(a[href*="game.bilibili.com"]){ + display: none !important; }`, }), // 隐藏 游戏中心弹出框 @@ -560,6 +580,10 @@ if (!isPageLiveHome()) { } #biliMainHeader .left-entry .v-popover-wrap:has(>a[href*="show.bilibili.com"]) { display: none !important; + } + /* 番剧页 */ + [class^="BiliHeaderV3_leftEntry__"] li:has(a[href*="show.bilibili.com"]){ + display: none !important; }`, }), // 隐藏 漫画 @@ -575,6 +599,10 @@ if (!isPageLiveHome()) { } #biliMainHeader .left-entry .v-popover-wrap:has(>a[href*="manga.bilibili.com"]) { display: none !important; + } + /* 番剧页 */ + [class^="BiliHeaderV3_leftEntry__"] li:has(a[href*="manga.bilibili.com"]){ + display: none !important; }`, }), // 隐藏 漫画弹出框 @@ -598,6 +626,10 @@ if (!isPageLiveHome()) { } #biliMainHeader .left-entry .v-popover-wrap:has(>a[href*="bilibili.com/match/"]) { display: none !important; + } + /* 番剧页 */ + [class^="BiliHeaderV3_leftEntry__"] li:has(a[href*="www.bilibili.com/v/game/match"]){ + display: none !important; }`, }), // 隐藏 活动/活动直播 @@ -902,6 +934,10 @@ if (!isPageLiveHome()) { /* 旧版header */ #internationalHeader .nav-user-center >div:has(.mini-upload) { visibility: hidden !important; + } + /* 番剧页 */ + [class^="BiliHeaderV3_headerUploadEntry"] { + visibility: hidden !important; }`, }), ] @@ -917,7 +953,7 @@ if (!isPageLiveHome()) { maxValue: 2000, disableValue: -1, unit: 'px', - itemCSS: `.bili-header .bili-header__bar {padding-left: ???px !important;}`, + itemCSS: `.bili-header .bili-header__bar, [class^="BiliHeaderV3_biliHeaderBar___"] {padding-left: ???px !important;}`, itemCSSPlaceholder: '???', }), new NumberItem({ @@ -943,7 +979,7 @@ if (!isPageLiveHome()) { maxValue: 2000, disableValue: -1, unit: 'px', - itemCSS: `.bili-header .bili-header__bar {padding-right: ???px !important;}`, + itemCSS: `.bili-header .bili-header__bar, [class^="BiliHeaderV3_biliHeaderBar___"] {padding-right: ???px !important;}`, itemCSSPlaceholder: '???', }), ] From 6204dfdd5113faa5c1ece16720ee11ef06d12a2e Mon Sep 17 00:00:00 2001 From: festoney8 Date: Sun, 16 Jun 2024 01:01:00 +0800 Subject: [PATCH 03/10] delete: common header watchlater items --- CHANGELOG.md | 3 +- src/rules/common.ts | 85 +++------------------------------------------ src/rules/video.ts | 42 ---------------------- 3 files changed, 7 insertions(+), 123 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0d63755..59b04455 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,11 @@ ## 3.7.1 -- 重构:URL净化、BV号转AV号 +- 优化:重写URL净化、BV号转AV号功能 - 优化:去除播放页网址跳变问题 - 优化:减少URL变化对浏览器历史记录的影响 - 优化:顶栏净化对版权视频页优化 +- 移除:顶栏右侧稍后再看相关功能,适配网页变动 ## 3.7.0 diff --git a/src/rules/common.ts b/src/rules/common.ts index 4f3aeca6..85ea75a5 100644 --- a/src/rules/common.ts +++ b/src/rules/common.ts @@ -1,5 +1,5 @@ import { Group } from '../components/group' -import { CheckboxItem, NumberItem, RadioItem } from '../components/item' +import { CheckboxItem, NumberItem } from '../components/item' import { isPageBangumi, isPageChannel, @@ -811,32 +811,11 @@ if (!isPageLiveHome()) { display: none !important; }`, }), - // 收藏、稍后再看 相关 一组互斥选项 - // 显示收藏 (官方默认), 默认开启 - new RadioItem({ - itemID: 'common-nav-favorite-watchlater-default', - description: '显示 收藏 (官方默认)\n新增稍后再看视频时,自动切换为稍后再看', - radioName: 'common-header-fav-option', - radioItemIDList: [ - 'common-nav-favorite-watchlater-default', - 'common-hide-nav-favorite', - 'common-hide-nav-favorite-keep-watchlater', - 'common-nav-keep-watchlater', - ], - defaultStatus: true, - }), - // 隐藏 收藏, 隐藏 稍后再看 - new RadioItem({ + // 隐藏 收藏 + new CheckboxItem({ itemID: 'common-hide-nav-favorite', - description: '隐藏 收藏,隐藏 稍后再看', - radioName: 'common-header-fav-option', - radioItemIDList: [ - 'common-nav-favorite-watchlater-default', - 'common-hide-nav-favorite', - 'common-hide-nav-favorite-keep-watchlater', - 'common-nav-keep-watchlater', - ], - itemCSS: `.right-entry .v-popover-wrap:has(.header-favorite-container, [data-idx="fav"]) { + description: '隐藏 收藏', + itemCSS: `.right-entry .v-popover-wrap:has(.right-entry__outside[href$="/favlist"]) { display: none !important; } /* 旧版header */ @@ -844,60 +823,6 @@ if (!isPageLiveHome()) { display: none !important; }`, }), - // 隐藏 收藏, 显示 稍后再看 - new RadioItem({ - itemID: 'common-hide-nav-favorite-keep-watchlater', - description: '隐藏 收藏,显示 稍后再看', - radioName: 'common-header-fav-option', - radioItemIDList: [ - 'common-nav-favorite-watchlater-default', - 'common-hide-nav-favorite', - 'common-hide-nav-favorite-keep-watchlater', - 'common-nav-keep-watchlater', - ], - itemCSS: ` - /* 移除加入稍后再看时的上翻动画 */ - .right-entry .v-popover-wrap .header-favorite-container-box { - animation: unset !important; - } - .right-entry .v-popover-wrap .header-favorite-container-box .header-favorite-container__up { - display: none !important; - } - .right-entry .v-popover-wrap .header-favorite-container-box .header-favorite-container__down { - margin-top: 4px !important; - } - @media (max-width: 1279.9px) { - .right-entry .v-popover-wrap .header-favorite-container-box .header-favorite-container__down { - top: 10px; - } - }`, - }), - // 显示 收藏, 显示 稍后再看(实验性) - new RadioItem({ - itemID: 'common-nav-keep-watchlater', - description: '显示 收藏,显示 稍后再看(实验性)', - radioName: 'common-header-fav-option', - radioItemIDList: [ - 'common-nav-favorite-watchlater-default', - 'common-hide-nav-favorite', - 'common-hide-nav-favorite-keep-watchlater', - 'common-nav-keep-watchlater', - ], - itemCSS: ` - /* 移除加入稍后再看时的上翻动画 */ - .right-entry .v-popover-wrap .header-favorite-container-box { - display: flex !important; - animation: unset !important; - } - .right-entry .v-popover-wrap .header-favorite-container-box .header-favorite-container__down { - margin-top: 0 !important; - } - @media (max-width: 1279.9px) { - .right-entry .v-popover-wrap .header-favorite-container-box .header-favorite-container__down { - top: 15px; - } - }`, - }), // 隐藏 历史 new CheckboxItem({ itemID: 'common-hide-nav-history', diff --git a/src/rules/video.ts b/src/rules/video.ts index 67a895c7..e7ce9728 100644 --- a/src/rules/video.ts +++ b/src/rules/video.ts @@ -37,48 +37,6 @@ if (isPageVideo() || isPagePlaylist()) { } const disableAdjustVolume = () => {} -/** 全屏时可滚动 */ -// const fullScreenScroll = () => { -// waitForEle(document.body, '.bpx-player-ctrl-web ~ .bpx-player-ctrl-full', (node: Node): boolean => { -// return node instanceof HTMLElement && (node as HTMLElement).className.includes('bpx-player-ctrl-full') -// }).then(() => { -// const isFull = () => { -// return ( -// document.fullscreenElement || -// (window.innerWidth === screen.width && window.innerHeight === screen.height) -// ) -// } - -// // 触发用户稀有事件,绕过浏览器API对requestFullscreen的限制 -// // 取消播放器触发的全屏,用document.body触发全屏,置于top-layer -// // target必须赋予到变量,否则无法过检测 -// const ele = document.body -// ele.addEventListener('touchend', () => ele.requestFullscreen().then().catch()) - -// // 修改全屏按钮动作,全屏可滚动 = 网页全屏滚动 + 浏览器全屏 -// const webScreenBtn = document.querySelector('.bpx-player-ctrl-web') -// const fullScreenBtn = document.querySelector('.bpx-player-ctrl-full') -// if (webScreenBtn && fullScreenBtn) { -// const newBtn = fullScreenBtn.cloneNode(true) as HTMLElement -// fullScreenBtn.parentElement!.replaceChild(newBtn, fullScreenBtn) -// newBtn.onclick = async () => { -// if (isFull() || (!isFull() && !document.querySelector('.webscreen-fix'))) { -// webScreenBtn.click() -// } -// if (!isFull()) { -// ele.dispatchEvent(new TouchEvent('touchend')) -// webScreenBtn.style.display = 'none' -// } else { -// webScreenBtn.style.display = 'block' -// } -// } -// document.addEventListener('fullscreenchange', () => { -// if (isFull()) { -// } -// }) -// } -// }) -// } const videoGroupList: Group[] = [] From 201e00d8433b14eb1d47860e3f3fcfcc7d1b54bf Mon Sep 17 00:00:00 2001 From: festoney8 Date: Sun, 16 Jun 2024 02:17:54 +0800 Subject: [PATCH 04/10] feat: dyn page checked uploader opacity and display --- CHANGELOG.md | 1 + src/rules/dynamic.ts | 42 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59b04455..ba1b23ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## 3.7.1 +- 新增:动态页淡化/隐藏已查看过动态的UP主 - 优化:重写URL净化、BV号转AV号功能 - 优化:去除播放页网址跳变问题 - 优化:减少URL变化对浏览器历史记录的影响 diff --git a/src/rules/dynamic.ts b/src/rules/dynamic.ts index 315219b5..d4e74f39 100644 --- a/src/rules/dynamic.ts +++ b/src/rules/dynamic.ts @@ -125,8 +125,8 @@ if (isPageDynamic()) { ] dynamicGroupList.push(new Group('dynamic-right', '右栏 热门话题', rightItems)) - // 中栏 - const centerItems = [ + // 中栏顶部 + const centerTopItems = [ // 扩增 中栏宽度 new CheckboxItem({ itemID: 'expand-dynamic-page-bili-dyn-width', @@ -167,12 +167,41 @@ if (isPageDynamic()) { } `, }), + // 淡化 UP 主列表 已查看项 + new CheckboxItem({ + itemID: 'dynamic-page-up-list-checked-item-opacity', + description: '淡化 UP 主列表 已查看项', + itemCSS: ` + .bili-dyn-up-list__item:not(.active):has(.bili-dyn-up-list__item__face .bili-dyn-up-list__item__face__img:only-child) { + transition: opacity 0.2s linear; + opacity: 0.25; + } + .bili-dyn-up-list__item:hover { + transition: opacity 0.1s linear !important; + opacity: 1 !important; + }`, + }), + // 隐藏 UP 主列表 已查看项 + new CheckboxItem({ + itemID: 'dynamic-page-up-list-checked-item-hide', + description: '隐藏 UP 主列表 已查看项', + itemCSS: ` + @keyframes disappear { + from { display: flex; } + to { display: none; } + } + .bili-dyn-up-list__item:not(.active):has(.bili-dyn-up-list__item__face .bili-dyn-up-list__item__face__img:only-child) { + animation: disappear; + animation-delay: 1.2s; + animation-fill-mode: forwards; + }`, + }), // 隐藏 动态发布框 new CheckboxItem({ itemID: 'hide-dynamic-page-bili-dyn-publishing', description: '隐藏 动态发布框', itemCSS: `.bili-dyn-publishing {display: none !important;} - main section:nth-child(1) {margin-bottom: 0 !important;}`, + main section:nth-child(1) {margin-bottom: 0 !important;}`, }), // 隐藏 动态分类Tab bar new CheckboxItem({ @@ -180,6 +209,11 @@ if (isPageDynamic()) { description: '隐藏 动态分类Tab bar', itemCSS: `.bili-dyn-list-tabs {display: none !important;}`, }), + ] + dynamicGroupList.push(new Group('dynamic-center-top', '中栏 顶部功能', centerTopItems)) + + // 中栏 动态列表 + const centerDynItems = [ // 隐藏 头像框 new CheckboxItem({ itemID: 'hide-dynamic-page-bili-dyn-avatar-pendent', @@ -319,7 +353,7 @@ if (isPageDynamic()) { }, }), ] - dynamicGroupList.push(new Group('dynamic-center', '中栏 动态列表', centerItems)) + dynamicGroupList.push(new Group('dynamic-center-dyn', '中栏 动态列表', centerDynItems)) // 动态评论区, 尽可能同步video page const commentItems = [ From 2e82c96b78af49a4f0c5a667776682a240a99dc8 Mon Sep 17 00:00:00 2001 From: festoney8 Date: Sun, 16 Jun 2024 21:01:04 +0800 Subject: [PATCH 05/10] update: util func --- src/filters/commentFilter/pages/dynamic.ts | 17 +++++++---------- src/filters/commentFilter/pages/video.ts | 8 ++------ src/filters/videoFilter/pages/channel.ts | 4 ++-- src/filters/videoFilter/pages/homepage.ts | 4 ++-- src/filters/videoFilter/pages/popular.ts | 4 ++-- src/filters/videoFilter/pages/search.ts | 4 ++-- src/filters/videoFilter/pages/space.ts | 4 ++-- src/filters/videoFilter/pages/video.ts | 8 ++------ src/rules/common.ts | 2 +- src/rules/video.ts | 19 ++++++++----------- src/utils/tool.ts | 4 ++-- 11 files changed, 32 insertions(+), 46 deletions(-) diff --git a/src/filters/commentFilter/pages/dynamic.ts b/src/filters/commentFilter/pages/dynamic.ts index be1c1fea..53a10979 100644 --- a/src/filters/commentFilter/pages/dynamic.ts +++ b/src/filters/commentFilter/pages/dynamic.ts @@ -167,16 +167,13 @@ if (isPageDynamic()) { waitForEle( document, '.bili-dyn-home--member, .bili-comment-container, .bili-comment, #app', - (node: Node): boolean => { - if (node instanceof HTMLElement) { - return ( - (node as HTMLElement).className === 'bili-dyn-home--member' || - (node as HTMLElement).className.includes('bili-comment-container') || - (node as HTMLElement).className.includes('bili-comment') || - (node as HTMLElement).id === 'app' - ) - } - return false + (node: HTMLElement): boolean => { + return ( + node.className === 'bili-dyn-home--member' || + node.className?.includes('bili-comment-container') || + node.className?.includes('bili-comment') || + node.id === 'app' + ) }, ).then((ele) => { if (ele) { diff --git a/src/filters/commentFilter/pages/video.ts b/src/filters/commentFilter/pages/video.ts index 76658eca..63123c44 100644 --- a/src/filters/commentFilter/pages/video.ts +++ b/src/filters/commentFilter/pages/video.ts @@ -159,12 +159,8 @@ if (isPageVideo() || isPageBangumi() || isPagePlaylist()) { } try { - waitForEle(document, '#comment, #comment-body, .playlist-comment', (node: Node): boolean => { - return ( - node instanceof HTMLElement && - (['comment', 'comment-body'].includes((node as HTMLElement).id) || - (node as HTMLElement).className === 'playlist-comment') - ) + waitForEle(document, '#comment, #comment-body, .playlist-comment', (node: HTMLElement): boolean => { + return ['comment', 'comment-body'].includes(node.id) || node.className === 'playlist-comment' }).then((ele) => { if (ele) { commentListContainer = ele diff --git a/src/filters/videoFilter/pages/channel.ts b/src/filters/videoFilter/pages/channel.ts index d265c5f8..bdb24ef1 100644 --- a/src/filters/videoFilter/pages/channel.ts +++ b/src/filters/videoFilter/pages/channel.ts @@ -143,8 +143,8 @@ if (isPageChannel()) { } try { // 监听视频列表出现 - waitForEle(document, 'main.channel-layout', (node: Node): boolean => { - return node instanceof HTMLElement && (node as HTMLElement).className === 'channel-layout' + waitForEle(document, 'main.channel-layout', (node: HTMLElement): boolean => { + return node.className === 'channel-layout' }).then((ele) => { if (ele) { videoListContainer = ele diff --git a/src/filters/videoFilter/pages/homepage.ts b/src/filters/videoFilter/pages/homepage.ts index 18e2b67d..dbd611bf 100644 --- a/src/filters/videoFilter/pages/homepage.ts +++ b/src/filters/videoFilter/pages/homepage.ts @@ -177,8 +177,8 @@ if (isPageHomepage()) { try { // 监听视频列表出现 - waitForEle(document, '.container.is-version8', (node: Node): boolean => { - return node instanceof HTMLElement && (node as HTMLElement).className === 'container is-version8' + waitForEle(document, '.container.is-version8', (node: HTMLElement): boolean => { + return node.className === 'container is-version8' }).then((ele) => { if (ele) { videoListContainer = ele diff --git a/src/filters/videoFilter/pages/popular.ts b/src/filters/videoFilter/pages/popular.ts index 4601b3bd..5536c692 100644 --- a/src/filters/videoFilter/pages/popular.ts +++ b/src/filters/videoFilter/pages/popular.ts @@ -260,8 +260,8 @@ if (isPagePopular()) { try { // 监听视频列表出现 - waitForEle(document, '#app', (node: Node): boolean => { - return node instanceof HTMLElement && (node as HTMLElement).id === 'app' + waitForEle(document, '#app', (node: HTMLElement): boolean => { + return node.id === 'app' }).then((ele) => { if (ele) { videoListContainer = ele diff --git a/src/filters/videoFilter/pages/search.ts b/src/filters/videoFilter/pages/search.ts index 0d3b4471..f1eb3bdc 100644 --- a/src/filters/videoFilter/pages/search.ts +++ b/src/filters/videoFilter/pages/search.ts @@ -146,8 +146,8 @@ if (isPageSearch()) { try { // 监听视频列表出现 - waitForEle(document, '.search-content', (node: Node): boolean => { - return node instanceof HTMLElement && (node as HTMLElement).className?.includes('search-content') + waitForEle(document, '.search-content', (node: HTMLElement): boolean => { + return node.className?.includes('search-content') }).then((ele) => { if (ele) { videoListContainer = ele diff --git a/src/filters/videoFilter/pages/space.ts b/src/filters/videoFilter/pages/space.ts index f4c81441..52787c60 100644 --- a/src/filters/videoFilter/pages/space.ts +++ b/src/filters/videoFilter/pages/space.ts @@ -107,8 +107,8 @@ if (isPageSpace()) { } try { // 监听视频列表出现 - waitForEle(document, '#app', (node: Node): boolean => { - return node instanceof HTMLElement && (node as HTMLElement).id === 'app' + waitForEle(document, '#app', (node: HTMLElement): boolean => { + return node.id === 'app' }).then((ele) => { if (ele) { videoListContainer = ele diff --git a/src/filters/videoFilter/pages/video.ts b/src/filters/videoFilter/pages/video.ts index 27f8348c..26c1dbe9 100644 --- a/src/filters/videoFilter/pages/video.ts +++ b/src/filters/videoFilter/pages/video.ts @@ -194,12 +194,8 @@ if (isPageVideo() || isPagePlaylist()) { try { // 监听视频列表出现 - waitForEle(document, '#reco_list, .recommend-list-container', (node: Node): boolean => { - return ( - node instanceof HTMLElement && - ((node as HTMLElement).id === 'reco_list' || - (node as HTMLElement).className === 'recommend-list-container') - ) + waitForEle(document, '#reco_list, .recommend-list-container', (node: HTMLElement): boolean => { + return node.id === 'reco_list' || node.className === 'recommend-list-container' }).then((ele) => { if (ele) { videoListContainer = ele diff --git a/src/rules/common.ts b/src/rules/common.ts index 85ea75a5..d7420ea9 100644 --- a/src/rules/common.ts +++ b/src/rules/common.ts @@ -14,7 +14,6 @@ import { } from '../utils/page-type' import URLCleanerInstance from '../utils/url-cleaner' -// Grouplist const commonGroupList: Group[] = [] // 通用 页面直角化,去除圆角,根据URL选取CSS @@ -421,6 +420,7 @@ const basicItems = [ }), ] commonGroupList.push(new Group('common-basic', '全站通用项 基本功能', basicItems)) + // 通用header净化,直播首页除外 if (!isPageLiveHome()) { // 顶栏左侧 diff --git a/src/rules/video.ts b/src/rules/video.ts index e7ce9728..8a2abdc0 100644 --- a/src/rules/video.ts +++ b/src/rules/video.ts @@ -83,7 +83,10 @@ if (isPageVideo() || isPagePlaylist()) { partNum += `?p=${params.get('p')}` } const aid = dec(bvid) - return `https://www.bilibili.com/video/av${aid}/${partNum}${urlObj.hash}` + if (partNum || urlObj.hash) { + return `https://www.bilibili.com/video/av${aid}/${partNum}${urlObj.hash}` + } + return `https://www.bilibili.com/video/av${aid}` } } return url @@ -184,11 +187,8 @@ if (isPageVideo() || isPagePlaylist()) { const listener = () => { window.scrollTo(0, 60) // 监听宽屏按钮出现 - waitForEle(document.body, '.bpx-player-ctrl-wide', (node: Node): boolean => { - return ( - node instanceof HTMLElement && - (node as HTMLElement).className.includes('bpx-player-ctrl-wide') - ) + waitForEle(document.body, '.bpx-player-ctrl-wide', (node: HTMLElement): boolean => { + return node.className?.includes('bpx-player-ctrl-wide') }).then((wideBtn) => { if (wideBtn) { wideBtn.click() @@ -280,11 +280,8 @@ if (isPageVideo() || isPagePlaylist()) { // 监听网页全屏按钮出现 const listener = () => { - waitForEle(document, '.bpx-player-ctrl-web', (node: Node): boolean => { - return ( - node instanceof HTMLElement && - (node as HTMLElement).className.includes('bpx-player-ctrl-web') - ) + waitForEle(document, '.bpx-player-ctrl-web', (node: HTMLElement): boolean => { + return node.className?.includes('bpx-player-ctrl-web') }).then((webBtn) => { if (webBtn) { webBtn.addEventListener('click', () => { diff --git a/src/utils/tool.ts b/src/utils/tool.ts index 6f0b3813..1d935a63 100644 --- a/src/utils/tool.ts +++ b/src/utils/tool.ts @@ -43,7 +43,7 @@ export const isEleHide = (ele: HTMLElement) => { export const waitForEle = async ( watchEle: HTMLElement | Document, selector: string, - isTargetNode: (node: Node) => boolean, + isTargetNode: (node: HTMLElement) => boolean, ): Promise => { let ele = watchEle.querySelector(selector) as HTMLElement | null if (ele) { @@ -54,7 +54,7 @@ export const waitForEle = async ( mutationList.forEach((mutation) => { if (mutation.addedNodes) { mutation.addedNodes.forEach((node) => { - if (isTargetNode(node)) { + if (node instanceof HTMLElement && isTargetNode(node)) { obverser.disconnect() ele = watchEle.querySelector(selector) as HTMLElement | null resolve(ele) From 67be78863d044b49ff3a251d97a9ff5d90e79108 Mon Sep 17 00:00:00 2001 From: festoney8 Date: Mon, 17 Jun 2024 03:14:45 +0800 Subject: [PATCH 06/10] feat: common nav fav select watchlater #86 --- CHANGELOG.md | 3 +- src/filters/commentFilter/pages/dynamic.ts | 4 +- src/filters/videoFilter/pages/search.ts | 2 +- src/rules/common.ts | 49 +++++++++++++++++++--- src/rules/video.ts | 6 +-- src/utils/tool.ts | 3 ++ 6 files changed, 54 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba1b23ce..2fee2eb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,13 @@ ## 3.7.1 +- 移除:顶栏右侧稍后再看相关功能,适配网页变动 - 新增:动态页淡化/隐藏已查看过动态的UP主 +- 新增:顶栏右侧收藏弹出框,自动选中稍后再看 - 优化:重写URL净化、BV号转AV号功能 - 优化:去除播放页网址跳变问题 - 优化:减少URL变化对浏览器历史记录的影响 - 优化:顶栏净化对版权视频页优化 -- 移除:顶栏右侧稍后再看相关功能,适配网页变动 ## 3.7.0 diff --git a/src/filters/commentFilter/pages/dynamic.ts b/src/filters/commentFilter/pages/dynamic.ts index 53a10979..ce9c76cd 100644 --- a/src/filters/commentFilter/pages/dynamic.ts +++ b/src/filters/commentFilter/pages/dynamic.ts @@ -170,8 +170,8 @@ if (isPageDynamic()) { (node: HTMLElement): boolean => { return ( node.className === 'bili-dyn-home--member' || - node.className?.includes('bili-comment-container') || - node.className?.includes('bili-comment') || + node.className.includes('bili-comment-container') || + node.className.includes('bili-comment') || node.id === 'app' ) }, diff --git a/src/filters/videoFilter/pages/search.ts b/src/filters/videoFilter/pages/search.ts index f1eb3bdc..58e49992 100644 --- a/src/filters/videoFilter/pages/search.ts +++ b/src/filters/videoFilter/pages/search.ts @@ -147,7 +147,7 @@ if (isPageSearch()) { try { // 监听视频列表出现 waitForEle(document, '.search-content', (node: HTMLElement): boolean => { - return node.className?.includes('search-content') + return node.className.includes('search-content') }).then((ele) => { if (ele) { videoListContainer = ele diff --git a/src/rules/common.ts b/src/rules/common.ts index d7420ea9..785c369e 100644 --- a/src/rules/common.ts +++ b/src/rules/common.ts @@ -331,8 +331,7 @@ const basicItems = [ } }`, }), - // URL参数净化, 在urlchange时需重载, 默认开启, 关闭功能需刷新 - // 以前会出现URL缺少参数导致充电窗口载入失败报错NaN的bug, 现无法复现, 猜测已修复 + // URL参数净化, 默认开启 new CheckboxItem({ itemID: 'url-cleaner', description: 'URL参数净化 (充电时需关闭)', @@ -398,11 +397,9 @@ const basicItems = [ for (const k of temp) { params.delete(k) } - if (params.get('p') === '1') { - params.delete('p') - } + params.get('p') === '1' && params.delete('p') - urlObj.search = params.toString() + urlObj.search = params.toString().replace(/\/$/, '') return urlObj.toString() } catch (err) { return url @@ -823,6 +820,46 @@ if (!isPageLiveHome()) { display: none !important; }`, }), + // 收藏弹出框 自动选中稍后再看 + new CheckboxItem({ + itemID: 'common-nav-favorite-select-watchlater', + description: '收藏弹出框 自动选中稍后再看', + itemFunc: () => { + const listener = () => { + let cnt = 0 + const id = setInterval(() => { + const ele = document.querySelector( + `.right-entry .v-popover-wrap:has(.right-entry__outside[href$="/favlist"]), + .nav-user-center .user-con .item:has(.mini-favorite)`, + ) + if (ele) { + clearInterval(id) + ele.addEventListener('mouseenter', () => { + let innerCnt = 0 + const watchLaterId = setInterval(() => { + const watchlater = document.querySelector( + `:is(.favorite-panel-popover, .vp-container .tabs-panel) .tab-item:nth-child(2)`, + ) as HTMLElement + if (watchlater) { + watchlater.click() + clearInterval(watchLaterId) + } else { + innerCnt++ + innerCnt > 250 && clearInterval(watchLaterId) + } + }, 20) + }) + } else { + cnt++ + cnt > 100 && clearInterval(id) + } + }, 200) + } + document.readyState === 'complete' + ? listener() + : document.addEventListener('DOMContentLoaded', listener) + }, + }), // 隐藏 历史 new CheckboxItem({ itemID: 'common-hide-nav-history', diff --git a/src/rules/video.ts b/src/rules/video.ts index 8a2abdc0..b0d2d2b7 100644 --- a/src/rules/video.ts +++ b/src/rules/video.ts @@ -188,7 +188,7 @@ if (isPageVideo() || isPagePlaylist()) { window.scrollTo(0, 60) // 监听宽屏按钮出现 waitForEle(document.body, '.bpx-player-ctrl-wide', (node: HTMLElement): boolean => { - return node.className?.includes('bpx-player-ctrl-wide') + return node.className.includes('bpx-player-ctrl-wide') }).then((wideBtn) => { if (wideBtn) { wideBtn.click() @@ -280,8 +280,8 @@ if (isPageVideo() || isPagePlaylist()) { // 监听网页全屏按钮出现 const listener = () => { - waitForEle(document, '.bpx-player-ctrl-web', (node: HTMLElement): boolean => { - return node.className?.includes('bpx-player-ctrl-web') + waitForEle(document.body, '.bpx-player-ctrl-web', (node: HTMLElement): boolean => { + return node.className.includes('bpx-player-ctrl-web') }).then((webBtn) => { if (webBtn) { webBtn.addEventListener('click', () => { diff --git a/src/utils/tool.ts b/src/utils/tool.ts index 1d935a63..e08a8745 100644 --- a/src/utils/tool.ts +++ b/src/utils/tool.ts @@ -45,6 +45,9 @@ export const waitForEle = async ( selector: string, isTargetNode: (node: HTMLElement) => boolean, ): Promise => { + if (!selector) { + return null + } let ele = watchEle.querySelector(selector) as HTMLElement | null if (ele) { return ele From 4fc4e6b29fe77ef50acc5fcb1158bf6dc41d00f5 Mon Sep 17 00:00:00 2001 From: festoney8 Date: Mon, 17 Jun 2024 04:49:26 +0800 Subject: [PATCH 07/10] feat: bangumi page normal screen width, update web scrollable --- CHANGELOG.md | 5 ++-- src/rules/bangumi.ts | 58 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fee2eb9..fdcea3f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,9 @@ ## 3.7.1 - 移除:顶栏右侧稍后再看相关功能,适配网页变动 -- 新增:动态页淡化/隐藏已查看过动态的UP主 -- 新增:顶栏右侧收藏弹出框,自动选中稍后再看 +- 新增:顶栏右侧收藏按钮弹出框,自动选中稍后再看 +- 新增:动态页 淡化/隐藏已查看过动态的UP主 +- 新增:番剧页 普通播放模式宽度调节 - 优化:重写URL净化、BV号转AV号功能 - 优化:去除播放页网址跳变问题 - 优化:减少URL变化对浏览器历史记录的影响 diff --git a/src/rules/bangumi.ts b/src/rules/bangumi.ts index 45a90c0d..ea585f61 100644 --- a/src/rules/bangumi.ts +++ b/src/rules/bangumi.ts @@ -1,8 +1,9 @@ import { GM_getValue, GM_setValue } from '$' import { Group } from '../components/group' -import { CheckboxItem } from '../components/item' +import { CheckboxItem, NumberItem } from '../components/item' import { error } from '../utils/logger' import { isPageBangumi } from '../utils/page-type' +import { waitForEle } from '../utils/tool' const bangumiGroupList: Group[] = [] @@ -59,44 +60,81 @@ if (isPageBangumi()) { description: '顶栏 滚动页面后不再吸附顶部', itemCSS: `.fixed-header .bili-header__bar {position: relative !important;}`, }), + ] + bangumiGroupList.push(new Group('bangumi-basic', '版权视频播放页 基本功能', basicItems)) + + // 播放设定 + const playerInitItems = [ // 网页全屏时 页面可滚动 new CheckboxItem({ itemID: 'webscreen-scrollable', description: '网页全屏时 页面可滚动 滚轮调音量失效\n(Firefox 不适用)', itemCSS: ` - body:has(#bilibili-player-wrap[class^='video_playerFullScreen']) { + body:has(#bilibili-player-wrap[class*='video_playerFullScreen']) { overflow: auto !important; position: relative !important; } - body:has(#bilibili-player-wrap[class^='video_playerFullScreen']) #bilibili-player-wrap { + body:has(#bilibili-player-wrap[class*='video_playerFullScreen']) #bilibili-player-wrap { position: absolute !important; width: 100vw !important; height: 100vh !important; } - body:has(#bilibili-player-wrap[class^='video_playerFullScreen']) .main-container { + body:has(#bilibili-player-wrap[class*='video_playerFullScreen']) .main-container { position: static !important; margin: 0 auto !important; padding-top: calc(100vh + 15px) !important; } - body:has(#bilibili-player-wrap[class^='video_playerFullScreen']) .bpx-player-video-area { + body:has(#bilibili-player-wrap[class*='video_playerFullScreen']) .bpx-player-video-area { flex: unset !important; } - body:has(#bilibili-player-wrap[class^='video_playerFullScreen'])::-webkit-scrollbar { + body:has(#bilibili-player-wrap[class*='video_playerFullScreen'])::-webkit-scrollbar { display: none !important; } /* firefox */ @-moz-document url-prefix() { - :is(html, body):has(#bilibili-player-wrap[class^='video_playerFullScreen']) { + :is(html, body):has(#bilibili-player-wrap[class*='video_playerFullScreen']) { scrollbar-width: none !important; } } `, - // 在Chrome上可以神奇的禁用滚轮调节音量,Firefox不生效 - itemFunc: () => document.addEventListener('wheel', disableAdjustVolume), + itemFunc: () => { + // 在Chrome上可以神奇的禁用滚轮调节音量,Firefox不生效 + document.addEventListener('wheel', disableAdjustVolume) + // 监听网页全屏按钮出现 + const listener = () => { + waitForEle(document.body, '.bpx-player-ctrl-web', (node: HTMLElement): boolean => { + return node.className.includes('bpx-player-ctrl-web') + }).then((webBtn) => { + if (webBtn) { + webBtn.addEventListener('click', () => { + if (webBtn.classList.contains('bpx-state-entered')) { + window.scrollTo(0, 0) + } + }) + } + }) + } + document.readyState === 'complete' + ? listener() + : document.addEventListener('DOMContentLoaded', listener) + }, callback: () => document.removeEventListener('wheel', disableAdjustVolume), }), + // 普通播放 视频宽度调节 + new NumberItem({ + itemID: 'normalscreen-width', + description: '普通播放 视频宽度调节(-1禁用)', + defaultValue: -1, + minValue: -1, + maxValue: 100, + disableValue: -1, + unit: 'vw', + // 官方样式写的棒真是太好了 + itemCSS: `.home-container:not(.wide) {--video-width: ???vw;}`, + itemCSSPlaceholder: '???', + }), ] - bangumiGroupList.push(new Group('bangumi-basic', '版权视频播放页 基本功能', basicItems)) + bangumiGroupList.push(new Group('player-mode', '播放设定(实验功能)', playerInitItems)) // 播放器 const playerItems = [ From 57bca4fe4d175b58690ed328b138928085883b6b Mon Sep 17 00:00:00 2001 From: festoney8 Date: Mon, 17 Jun 2024 05:34:52 +0800 Subject: [PATCH 08/10] update: dyn page checked item hide --- src/rules/dynamic.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/rules/dynamic.ts b/src/rules/dynamic.ts index d4e74f39..fd73ead7 100644 --- a/src/rules/dynamic.ts +++ b/src/rules/dynamic.ts @@ -173,7 +173,7 @@ if (isPageDynamic()) { description: '淡化 UP 主列表 已查看项', itemCSS: ` .bili-dyn-up-list__item:not(.active):has(.bili-dyn-up-list__item__face .bili-dyn-up-list__item__face__img:only-child) { - transition: opacity 0.2s linear; + transition: opacity 0.2s ease-out; opacity: 0.25; } .bili-dyn-up-list__item:hover { @@ -186,14 +186,23 @@ if (isPageDynamic()) { itemID: 'dynamic-page-up-list-checked-item-hide', description: '隐藏 UP 主列表 已查看项', itemCSS: ` + /* keyframes 不支持 display, 但chrome可正常处理, firefox不消失 */ @keyframes disappear { - from { display: flex; } - to { display: none; } + 0% {opacity: 1; width: 68px; margin-right: 6px;} + 99% {opacity: 0; width: 0; margin-right: 0;} + 100% {opacity: 0; width: 0; margin-right: 0; display: none;} } .bili-dyn-up-list__item:not(.active):has(.bili-dyn-up-list__item__face .bili-dyn-up-list__item__face__img:only-child) { animation: disappear; - animation-delay: 1.2s; + animation-duration: .5s; + animation-delay: 1s; animation-fill-mode: forwards; + } + /* firefox无动画 */ + @-moz-document url-prefix() { + .bili-dyn-up-list__item:not(.active):has(.bili-dyn-up-list__item__face .bili-dyn-up-list__item__face__img:only-child) { + display: none; + } }`, }), // 隐藏 动态发布框 From 6af52a17d512dd0c49295f024c91e413ce90d803 Mon Sep 17 00:00:00 2001 From: festoney8 Date: Tue, 18 Jun 2024 02:30:06 +0800 Subject: [PATCH 09/10] update: popular page hide banner --- src/rules/common.ts | 27 ++++++++++++++++++++------- src/rules/popular.ts | 15 +++++++++++++-- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/rules/common.ts b/src/rules/common.ts index 785c369e..bf88d0b2 100644 --- a/src/rules/common.ts +++ b/src/rules/common.ts @@ -915,7 +915,12 @@ if (!isPageLiveHome()) { maxValue: 2000, disableValue: -1, unit: 'px', - itemCSS: `.bili-header .bili-header__bar, [class^="BiliHeaderV3_biliHeaderBar___"] {padding-left: ???px !important;}`, + itemCSS: ` + .bili-header .bili-header__bar, + .mini-header__content, + [class^="BiliHeaderV3_biliHeaderBar___"] { + padding-left: ???px !important; + }`, itemCSSPlaceholder: '???', }), new NumberItem({ @@ -926,11 +931,14 @@ if (!isPageLiveHome()) { maxValue: 2000, disableValue: -1, unit: 'px', - itemCSS: `.bili-header .center-search-container .center-search__bar { - width: ???px !important; - max-width: ???px !important; - min-width: 0px !important; - }`, + itemCSS: ` + .bili-header .center-search-container .center-search__bar, + .bili-header-m .nav-search-box, + .international-header .nav-search-box { + width: ???px !important; + max-width: ???px !important; + min-width: 0px !important; + }`, itemCSSPlaceholder: '???', }), new NumberItem({ @@ -941,7 +949,12 @@ if (!isPageLiveHome()) { maxValue: 2000, disableValue: -1, unit: 'px', - itemCSS: `.bili-header .bili-header__bar, [class^="BiliHeaderV3_biliHeaderBar___"] {padding-right: ???px !important;}`, + itemCSS: ` + .bili-header .bili-header__bar, + .mini-header__content, + [class^="BiliHeaderV3_biliHeaderBar___"] { + padding-right: ???px !important; + }`, itemCSSPlaceholder: '???', }), ] diff --git a/src/rules/popular.ts b/src/rules/popular.ts index 4d187b9f..bab78c46 100644 --- a/src/rules/popular.ts +++ b/src/rules/popular.ts @@ -13,7 +13,8 @@ if (isPagePopular()) { new CheckboxItem({ itemID: 'homepage-hide-banner', description: '隐藏 横幅banner', - itemCSS: `.header-banner__inner, .bili-header__banner { + itemCSS: ` + .header-banner__inner, .bili-header__banner { display: none !important; } .bili-header .bili-header__bar:not(.slide-down) { @@ -45,7 +46,17 @@ if (isPagePopular()) { } /* header高度 */ #biliMainHeader {min-height: unset !important;} - `, + + /* 旧版banner */ + #internationalHeader .bili-banner {display: none;} + .mini-header__content {box-shadow: 0 2px 4px #00000014;} + .bili-icon_dingdao_zhuzhan:before {color: #00AEEC;} + .mini-header__content .nav-link .nav-link-ul .nav-link-item .link {color: black; text-shadow: unset;} + .mini-header__content .nav-search-box {border: 1px solid #E3E5E7;} + #nav_searchform {background-color: #F2F3F4 !important;} + .bili-header-m .nav-search .nav-search-btn, .international-header .nav-search .nav-search-btn {background-color: #F2F3F4;} + .mini-header__content .nav-user-center .user-con .item .name {color: black; text-shadow: unset;} + `, }), // 隐藏 滚动页面时 顶部吸附顶栏, 同步首页设定 new CheckboxItem({ From 726bf6f4d06ea983644896690f3619b9de7b4211 Mon Sep 17 00:00:00 2001 From: festoney8 Date: Tue, 18 Jun 2024 21:00:39 +0800 Subject: [PATCH 10/10] feat: video page right container sticky bottom #84, #87 --- CHANGELOG.md | 2 + src/rules/video.ts | 155 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 122 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fdcea3f8..443872fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ - 新增:顶栏右侧收藏按钮弹出框,自动选中稍后再看 - 新增:动态页 淡化/隐藏已查看过动态的UP主 - 新增:番剧页 普通播放模式宽度调节 +- 新增:播放页 修复/禁用右栏底部吸附 +- 修复:播放页 右栏宽度异常 - 优化:重写URL净化、BV号转AV号功能 - 优化:去除播放页网址跳变问题 - 优化:减少URL变化对浏览器历史记录的影响 diff --git a/src/rules/video.ts b/src/rules/video.ts index b0d2d2b7..1ce81460 100644 --- a/src/rules/video.ts +++ b/src/rules/video.ts @@ -170,16 +170,6 @@ if (isPageVideo() || isPagePlaylist()) { html[bili-cleaner-is-wide] #playerWrap:has(.bpx-player-container[data-screen="mini"]) { width: fit-content; } - /* 修复右栏底部吸附计算top时位置跳变 */ - .video-container-v1 .right-container { - display: flex; - } - .video-container-v1 .right-container .right-container-inner { - position: sticky !important; - top: unset !important; - bottom: 0 !important; - align-self: flex-end !important; - } `, itemFunc: () => { wideScreenLock = true @@ -255,19 +245,11 @@ if (isPageVideo() || isPagePlaylist()) { .webscreen-fix :is(.right-container, .playlist-container--right) { padding-top: 100vh; } - /* 底部吸附 */ - .webscreen-fix .right-container { - display: flex; - } - .webscreen-fix :is(.right-container-inner, .playlist-container--right) { - position: sticky; - bottom: 0; - align-self: flex-end; - } + /* 滚动条 */ .webscreen-fix::-webkit-scrollbar { display: none !important; } - /* firefox */ + /* firefox滚动条 */ @-moz-document url-prefix() { html:has(.webscreen-fix), body.webscreen-fix { scrollbar-width: none !important; @@ -412,17 +394,6 @@ if (isPageVideo() || isPagePlaylist()) { height: calc(100% - 46px); background-color: black; } - - /* 修复右栏底部吸附计算top时位置跳变 */ - .video-container-v1 .right-container { - display: flex; - } - .video-container-v1 .right-container .right-container-inner { - position: sticky !important; - top: unset !important; - bottom: 0 !important; - align-self: flex-end !important; - } `, itemCSSPlaceholder: '???', }), @@ -751,6 +722,70 @@ if (isPageVideo() || isPagePlaylist() || isPageFestival()) { document.querySelector(`style[bili-cleaner-css=video-page-bpx-player-mini-mode-wheel-adjust]`)?.remove() }, }), + // // 小窗播放器 记录小窗位置 + // new CheckboxItem({ + // itemID: 'video-page-bpx-player-mini-mode-position-record', + // description: '小窗播放器 记录小窗位置', + // itemFunc: () => { + // let isListening = false + // const listener = () => { + // waitForEle(document.body, '#bilibili-player .bpx-player-container', (node: HTMLElement) => { + // return node.className.startsWith('bpx-player-container') + // }).then((player) => { + // if (player) { + // const observer = new MutationObserver((mutationsList) => { + // console.log('fired') + // for (const mutation of mutationsList) { + // if (mutation.attributeName === 'data-screen') { + // const target = mutation.target as HTMLElement + // if ( + // target instanceof HTMLElement && + // target.getAttribute('data-screen') === 'mini' + // ) { + // const right = GM_getValue( + // 'BILICLEANER_video-page-bpx-player-mini-mode-position-record-right', + // ) + // const bottom = GM_getValue( + // 'BILICLEANER_video-page-bpx-player-mini-mode-position-record-bottom', + // ) + // if (right !== undefined && bottom !== undefined) { + // target.style.right = `${right}px` + // target.style.bottom = `${bottom}px` + // } + // // 监听小窗移动 + // if (!isListening) { + // isListening = true + // player.addEventListener('mouseleave', () => { + // if (player.getAttribute('data-screen') !== 'mini') { + // return + // } + // GM_setValue( + // 'BILICLEANER_video-page-bpx-player-mini-mode-position-record-right', + // parseInt(player.style.right), + // ) + // GM_setValue( + // 'BILICLEANER_video-page-bpx-player-mini-mode-position-record-bottom', + // parseInt(player.style.bottom), + // ) + // }) + // } + // break + // } + // } + // } + // }) + // observer.observe(player, { attributes: true, subtree: false }) + // } + // }) + // } + // document.readyState === 'complete' + // ? listener() + // : document.addEventListener('DOMContentLoaded', listener) + // }, + // callback: () => { + // document.querySelector(`style[bili-cleaner-css=video-page-bpx-player-mini-mode-wheel-adjust]`)?.remove() + // }, + // }), ] videoGroupList.push(new Group('video-player', '播放器', playerItems)) @@ -1187,6 +1222,38 @@ if (isPageVideo() || isPagePlaylist()) { // 右侧视频栏 const rightItems = [ + // 优化 右栏底部吸附 实验功能 + new CheckboxItem({ + itemID: 'video-page-right-container-sticky-optimize', + description: '优化 右栏底部吸附 (实验功能)', + itemCSS: ` + /* 修复右栏底部吸附计算top时位置跳变 */ + .video-container-v1 .right-container { + display: flex !important; + } + .video-container-v1 .right-container .right-container-inner { + position: sticky !important; + top: unset !important; + align-self: flex-end !important; + /* fix #87, #84 */ + max-width: 100% !important; + padding-bottom: 0 !important; + } + /* 小窗播放器挡住下方视频 #87 */ + body:has(.mini-player-window.on) .video-container-v1 .right-container .right-container-inner { + bottom: 240px !important; + } + body:has(.mini-player-window:not(.on)) .video-container-v1 .right-container .right-container-inner { + bottom: 10px !important; + } + `, + }), + // 禁用 滚动页面时右栏底部吸附 + new CheckboxItem({ + itemID: 'video-page-right-container-sticky-disable', + description: '禁用 右栏底部吸附', + itemCSS: `.right-container .right-container-inner {position: static !important;}`, + }), // 隐藏 广告, 默认开启 new CheckboxItem({ itemID: 'video-page-hide-right-container-ad', @@ -1358,16 +1425,34 @@ if (isPageVideo() || isPagePlaylist()) { itemID: 'video-page-hide-right-container-right-bottom-banner', description: '隐藏 活动banner', defaultStatus: true, - itemCSS: `#right-bottom-banner {display: none !important;} - .video-container-v1 .right-container .right-container-inner {padding-bottom: 15px !important;}`, + itemCSS: ` + #right-bottom-banner { + display: none !important; + } + /* 小窗视频防挡 #87 */ + body:has(.mini-player-window.on) .video-container-v1 .right-container .right-container-inner { + padding-bottom: 240px; + } + body:has(.mini-player-window:not(.on)) .video-container-v1 .right-container .right-container-inner { + padding-bottom: 10px; + } + `, }), // 隐藏 直播间推荐, 默认开启 new CheckboxItem({ itemID: 'video-page-hide-right-container-live', description: '隐藏 直播间推荐', defaultStatus: true, - itemCSS: `.right-container .pop-live-small-mode {display: none !important;} - .video-container-v1 .right-container .right-container-inner {padding-bottom: 15px !important;}`, + itemCSS: ` + .right-container .pop-live-small-mode {display: none !important;} + /* 小窗视频防挡 #87 */ + body:has(.mini-player-window.on) .video-container-v1 .right-container .right-container-inner { + padding-bottom: 240px; + } + body:has(.mini-player-window:not(.on)) .video-container-v1 .right-container .right-container-inner { + padding-bottom: 10px; + } + `, }), ] videoGroupList.push(new Group('video-right', '右侧 视频栏', rightItems))