From a2b7dff392f0931e4c32a3e0c10cfa8efadb1da8 Mon Sep 17 00:00:00 2001 From: mtvpls Date: Wed, 3 Dec 2025 20:21:44 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=92=AD=E6=94=BE=E9=A1=B550?= =?UTF-8?q?0=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .next | 1 - CHANGELOG | 9 ++ pnpm-lock.yaml | 14 ++- src/app/admin/page.tsx | 2 +- src/app/play/page.tsx | 145 +++++++++++++++++------------- src/components/DoubanComments.tsx | 10 +-- src/lib/changelog.ts | 13 +++ src/lib/version.ts | 2 +- 9 files changed, 125 insertions(+), 72 deletions(-) delete mode 120000 .next diff --git a/.gitignore b/.gitignore index 8669019..41e2415 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ /coverage # next.js +.next /.next/ /out/ diff --git a/.next b/.next deleted file mode 120000 index 27e4e2f..0000000 --- a/.next +++ /dev/null @@ -1 +0,0 @@ -/.next \ No newline at end of file diff --git a/CHANGELOG b/CHANGELOG index 82d4491..2b973ff 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,12 @@ +## [200.1.0] - 2025-12-03 + +### Changed +- 评论抓取功能更改为懒加载 +- 评论抓取功能增加开关,默认为关闭 + +### Fixed +- 修复播放页500错误 + ## [200.0.0] - 2025-12-02 ### Added diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c8358f9..abb868f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1161,24 +1161,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@next/swc-linux-arm64-musl@14.2.33': resolution: {integrity: sha512-Bm+QulsAItD/x6Ih8wGIMfRJy4G73tu1HJsrccPW6AfqdZd0Sfm5Imhgkgq2+kly065rYMnCOxTBvmvFY1BKfg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@next/swc-linux-x64-gnu@14.2.33': resolution: {integrity: sha512-FnFn+ZBgsVMbGDsTqo8zsnRzydvsGV8vfiWwUo1LD8FTmPTdV+otGSWKc4LJec0oSexFnCYVO4hX8P8qQKaSlg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@next/swc-linux-x64-musl@14.2.33': resolution: {integrity: sha512-345tsIWMzoXaQndUTDv1qypDRiebFxGYx9pYkhwY4hBRaOLt8UGfiWKr9FSSHs25dFIf8ZqIFaPdy5MljdoawA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@next/swc-win32-arm64-msvc@14.2.33': resolution: {integrity: sha512-nscpt0G6UCTkrT2ppnJnFsYbPDQwmum4GNXYTeoTIdsmMydSKFz9Iny2jpaRupTb+Wl298+Rh82WKzt9LCcqSQ==} @@ -1695,41 +1699,49 @@ packages: resolution: {integrity: sha512-vdqBh911wc5awE2bX2zx3eflbyv8U9xbE/jVKAm425eRoOVv/VseGZsqi3A3SykckSpF4wSROkbQPvbQFn8EsA==} cpu: [arm64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-arm64-musl@1.9.0': resolution: {integrity: sha512-/8JFZ/SnuDr1lLEVsxsuVwrsGquTvT51RZGvyDB/dOK3oYK2UqeXzgeyq6Otp8FZXQcEYqJwxb9v+gtdXn03eQ==} cpu: [arm64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-ppc64-gnu@1.9.0': resolution: {integrity: sha512-FkJjybtrl+rajTw4loI3L6YqSOpeZfDls4SstL/5lsP2bka9TiHUjgMBjygeZEis1oC8LfJTS8FSgpKPaQx2tQ==} cpu: [ppc64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-riscv64-gnu@1.9.0': resolution: {integrity: sha512-w/NZfHNeDusbqSZ8r/hp8iL4S39h4+vQMc9/vvzuIKMWKppyUGKm3IST0Qv0aOZ1rzIbl9SrDeIqK86ZpUK37w==} cpu: [riscv64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-riscv64-musl@1.9.0': resolution: {integrity: sha512-bEPBosut8/8KQbUixPry8zg/fOzVOWyvwzOfz0C0Rw6dp+wIBseyiHKjkcSyZKv/98edrbMknBaMNJfA/UEdqw==} cpu: [riscv64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-s390x-gnu@1.9.0': resolution: {integrity: sha512-LDtMT7moE3gK753gG4pc31AAqGUC86j3AplaFusc717EUGF9ZFJ356sdQzzZzkBk1XzMdxFyZ4f/i35NKM/lFA==} cpu: [s390x] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-x64-gnu@1.9.0': resolution: {integrity: sha512-WmFd5KINHIXj8o1mPaT8QRjA9HgSXhN1gl9Da4IZihARihEnOylu4co7i/yeaIpcfsI6sYs33cNZKyHYDh0lrA==} cpu: [x64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-x64-musl@1.9.0': resolution: {integrity: sha512-CYuXbANW+WgzVRIl8/QvZmDaZxrqvOldOwlbUjIM4pQ46FJ0W5cinJ/Ghwa/Ng1ZPMJMk1VFdsD/XwmCGIXBWg==} cpu: [x64] os: [linux] + libc: [musl] '@unrs/resolver-binding-wasm32-wasi@1.9.0': resolution: {integrity: sha512-6Rp2WH0OoitMYR57Z6VE8Y6corX8C6QEMWLgOV6qXiJIeZ1F9WGXY/yQ8yDC4iTraotyLOeJ2Asea0urWj2fKQ==} @@ -10010,7 +10022,7 @@ snapshots: '@next/env': 14.2.33 '@swc/helpers': 0.5.5 busboy: 1.6.0 - caniuse-lite: 1.0.30001723 + caniuse-lite: 1.0.30001759 graceful-fs: 4.2.11 postcss: 8.4.31 react: 18.3.1 diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 4c8f799..1b93c49 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -4078,7 +4078,7 @@ const SiteConfigComponent = ({ config, refreshConfig }: { config: AdminConfig |

- 评论功能为逆向抓取豆瓣评论数据,开启后请自行承担相关责任和风险。 + 评论功能为逆向抓取豆瓣评论数据,此功能仅供学习,开启后请自行承担相关责任和风险。

diff --git a/src/app/play/page.tsx b/src/app/play/page.tsx index 114b35a..d323aa7 100644 --- a/src/app/play/page.tsx +++ b/src/app/play/page.tsx @@ -2,13 +2,9 @@ 'use client'; -import Artplayer from 'artplayer'; -import artplayerPluginDanmuku from 'artplayer-plugin-danmuku'; -import Hls from 'hls.js'; import { Heart } from 'lucide-react'; import { useRouter, useSearchParams } from 'next/navigation'; import { Suspense, useEffect, useRef, useState } from 'react'; -import { render as anime4kRender } from 'anime4k-webgpu'; import { @@ -686,7 +682,7 @@ function PlayPageClient() { canvas.style.cursor = 'pointer'; // 在canvas上监听点击事件,触发播放器的暂停/播放切换 - const handleCanvasClick = (e: MouseEvent) => { + const handleCanvasClick = () => { if (artPlayerRef.current) { artPlayerRef.current.toggle(); } @@ -694,7 +690,7 @@ function PlayPageClient() { canvas.addEventListener('click', handleCanvasClick); // 在canvas上监听双击事件,触发全屏切换 - const handleCanvasDblClick = (e: MouseEvent) => { + const handleCanvasDblClick = () => { if (artPlayerRef.current) { artPlayerRef.current.fullscreen = !artPlayerRef.current.fullscreen; } @@ -703,36 +699,37 @@ function PlayPageClient() { // 隐藏原始video元素 video.style.display = 'none'; - + // 插入canvas到容器 container.insertBefore(canvas, video); - // 动态导入对应的模式 + // 动态导入 anime4k-webgpu 及对应的模式 + const { render: anime4kRender, ModeA, ModeB, ModeC, ModeAA, ModeBB, ModeCA } = await import('anime4k-webgpu'); + let ModeClass: any; const modeName = anime4kModeRef.current; - const modeModule = await import('anime4k-webgpu'); switch (modeName) { case 'ModeA': - ModeClass = modeModule.ModeA; + ModeClass = ModeA; break; case 'ModeB': - ModeClass = modeModule.ModeB; + ModeClass = ModeB; break; case 'ModeC': - ModeClass = modeModule.ModeC; + ModeClass = ModeC; break; case 'ModeAA': - ModeClass = modeModule.ModeAA; + ModeClass = ModeAA; break; case 'ModeBB': - ModeClass = modeModule.ModeBB; + ModeClass = ModeBB; break; case 'ModeCA': - ModeClass = modeModule.ModeCA; + ModeClass = ModeCA; break; default: - ModeClass = modeModule.ModeA; + ModeClass = ModeA; } // 使用anime4k-webgpu的render函数 @@ -1005,38 +1002,41 @@ function PlayPageClient() { } }; - class CustomHlsJsLoader extends Hls.DefaultConfig.loader { - constructor(config: any) { - super(config); - const load = this.load.bind(this); - this.load = function (context: any, config: any, callbacks: any) { - // 拦截manifest和level请求 - if ( - (context as any).type === 'manifest' || - (context as any).type === 'level' - ) { - const onSuccess = callbacks.onSuccess; - callbacks.onSuccess = function ( - response: any, - stats: any, - context: any + // 创建自定义 HLS loader 的工厂函数 + const createCustomHlsLoader = (HlsLib: any) => { + return class CustomHlsJsLoader extends HlsLib.DefaultConfig.loader { + constructor(config: any) { + super(config); + const load = this.load.bind(this); + this.load = function (context: any, config: any, callbacks: any) { + // 拦截manifest和level请求 + if ( + (context as any).type === 'manifest' || + (context as any).type === 'level' ) { - // 如果是m3u8文件,处理内容以移除广告分段 - if (response.data && typeof response.data === 'string') { - // 过滤掉广告段 - 实现更精确的广告过滤逻辑 - response.data = filterAdsFromM3U8( - currentSourceRef.current, - response.data - ); - } - return onSuccess(response, stats, context, null); - }; - } - // 执行原始load方法 - load(context, config, callbacks); - }; - } - } + const onSuccess = callbacks.onSuccess; + callbacks.onSuccess = function ( + response: any, + stats: any, + context: any + ) { + // 如果是m3u8文件,处理内容以移除广告分段 + if (response.data && typeof response.data === 'string') { + // 过滤掉广告段 - 实现更精确的广告过滤逻辑 + response.data = filterAdsFromM3U8( + currentSourceRef.current, + response.data + ); + } + return onSuccess(response, stats, context, null); + }; + } + // 执行原始load方法 + load(context, config, callbacks); + }; + } + }; + }; // 当集数索引变化时自动更新视频地址 useEffect(() => { @@ -1503,8 +1503,9 @@ function PlayPageClient() { } }; - // 手动重新选择弹幕源(忽略记忆) - const handleReselectDanmakuSource = async () => { + // 手动重新选择弹幕源(忽略记忆)- 保留供将来使用 + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const _handleReselectDanmakuSource = async () => { const title = videoTitleRef.current; if (!title) { console.warn('视频标题为空,无法搜索弹幕'); @@ -1920,8 +1921,6 @@ function PlayPageClient() { useEffect(() => { if ( - !Artplayer || - !Hls || !videoUrl || loading || currentEpisodeIndex === null || @@ -1973,13 +1972,29 @@ function PlayPageClient() { cleanupPlayer(); } - try { - // 创建新的播放器实例 - Artplayer.PLAYBACK_RATE = [0.5, 0.75, 1, 1.25, 1.5, 2, 3]; - Artplayer.USE_RAF = true; + // 异步初始化播放器 + const initPlayer = async () => { + try { + // 动态导入播放器库 + const [ArtplayerModule, HlsModule, DanmukuPlugin] = await Promise.all([ + import('artplayer'), + import('hls.js'), + import('artplayer-plugin-danmuku'), + ]); - artPlayerRef.current = new Artplayer({ - container: artRef.current, + const Artplayer = ArtplayerModule.default; + const Hls = HlsModule.default; + const artplayerPluginDanmuku = DanmukuPlugin.default as any; + + // 创建自定义 HLS loader + const CustomHlsJsLoader = createCustomHlsLoader(Hls); + + // 创建新的播放器实例 + Artplayer.PLAYBACK_RATE = [0.5, 0.75, 1, 1.25, 1.5, 2, 3]; + Artplayer.USE_RAF = true; + + artPlayerRef.current = new Artplayer({ + container: artRef.current!, url: videoUrl, poster: videoCover, volume: 0.7, @@ -2034,9 +2049,9 @@ function PlayPageClient() { maxBufferSize: 60 * 1000 * 1000, // 约 60MB,超出后触发清理 /* 自定义loader */ - loader: blockAdEnabledRef.current + loader: (blockAdEnabledRef.current ? CustomHlsJsLoader - : Hls.DefaultConfig.loader, + : Hls.DefaultConfig.loader) as any, }); hls.loadSource(url); @@ -2513,10 +2528,14 @@ function PlayPageClient() { videoUrl ); } - } catch (err) { - console.error('创建播放器失败:', err); - setError('播放器初始化失败'); - } + } catch (err) { + console.error('创建播放器失败:', err); + setError('播放器初始化失败'); + } + }; + + // 调用异步初始化函数 + initPlayer(); }, [videoUrl, loading, blockAdEnabled, currentEpisodeIndex, detail]); // 当组件卸载时清理定时器、Wake Lock 和播放器资源 diff --git a/src/components/DoubanComments.tsx b/src/components/DoubanComments.tsx index af4633f..e631ebd 100644 --- a/src/components/DoubanComments.tsx +++ b/src/components/DoubanComments.tsx @@ -34,11 +34,6 @@ export default function DoubanComments({ doubanId }: DoubanCommentsProps) { const enableComments = useEnableComments(); - // 如果评论功能被禁用,不显示任何内容 - if (!enableComments) { - return null; - } - const fetchComments = useCallback(async (startIndex: number) => { try { console.log('正在获取评论,起始位置:', startIndex); @@ -129,6 +124,11 @@ export default function DoubanComments({ doubanId }: DoubanCommentsProps) { ); }; + // 如果评论功能被禁用,不显示任何内容 + if (!enableComments) { + return null; + } + // 初始状态:显示查看评论按钮 if (!hasStartedLoading) { return ( diff --git a/src/lib/changelog.ts b/src/lib/changelog.ts index 29f29d0..77fe6ad 100644 --- a/src/lib/changelog.ts +++ b/src/lib/changelog.ts @@ -11,6 +11,19 @@ export interface ChangelogEntry { export const changelog: ChangelogEntry[] = [ { + version: "200.1.0", + date: "2025-12-03", + added: [ + ], + changed: [ + "评论抓取功能更改为懒加载", + "评论抓取功能增加开关,默认为关闭", + ], + fixed: [ + "修复播放页500错误" + ] + }, + { version: "200.0.0", date: "2025-12-02", added: [ diff --git a/src/lib/version.ts b/src/lib/version.ts index 8494bdd..494140f 100644 --- a/src/lib/version.ts +++ b/src/lib/version.ts @@ -1,6 +1,6 @@ /* eslint-disable no-console */ -const CURRENT_VERSION = '200.0.0'; +const CURRENT_VERSION = '200.1.0'; // 导出当前版本号供其他地方使用 export { CURRENT_VERSION };