From d46bb6807e3a1b599ceebca7e4a1a23da95bab31 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 17:02:24 +0000 Subject: [PATCH 1/5] Initial plan From f8f0fd3fe106db16861d0b772c818a5177e8bdea Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 17:05:10 +0000 Subject: [PATCH 2/5] feat: capture upstream segment PDT and write atomic pdt file Agent-Logs-Url: https://github.com/paul-1/plugin-SiriusXM/sessions/25d4d8bf-217c-4941-a1a6-967bebfa9a09 Co-authored-by: paul-1 <6473457+paul-1@users.noreply.github.com> --- Plugins/SiriusXM/Bin/sxm.pl | 53 ++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/Plugins/SiriusXM/Bin/sxm.pl b/Plugins/SiriusXM/Bin/sxm.pl index 3cf7086..d496515 100755 --- a/Plugins/SiriusXM/Bin/sxm.pl +++ b/Plugins/SiriusXM/Bin/sxm.pl @@ -429,6 +429,7 @@ sub new { channel_cookies => {}, # Store per-channel cookie jars segment_cache => {}, # Store cached segments per channel_id segment_queue => {}, # Track segments to be cached per channel_id + segment_pdt => {}, # Track upstream #EXT-X-PROGRAM-DATE-TIME per segment (per channel_id) segment_retry_count => {}, # Track consecutive fetch failures per segment (per channel) last_segment => {}, # Track last requested segment per channel_id playlist_cache => {}, # Store cached m3u8 content per channel_id @@ -1924,15 +1925,21 @@ sub extract_segments_from_playlist { my @lines = split /\r?\n/, $content; my @segments = (); my $expecting_uri = 0; + my $current_pdt; for my $line (@lines) { $line =~ s/^\s+|\s+$//g; next if $line eq ''; - if ($line =~ /^#EXTINF:/) { + if ($line =~ /^#EXT-X-PROGRAM-DATE-TIME:(.+)$/) { + $current_pdt = $1; + } elsif ($line =~ /^#EXTINF:/) { $expecting_uri = 1; } elsif ($expecting_uri && $line !~ /^#/ && $line =~ /\.aac/) { push @segments, $line; + if (defined $current_pdt && !exists $self->{segment_pdt}->{$channel_id}->{$line}) { + $self->{segment_pdt}->{$channel_id}->{$line} = $current_pdt; + } $expecting_uri = 0; } } @@ -2173,6 +2180,7 @@ sub get_cached_segment { # Track this as the last requested segment for this channel $self->{last_segment}->{$channel_id} = $segment_path; + $self->write_segment_pdt_file($channel_id, $segment_path); # Check if caching is enabled my $caching_enabled = $CONFIG{segment_drop} >= 1; @@ -2210,6 +2218,48 @@ sub get_cached_segment { return $data; } +# Write the upstream PDT for the requested segment to cache_dir/pdt_.txt +sub write_segment_pdt_file { + my ($self, $channel_id, $segment_path) = @_; + + my $segment_pdt = $self->{segment_pdt}->{$channel_id}->{$segment_path}; + if (!defined $segment_pdt || $segment_pdt eq '') { + main::log_trace("No upstream PDT recorded for segment $segment_path on channel $channel_id"); + return; + } + + my $cookiefile = $main::CONFIG{cookiefile}; + if (!$cookiefile) { + main::log_debug("Cookie file not configured; skipping PDT file update for channel $channel_id"); + return; + } + + my $cache_dir = dirname($cookiefile); + if (!$cache_dir) { + main::log_debug("Could not determine cache directory; skipping PDT file update for channel $channel_id"); + return; + } + + my $tmp_file = File::Spec->catfile($cache_dir, "pdt_${channel_id}.txt.tmp"); + my $pdt_file = File::Spec->catfile($cache_dir, "pdt_${channel_id}.txt"); + + eval { + open(my $fh, '>', $tmp_file) or die "Cannot open temp PDT file: $!"; + print $fh $segment_pdt . "\n"; + close($fh) or die "Cannot close temp PDT file: $!"; + + rename($tmp_file, $pdt_file) or die "Cannot rename PDT file: $!"; + 1; + } or do { + my $err = $@ || 'unknown error'; + unlink($tmp_file) if -e $tmp_file; + main::log_debug("Failed writing PDT file for channel $channel_id: $err"); + return; + }; + + main::log_trace("Updated PDT file for channel $channel_id"); +} + sub select_quality_variant { my ($self, $master_playlist, $base_url, $quality, $channel_id) = @_; @@ -2955,6 +3005,7 @@ sub clear_channel_cache { # Clear segment cache and queue delete $self->{segment_cache}->{$channel_id}; delete $self->{segment_queue}->{$channel_id}; + delete $self->{segment_pdt}->{$channel_id}; delete $self->{segment_retry_count}->{$channel_id}; delete $self->{last_segment}->{$channel_id}; From bf85f075de19b678f260ff5ed830c57c1d0eb273 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 17:27:37 +0000 Subject: [PATCH 3/5] fix: remove channel pdt file on clear and skip redundant pdt writes Agent-Logs-Url: https://github.com/paul-1/plugin-SiriusXM/sessions/cdc43f7f-912c-48c8-b249-3f8497366925 Co-authored-by: paul-1 <6473457+paul-1@users.noreply.github.com> --- Plugins/SiriusXM/Bin/sxm.pl | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Plugins/SiriusXM/Bin/sxm.pl b/Plugins/SiriusXM/Bin/sxm.pl index 62e8dc6..4780ed9 100755 --- a/Plugins/SiriusXM/Bin/sxm.pl +++ b/Plugins/SiriusXM/Bin/sxm.pl @@ -430,6 +430,7 @@ sub new { segment_cache => {}, # Store cached segments per channel_id segment_queue => {}, # Track segments to be cached per channel_id segment_pdt => {}, # Track upstream #EXT-X-PROGRAM-DATE-TIME per segment (per channel_id) + last_written_segment_pdt => {}, # Last PDT written to disk per channel_id (to avoid redundant writes) segment_retry_count => {}, # Track consecutive fetch failures per segment (per channel) last_segment => {}, # Track last requested segment per channel_id playlist_cache => {}, # Store cached m3u8 content per channel_id @@ -2243,12 +2244,20 @@ sub write_segment_pdt_file { my $tmp_file = File::Spec->catfile($cache_dir, "pdt_${channel_id}.txt.tmp"); my $pdt_file = File::Spec->catfile($cache_dir, "pdt_${channel_id}.txt"); + if (defined $self->{last_written_segment_pdt}->{$channel_id} + && $self->{last_written_segment_pdt}->{$channel_id} eq $segment_pdt + && -e $pdt_file) { + main::log_trace("PDT unchanged for channel $channel_id; skipping file write"); + return; + } + eval { open(my $fh, '>', $tmp_file) or die "Cannot open temp PDT file: $!"; print $fh $segment_pdt . "\n"; close($fh) or die "Cannot close temp PDT file: $!"; rename($tmp_file, $pdt_file) or die "Cannot rename PDT file: $!"; + $self->{last_written_segment_pdt}->{$channel_id} = $segment_pdt; 1; } or do { my $err = $@ || 'unknown error'; @@ -3006,8 +3015,20 @@ sub clear_channel_cache { delete $self->{segment_cache}->{$channel_id}; delete $self->{segment_queue}->{$channel_id}; delete $self->{segment_pdt}->{$channel_id}; + delete $self->{last_written_segment_pdt}->{$channel_id}; delete $self->{segment_retry_count}->{$channel_id}; delete $self->{last_segment}->{$channel_id}; + + # Remove persisted PDT file for this channel from cache dir + if ($main::CONFIG{cookiefile}) { + my $cache_dir = dirname($main::CONFIG{cookiefile}); + if ($cache_dir) { + my $pdt_file = File::Spec->catfile($cache_dir, "pdt_${channel_id}.txt"); + my $pdt_tmp_file = File::Spec->catfile($cache_dir, "pdt_${channel_id}.txt.tmp"); + unlink($pdt_file) if -e $pdt_file; + unlink($pdt_tmp_file) if -e $pdt_tmp_file; + } + } # Clear activity tracking delete $self->{channel_last_activity}->{$channel_id}; From c31b47755ae87c0a09174a0da5709699b27477ea Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 17:33:36 +0000 Subject: [PATCH 4/5] fix: move pdt files to TMPDIR siriusxm path Agent-Logs-Url: https://github.com/paul-1/plugin-SiriusXM/sessions/22899720-e844-4291-8103-b37bd75fc26e Co-authored-by: paul-1 <6473457+paul-1@users.noreply.github.com> --- Plugins/SiriusXM/Bin/sxm.pl | 44 ++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/Plugins/SiriusXM/Bin/sxm.pl b/Plugins/SiriusXM/Bin/sxm.pl index 4780ed9..1f966bd 100755 --- a/Plugins/SiriusXM/Bin/sxm.pl +++ b/Plugins/SiriusXM/Bin/sxm.pl @@ -2219,7 +2219,7 @@ sub get_cached_segment { return $data; } -# Write the upstream PDT for the requested segment to cache_dir/pdt_.txt +# Write the upstream PDT for the requested segment to $TMPDIR/siriusxm/pdt_.txt sub write_segment_pdt_file { my ($self, $channel_id, $segment_path) = @_; @@ -2229,20 +2229,21 @@ sub write_segment_pdt_file { return; } - my $cookiefile = $main::CONFIG{cookiefile}; - if (!$cookiefile) { - main::log_debug("Cookie file not configured; skipping PDT file update for channel $channel_id"); - return; - } - - my $cache_dir = dirname($cookiefile); - if (!$cache_dir) { - main::log_debug("Could not determine cache directory; skipping PDT file update for channel $channel_id"); - return; + my $tmp_dir = $ENV{TMPDIR} || $ENV{TEMP} || '/tmp'; + my $pdt_dir = File::Spec->catdir($tmp_dir, 'siriusxm'); + if (!-d $pdt_dir) { + eval { + make_path($pdt_dir, { mode => 0755 }); + 1; + } or do { + my $err = $@ || 'unknown error'; + main::log_debug("Could not create PDT directory $pdt_dir for channel $channel_id: $err"); + return; + }; } - my $tmp_file = File::Spec->catfile($cache_dir, "pdt_${channel_id}.txt.tmp"); - my $pdt_file = File::Spec->catfile($cache_dir, "pdt_${channel_id}.txt"); + my $tmp_file = File::Spec->catfile($pdt_dir, "pdt_${channel_id}.txt.tmp"); + my $pdt_file = File::Spec->catfile($pdt_dir, "pdt_${channel_id}.txt"); if (defined $self->{last_written_segment_pdt}->{$channel_id} && $self->{last_written_segment_pdt}->{$channel_id} eq $segment_pdt @@ -3019,15 +3020,14 @@ sub clear_channel_cache { delete $self->{segment_retry_count}->{$channel_id}; delete $self->{last_segment}->{$channel_id}; - # Remove persisted PDT file for this channel from cache dir - if ($main::CONFIG{cookiefile}) { - my $cache_dir = dirname($main::CONFIG{cookiefile}); - if ($cache_dir) { - my $pdt_file = File::Spec->catfile($cache_dir, "pdt_${channel_id}.txt"); - my $pdt_tmp_file = File::Spec->catfile($cache_dir, "pdt_${channel_id}.txt.tmp"); - unlink($pdt_file) if -e $pdt_file; - unlink($pdt_tmp_file) if -e $pdt_tmp_file; - } + # Remove persisted PDT files for this channel from $TMPDIR/siriusxm + my $tmp_dir = $ENV{TMPDIR} || $ENV{TEMP} || '/tmp'; + my $pdt_dir = File::Spec->catdir($tmp_dir, 'siriusxm'); + if (-d $pdt_dir) { + my $pdt_file = File::Spec->catfile($pdt_dir, "pdt_${channel_id}.txt"); + my $pdt_tmp_file = File::Spec->catfile($pdt_dir, "pdt_${channel_id}.txt.tmp"); + unlink($pdt_file) if -e $pdt_file; + unlink($pdt_tmp_file) if -e $pdt_tmp_file; } # Clear activity tracking From cabadac7293db3d5d89e950dfb3c4fc27b618cec Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 17:43:04 +0000 Subject: [PATCH 5/5] fix: call File::Path::make_path in SiriusXM package Agent-Logs-Url: https://github.com/paul-1/plugin-SiriusXM/sessions/eb983754-bc68-4c03-8a49-6322b34df90f Co-authored-by: paul-1 <6473457+paul-1@users.noreply.github.com> --- Plugins/SiriusXM/Bin/sxm.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/SiriusXM/Bin/sxm.pl b/Plugins/SiriusXM/Bin/sxm.pl index 1f966bd..84d074d 100755 --- a/Plugins/SiriusXM/Bin/sxm.pl +++ b/Plugins/SiriusXM/Bin/sxm.pl @@ -2233,7 +2233,7 @@ sub write_segment_pdt_file { my $pdt_dir = File::Spec->catdir($tmp_dir, 'siriusxm'); if (!-d $pdt_dir) { eval { - make_path($pdt_dir, { mode => 0755 }); + File::Path::make_path($pdt_dir, { mode => 0755 }); 1; } or do { my $err = $@ || 'unknown error';