diff --git a/server/routes/proxy.js b/server/routes/proxy.js index 12f6fda..45acecf 100644 --- a/server/routes/proxy.js +++ b/server/routes/proxy.js @@ -317,28 +317,18 @@ router.get('/epg/:sourceId', async (req, res) => { const sourceId = parseInt(req.params.sourceId); const db = getDb(); - // Return channels + programmes - // Frontend EpgGuide.js expects { channels: [], programmes: [] } - // It fetches ALL data. We should support timestamps later. + // Time window: 24 hours ago to 24 hours from now + // This prevents returning millions of rows and crashing the server/browser + const windowStart = Date.now() - (24 * 60 * 60 * 1000); // -24 hours + const windowEnd = Date.now() + (24 * 60 * 60 * 1000); // +24 hours - // EPG Channels (from playlist_items where type='live') - // Ideally we only return channels that HAVE epg data? - // Or just all channels for this source? - // The parser returns `channels` (xmltv channel definitions). - // We didn't strictly store XMLTV channel defs in `epg_programs`. - // We relied on mapping `channel_id` in `epg_programs`. - // Let's return the `playlist_items` as "channels" but mapped to EPG expectations? - // EpgGuide joins on `id === tvgId` or `name === name`. - - // Fetch programs - - - let programsQuery = `SELECT channel_id as channelId, start_time, end_time, title, description, data FROM epg_programs WHERE source_id = ?`; - const params = [sourceId]; - - // Only valid programs? - // programsQuery += ` AND end_time > ?`; - // params.push(Date.now() - 86400000); // last 24h + // Fetch programs within the time window + let programsQuery = ` + SELECT channel_id as channelId, start_time, end_time, title, description, data + FROM epg_programs + WHERE source_id = ? AND end_time > ? AND start_time < ? + `; + const params = [sourceId, windowStart, windowEnd]; const programs = db.prepare(programsQuery).all(...params); diff --git a/server/routes/remux.js b/server/routes/remux.js index 2f0db39..a9e49fa 100644 --- a/server/routes/remux.js +++ b/server/routes/remux.js @@ -40,11 +40,13 @@ router.get('/', (req, res) => { '-reconnect_streamed', '1', '-reconnect_delay_max', '5', '-i', url, + // Map all streams explicitly + '-map', '0', // Copy ALL streams without re-encoding '-c', 'copy', - // Convert AAC from ADTS format (TS) to ASC format (MP4) - // Required when remuxing MPEG-TS with AAC audio to MP4 - '-bsf:a', 'aac_adtstoasc', + // NOTE: We intentionally do NOT use -bsf:a aac_adtstoasc here + // That filter only works for AAC audio and breaks AC3/EAC3/MP3. + // If AAC audio from MPEG-TS fails in MP4, use /api/transcode instead. // Handle timestamp discontinuities at output '-fps_mode', 'passthrough', '-max_muxing_queue_size', '1024', diff --git a/server/services/syncService.js b/server/services/syncService.js index f29592c..2956fe8 100644 --- a/server/services/syncService.js +++ b/server/services/syncService.js @@ -336,13 +336,9 @@ class SyncService { async syncM3u(source) { console.log(`[Sync] Fetching M3U playlist for ${source.name}`); - // Fetch and parse using existing parser - // We use fetch directly here to get the stream/text - const response = await fetch(source.url); - if (!response.ok) throw new Error(`Failed to fetch M3U: ${response.status}`); - - const text = await response.text(); - const { channels, groups } = await m3uParser.parse(text); + // Use the streaming parser directly to avoid loading entire file into memory + // This prevents OOM crashes on large playlists (100MB+) + const { channels, groups } = await m3uParser.fetchAndParse(source.url); console.log(`[Sync] M3U Parsed: ${channels.length} channels, ${groups.length} groups`);