修复解析切集的加载状态问题

This commit is contained in:
mtvpls
2026-03-22 17:07:28 +08:00
parent 52905f8bdc
commit 4437a4c461
2 changed files with 61 additions and 5 deletions

View File

@@ -27,11 +27,13 @@
-**视频超分 (Anime4K)**:使用 WebGPU 技术实现实时视频画质增强(支持 1.5x/2x/3x/4x 超分)
- 💬 **弹幕系统**:完整的弹幕搜索、匹配、加载功能,支持弹幕设置持久化、弹幕屏蔽
- 📝 **豆瓣评论抓取**:自动抓取并展示豆瓣电影短评,支持分页加载
- 🧩 **视频源脚本**:支持通过脚本自定义视频源、搜索、详情与播放解析逻辑(实验性)
- 🪒**自定义去广告**:你可以自定义你的去广告代码,实现更强力的去广告功能
- 🚀 **更快更顺滑**:相较原版项目整体速度更快,交互体验更好
- 🎭 **观影室**:支持多人同步观影、实时聊天、语音通话等功能(实验性)。
- 📥 **M3U8完整下载**通过合并m3u8片段实现完整视频下载。
- 📥 **M3U8完整下载**支持浏览器内合并 m3u8 片段下载,也支持下载到本地文件夹并无感播放本地视频
- 💾 **服务器离线下载**:支持在服务器端下载视频文件,支持断点续传,提前下载到家秒加载 。
- 📚 **私人影库**:接入 OpenListEmby可打造专属私人影库亦可观看网盘资源。
- 📚 **私人影库**:接入 OpenListEmby 或小雅,可打造专属私人影库,亦可观看网盘资源。
## ✨ 功能特性

View File

@@ -1367,13 +1367,15 @@ function PlayPageClient() {
// 换源加载状态
const [isVideoLoading, setIsVideoLoading] = useState(true);
const [videoLoadingStage, setVideoLoadingStage] = useState<
'initing' | 'sourceChanging'
'initing' | 'sourceChanging' | 'episodeChanging'
>('initing');
const [videoError, setVideoError] = useState<string | null>(null);
// 直链播放时 CORS 失败的原始 URL用于显示"使用代理播放"按钮
const [corsFailedUrl, setCorsFailedUrl] = useState<string | null>(null);
// 标记当前视频是否已经尝试过代理(防止 415→直连→失败→代理 的无限循环)
const proxyAttemptedRef = useRef(false);
const videoUrlRequestSeqRef = useRef(0);
const lastVideoRequestKeyRef = useRef<string | null>(null);
// 直链代理域名记忆:检查某个域名是否需要代理
const isDirectplayDomainProxied = (url: string): boolean => {
@@ -2124,11 +2126,39 @@ function PlayPageClient() {
return;
}
const requestKey = `${detailData.source}|${detailData.id}|${episodeIndex}`;
const isEpisodeSwitchRequest = lastVideoRequestKeyRef.current !== requestKey;
lastVideoRequestKeyRef.current = requestKey;
const requestSeq = ++videoUrlRequestSeqRef.current;
let newUrl = detailData?.episodes[episodeIndex] || '';
const isXiaoyaLazyPlayUrl = newUrl.startsWith('/api/xiaoya/play');
if (isEpisodeSwitchRequest && isXiaoyaLazyPlayUrl) {
setVideoLoadingStage('episodeChanging');
setIsVideoLoading(true);
setVideoError(null);
setCorsFailedUrl(null);
if (artPlayerRef.current?.video) {
try {
const video = artPlayerRef.current.video as HTMLVideoElement;
video.pause();
video.removeAttribute('src');
video.load();
} catch (error) {
console.warn('切集时清空旧视频源失败:', error);
}
}
if (videoUrl) {
setVideoUrl('');
}
}
// 如果是小雅或 openlist 接口,先请求获取真实 URL
const isSpecialLazyPlayUrl =
newUrl.startsWith('/api/xiaoya/play') ||
isXiaoyaLazyPlayUrl ||
newUrl.startsWith('/api/openlist/play') ||
newUrl.startsWith('/api/source-script/play');
@@ -2145,6 +2175,9 @@ function PlayPageClient() {
const response = await fetch(fetchUrl);
const data = await response.json();
if (requestSeq !== videoUrlRequestSeqRef.current) {
return;
}
if (data.url) {
newUrl = data.url;
// 保存清晰度列表
@@ -2155,6 +2188,9 @@ function PlayPageClient() {
}
}
} catch (error) {
if (requestSeq !== videoUrlRequestSeqRef.current) {
return;
}
console.error('获取播放链接失败:', error);
setVideoQualities([]);
currentXiaoyaUrlRef.current = ''; // 获取失败,清空
@@ -2172,6 +2208,9 @@ function PlayPageClient() {
currentId || undefined,
episodeIndex
);
if (requestSeq !== videoUrlRequestSeqRef.current) {
return;
}
if (fileSystemCheck.hasLocal && fileSystemCheck.dirHandle) {
// 使用本地文件播放
@@ -2242,6 +2281,9 @@ function PlayPageClient() {
// 如果没有 File System API 本地文件,检查服务器端本地下载
if (!fileSystemCheck.hasLocal) {
const hasLocalFile = await checkLocalDownload(currentSource, currentId, episodeIndex);
if (requestSeq !== videoUrlRequestSeqRef.current) {
return;
}
if (hasLocalFile) {
// 使用本地代理接口,URL以.m3u8结尾以便Artplayer自动识别
@@ -2269,7 +2311,10 @@ function PlayPageClient() {
}
}
if (newUrl !== videoUrl) {
if (isEpisodeSwitchRequest || newUrl !== videoUrl) {
if (requestSeq !== videoUrlRequestSeqRef.current) {
return;
}
setVideoUrl(newUrl);
}
};
@@ -3934,6 +3979,9 @@ function PlayPageClient() {
if (artPlayerRef.current && artPlayerRef.current.paused) {
saveCurrentPlayProgress();
}
setVideoLoadingStage('episodeChanging');
setIsVideoLoading(true);
setVideoError(null);
setCurrentEpisodeIndex(episodeNumber);
}
};
@@ -3945,6 +3993,9 @@ function PlayPageClient() {
if (artPlayerRef.current && !artPlayerRef.current.paused) {
saveCurrentPlayProgress();
}
setVideoLoadingStage('episodeChanging');
setIsVideoLoading(true);
setVideoError(null);
setCurrentEpisodeIndex(idx - 1);
}
};
@@ -3993,6 +4044,9 @@ function PlayPageClient() {
const isFiltered = episodeTitle && isEpisodeFilteredByTitle(episodeTitle);
if (!isFiltered) {
setVideoLoadingStage('episodeChanging');
setIsVideoLoading(true);
setVideoError(null);
setCurrentEpisodeIndex(nextIdx);
return;
}