From 1b7a3e8113793f6de24e3e7f27f8eab7684165df Mon Sep 17 00:00:00 2001 From: Storm Dragon Date: Sat, 26 Jul 2025 10:16:43 -0400 Subject: [PATCH] Fixed a bug with id comparison. --- ttyverse.pl | 84 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 31 deletions(-) diff --git a/ttyverse.pl b/ttyverse.pl index 7e6b639..dcb6dc4 100755 --- a/ttyverse.pl +++ b/ttyverse.pl @@ -4919,32 +4919,44 @@ sub refresh { unless ($notimeline || $anonymous) { # in streaming mode, use $last_id # in API mode, use $fetch_id + my $since_id = ($dostream) ? $last_id : $fetch_id; + print $stdout "-- DEBUG: Calling timeline API with since_id='$since_id', dostream=$dostream, last_id='$last_id', fetch_id='$fetch_id'\n" if ($verbose); my $base_json_ref = &grabjson($url, - ($dostream) ? $last_id : $fetch_id, + $since_id, 0, (($last_id) ? 250 : $fetchwanted || $backload), { "type" => "timeline", "payload" => "api" }, 1); # if I can't get my own timeline, ABORT! highest priority! - return if (!defined($base_json_ref) || - ref($base_json_ref) ne 'ARRAY'); + if (!defined($base_json_ref) || ref($base_json_ref) ne 'ARRAY') { + print $stdout "-- DEBUG: grabjson failed for timeline - base_json_ref is " . + (defined($base_json_ref) ? ref($base_json_ref) : 'undefined') . "\n" if ($verbose); + return; + } + print $stdout "-- DEBUG: grabjson returned " . scalar(@{ $base_json_ref }) . " posts from timeline\n" if ($verbose); # we have to filter against the ID cache right now, because # we might not have any other streams! if ($fetch_id && $last_id) { + print $stdout "-- DEBUG: Filtering timeline posts (fetch_id=$fetch_id, last_id=$last_id)\n" if ($verbose); $my_json_ref = []; my $l; my %k; # need temporary dedupe + my $filtered_count = 0; foreach $l (@{ $base_json_ref }) { - unless (length($id_cache{$l->{'id_str'}}) || + if (length($id_cache{$l->{'id_str'}}) || $filter_next{$l->{'id_str'}} || $k{$l->{'id_str'}}) { + $filtered_count++; + } else { push(@{ $my_json_ref }, $l); $k{$l->{'id_str'}}++; } } + print $stdout "-- DEBUG: After filtering: " . scalar(@{ $my_json_ref }) . " posts remain, $filtered_count filtered out\n" if ($verbose); } else { + print $stdout "-- DEBUG: No filtering applied (fetch_id=$fetch_id, last_id=$last_id)\n" if ($verbose); $my_json_ref = $base_json_ref; } } @@ -5106,7 +5118,13 @@ sub refresh { $fetch_id = 0 if ($last_id == 0); &send_removereadline if ($termrl); if ($dont_refresh_first_time) { - $last_id = &max($my_json_ref->[0]->{'id_str'}, $last_id); + print $stdout "-- DEBUG: First time startup path - posts in array: " . scalar(@{ $my_json_ref || [] }) . "\n" if ($verbose); + if (scalar(@{ $my_json_ref || [] }) > 0 && defined($my_json_ref->[0]->{'id_str'})) { + print $stdout "-- DEBUG: First time startup - setting last_id from '" . $my_json_ref->[0]->{'id_str'} . "'\n" if ($verbose); + $last_id = &max($my_json_ref->[0]->{'id_str'}, $last_id); + } else { + print $stdout "-- DEBUG: First time startup - no posts or invalid ID, keeping last_id='$last_id'\n" if ($verbose); + } } else { ($last_id, $crap) = &tdisplay($my_json_ref, undef, $relative_last_id); @@ -5265,7 +5283,19 @@ sub tdisplay { # used by both synchronous /again and asynchronous refreshes print $stdout "-- sorry, nothing to display.\n"; $wrapseq = 1; } - return (&max($my_json_ref->[0]->{'id_str'}, $last_id), $j); + # Safe ID calculation - handle empty arrays + my $new_max_id; + if (scalar(@{ $my_json_ref }) > 0 && defined($my_json_ref->[0]->{'id_str'})) { + my $first_post_id = $my_json_ref->[0]->{'id_str'}; + print $stdout "-- DEBUG: First post ID: '$first_post_id', current last_id: '$last_id'\n" if ($verbose); + $new_max_id = &max($first_post_id, $last_id); + print $stdout "-- DEBUG: max('$first_post_id', '$last_id') = '$new_max_id'\n" if ($verbose); + } else { + $new_max_id = $last_id; + print $stdout "-- DEBUG: No valid posts for ID calculation, using last_id='$last_id'\n" if ($verbose); + } + print $stdout "-- DEBUG: tdisplay returning max_id='$new_max_id' (from " . scalar(@{ $my_json_ref }) . " posts)\n" if ($verbose); + return ($new_max_id, $j); } sub dt_tdisplay { @@ -6591,7 +6621,7 @@ sub sendbackgroundkey { } sub thump { - print $stdout "-- DEBUG: Sending update command to background\n" if ($superverbose); + print $stdout "-- DEBUG: Manual refresh requested, sending update command to background\n" if ($verbose); print C "update-------------\n"; &sync_semaphore; } @@ -7408,6 +7438,13 @@ sub grabjson { my $resource = (scalar(@xargs)) ? [ $url, join('&', sort @xargs) ] : $url; + + # Debug: show the actual API call being made + if ($verbose && ref($resource) eq 'ARRAY') { + print $stdout "-- DEBUG: API call: $resource->[0]?$resource->[1]\n"; + } elsif ($verbose) { + print $stdout "-- DEBUG: API call: $resource\n"; + } chomp($data = &backticks($baseagent, '/dev/null', undef, $resource, undef, @@ -7556,34 +7593,16 @@ sub normalizejson { # id -> id_str if needed if (!length($i->{'id_str'})) { - my $k = "" + (0 + $i->{'id'}); - if ($k !~ /[eE][+-]/) { - $i->{'id_str'} = $k; - } else { - # desperately try to convert - $k =~ s/[eE][+-]\d+$//; - $k =~ s/\.//g; - # this is a hack, so we warn. - &$exception(13, -"*** impending doom: ID overflows Perl precision; stubbed to $k\n"); - $i->{'id_str'} = $k; + # Fediverse servers use string IDs - copy directly without numeric conversion + if (defined($i->{'id'})) { + $i->{'id_str'} = $i->{'id'}; } } # irtsid -> irtsid_str (if there is one) if (!length($i->{'in_reply_to_status_id_str'}) && $i->{'in_reply_to_status_id'}) { - my $k = "" + (0+$i->{'in_reply_to_status_id'}); - if ($k !~ /[eE][+-]/) { - $i->{'in_reply_to_status_id_str'} = $k; - } else { - # desperately try to convert - $k =~ s/[eE][+-]\d+$//; - $k =~ s/\.//g; - # this is a hack, so we warn. - &$exception(13, -"*** impending doom: IRT-ID overflows Perl precision; stubbed to $k\n"); - $i->{'in_reply_to_status_id_str'} = $k; - } + # Fediverse servers use string IDs - copy directly without numeric conversion + $i->{'in_reply_to_status_id_str'} = $i->{'in_reply_to_status_id'}; } # normalize geo. if this has a source and it has a @@ -8164,7 +8183,10 @@ sub deutf16 { # see RFC 2781 4.3 return chr(($one << 10) + $two + 65536); } -sub max { return ($_[0] > $_[1]) ? $_[0] : $_[1]; } +sub max { + # Fediverse-only: use string comparison for post IDs + return ($_[0] gt $_[1]) ? $_[0] : $_[1]; +} sub min { return ($_[0] < $_[1]) ? $_[0] : $_[1]; } sub prolog { my $k = shift; return "" if (!scalar(@_));