修复播放页500错误

This commit is contained in:
mtvpls
2025-12-03 20:21:44 +08:00
parent 4e05c7bcaa
commit a2b7dff392
9 changed files with 125 additions and 72 deletions

1
.gitignore vendored
View File

@@ -9,6 +9,7 @@
/coverage /coverage
# next.js # next.js
.next
/.next/ /.next/
/out/ /out/

1
.next
View File

@@ -1 +0,0 @@
/.next

View File

@@ -1,3 +1,12 @@
## [200.1.0] - 2025-12-03
### Changed
- 评论抓取功能更改为懒加载
- 评论抓取功能增加开关,默认为关闭
### Fixed
- 修复播放页500错误
## [200.0.0] - 2025-12-02 ## [200.0.0] - 2025-12-02
### Added ### Added

14
pnpm-lock.yaml generated
View File

@@ -1161,24 +1161,28 @@ packages:
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc]
'@next/swc-linux-arm64-musl@14.2.33': '@next/swc-linux-arm64-musl@14.2.33':
resolution: {integrity: sha512-Bm+QulsAItD/x6Ih8wGIMfRJy4G73tu1HJsrccPW6AfqdZd0Sfm5Imhgkgq2+kly065rYMnCOxTBvmvFY1BKfg==} resolution: {integrity: sha512-Bm+QulsAItD/x6Ih8wGIMfRJy4G73tu1HJsrccPW6AfqdZd0Sfm5Imhgkgq2+kly065rYMnCOxTBvmvFY1BKfg==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl]
'@next/swc-linux-x64-gnu@14.2.33': '@next/swc-linux-x64-gnu@14.2.33':
resolution: {integrity: sha512-FnFn+ZBgsVMbGDsTqo8zsnRzydvsGV8vfiWwUo1LD8FTmPTdV+otGSWKc4LJec0oSexFnCYVO4hX8P8qQKaSlg==} resolution: {integrity: sha512-FnFn+ZBgsVMbGDsTqo8zsnRzydvsGV8vfiWwUo1LD8FTmPTdV+otGSWKc4LJec0oSexFnCYVO4hX8P8qQKaSlg==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc]
'@next/swc-linux-x64-musl@14.2.33': '@next/swc-linux-x64-musl@14.2.33':
resolution: {integrity: sha512-345tsIWMzoXaQndUTDv1qypDRiebFxGYx9pYkhwY4hBRaOLt8UGfiWKr9FSSHs25dFIf8ZqIFaPdy5MljdoawA==} resolution: {integrity: sha512-345tsIWMzoXaQndUTDv1qypDRiebFxGYx9pYkhwY4hBRaOLt8UGfiWKr9FSSHs25dFIf8ZqIFaPdy5MljdoawA==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl]
'@next/swc-win32-arm64-msvc@14.2.33': '@next/swc-win32-arm64-msvc@14.2.33':
resolution: {integrity: sha512-nscpt0G6UCTkrT2ppnJnFsYbPDQwmum4GNXYTeoTIdsmMydSKFz9Iny2jpaRupTb+Wl298+Rh82WKzt9LCcqSQ==} resolution: {integrity: sha512-nscpt0G6UCTkrT2ppnJnFsYbPDQwmum4GNXYTeoTIdsmMydSKFz9Iny2jpaRupTb+Wl298+Rh82WKzt9LCcqSQ==}
@@ -1695,41 +1699,49 @@ packages:
resolution: {integrity: sha512-vdqBh911wc5awE2bX2zx3eflbyv8U9xbE/jVKAm425eRoOVv/VseGZsqi3A3SykckSpF4wSROkbQPvbQFn8EsA==} resolution: {integrity: sha512-vdqBh911wc5awE2bX2zx3eflbyv8U9xbE/jVKAm425eRoOVv/VseGZsqi3A3SykckSpF4wSROkbQPvbQFn8EsA==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc]
'@unrs/resolver-binding-linux-arm64-musl@1.9.0': '@unrs/resolver-binding-linux-arm64-musl@1.9.0':
resolution: {integrity: sha512-/8JFZ/SnuDr1lLEVsxsuVwrsGquTvT51RZGvyDB/dOK3oYK2UqeXzgeyq6Otp8FZXQcEYqJwxb9v+gtdXn03eQ==} resolution: {integrity: sha512-/8JFZ/SnuDr1lLEVsxsuVwrsGquTvT51RZGvyDB/dOK3oYK2UqeXzgeyq6Otp8FZXQcEYqJwxb9v+gtdXn03eQ==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl]
'@unrs/resolver-binding-linux-ppc64-gnu@1.9.0': '@unrs/resolver-binding-linux-ppc64-gnu@1.9.0':
resolution: {integrity: sha512-FkJjybtrl+rajTw4loI3L6YqSOpeZfDls4SstL/5lsP2bka9TiHUjgMBjygeZEis1oC8LfJTS8FSgpKPaQx2tQ==} resolution: {integrity: sha512-FkJjybtrl+rajTw4loI3L6YqSOpeZfDls4SstL/5lsP2bka9TiHUjgMBjygeZEis1oC8LfJTS8FSgpKPaQx2tQ==}
cpu: [ppc64] cpu: [ppc64]
os: [linux] os: [linux]
libc: [glibc]
'@unrs/resolver-binding-linux-riscv64-gnu@1.9.0': '@unrs/resolver-binding-linux-riscv64-gnu@1.9.0':
resolution: {integrity: sha512-w/NZfHNeDusbqSZ8r/hp8iL4S39h4+vQMc9/vvzuIKMWKppyUGKm3IST0Qv0aOZ1rzIbl9SrDeIqK86ZpUK37w==} resolution: {integrity: sha512-w/NZfHNeDusbqSZ8r/hp8iL4S39h4+vQMc9/vvzuIKMWKppyUGKm3IST0Qv0aOZ1rzIbl9SrDeIqK86ZpUK37w==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
libc: [glibc]
'@unrs/resolver-binding-linux-riscv64-musl@1.9.0': '@unrs/resolver-binding-linux-riscv64-musl@1.9.0':
resolution: {integrity: sha512-bEPBosut8/8KQbUixPry8zg/fOzVOWyvwzOfz0C0Rw6dp+wIBseyiHKjkcSyZKv/98edrbMknBaMNJfA/UEdqw==} resolution: {integrity: sha512-bEPBosut8/8KQbUixPry8zg/fOzVOWyvwzOfz0C0Rw6dp+wIBseyiHKjkcSyZKv/98edrbMknBaMNJfA/UEdqw==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
libc: [musl]
'@unrs/resolver-binding-linux-s390x-gnu@1.9.0': '@unrs/resolver-binding-linux-s390x-gnu@1.9.0':
resolution: {integrity: sha512-LDtMT7moE3gK753gG4pc31AAqGUC86j3AplaFusc717EUGF9ZFJ356sdQzzZzkBk1XzMdxFyZ4f/i35NKM/lFA==} resolution: {integrity: sha512-LDtMT7moE3gK753gG4pc31AAqGUC86j3AplaFusc717EUGF9ZFJ356sdQzzZzkBk1XzMdxFyZ4f/i35NKM/lFA==}
cpu: [s390x] cpu: [s390x]
os: [linux] os: [linux]
libc: [glibc]
'@unrs/resolver-binding-linux-x64-gnu@1.9.0': '@unrs/resolver-binding-linux-x64-gnu@1.9.0':
resolution: {integrity: sha512-WmFd5KINHIXj8o1mPaT8QRjA9HgSXhN1gl9Da4IZihARihEnOylu4co7i/yeaIpcfsI6sYs33cNZKyHYDh0lrA==} resolution: {integrity: sha512-WmFd5KINHIXj8o1mPaT8QRjA9HgSXhN1gl9Da4IZihARihEnOylu4co7i/yeaIpcfsI6sYs33cNZKyHYDh0lrA==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc]
'@unrs/resolver-binding-linux-x64-musl@1.9.0': '@unrs/resolver-binding-linux-x64-musl@1.9.0':
resolution: {integrity: sha512-CYuXbANW+WgzVRIl8/QvZmDaZxrqvOldOwlbUjIM4pQ46FJ0W5cinJ/Ghwa/Ng1ZPMJMk1VFdsD/XwmCGIXBWg==} resolution: {integrity: sha512-CYuXbANW+WgzVRIl8/QvZmDaZxrqvOldOwlbUjIM4pQ46FJ0W5cinJ/Ghwa/Ng1ZPMJMk1VFdsD/XwmCGIXBWg==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl]
'@unrs/resolver-binding-wasm32-wasi@1.9.0': '@unrs/resolver-binding-wasm32-wasi@1.9.0':
resolution: {integrity: sha512-6Rp2WH0OoitMYR57Z6VE8Y6corX8C6QEMWLgOV6qXiJIeZ1F9WGXY/yQ8yDC4iTraotyLOeJ2Asea0urWj2fKQ==} resolution: {integrity: sha512-6Rp2WH0OoitMYR57Z6VE8Y6corX8C6QEMWLgOV6qXiJIeZ1F9WGXY/yQ8yDC4iTraotyLOeJ2Asea0urWj2fKQ==}
@@ -10010,7 +10022,7 @@ snapshots:
'@next/env': 14.2.33 '@next/env': 14.2.33
'@swc/helpers': 0.5.5 '@swc/helpers': 0.5.5
busboy: 1.6.0 busboy: 1.6.0
caniuse-lite: 1.0.30001723 caniuse-lite: 1.0.30001759
graceful-fs: 4.2.11 graceful-fs: 4.2.11
postcss: 8.4.31 postcss: 8.4.31
react: 18.3.1 react: 18.3.1

View File

@@ -4078,7 +4078,7 @@ const SiteConfigComponent = ({ config, refreshConfig }: { config: AdminConfig |
</span> </span>
</div> </div>
<p className='text-sm text-yellow-700 dark:text-yellow-400'> <p className='text-sm text-yellow-700 dark:text-yellow-400'>
</p> </p>
</div> </div>
</div> </div>

View File

@@ -2,13 +2,9 @@
'use client'; 'use client';
import Artplayer from 'artplayer';
import artplayerPluginDanmuku from 'artplayer-plugin-danmuku';
import Hls from 'hls.js';
import { Heart } from 'lucide-react'; import { Heart } from 'lucide-react';
import { useRouter, useSearchParams } from 'next/navigation'; import { useRouter, useSearchParams } from 'next/navigation';
import { Suspense, useEffect, useRef, useState } from 'react'; import { Suspense, useEffect, useRef, useState } from 'react';
import { render as anime4kRender } from 'anime4k-webgpu';
import { import {
@@ -686,7 +682,7 @@ function PlayPageClient() {
canvas.style.cursor = 'pointer'; canvas.style.cursor = 'pointer';
// 在canvas上监听点击事件触发播放器的暂停/播放切换 // 在canvas上监听点击事件触发播放器的暂停/播放切换
const handleCanvasClick = (e: MouseEvent) => { const handleCanvasClick = () => {
if (artPlayerRef.current) { if (artPlayerRef.current) {
artPlayerRef.current.toggle(); artPlayerRef.current.toggle();
} }
@@ -694,7 +690,7 @@ function PlayPageClient() {
canvas.addEventListener('click', handleCanvasClick); canvas.addEventListener('click', handleCanvasClick);
// 在canvas上监听双击事件触发全屏切换 // 在canvas上监听双击事件触发全屏切换
const handleCanvasDblClick = (e: MouseEvent) => { const handleCanvasDblClick = () => {
if (artPlayerRef.current) { if (artPlayerRef.current) {
artPlayerRef.current.fullscreen = !artPlayerRef.current.fullscreen; artPlayerRef.current.fullscreen = !artPlayerRef.current.fullscreen;
} }
@@ -703,36 +699,37 @@ function PlayPageClient() {
// 隐藏原始video元素 // 隐藏原始video元素
video.style.display = 'none'; video.style.display = 'none';
// 插入canvas到容器 // 插入canvas到容器
container.insertBefore(canvas, video); container.insertBefore(canvas, video);
// 动态导入对应的模式 // 动态导入 anime4k-webgpu 及对应的模式
const { render: anime4kRender, ModeA, ModeB, ModeC, ModeAA, ModeBB, ModeCA } = await import('anime4k-webgpu');
let ModeClass: any; let ModeClass: any;
const modeName = anime4kModeRef.current; const modeName = anime4kModeRef.current;
const modeModule = await import('anime4k-webgpu');
switch (modeName) { switch (modeName) {
case 'ModeA': case 'ModeA':
ModeClass = modeModule.ModeA; ModeClass = ModeA;
break; break;
case 'ModeB': case 'ModeB':
ModeClass = modeModule.ModeB; ModeClass = ModeB;
break; break;
case 'ModeC': case 'ModeC':
ModeClass = modeModule.ModeC; ModeClass = ModeC;
break; break;
case 'ModeAA': case 'ModeAA':
ModeClass = modeModule.ModeAA; ModeClass = ModeAA;
break; break;
case 'ModeBB': case 'ModeBB':
ModeClass = modeModule.ModeBB; ModeClass = ModeBB;
break; break;
case 'ModeCA': case 'ModeCA':
ModeClass = modeModule.ModeCA; ModeClass = ModeCA;
break; break;
default: default:
ModeClass = modeModule.ModeA; ModeClass = ModeA;
} }
// 使用anime4k-webgpu的render函数 // 使用anime4k-webgpu的render函数
@@ -1005,38 +1002,41 @@ function PlayPageClient() {
} }
}; };
class CustomHlsJsLoader extends Hls.DefaultConfig.loader { // 创建自定义 HLS loader 的工厂函数
constructor(config: any) { const createCustomHlsLoader = (HlsLib: any) => {
super(config); return class CustomHlsJsLoader extends HlsLib.DefaultConfig.loader {
const load = this.load.bind(this); constructor(config: any) {
this.load = function (context: any, config: any, callbacks: any) { super(config);
// 拦截manifest和level请求 const load = this.load.bind(this);
if ( this.load = function (context: any, config: any, callbacks: any) {
(context as any).type === 'manifest' || // 拦截manifest和level请求
(context as any).type === 'level' if (
) { (context as any).type === 'manifest' ||
const onSuccess = callbacks.onSuccess; (context as any).type === 'level'
callbacks.onSuccess = function (
response: any,
stats: any,
context: any
) { ) {
// 如果是m3u8文件处理内容以移除广告分段 const onSuccess = callbacks.onSuccess;
if (response.data && typeof response.data === 'string') { callbacks.onSuccess = function (
// 过滤掉广告段 - 实现更精确的广告过滤逻辑 response: any,
response.data = filterAdsFromM3U8( stats: any,
currentSourceRef.current, context: any
response.data ) {
); // 如果是m3u8文件处理内容以移除广告分段
} if (response.data && typeof response.data === 'string') {
return onSuccess(response, stats, context, null); // 过滤掉广告段 - 实现更精确的广告过滤逻辑
}; response.data = filterAdsFromM3U8(
} currentSourceRef.current,
// 执行原始load方法 response.data
load(context, config, callbacks); );
}; }
} return onSuccess(response, stats, context, null);
} };
}
// 执行原始load方法
load(context, config, callbacks);
};
}
};
};
// 当集数索引变化时自动更新视频地址 // 当集数索引变化时自动更新视频地址
useEffect(() => { 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; const title = videoTitleRef.current;
if (!title) { if (!title) {
console.warn('视频标题为空,无法搜索弹幕'); console.warn('视频标题为空,无法搜索弹幕');
@@ -1920,8 +1921,6 @@ function PlayPageClient() {
useEffect(() => { useEffect(() => {
if ( if (
!Artplayer ||
!Hls ||
!videoUrl || !videoUrl ||
loading || loading ||
currentEpisodeIndex === null || currentEpisodeIndex === null ||
@@ -1973,13 +1972,29 @@ function PlayPageClient() {
cleanupPlayer(); cleanupPlayer();
} }
try { // 异步初始化播放器
// 创建新的播放器实例 const initPlayer = async () => {
Artplayer.PLAYBACK_RATE = [0.5, 0.75, 1, 1.25, 1.5, 2, 3]; try {
Artplayer.USE_RAF = true; // 动态导入播放器库
const [ArtplayerModule, HlsModule, DanmukuPlugin] = await Promise.all([
import('artplayer'),
import('hls.js'),
import('artplayer-plugin-danmuku'),
]);
artPlayerRef.current = new Artplayer({ const Artplayer = ArtplayerModule.default;
container: artRef.current, 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, url: videoUrl,
poster: videoCover, poster: videoCover,
volume: 0.7, volume: 0.7,
@@ -2034,9 +2049,9 @@ function PlayPageClient() {
maxBufferSize: 60 * 1000 * 1000, // 约 60MB超出后触发清理 maxBufferSize: 60 * 1000 * 1000, // 约 60MB超出后触发清理
/* 自定义loader */ /* 自定义loader */
loader: blockAdEnabledRef.current loader: (blockAdEnabledRef.current
? CustomHlsJsLoader ? CustomHlsJsLoader
: Hls.DefaultConfig.loader, : Hls.DefaultConfig.loader) as any,
}); });
hls.loadSource(url); hls.loadSource(url);
@@ -2513,10 +2528,14 @@ function PlayPageClient() {
videoUrl videoUrl
); );
} }
} catch (err) { } catch (err) {
console.error('创建播放器失败:', err); console.error('创建播放器失败:', err);
setError('播放器初始化失败'); setError('播放器初始化失败');
} }
};
// 调用异步初始化函数
initPlayer();
}, [videoUrl, loading, blockAdEnabled, currentEpisodeIndex, detail]); }, [videoUrl, loading, blockAdEnabled, currentEpisodeIndex, detail]);
// 当组件卸载时清理定时器、Wake Lock 和播放器资源 // 当组件卸载时清理定时器、Wake Lock 和播放器资源

View File

@@ -34,11 +34,6 @@ export default function DoubanComments({ doubanId }: DoubanCommentsProps) {
const enableComments = useEnableComments(); const enableComments = useEnableComments();
// 如果评论功能被禁用,不显示任何内容
if (!enableComments) {
return null;
}
const fetchComments = useCallback(async (startIndex: number) => { const fetchComments = useCallback(async (startIndex: number) => {
try { try {
console.log('正在获取评论,起始位置:', startIndex); console.log('正在获取评论,起始位置:', startIndex);
@@ -129,6 +124,11 @@ export default function DoubanComments({ doubanId }: DoubanCommentsProps) {
); );
}; };
// 如果评论功能被禁用,不显示任何内容
if (!enableComments) {
return null;
}
// 初始状态:显示查看评论按钮 // 初始状态:显示查看评论按钮
if (!hasStartedLoading) { if (!hasStartedLoading) {
return ( return (

View File

@@ -11,6 +11,19 @@ export interface ChangelogEntry {
export const changelog: ChangelogEntry[] = [ export const changelog: ChangelogEntry[] = [
{ {
version: "200.1.0",
date: "2025-12-03",
added: [
],
changed: [
"评论抓取功能更改为懒加载",
"评论抓取功能增加开关,默认为关闭",
],
fixed: [
"修复播放页500错误"
]
},
{
version: "200.0.0", version: "200.0.0",
date: "2025-12-02", date: "2025-12-02",
added: [ added: [

View File

@@ -1,6 +1,6 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
const CURRENT_VERSION = '200.0.0'; const CURRENT_VERSION = '200.1.0';
// 导出当前版本号供其他地方使用 // 导出当前版本号供其他地方使用
export { CURRENT_VERSION }; export { CURRENT_VERSION };