/** * EPG Fetching Service * Fetches EPG data from multiple sources with fallback */ import { fetchAndParseXMLTV } from '../parsers/xmltv'; import type { EPGSource, EPGChannel, EPGProgram } from '../types'; /** * Default EPG Sources * iptv-org provides comprehensive international EPG with 30K+ channels * https://github.com/iptv-org/epg */ export const DEFAULT_EPG_SOURCES: EPGSource[] = [ { id: 'iptv-org-global', name: 'IPTV-Org Global EPG', url: 'https://iptv-org.github.io/epg/guides/all.xml.gz', enabled: true, priority: 100, // Low priority - fallback after provider EPG }, ]; /** * Fetch EPG data from a single source */ export async function fetchEPGFromSource( source: EPGSource, proxyUrl?: string ): Promise<{ channels: EPGChannel[]; programs: EPGProgram[] }> { try { const result = await fetchAndParseXMLTV( source.url, source.timezone, proxyUrl ); // Update source with success info source.lastFetch = new Date().toISOString(); delete source.lastError; return result; } catch (error) { // Update source with error info source.lastError = error instanceof Error ? error.message : String(error); throw new Error(`Failed to fetch EPG from ${source.name}: ${error}`); } } /** * Fetch EPG from multiple sources with fallback * Tries sources in priority order until one succeeds */ export async function fetchEPG( sources: EPGSource[] = DEFAULT_EPG_SOURCES, proxyUrl?: string ): Promise<{ channels: EPGChannel[]; programs: EPGProgram[]; source: EPGSource }> { const sortedSources = sources .filter((s) => s.enabled) .sort((a, b) => a.priority - b.priority); if (sortedSources.length === 0) { throw new Error('No enabled EPG sources available'); } const errors: string[] = []; for (const source of sortedSources) { try { const result = await fetchEPGFromSource(source, proxyUrl); return { ...result, source, }; } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); errors.push(`${source.name}: ${errorMsg}`); console.warn(`EPG source ${source.name} failed, trying next...`, error); continue; } } throw new Error(`All EPG sources failed:\n${errors.join('\n')}`); } /** * Fetch EPG for specific channels only (optimization) * This would require EPG sources that support filtering by channel IDs * For now, we fetch all and filter client-side */ export async function fetchEPGForChannels( _channelIds: string[], sources: EPGSource[] = DEFAULT_EPG_SOURCES, proxyUrl?: string ): Promise<{ channels: EPGChannel[]; programs: EPGProgram[]; source: EPGSource }> { // For now, fetch all EPG data // In the future, we could optimize by filtering at source level if supported return fetchEPG(sources, proxyUrl); }