diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c3501b2..9e797a09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## 3.7.4 + +- 修复:动态页 隐藏动态右侧饰品 +- 新增:播放页/番剧页 全屏时页面可滚动 +- 新增:首页 推荐视频预加载下一屏 + ## 3.7.3 - 新增:直播页 隐藏倒计时互动 diff --git a/src/filters/videoFilter/pages/homepage.ts b/src/filters/videoFilter/pages/homepage.ts index f2b22309..5b5a394e 100644 --- a/src/filters/videoFilter/pages/homepage.ts +++ b/src/filters/videoFilter/pages/homepage.ts @@ -15,7 +15,6 @@ import { UploaderKeywordAction, UploaderWhitelistAction, } from './actions/action' -import { GM_getValue } from '$' const homepagePageVideoFilterGroupList: Group[] = [] @@ -24,7 +23,7 @@ let isContextMenuFuncRunning = false let isContextMenuUploaderEnable = false let isContextMenuBvidEnable = false // 带已关注tag的视频不被过滤 -let isFollowingWhitelistEnable: boolean = GM_getValue('BILICLEANER_homepage-following-whitelist-filter-status', true) +let isFollowingWhitelistEnable = true if (isPageHomepage()) { let videoListContainer: HTMLElement diff --git a/src/rules/bangumi.ts b/src/rules/bangumi.ts index d869a387..7aa6f74f 100644 --- a/src/rules/bangumi.ts +++ b/src/rules/bangumi.ts @@ -94,8 +94,10 @@ if (isPageBangumi()) { } `, enableFunc: async () => { - // 在Chrome上可以神奇的禁用滚轮调节音量,Firefox不生效 + // 禁用滚动调音量 + document.removeEventListener('wheel', disableAdjustVolume) document.addEventListener('wheel', disableAdjustVolume) + // 监听网页全屏按钮出现 waitForEle(document.body, '.bpx-player-ctrl-web', (node: HTMLElement): boolean => { return node.className.includes('bpx-player-ctrl-web') @@ -112,6 +114,118 @@ if (isPageBangumi()) { enableFuncRunAt: 'document-end', disableFunc: async () => document.removeEventListener('wheel', disableAdjustVolume), }), + // 全屏时 页面可滚动 + new CheckboxItem({ + itemID: 'fullscreen-scrollable', + description: '全屏时 页面可滚动 滚轮调音量失效\n(实验功能,Firefox 不适用)', + itemCSS: ` + body:has(#bilibili-player-wrap[class*='video_playerFullScreen']) { + overflow: auto !important; + position: relative !important; + } + body:has(#bilibili-player-wrap[class*='video_playerFullScreen']) .home-container { + background-color: white; + } + 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 { + 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 { + flex: unset !important; + } + 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']) { + scrollbar-width: none !important; + } + } + `, + enableFunc: async () => { + if (!navigator.userAgent.toLocaleLowerCase().includes('chrome')) { + return + } + + // 禁用滚动调音量 + document.removeEventListener('wheel', disableAdjustVolume) + document.addEventListener('wheel', disableAdjustVolume) + + let cnt = 0 + const id = setInterval(() => { + const webBtn = document.body.querySelector( + '.bpx-player-ctrl-btn.bpx-player-ctrl-web', + ) as HTMLElement + const fullBtn = document.body.querySelector( + '.bpx-player-ctrl-btn.bpx-player-ctrl-full', + ) as HTMLElement + if (webBtn && fullBtn) { + clearInterval(id) + + const isFullScreen = (): 'ele' | 'f11' | 'not' => { + if (document.fullscreenElement) { + // 由元素申请的全屏 + return 'ele' + } else if (window.innerWidth === screen.width && window.innerHeight === screen.height) { + // 用户F11的全屏 + return 'f11' + } else { + // 非全屏 + return 'not' + } + } + + const isWebScreen = (): boolean => { + return webBtn.classList.contains('bpx-state-entered') + } + + // 全屏可滚动 = 网页全屏功能 + html/body元素申请全屏 + const newFullBtn = fullBtn.cloneNode(true) + newFullBtn.addEventListener('click', () => { + switch (isFullScreen()) { + case 'ele': + if (isWebScreen()) { + // 退出网页全屏,自动退出全屏 + webBtn.click() + } else { + document.exitFullscreen().then().catch() + } + break + case 'f11': + // f11全屏模式 + if (isWebScreen()) { + webBtn.click() + } else { + webBtn.click() + } + break + case 'not': + // 申请可滚动全屏 + document.body.requestFullscreen().then().catch() + if (!isWebScreen()) { + webBtn.click() + } + window.scrollTo(0, 0) + break + } + }) + fullBtn.parentElement?.replaceChild(newFullBtn, fullBtn) + } else { + cnt++ + cnt > 100 && clearInterval(id) + } + }, 100) + }, + enableFuncRunAt: 'document-end', + disableFunc: async () => document.removeEventListener('wheel', disableAdjustVolume), + }), // 普通播放 视频宽度调节 new NumberItem({ itemID: 'normalscreen-width', @@ -126,7 +240,7 @@ if (isPageBangumi()) { itemCSSPlaceholder: '???', }), ] - bangumiGroupList.push(new Group('player-mode', '播放设定(实验功能)', playerInitItems)) + bangumiGroupList.push(new Group('player-mode', '播放设定', playerInitItems)) // 播放器 const playerItems = [ diff --git a/src/rules/dynamic.ts b/src/rules/dynamic.ts index dcb2447d..10809583 100644 --- a/src/rules/dynamic.ts +++ b/src/rules/dynamic.ts @@ -61,7 +61,7 @@ if (isPageDynamic()) { // 修复字体 new CheckboxItem({ itemID: 'font-patch', - description: '修复字体 (实验功能)', + description: '修复字体', itemCSS: fontPatchCSS, }), ] @@ -243,7 +243,7 @@ if (isPageDynamic()) { new CheckboxItem({ itemID: 'hide-dynamic-page-bili-dyn-ornament', description: '隐藏 动态右侧饰品', - itemCSS: `.bili-dyn-ornament {display: none !important;}`, + itemCSS: `.bili-dyn-ornament, .bili-dyn-item__ornament {display: none !important;}`, }), // 隐藏 动态内容中 警告notice, 默认开启 new CheckboxItem({ diff --git a/src/rules/homepage.ts b/src/rules/homepage.ts index ebe11388..751d75b6 100644 --- a/src/rules/homepage.ts +++ b/src/rules/homepage.ts @@ -2,6 +2,7 @@ import { unsafeWindow } from '$' import { Group } from '../components/group' import { CheckboxItem, NumberItem, RadioItem } from '../components/item' import { isPageHomepage } from '../utils/page-type' +import { debounce, waitForEle } from '../utils/tool' const homepageGroupList: Group[] = [] @@ -345,7 +346,7 @@ if (isPageHomepage()) { background-color: unset !important; border-radius: unset !important; margin: 0 2px 0 0 !important; - font-size: unset !important; + font-size: 0 !important; line-height: unset !important; padding: unset !important; user-select: none !important; @@ -485,10 +486,10 @@ if (isPageHomepage()) { // 增大 视频载入 视频数量 new CheckboxItem({ itemID: 'homepage-increase-rcmd-load-size', - description: '增大 视频载入 视频数量 (实验性)', + description: '增大 视频载入 视频数量 (实验功能)', itemCSS: ` /* 扩增载入后会产生奇怪的骨架空位 */ - .floor-single-card:has(.skeleton, .skeleton-item) { + .container.is-version8 > .floor-single-card:has(.skeleton, .skeleton-item, .floor-skeleton) { display: none; }`, enableFunc: async () => { @@ -507,6 +508,72 @@ if (isPageHomepage()) { } }, }), + // 启用 预加载下一屏 + new CheckboxItem({ + itemID: 'homepage-rcmd-video-preload', + description: '启用 预加载下一屏 (实验功能)\n需开启 隐藏分区视频推荐', + itemCSS: ` + .load-more-anchor.preload { + position: fixed; + z-index: -99999; + visibility: hidden; + opacity: 0; + top: 0; + left: 0; + } + `, + enableFunc: async () => { + waitForEle(document.body, '.load-more-anchor', (node: HTMLElement) => { + return node.className === 'load-more-anchor' + }).then((anchor) => { + if (!anchor) { + return + } + const fireRcmdLoad = () => { + const firstSkeleton = document.querySelector( + '.bili-video-card:has(.bili-video-card__skeleton:not(.hide)):has(~ .load-more-anchor)', + ) as HTMLElement + if (!firstSkeleton || firstSkeleton.getBoundingClientRect().top > innerHeight * 2) { + return + } + + anchor.classList.add('preload') + new Promise((resolve) => { + const id = setInterval(() => { + const firstSkeleton = document.querySelector( + '.bili-video-card:has(.bili-video-card__skeleton:not(.hide)):has(~ .load-more-anchor)', + ) as HTMLElement + if (!firstSkeleton) { + clearInterval(id) + resolve() + } + + if (firstSkeleton.getBoundingClientRect().top < innerHeight * 2) { + new Promise((resolve) => setTimeout(resolve, 20)).then(() => { + window.dispatchEvent(new Event('scroll')) + }) + } else { + clearInterval(id) + resolve() + } + }, 200) + }).then(() => { + anchor.classList.remove('preload') + }) + } + + fireRcmdLoad() + + const debounceFireRcmdLoad = debounce(fireRcmdLoad, 250, true) + window.addEventListener('wheel', (e: WheelEvent) => { + if (e.deltaY > 0) { + debounceFireRcmdLoad() + } + }) + }) + }, + enableFuncRunAt: 'document-end', + }), ] homepageGroupList.push(new Group('homepage-rcmd-list', '视频列表', rcmdListItems)) diff --git a/src/rules/live.ts b/src/rules/live.ts index e03fa260..6e91bc69 100644 --- a/src/rules/live.ts +++ b/src/rules/live.ts @@ -112,7 +112,7 @@ if (isPageLiveRoom()) { // 修复字体 new CheckboxItem({ itemID: 'font-patch', - description: '修复字体 (实验功能)', + description: '修复字体', itemCSS: ` ${fontFaceRegular} body, diff --git a/src/rules/popular.ts b/src/rules/popular.ts index bab78c46..582cbd35 100644 --- a/src/rules/popular.ts +++ b/src/rules/popular.ts @@ -169,7 +169,7 @@ if (isPagePopular()) { // 修复字体 new CheckboxItem({ itemID: 'font-patch', - description: '修复字体 (实验功能)', + description: '修复字体', itemCSS: ` ${fontFaceRegular} ${fontFaceMedium} diff --git a/src/rules/space.ts b/src/rules/space.ts index e472cf48..e9bebcea 100644 --- a/src/rules/space.ts +++ b/src/rules/space.ts @@ -11,7 +11,7 @@ if (isPageSpace()) { // 修复字体 new CheckboxItem({ itemID: 'font-patch', - description: '修复字体 (实验功能)', + description: '修复字体', itemCSS: ` ${fontFaceRegular} body, diff --git a/src/rules/video.ts b/src/rules/video.ts index b3d646f8..8da4d2bf 100644 --- a/src/rules/video.ts +++ b/src/rules/video.ts @@ -171,7 +171,7 @@ if (isPageVideo() || isPagePlaylist()) { wideScreenLock = true unsafeWindow.isWide = true const listener = () => { - window.scrollTo(0, 60) + window.scrollTo(0, 64) // 监听宽屏按钮出现 waitForEle(document.body, '.bpx-player-ctrl-wide', (node: HTMLElement): boolean => { return node.className.includes('bpx-player-ctrl-wide') @@ -258,7 +258,8 @@ if (isPageVideo() || isPagePlaylist()) { } `, enableFunc: async () => { - // 在Chrome上可以神奇的禁用滚轮调节音量,Firefox不生效 + // 禁用滚动调音量, firefox不生效 + document.removeEventListener('wheel', disableAdjustVolume) document.addEventListener('wheel', disableAdjustVolume) // 监听网页全屏按钮出现 @@ -277,6 +278,151 @@ if (isPageVideo() || isPagePlaylist()) { enableFuncRunAt: 'document-end', disableFunc: async () => document.removeEventListener('wheel', disableAdjustVolume), }), + // 全屏时 页面可滚动 + new CheckboxItem({ + itemID: 'fullscreen-scrollable', + description: '全屏时 页面可滚动 滚轮调音量失效\n(实验功能,Firefox 不适用)', + itemCSS: ` + .webscreen-fix { + position: unset; + top: unset; + left: unset; + margin: unset; + padding: unset; + width: unset; + height: unset; + } + .webscreen-fix #biliMainHeader { + display: none; + } + .webscreen-fix #mirror-vdcon { + box-sizing: content-box; + position: relative; + } + .webscreen-fix #danmukuBox { + margin-top: 0 !important; + } + .webscreen-fix :is(.left-container, .playlist-container--left) { + position: static !important; + padding-top: 100vh; + min-width: 56vw !important; + } + .webscreen-fix :is(.left-container, .playlist-container--left) .video-info-container { + height: fit-content; + } + .webscreen-fix :is(.left-container, .playlist-container--left) #bilibili-player.mode-webscreen { + position: static; + border-radius: unset; + z-index: unset; + left: unset; + top: unset; + width: 100%; + height: 100%; + } + .webscreen-fix :is(.left-container, .playlist-container--left) #playerWrap { + position: absolute; + left: 0; + right: 0; + top: 0; + height: 100vh; + width: 100vw; + padding-right: 0; + } + .webscreen-fix :is(.right-container, .playlist-container--right) { + padding-top: 100vh; + } + /* 隐藏小窗 */ + .webscreen-fix .float-nav-exp .nav-menu .item.mini, + .webscreen-fix .fixed-sidenav-storage .mini-player-window { + display: none !important; + } + /* 滚动条 */ + .webscreen-fix::-webkit-scrollbar { + display: none !important; + } + /* firefox滚动条 */ + @-moz-document url-prefix() { + html:has(.webscreen-fix), body.webscreen-fix { + scrollbar-width: none !important; + } + } + `, + enableFunc: async () => { + if (!navigator.userAgent.toLocaleLowerCase().includes('chrome')) { + return + } + // 禁用滚动调音量 + document.removeEventListener('wheel', disableAdjustVolume) + document.addEventListener('wheel', disableAdjustVolume) + + let cnt = 0 + const id = setInterval(() => { + const webBtn = document.body.querySelector( + '.bpx-player-ctrl-btn.bpx-player-ctrl-web', + ) as HTMLElement + const fullBtn = document.body.querySelector( + '.bpx-player-ctrl-btn.bpx-player-ctrl-full', + ) as HTMLElement + if (webBtn && fullBtn) { + clearInterval(id) + + const isFullScreen = (): 'ele' | 'f11' | 'not' => { + if (document.fullscreenElement) { + // 由元素申请的全屏 + return 'ele' + } else if (window.innerWidth === screen.width && window.innerHeight === screen.height) { + // 用户F11的全屏 + return 'f11' + } else { + // 非全屏 + return 'not' + } + } + + const isWebScreen = (): boolean => { + return webBtn.classList.contains('bpx-state-entered') + } + + // 全屏可滚动 = 网页全屏功能 + html/body元素申请全屏 + const newFullBtn = fullBtn.cloneNode(true) + newFullBtn.addEventListener('click', () => { + switch (isFullScreen()) { + case 'ele': + if (isWebScreen()) { + // 退出网页全屏,自动退出全屏 + webBtn.click() + } else { + document.exitFullscreen().then().catch() + } + break + case 'f11': + // f11全屏模式 + if (isWebScreen()) { + webBtn.click() + } else { + webBtn.click() + } + break + case 'not': + // 申请可滚动全屏 + document.body.requestFullscreen().then().catch() + if (!isWebScreen()) { + webBtn.click() + } + window.scrollTo(0, 0) + break + } + }) + fullBtn.parentElement?.replaceChild(newFullBtn, fullBtn) + } else { + cnt++ + cnt > 100 && clearInterval(id) + } + }, 100) + }, + enableFuncRunAt: 'document-end', + disableFunc: async () => document.removeEventListener('wheel', disableAdjustVolume), + }), // 播放器和视频标题 交换位置 new CheckboxItem({ itemID: 'video-page-exchange-player-position', @@ -394,7 +540,7 @@ if (isPageVideo() || isPagePlaylist()) { itemCSSPlaceholder: '???', }), ] - videoGroupList.push(new Group('player-mode', '播放设定(实验功能)', playerInitItems)) + videoGroupList.push(new Group('player-mode', '播放设定', playerInitItems)) // 视频信息 const infoItems = [ @@ -562,12 +708,6 @@ if (isPageVideo() || isPagePlaylist() || isPageFestival()) { description: '隐藏 高赞弹幕前点赞按钮', itemCSS: `.bili-dm .bili-high-icon {display: none !important}`, }), - // 隐藏 爆炸特效弹幕 - new CheckboxItem({ - itemID: 'video-page-bpx-player-bili-dm-boom', - description: '隐藏 爆炸特效弹幕', - itemCSS: `.bili-boom {display: none !important}`, - }), // 彩色渐变弹幕 变成白色 new CheckboxItem({ itemID: 'video-page-bpx-player-bili-dm-vip-white', diff --git a/src/rules/watchlater.ts b/src/rules/watchlater.ts index d1e4ac36..91ee7f42 100644 --- a/src/rules/watchlater.ts +++ b/src/rules/watchlater.ts @@ -80,7 +80,7 @@ if (isPageWatchlater()) { // 修复字体 new CheckboxItem({ itemID: 'font-patch', - description: '修复字体 (实验功能)', + description: '修复字体', itemCSS: ` ${fontFaceRegular} ${fontFaceMedium} diff --git a/src/utils/tool.ts b/src/utils/tool.ts index 76d4e823..1c904869 100644 --- a/src/utils/tool.ts +++ b/src/utils/tool.ts @@ -1,15 +1,14 @@ -// export const debounce = void>( -// func: T, -// wait: number, -// ): ((...args: Parameters) => void) => { -// let timeout: ReturnType -// return (...args: Parameters): void => { -// clearTimeout(timeout) -// timeout = setTimeout(() => { -// func(...args) -// }, wait) -// } -// } +export const debounce = (fn: (...params: any[]) => any, wait: number, immed: boolean = false) => { + let timer: number | undefined = undefined + return function (this: any, ...args: any[]) { + if (timer === undefined && immed) { + fn.apply(this, args) + } + clearTimeout(timer) + timer = setTimeout(() => fn.apply(this, args), wait) + return timer + } +} // 匹配BV号 const bvidPattern = /(BV[1-9A-HJ-NP-Za-km-z]+)/ diff --git a/vite.config.ts b/vite.config.ts index 84709225..99b72353 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.3', + version: '3.7.4', description: '净化 B站/哔哩哔哩 页面,支持「精简功能、播放器净化、过滤视频、过滤评论、全站黑白名单」,提供 300+ 功能,定制自己的 B 站', author: 'festoney8',