@@ -18,6 +18,9 @@ my $cache = Slim::Utils::Cache->new();
1818# Cache timeout in seconds
1919use constant CACHE_TIMEOUT => 86400; # 24 hours (1 day)
2020
21+ # Track in-flight channel requests to prevent concurrent calls
22+ my %channel_fetch_callbacks = ();
23+
2124sub init {
2225 my $class = shift ;
2326 $log -> debug(" Initializing SiriusXM API" );
@@ -29,14 +32,18 @@ sub cleanup {
2932 # Clear any cached data
3033 $cache -> remove(' siriusxm_channels' );
3134 $cache -> remove(' siriusxm_channel_info' );
35+ $cache -> remove(' siriusxm_processed_channels' );
3236 $cache -> remove(' siriusxm_auth_token' );
37+ # Clear any pending callbacks
38+ %channel_fetch_callbacks = ();
3339}
3440
3541sub invalidateChannelCache {
3642 my $class = shift ;
3743 $log -> info(" Invalidating channel cache due to playback failure" );
3844 $cache -> remove(' siriusxm_channels' );
3945 $cache -> remove(' siriusxm_channel_info' );
46+ $cache -> remove(' siriusxm_processed_channels' );
4047}
4148
4249=begin comment
@@ -208,6 +215,27 @@ sub getChannels {
208215 return ;
209216 }
210217
218+ # Check if we have completely processed channel data in cache
219+ # This includes both proxy data and station mappings
220+ my $cached_processed = $cache -> get(' siriusxm_processed_channels' );
221+ if ($cached_processed ) {
222+ $log -> debug(" Using cached processed channel data" );
223+ my $menu_items = $class -> buildCategoryMenu($cached_processed );
224+ $cache -> set(' siriusxm_channels' , $menu_items , CACHE_TIMEOUT);
225+ $cb -> ($menu_items );
226+ return ;
227+ }
228+
229+ # Check if we're already fetching channels
230+ if (exists $channel_fetch_callbacks {' in_progress' }) {
231+ $log -> debug(" Channel fetch already in progress, queuing callback" );
232+ push @{$channel_fetch_callbacks {' in_progress' }}, $cb if $cb ;
233+ return ;
234+ }
235+
236+ # Initialize the callback queue
237+ $channel_fetch_callbacks {' in_progress' } = $cb ? [$cb ] : [];
238+
211239 my $port = $prefs -> get(' port' ) || ' 9999' ;
212240 my $url = " http://localhost:$port /channel/all" ;
213241
@@ -228,31 +256,52 @@ sub getChannels {
228256
229257 if ($@ ) {
230258 $log -> error(" Failed to parse channel data from proxy: $@ " );
231- $cb -> ([]);
259+ # Call all queued callbacks with empty result
260+ for my $callback (@{$channel_fetch_callbacks {' in_progress' } || []}) {
261+ $callback -> ([]) if $callback ;
262+ }
263+ delete $channel_fetch_callbacks {' in_progress' };
232264 return ;
233265 }
234266
235267 # Process and organize channels by category
236- my $categories = $class -> processChannelData($channels_data );
237-
238- # Build hierarchical menu structure
239- my $menu_items = $class -> buildCategoryMenu($categories );
240-
241- # Cache both the menu structure and the processed channel data separately
242- $cache -> set(' siriusxm_channels' , $menu_items , CACHE_TIMEOUT);
243- $cache -> set(' siriusxm_channel_info' , $categories , CACHE_TIMEOUT);
244-
245- $log -> info(" Retrieved and processed channels into menu structure" );
246- $cb -> ($menu_items );
268+ # First fetch station listings from xmplaylist.com for accurate mappings
269+ Plugins::SiriusXM::APImetadata-> fetchStationListings(sub {
270+ my $station_lookup = shift || {};
271+ my $categories = $class -> processChannelData($channels_data , $station_lookup );
272+
273+ # Cache the completely processed channel data with station mappings
274+ $cache -> set(' siriusxm_processed_channels' , $categories , CACHE_TIMEOUT);
275+
276+ # Build hierarchical menu structure
277+ my $menu_items = $class -> buildCategoryMenu($categories );
278+
279+ # Cache the menu structure
280+ $cache -> set(' siriusxm_channels' , $menu_items , CACHE_TIMEOUT);
281+ $cache -> set(' siriusxm_channel_info' , $categories , CACHE_TIMEOUT);
282+
283+ $log -> info(" Retrieved and processed channels into menu structure" );
284+
285+ # Call all queued callbacks with the result
286+ for my $callback (@{$channel_fetch_callbacks {' in_progress' } || []}) {
287+ $callback -> ($menu_items ) if $callback ;
288+ }
289+ delete $channel_fetch_callbacks {' in_progress' };
290+ });
247291 },
248292 sub {
249293 my ($http , $error ) = @_ ;
250294 $log -> error(" Failed to fetch channels from proxy: $error " );
251295
252296 # Invalidate cache since proxy communication failed
253297 $cache -> remove(' siriusxm_channels' );
298+ $cache -> remove(' siriusxm_processed_channels' );
254299
255- $cb -> ([]);
300+ # Call all queued callbacks with empty result
301+ for my $callback (@{$channel_fetch_callbacks {' in_progress' } || []}) {
302+ $callback -> ([]) if $callback ;
303+ }
304+ delete $channel_fetch_callbacks {' in_progress' };
256305 },
257306 {
258307 timeout => 30,
@@ -413,18 +462,28 @@ sub normalizeChannelName {
413462
414463
415464sub processChannelData {
416- my ($class , $raw_channels ) = @_ ;
465+ my ($class , $raw_channels , $station_lookup ) = @_ ;
417466
418467 return [] unless $raw_channels && ref ($raw_channels ) eq ' ARRAY' ;
419468
469+ $station_lookup ||= {}; # Default to empty hash if not provided
420470 my %categories = ();
421471
422472 # Process channels and organize by primary category
423473 for my $channel (@$raw_channels ) {
424474 next unless $channel -> {channelId } && $channel -> {name };
425475
426476 my $channel_name = $channel -> {name };
427- my $xmp_name = $class -> normalizeChannelName($channel_name );
477+ my $sirius_number = $channel -> {siriusChannelNumber } || $channel -> {channelNumber } || ' ' ;
478+
479+ # Get xmplaylist name from station lookup if available
480+ my $xmp_name ;
481+ if ($sirius_number && $station_lookup -> {$sirius_number }) {
482+ $xmp_name = $station_lookup -> {$sirius_number };
483+ $log -> debug(" Using xmplaylist deeplink for channel $sirius_number : $xmp_name " );
484+ } else {
485+ $log -> debug(" No xmplaylist metadata available for channel $sirius_number ($channel_name ), will use channel artwork" );
486+ }
428487
429488 # Find the primary category
430489 my $primary_category = ' Other' ; # Default fallback
@@ -516,7 +575,16 @@ sub getChannelsSortedByNumber {
516575
517576 $log -> debug(" Getting channels sorted by channel number" );
518577
519- # Check cache first
578+ # Check cache first for the processed data
579+ my $cached_processed = $cache -> get(' siriusxm_processed_channels' );
580+ if ($cached_processed ) {
581+ $log -> debug(" Building channel list from cached processed data" );
582+ my $sorted_channels = $class -> buildChannelNumberMenu($cached_processed );
583+ $cb -> ($sorted_channels );
584+ return ;
585+ }
586+
587+ # Check legacy cache for backward compatibility
520588 my $cached_channel_info = $cache -> get(' siriusxm_channel_info' );
521589 if ($cached_channel_info ) {
522590 $log -> debug(" Building channel list from cached data" );
@@ -529,8 +597,8 @@ sub getChannelsSortedByNumber {
529597 $class -> getChannels($client , sub {
530598 my $category_menu = shift ;
531599
532- # Get the channel info from cache (which should be populated by getChannels)
533- my $channel_info = $cache -> get(' siriusxm_channel_info' );
600+ # Get the processed channel info from cache (which should be populated by getChannels)
601+ my $channel_info = $cache -> get(' siriusxm_processed_channels ' ) || $cache -> get( ' siriusxm_channel_info' );
534602 if ($channel_info ) {
535603 my $sorted_channels = $class -> buildChannelNumberMenu($channel_info );
536604 $cb -> ($sorted_channels );
0 commit comments