@@ -249,49 +249,57 @@ private function generate($playlist)
249249 // Get programmes from cache for date range
250250 $ cachedProgrammes = $ cacheService ->getCachedProgrammesRange ($ epg , $ startDate , $ endDate , $ epgChannelIds );
251251
252- // Output programmes from cache
253- foreach ($ cachedProgrammes as $ channelId => $ programmes ) {
254- foreach ($ programmes as $ programme ) {
255- // Find matching channels for this EPG channel ID
256- $ filtered = array_filter ($ channels , fn ($ ch ) => array_key_exists ($ channelId , $ ch ));
257- if (!count ($ filtered )) {
258- continue ;
252+ // Pre-build channel mapping index for O(1) lookups
253+ $ channelMapping = [];
254+ foreach ($ channels as $ channelMap ) {
255+ foreach ($ channelMap as $ epgChannelId => $ mappedId ) {
256+ if (!isset ($ channelMapping [$ epgChannelId ])) {
257+ $ channelMapping [$ epgChannelId ] = [];
259258 }
259+ $ channelMapping [$ epgChannelId ][] = $ mappedId ;
260+ }
261+ }
260262
261- foreach ($ filtered as $ ch ) {
262- $ mappedChannelId = $ ch [$ channelId ];
263+ // Output programmes from cache
264+ foreach ($ cachedProgrammes as $ channelId => $ programmes ) {
265+ // Skip if no mapping for this channel
266+ if (!isset ($ channelMapping [$ channelId ])) {
267+ continue ;
268+ }
263269
264- // Format times for XMLTV
265- $ start = $ this ->formatXmltvDateTime ($ programme ['start ' ]);
266- $ stop = $ this ->formatXmltvDateTime ($ programme ['stop ' ]);
270+ foreach ($ programmes as $ programme ) {
271+ // Format times once per programme (not per channel mapping)
272+ $ start = $ this ->formatXmltvDateTime ($ programme ['start ' ]);
273+ $ stop = $ this ->formatXmltvDateTime ($ programme ['stop ' ]);
267274
268- // Output programme tag
269- echo ' <programme channel=" ' . htmlspecialchars ($ mappedChannelId ) . '" ' ;
270- if ($ start ) echo ' start=" ' . $ start . '" ' ;
271- if ($ stop ) echo ' stop=" ' . $ stop . '" ' ;
272- echo '> ' . PHP_EOL ;
275+ foreach ($ channelMapping [$ channelId ] as $ mappedChannelId ) {
276+ // Build programme XML in buffer for batch output
277+ $ progXml = ' <programme channel=" ' . htmlspecialchars ($ mappedChannelId ) . '" ' ;
278+ if ($ start ) $ progXml .= ' start=" ' . $ start . '" ' ;
279+ if ($ stop ) $ progXml .= ' stop=" ' . $ stop . '" ' ;
280+ $ progXml .= '> ' . PHP_EOL ;
273281
274282 if ($ programme ['title ' ]) {
275- echo ' <title> ' . htmlspecialchars ($ programme ['title ' ]) . '</title> ' . PHP_EOL ;
283+ $ progXml .= ' <title> ' . htmlspecialchars ($ programme ['title ' ]) . '</title> ' . PHP_EOL ;
276284 }
277285 if ($ programme ['subtitle ' ]) {
278- echo ' <sub-title> ' . htmlspecialchars ($ programme ['subtitle ' ]) . '</sub-title> ' . PHP_EOL ;
286+ $ progXml .= ' <sub-title> ' . htmlspecialchars ($ programme ['subtitle ' ]) . '</sub-title> ' . PHP_EOL ;
279287 }
280288 if ($ programme ['desc ' ]) {
281- echo ' <desc> ' . htmlspecialchars ($ programme ['desc ' ]) . '</desc> ' . PHP_EOL ;
289+ $ progXml .= ' <desc> ' . htmlspecialchars ($ programme ['desc ' ]) . '</desc> ' . PHP_EOL ;
282290 }
283291 if ($ programme ['category ' ]) {
284- echo ' <category> ' . htmlspecialchars ($ programme ['category ' ]) . '</category> ' . PHP_EOL ;
292+ $ progXml .= ' <category> ' . htmlspecialchars ($ programme ['category ' ]) . '</category> ' . PHP_EOL ;
285293 }
286294 if ($ programme ['episode_num ' ]) {
287- echo ' <episode-num system="xmltv_ns"> ' . htmlspecialchars ($ programme ['episode_num ' ]) . '</episode-num> ' . PHP_EOL ;
295+ $ progXml .= ' <episode-num system="xmltv_ns"> ' . htmlspecialchars ($ programme ['episode_num ' ]) . '</episode-num> ' . PHP_EOL ;
288296 }
289297 if ($ programme ['icon ' ]) {
290298 $ icon = htmlspecialchars ($ programme ['icon ' ]);
291299 if ($ logoProxyEnabled ) {
292300 $ icon = LogoProxyController::generateProxyUrl ($ icon );
293301 }
294- echo ' <icon src=" ' . $ icon . '"/> ' . PHP_EOL ;
302+ $ progXml .= ' <icon src=" ' . $ icon . '"/> ' . PHP_EOL ;
295303 }
296304 // Program artwork images (NEW)
297305 if (!empty ($ programme ['images ' ] ?? null ) && is_array ($ programme ['images ' ])) {
@@ -308,17 +316,18 @@ private function generate($playlist)
308316 $ orient = htmlspecialchars ($ image ['orient ' ], ENT_XML1 );
309317 $ size = htmlspecialchars ($ image ['size ' ], ENT_XML1 );
310318
311- echo " <icon src= \"{$ url }\" type= \"{$ type }\" width= \"{$ width }\" height= \"{$ height }\" orient= \"{$ orient }\" size= \"{$ size }\" /> \n" ;
319+ $ progXml .= " <icon src= \"{$ url }\" type= \"{$ type }\" width= \"{$ width }\" height= \"{$ height }\" orient= \"{$ orient }\" size= \"{$ size }\" /> \n" ;
312320 }
313321 }
314322 if ($ programme ['rating ' ]) {
315- echo ' <rating><value> ' . htmlspecialchars ($ programme ['rating ' ]) . '</value></rating> ' . PHP_EOL ;
323+ $ progXml .= ' <rating><value> ' . htmlspecialchars ($ programme ['rating ' ]) . '</value></rating> ' . PHP_EOL ;
316324 }
317325 if (!empty ($ programme ['new ' ]) && $ programme ['new ' ]) {
318- echo ' <new /> ' . PHP_EOL ;
326+ $ progXml .= ' <new /> ' . PHP_EOL ;
319327 }
320328
321- echo ' </programme> ' . PHP_EOL ;
329+ $ progXml .= ' </programme> ' . PHP_EOL ;
330+ echo $ progXml ;
322331 }
323332 }
324333 }
@@ -334,41 +343,43 @@ private function generate($playlist)
334343
335344 // If dummy EPG channels, generate dummy programmes
336345 if (count ($ dummyEpgChannels ) > 0 ) {
346+ // Pre-calculate all time slots once (major optimization)
347+ $ timeSlots = [];
348+ $ startTime = Carbon::now ()->startOf ('day ' )->subMinutes ($ dummyEpgLength );
349+ $ iterations = (int )((5 * 24 * 60 ) / $ dummyEpgLength );
350+
351+ for ($ i = 0 ; $ i < $ iterations ; $ i ++) {
352+ $ startTime ->addMinutes ($ dummyEpgLength );
353+ $ timeSlots [] = [
354+ 'start ' => str_replace (': ' , '' , $ startTime ->format ('YmdHis P ' )),
355+ 'end ' => str_replace (': ' , '' , $ startTime ->copy ()->addMinutes ($ dummyEpgLength )->format ('YmdHis P ' ))
356+ ];
357+ }
358+
359+ // Generate programmes for each channel using pre-calculated time slots
337360 foreach ($ dummyEpgChannels as $ dummyEpgChannel ) {
338361 $ tvgId = $ dummyEpgChannel ['tvg_id ' ];
339362 $ title = $ dummyEpgChannel ['title ' ];
340363 $ icon = $ dummyEpgChannel ['icon ' ];
341- $ channelNo = $ dummyEpgChannel ['channel_no ' ];
342364 $ group = $ dummyEpgChannel ['group ' ];
343365 $ includeCategory = $ dummyEpgChannel ['include_category ' ];
344366
345- // Generate dummy programmes for the specified length
346- $ startTime = Carbon::now ()
347- ->startOf ('day ' )
348- ->subMinutes ($ dummyEpgLength );
349-
350- // Generate 5 days worth of EPG data, based on the `$dummyEpgLength`, which is how long the programme should last in minutes
351- for ($ i = 0 ; $ i < (5 * 24 * 60 ) / $ dummyEpgLength ; $ i ++) {
352- $ startTime ->addMinutes ($ dummyEpgLength );
353- $ endTime = clone $ startTime ;
354- $ endTime ->addMinutes ($ dummyEpgLength );
355-
356- // Format the start and end times
357- $ start = str_replace (': ' , '' , $ startTime ->format ('YmdHis P ' ));
358- $ end = str_replace (': ' , '' , $ endTime ->format ('YmdHis P ' ));
359-
360- // Output the <programme> tag
361- echo ' <programme channel=" ' . $ tvgId . '" start=" ' . $ start . '" stop=" ' . $ end . '"> ' . PHP_EOL ;
362- echo ' <title> ' . $ title . '</title> ' . PHP_EOL ;
367+ // Build all programmes for this channel in one string buffer
368+ $ buffer = '' ;
369+ foreach ($ timeSlots as $ slot ) {
370+ $ buffer .= ' <programme channel=" ' . $ tvgId . '" start=" ' . $ slot ['start ' ] . '" stop=" ' . $ slot ['end ' ] . '"> ' . PHP_EOL ;
371+ $ buffer .= ' <title> ' . $ title . '</title> ' . PHP_EOL ;
363372 if ($ icon ) {
364- echo ' <icon src=" ' . $ icon . '"/> ' . PHP_EOL ;
373+ $ buffer .= ' <icon src=" ' . $ icon . '"/> ' . PHP_EOL ;
365374 }
366- echo ' <desc> ' . $ title . '</desc> ' . PHP_EOL ;
375+ $ buffer .= ' <desc> ' . $ title . '</desc> ' . PHP_EOL ;
367376 if ($ includeCategory ) {
368- echo ' <category lang="en"> ' . $ group . '</category> ' . PHP_EOL ;
377+ $ buffer .= ' <category lang="en"> ' . $ group . '</category> ' . PHP_EOL ;
369378 }
370- echo ' </programme> ' . PHP_EOL ;
379+ $ buffer .= ' </programme> ' . PHP_EOL ;
371380 }
381+ // Single echo per channel instead of 600+ echoes
382+ echo $ buffer ;
372383 }
373384 }
374385
0 commit comments