优化弹幕加载提示
This commit is contained in:
@@ -1809,6 +1809,9 @@ function PlayPageClient() {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取弹幕剧集列表失败:', error);
|
console.error('获取弹幕剧集列表失败:', error);
|
||||||
|
if (artPlayerRef.current) {
|
||||||
|
artPlayerRef.current.notice.show = '弹幕加载失败:无法获取剧集列表';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1825,6 +1828,9 @@ function PlayPageClient() {
|
|||||||
setDanmakuMatches(searchResult.animes);
|
setDanmakuMatches(searchResult.animes);
|
||||||
setShowDanmakuSourceSelector(true);
|
setShowDanmakuSourceSelector(true);
|
||||||
setDanmakuLoading(false);
|
setDanmakuLoading(false);
|
||||||
|
if (artPlayerRef.current) {
|
||||||
|
artPlayerRef.current.notice.show = `找到 ${searchResult.animes.length} 个弹幕源,请选择`;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1874,12 +1880,21 @@ function PlayPageClient() {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.warn('未找到剧集信息');
|
console.warn('未找到剧集信息');
|
||||||
|
if (artPlayerRef.current) {
|
||||||
|
artPlayerRef.current.notice.show = '弹幕加载失败:未找到剧集信息';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.warn('未找到匹配的弹幕');
|
console.warn('未找到匹配的弹幕');
|
||||||
|
if (artPlayerRef.current) {
|
||||||
|
artPlayerRef.current.notice.show = '未找到匹配的弹幕,可在弹幕选项卡手动搜索';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('自动搜索弹幕失败:', error);
|
console.error('自动搜索弹幕失败:', error);
|
||||||
|
if (artPlayerRef.current) {
|
||||||
|
artPlayerRef.current.notice.show = '弹幕加载失败,请检查网络或稍后重试';
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
setDanmakuLoading(false);
|
setDanmakuLoading(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect, useRef } from 'react';
|
||||||
import { X, Plus, Trash2, ToggleLeft, ToggleRight } from 'lucide-react';
|
import { X, Plus, Trash2, ToggleLeft, ToggleRight } from 'lucide-react';
|
||||||
import { DanmakuFilterConfig, DanmakuFilterRule } from '@/lib/types';
|
import { DanmakuFilterConfig, DanmakuFilterRule } from '@/lib/types';
|
||||||
import { getDanmakuFilterConfig, saveDanmakuFilterConfig } from '@/lib/db.client';
|
import { getDanmakuFilterConfig, saveDanmakuFilterConfig } from '@/lib/db.client';
|
||||||
@@ -26,6 +26,8 @@ export default function DanmakuFilterSettings({
|
|||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
const [isVisible, setIsVisible] = useState(false);
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
const [isAnimating, setIsAnimating] = useState(false);
|
const [isAnimating, setIsAnimating] = useState(false);
|
||||||
|
const [inputKey, setInputKey] = useState(0); // 用于强制重新渲染输入框
|
||||||
|
const inputRef = useRef<HTMLInputElement>(null); // 用于直接操作输入框 DOM
|
||||||
|
|
||||||
// 控制动画状态
|
// 控制动画状态
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -176,7 +178,17 @@ export default function DanmakuFilterSettings({
|
|||||||
rules: [...prev.rules, newRule],
|
rules: [...prev.rules, newRule],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// 清空输入框并强制重新渲染
|
||||||
setNewKeyword('');
|
setNewKeyword('');
|
||||||
|
|
||||||
|
// 使用 setTimeout 确保在状态更新后操作 DOM
|
||||||
|
setTimeout(() => {
|
||||||
|
if (inputRef.current) {
|
||||||
|
inputRef.current.value = ''; // 直接清空 DOM 值
|
||||||
|
inputRef.current.blur(); // 失去焦点,阻止自动填充
|
||||||
|
}
|
||||||
|
setInputKey(prev => prev + 1); // 强制重新渲染输入框
|
||||||
|
}, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 删除规则
|
// 删除规则
|
||||||
@@ -279,11 +291,19 @@ export default function DanmakuFilterSettings({
|
|||||||
</h3>
|
</h3>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<input
|
<input
|
||||||
|
key={inputKey}
|
||||||
|
ref={inputRef}
|
||||||
type="text"
|
type="text"
|
||||||
value={newKeyword}
|
value={newKeyword}
|
||||||
onChange={(e) => setNewKeyword(e.target.value)}
|
onChange={(e) => setNewKeyword(e.target.value)}
|
||||||
onKeyPress={(e) => e.key === 'Enter' && handleAddRule()}
|
onKeyPress={(e) => e.key === 'Enter' && handleAddRule()}
|
||||||
placeholder="输入要屏蔽的关键字"
|
placeholder="输入要屏蔽的关键字"
|
||||||
|
autoComplete="off"
|
||||||
|
autoCorrect="off"
|
||||||
|
autoCapitalize="off"
|
||||||
|
spellCheck="false"
|
||||||
|
data-form-type="other"
|
||||||
|
data-lpignore="true"
|
||||||
className="w-full px-4 py-3 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-lg border border-gray-200 dark:border-gray-600 focus:border-teal-500 focus:outline-none focus:ring-2 focus:ring-teal-500/20 transition-all duration-200"
|
className="w-full px-4 py-3 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-lg border border-gray-200 dark:border-gray-600 focus:border-teal-500 focus:outline-none focus:ring-2 focus:ring-teal-500/20 transition-all duration-200"
|
||||||
/>
|
/>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { MagnifyingGlassIcon } from '@heroicons/react/24/outline';
|
import { MagnifyingGlassIcon } from '@heroicons/react/24/outline';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
|
||||||
import { getEpisodes, searchAnime } from '@/lib/danmaku/api';
|
import { getEpisodes, searchAnime } from '@/lib/danmaku/api';
|
||||||
import type {
|
import type {
|
||||||
@@ -30,6 +30,7 @@ export default function DanmakuPanel({
|
|||||||
const [isSearching, setIsSearching] = useState(false);
|
const [isSearching, setIsSearching] = useState(false);
|
||||||
const [isLoadingEpisodes, setIsLoadingEpisodes] = useState(false);
|
const [isLoadingEpisodes, setIsLoadingEpisodes] = useState(false);
|
||||||
const [searchError, setSearchError] = useState<string | null>(null);
|
const [searchError, setSearchError] = useState<string | null>(null);
|
||||||
|
const initializedRef = useRef(false); // 标记是否已初始化过
|
||||||
|
|
||||||
// 搜索弹幕
|
// 搜索弹幕
|
||||||
const handleSearch = useCallback(async (keyword: string) => {
|
const handleSearch = useCallback(async (keyword: string) => {
|
||||||
@@ -116,12 +117,13 @@ export default function DanmakuPanel({
|
|||||||
[currentSelection]
|
[currentSelection]
|
||||||
);
|
);
|
||||||
|
|
||||||
// 当视频标题变化时,更新搜索关键词
|
// 当视频标题首次加载时,初始化搜索关键词(仅执行一次)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (videoTitle && !searchKeyword) {
|
if (videoTitle && !initializedRef.current) {
|
||||||
setSearchKeyword(videoTitle);
|
setSearchKeyword(videoTitle);
|
||||||
|
initializedRef.current = true; // 标记已初始化,防止后续自动填充
|
||||||
}
|
}
|
||||||
}, [videoTitle, searchKeyword]);
|
}, [videoTitle]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex h-full flex-col overflow-hidden'>
|
<div className='flex h-full flex-col overflow-hidden'>
|
||||||
@@ -138,6 +140,12 @@ export default function DanmakuPanel({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
placeholder='输入动漫名称搜索弹幕...'
|
placeholder='输入动漫名称搜索弹幕...'
|
||||||
|
autoComplete='off'
|
||||||
|
autoCorrect='off'
|
||||||
|
autoCapitalize='off'
|
||||||
|
spellCheck='false'
|
||||||
|
data-form-type='other'
|
||||||
|
data-lpignore='true'
|
||||||
className='flex-1 rounded-lg border border-gray-300 px-3 py-2 text-sm
|
className='flex-1 rounded-lg border border-gray-300 px-3 py-2 text-sm
|
||||||
transition-colors focus:border-green-500 focus:outline-none
|
transition-colors focus:border-green-500 focus:outline-none
|
||||||
focus:ring-2 focus:ring-green-500/20
|
focus:ring-2 focus:ring-green-500/20
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export async function searchAnime(
|
|||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error('弹幕服务器连接异常,请检查你的设置');
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = (await response.json()) as DanmakuSearchResponse;
|
const data = (await response.json()) as DanmakuSearchResponse;
|
||||||
@@ -52,7 +52,7 @@ export async function matchAnime(
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error('弹幕服务器连接异常,请检查你的设置');
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = (await response.json()) as DanmakuMatchResponse;
|
const data = (await response.json()) as DanmakuMatchResponse;
|
||||||
@@ -78,7 +78,7 @@ export async function getEpisodes(
|
|||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error('弹幕服务器连接异常,请检查你的设置');
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = (await response.json()) as DanmakuEpisodesResponse;
|
const data = (await response.json()) as DanmakuEpisodesResponse;
|
||||||
@@ -107,7 +107,7 @@ export async function getDanmakuById(
|
|||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error('弹幕服务器连接异常,请检查你的设置');
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = (await response.json()) as DanmakuCommentsResponse;
|
const data = (await response.json()) as DanmakuCommentsResponse;
|
||||||
@@ -125,7 +125,7 @@ export async function getDanmakuByUrl(url: string): Promise<DanmakuComment[]> {
|
|||||||
const response = await fetch(apiUrl);
|
const response = await fetch(apiUrl);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error('弹幕服务器连接异常,请检查你的设置');
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = (await response.json()) as DanmakuCommentsResponse;
|
const data = (await response.json()) as DanmakuCommentsResponse;
|
||||||
|
|||||||
Reference in New Issue
Block a user