mirror of
https://github.com/KuekHaoYang/KVideo.git
synced 2026-08-12 23:33:43 +08:00
feat: add video resolution detection and expose callback in player components
This commit is contained in:
@@ -9,6 +9,7 @@ import { EpisodeList } from '@/components/player/EpisodeList';
|
||||
import { PlayerError } from '@/components/player/PlayerError';
|
||||
import { SourceInfo } from '@/components/player/EpisodeList';
|
||||
import type { VideoSource } from '@/lib/types';
|
||||
import type { VideoResolutionInfo } from '@/components/player/hooks/useVideoResolution';
|
||||
import { useVideoPlayer } from '@/lib/hooks/useVideoPlayer';
|
||||
import { useHistory } from '@/lib/store/history-store';
|
||||
import { FavoritesSidebar } from '@/components/favorites/FavoritesSidebar';
|
||||
@@ -265,6 +266,9 @@ function PlayerContent() {
|
||||
const [currentSourceId, setCurrentSourceId] = useState(source);
|
||||
const playerTimeRef = useRef(0);
|
||||
|
||||
// Track detected video resolution from the player
|
||||
const [detectedResolution, setDetectedResolution] = useState<VideoResolutionInfo | null>(null);
|
||||
|
||||
// Add initial history entry when video data is loaded
|
||||
useEffect(() => {
|
||||
if (videoData && playUrl && videoId) {
|
||||
@@ -363,6 +367,7 @@ function PlayerContent() {
|
||||
videoTitle={videoData?.vod_name || title || ''}
|
||||
episodeName={videoData?.episodes?.[currentEpisode]?.name || ''}
|
||||
externalTimeRef={playerTimeRef}
|
||||
onResolutionDetected={setDetectedResolution}
|
||||
/>
|
||||
<div className="hidden lg:block">
|
||||
<VideoMetadata
|
||||
@@ -425,6 +430,7 @@ function PlayerContent() {
|
||||
onToggleReverse={handleToggleReverse}
|
||||
sources={groupedSources.length > 0 ? groupedSources : undefined}
|
||||
currentSource={currentSourceId || source || ''}
|
||||
currentResolution={detectedResolution}
|
||||
onSourceChange={(newSource) => {
|
||||
const params = new URLSearchParams();
|
||||
params.set('id', String(newSource.id));
|
||||
|
||||
@@ -18,6 +18,8 @@ interface CustomVideoPlayerProps {
|
||||
// Danmaku props
|
||||
videoTitle?: string;
|
||||
episodeName?: string;
|
||||
// Resolution callback
|
||||
onResolutionDetected?: (info: import('./hooks/useVideoResolution').VideoResolutionInfo) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,6 +31,8 @@ interface DesktopVideoPlayerProps {
|
||||
// Danmaku props
|
||||
videoTitle?: string;
|
||||
episodeName?: string;
|
||||
// Resolution callback
|
||||
onResolutionDetected?: (info: import('./hooks/useVideoResolution').VideoResolutionInfo) => void;
|
||||
}
|
||||
|
||||
export function DesktopVideoPlayer({
|
||||
@@ -46,6 +48,7 @@ export function DesktopVideoPlayer({
|
||||
isReversed = false,
|
||||
videoTitle = '',
|
||||
episodeName = '',
|
||||
onResolutionDetected,
|
||||
}: DesktopVideoPlayerProps) {
|
||||
const { refs, data, actions } = useDesktopPlayerState();
|
||||
const { fullscreenType: settingsFullscreenType } = usePlayerSettings();
|
||||
@@ -55,6 +58,13 @@ export function DesktopVideoPlayer({
|
||||
// Detect actual video resolution
|
||||
const videoResolution = useVideoResolution(refs.videoRef);
|
||||
|
||||
// Notify parent when resolution is detected
|
||||
React.useEffect(() => {
|
||||
if (videoResolution && onResolutionDetected) {
|
||||
onResolutionDetected(videoResolution);
|
||||
}
|
||||
}, [videoResolution, onResolutionDetected]);
|
||||
|
||||
// Danmaku
|
||||
const { danmakuEnabled, setDanmakuEnabled, comments: danmakuComments } = useDanmaku({
|
||||
videoTitle,
|
||||
|
||||
@@ -10,6 +10,7 @@ import { Button } from '@/components/ui/Button';
|
||||
import { useKeyboardNavigation } from '@/lib/hooks/useKeyboardNavigation';
|
||||
import { settingsStore } from '@/lib/store/settings-store';
|
||||
import { extractQualityLabel } from '@/lib/utils/video';
|
||||
import type { VideoResolutionInfo } from './hooks/useVideoResolution';
|
||||
|
||||
interface Episode {
|
||||
name?: string;
|
||||
@@ -36,6 +37,8 @@ interface EpisodeListProps {
|
||||
sources?: SourceInfo[];
|
||||
currentSource?: string;
|
||||
onSourceChange?: (source: SourceInfo) => void;
|
||||
// Actual detected resolution for the current source
|
||||
currentResolution?: VideoResolutionInfo | null;
|
||||
}
|
||||
|
||||
export function EpisodeList({
|
||||
@@ -47,6 +50,7 @@ export function EpisodeList({
|
||||
sources,
|
||||
currentSource,
|
||||
onSourceChange,
|
||||
currentResolution,
|
||||
}: EpisodeListProps) {
|
||||
const listRef = useRef<HTMLDivElement>(null);
|
||||
const buttonRefs = useRef<(HTMLButtonElement | null)[]>([]);
|
||||
@@ -228,6 +232,11 @@ export function EpisodeList({
|
||||
<span className="text-sm font-medium text-[var(--text-color)] truncate">
|
||||
{currentSourceInfo?.sourceName || currentSourceInfo?.source || '当前来源'}
|
||||
</span>
|
||||
{currentResolution && (
|
||||
<span className={`inline-flex items-center px-1 py-0 rounded text-[9px] font-bold text-white ${currentResolution.color} flex-shrink-0`}>
|
||||
{currentResolution.label}
|
||||
</span>
|
||||
)}
|
||||
<Badge variant="primary" className="flex-shrink-0">{sources!.length}</Badge>
|
||||
</div>
|
||||
<Icons.ChevronDown
|
||||
@@ -322,6 +331,14 @@ export function EpisodeList({
|
||||
<div className="font-medium text-sm truncate flex items-center gap-1.5">
|
||||
{source.sourceName || source.source}
|
||||
{(() => {
|
||||
// For the current source, prefer actual detected resolution
|
||||
if (isCurrent && currentResolution) {
|
||||
return (
|
||||
<span className={`inline-flex items-center px-1 py-0 rounded text-[9px] font-bold text-white ${currentResolution.color}`}>
|
||||
{currentResolution.label}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
const qb = extractQualityLabel(source.remarks);
|
||||
return qb ? (
|
||||
<span className={`inline-flex items-center px-1 py-0 rounded text-[9px] font-bold text-white ${qb.color}`}>
|
||||
@@ -402,6 +419,14 @@ export function EpisodeList({
|
||||
<div className="font-medium text-sm truncate flex items-center gap-1.5">
|
||||
{source.sourceName || source.source}
|
||||
{(() => {
|
||||
// For the current source, prefer actual detected resolution
|
||||
if (isCurrent && currentResolution) {
|
||||
return (
|
||||
<span className={`inline-flex items-center px-1 py-0 rounded text-[9px] font-bold text-white ${currentResolution.color}`}>
|
||||
{currentResolution.label}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
const qb = extractQualityLabel(source.remarks);
|
||||
return qb ? (
|
||||
<span className={`inline-flex items-center px-1 py-0 rounded text-[9px] font-bold text-white ${qb.color}`}>
|
||||
|
||||
@@ -25,6 +25,8 @@ interface VideoPlayerProps {
|
||||
episodeName?: string;
|
||||
// Expose current time to parent
|
||||
externalTimeRef?: React.MutableRefObject<number>;
|
||||
// Resolution callback
|
||||
onResolutionDetected?: (info: import('./hooks/useVideoResolution').VideoResolutionInfo) => void;
|
||||
}
|
||||
|
||||
export function VideoPlayer({
|
||||
@@ -39,6 +41,7 @@ export function VideoPlayer({
|
||||
videoTitle,
|
||||
episodeName,
|
||||
externalTimeRef,
|
||||
onResolutionDetected,
|
||||
}: VideoPlayerProps) {
|
||||
const [videoError, setVideoError] = useState<string>('');
|
||||
const [useProxy, setUseProxy] = useState(false);
|
||||
@@ -244,6 +247,7 @@ export function VideoPlayer({
|
||||
isReversed={isReversed}
|
||||
videoTitle={videoTitle}
|
||||
episodeName={episodeName}
|
||||
onResolutionDetected={onResolutionDetected}
|
||||
/>
|
||||
)}
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user