mirror of
https://github.com/KuekHaoYang/KVideo.git
synced 2026-08-21 11:43:41 +08:00
feat: enhance IPTV player with comprehensive controls, improved stream loading robustness, and UI refinements including volume, progress, and fullscreen.
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import { parseM3U, type M3UChannel } from '@/lib/utils/m3u-parser';
|
||||
import { parseM3U, groupChannelsByName, type M3UChannel } from '@/lib/utils/m3u-parser';
|
||||
|
||||
export interface IPTVSource {
|
||||
id: string;
|
||||
@@ -32,7 +32,6 @@ interface IPTVActions {
|
||||
interface IPTVStore extends IPTVState, IPTVActions {}
|
||||
|
||||
const MAX_CONCURRENT = 3;
|
||||
const MAX_CHANNELS = 5000; // Safety limit to prevent UI freeze
|
||||
|
||||
async function fetchWithConcurrencyLimit<T>(
|
||||
tasks: (() => Promise<T>)[],
|
||||
@@ -111,13 +110,11 @@ export const useIPTVStore = create<IPTVStore>()(
|
||||
|
||||
await fetchWithConcurrencyLimit(tasks, MAX_CONCURRENT);
|
||||
|
||||
// Limit total channels for performance
|
||||
const finalChannels = allChannels.length > MAX_CHANNELS
|
||||
? allChannels.slice(0, MAX_CHANNELS)
|
||||
: allChannels;
|
||||
// Group channels with the same name into multi-route entries
|
||||
const grouped = groupChannelsByName(allChannels);
|
||||
|
||||
set({
|
||||
cachedChannels: finalChannels,
|
||||
cachedChannels: grouped,
|
||||
cachedGroups: Array.from(allGroups).sort(),
|
||||
lastRefreshed: Date.now(),
|
||||
isLoading: false,
|
||||
|
||||
@@ -10,6 +10,7 @@ export interface M3UChannel {
|
||||
group?: string;
|
||||
tvgId?: string;
|
||||
tvgName?: string;
|
||||
routes?: string[];
|
||||
}
|
||||
|
||||
export interface M3UPlaylist {
|
||||
@@ -76,3 +77,37 @@ export function parseM3U(content: string): M3UPlaylist {
|
||||
groups: Array.from(groupSet).sort(),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Group channels with the same name into single entries with multiple routes.
|
||||
* This merges duplicate channel names (common in M3U playlists with multiple streams).
|
||||
*/
|
||||
export function groupChannelsByName(channels: M3UChannel[]): M3UChannel[] {
|
||||
const groups = new Map<string, M3UChannel>();
|
||||
|
||||
for (const ch of channels) {
|
||||
const key = ch.name.toLowerCase().trim();
|
||||
const existing = groups.get(key);
|
||||
if (existing) {
|
||||
if (!existing.routes) {
|
||||
existing.routes = [existing.url];
|
||||
}
|
||||
if (!existing.routes.includes(ch.url)) {
|
||||
existing.routes.push(ch.url);
|
||||
}
|
||||
// Use first logo found
|
||||
if (!existing.logo && ch.logo) existing.logo = ch.logo;
|
||||
} else {
|
||||
groups.set(key, { ...ch });
|
||||
}
|
||||
}
|
||||
|
||||
// Only add routes array when there are multiple routes
|
||||
const result = Array.from(groups.values());
|
||||
for (const ch of result) {
|
||||
if (ch.routes && ch.routes.length <= 1) {
|
||||
delete ch.routes;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user