mirror of
https://github.com/KuekHaoYang/KVideo.git
synced 2026-08-18 10:13:43 +08:00
feat: Implement language filtering and display language information across video components.
This commit is contained in:
@@ -73,6 +73,7 @@ export async function getVideoDetail(
|
||||
vod_director: videoData.vod_director,
|
||||
vod_content: videoData.vod_content,
|
||||
type_name: videoData.type_name,
|
||||
vod_lang: videoData.vod_lang,
|
||||
episodes,
|
||||
source: source.id,
|
||||
source_code: playFrom[selectedIndex] || '',
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect, useMemo, useCallback } from 'react';
|
||||
import type { LanguageBadge } from '@/lib/types';
|
||||
|
||||
/**
|
||||
* Custom hook to collect and filter by vod_lang values from video results
|
||||
* Mirrors useTypeBadges pattern
|
||||
*/
|
||||
export function useLanguageBadges<T extends { vod_lang?: string }>(videos: T[]) {
|
||||
const [selectedLangs, setSelectedLangs] = useState<Set<string>>(new Set());
|
||||
|
||||
// Collect and count language badges from videos
|
||||
const languageBadges = useMemo<LanguageBadge[]>(() => {
|
||||
const langMap = new Map<string, number>();
|
||||
|
||||
videos.forEach(video => {
|
||||
if (video.vod_lang && video.vod_lang.trim()) {
|
||||
const lang = video.vod_lang.trim();
|
||||
langMap.set(lang, (langMap.get(lang) || 0) + 1);
|
||||
}
|
||||
});
|
||||
|
||||
return Array.from(langMap.entries())
|
||||
.map(([lang, count]) => ({ lang, count }))
|
||||
.sort((a, b) => b.count - a.count);
|
||||
}, [videos]);
|
||||
|
||||
// Filter videos by selected languages
|
||||
const filteredVideos = useMemo(() => {
|
||||
if (selectedLangs.size === 0) {
|
||||
return videos;
|
||||
}
|
||||
|
||||
return videos.filter(video =>
|
||||
video.vod_lang && selectedLangs.has(video.vod_lang.trim())
|
||||
);
|
||||
}, [videos, selectedLangs]);
|
||||
|
||||
// Toggle language selection
|
||||
const toggleLang = useCallback((lang: string) => {
|
||||
setSelectedLangs(prev => {
|
||||
const newSet = new Set(prev);
|
||||
if (newSet.has(lang)) {
|
||||
newSet.delete(lang);
|
||||
} else {
|
||||
newSet.add(lang);
|
||||
}
|
||||
return newSet;
|
||||
});
|
||||
}, []);
|
||||
|
||||
// Auto-cleanup: remove selected langs that no longer exist in badges
|
||||
useEffect(() => {
|
||||
const availableLangs = new Set(languageBadges.map(b => b.lang));
|
||||
|
||||
setSelectedLangs(prev => {
|
||||
const filtered = new Set(
|
||||
Array.from(prev).filter(lang => availableLangs.has(lang))
|
||||
);
|
||||
|
||||
if (filtered.size !== prev.size) {
|
||||
return filtered;
|
||||
}
|
||||
return prev;
|
||||
});
|
||||
}, [languageBadges]);
|
||||
|
||||
return {
|
||||
languageBadges,
|
||||
selectedLangs,
|
||||
filteredVideos,
|
||||
toggleLang,
|
||||
};
|
||||
}
|
||||
@@ -36,6 +36,7 @@ export interface VideoItem {
|
||||
vod_actor?: string;
|
||||
vod_director?: string;
|
||||
vod_content?: string;
|
||||
vod_lang?: string;
|
||||
source: string;
|
||||
latency?: number; // Response time in milliseconds
|
||||
}
|
||||
@@ -57,6 +58,11 @@ export interface TypeBadge {
|
||||
count: number;
|
||||
}
|
||||
|
||||
export interface LanguageBadge {
|
||||
lang: string;
|
||||
count: number;
|
||||
}
|
||||
|
||||
// Episode Information
|
||||
export interface Episode {
|
||||
name: string;
|
||||
@@ -76,6 +82,7 @@ export interface VideoDetail {
|
||||
vod_director?: string;
|
||||
vod_content?: string;
|
||||
type_name?: string;
|
||||
vod_lang?: string;
|
||||
episodes: Episode[];
|
||||
source: string;
|
||||
source_code: string;
|
||||
@@ -134,6 +141,7 @@ export interface ApiDetailResponse {
|
||||
vod_director?: string;
|
||||
vod_content?: string;
|
||||
type_name?: string;
|
||||
vod_lang?: string;
|
||||
vod_play_from?: string;
|
||||
vod_play_url?: string;
|
||||
}>;
|
||||
|
||||
Reference in New Issue
Block a user