Fix for dms showing timeout or no data. Locally tracking them to prevent showing them over and over.

This commit is contained in:
Storm Dragon
2025-07-28 13:11:52 -04:00
parent 694acbf0d8
commit 79d7e1e763
+157 -21
View File
@@ -40,12 +40,10 @@ BEGIN {
$command_line = $0; $0 = "TTYverse";
$TTYverse_VERSION = "2025.07.25";
$TTYverse_PATCH_VERSION = "";
$TTYverse_RC_NUMBER = 0; # non-zero for release candidate
# this is kludgy, yes.
$LANG = $ENV{'LANG'} || $ENV{'GDM_LANG'} || $ENV{'LC_CTYPE'} ||
$ENV{'ALL'};
$my_version_string = ($TTYverse_PATCH_VERSION) ? "${TTYverse_VERSION}.${TTYverse_PATCH_VERSION}" : "${TTYverse_VERSION}";
$my_version_string = $TTYverse_VERSION;
(warn ("$my_version_string\n"), exit) if ($version);
# Set up XDG directories early for -create-rc and extensions
@@ -224,7 +222,6 @@ EOF
undef $master_store;
undef %push_stack;
$padded_patch_version = substr($TTYverse_PATCH_VERSION . " ", 0, 2);
%opts_boolean = map { $_ => 1 } qw(
ansi noansi verbose superverbose ttytteristas noprompt
@@ -263,7 +260,7 @@ EOF
);
%opts_can_set = map { $_ => 1 } qw(
url pause dmurl dmpause superverbose ansi verbose
url pause dmurl dmpause dmmarkread superverbose ansi verbose
update uurl rurl wurl avatar ttytteristas frurl track
rlurl noprompt shoreblogurl newline wrap verify autosplit
notimeline queryurl fediverseserver colourprompt colourme
@@ -1093,9 +1090,10 @@ $slowpost ||= 0;
$twarg ||= undef;
$verbose ||= $superverbose;
$dmpause = 4 if (!defined $dmpause); # NOT ||= ... zero is a VALID value!
$dmpause = 4 if (!defined $dmpause); # NOT ||= ... zero is a VALID value!
$dmpause = 0 if ($anonymous);
$dmpause = 0 if ($pause eq '0');
$dmmarkread = 1 if (!defined $dmmarkread); # Default to enabled
$ansi = ($noansi) ? 0 :
(($ansi || $ENV{'TERM'} eq 'ansi' || $ENV{'TERM'} eq 'xterm-color')
? 1 : 0);
@@ -1748,6 +1746,7 @@ if ($daemon) {
&update_effpause;
&refresh(0);
$dont_refresh_first_time = 0;
# Move DM refresh after timeline refresh so timeline updates show even if no unread DMs
if ($dmpause) {
if (!--$dmcount) {
&dmrefresh(0);
@@ -1833,7 +1832,7 @@ unless ($simplestart) {
print <<"EOF";
========================================
TTYverse ${TTYverse_VERSION}.${padded_patch_version} (c)2025 Storm Dragon
TTYverse ${TTYverse_VERSION} (c)2025 Storm Dragon
all rights reserved.
https://git.stormux.org/storm/ttyverse
@@ -4649,7 +4648,9 @@ $stream_failure = 0;
$dm_first_time = ($dmpause) ? 1 : 0;
$dm_display_only = 0; # Flag to suppress notifications during user-initiated /dms commands
$dm_notification_sent = 0; # Flag to prevent duplicate notifications per refresh cycle
# DM tracking now uses Mastodon's unread flag instead of content comparison
# DM tracking now uses Mastodon's unread flag with local read tracking fallback
%dm_seen_status = (); # Hash to track seen conversation_id:last_status_id pairs
&load_dm_seen_status(); # Load persistent tracking data
$stuck_stdin = 0;
# tell the foreground we are ready
@@ -5994,6 +5995,24 @@ sub dmrefresh {
print $stdout "-- DEBUG: DM response: " . scalar(@{ $my_json_ref }) . " conversations, disp_max=$disp_max\n" if ($verbose);
# For background refresh, check if there are any unread DMs first
if (!$interactive && !$sent_dm && $disp_max) {
my $has_unread = 0;
for (my $check_i = 0; $check_i < $disp_max; $check_i++) {
my $check_j = $my_json_ref->[$check_i];
next if (!$check_j->{'accounts'} || !@{$check_j->{'accounts'}} || !$check_j->{'last_status'});
if ($check_j->{'unread'}) {
$has_unread = 1;
last;
}
}
if (!$has_unread) {
print $stdout "-- DEBUG: No unread DMs found in background refresh, returning early\n" if ($verbose);
return;
}
print $stdout "-- DEBUG: Found unread DMs in background refresh, proceeding\n" if ($verbose);
}
if ($disp_max) { # an empty list can be valid
if ($dm_first_time) {
sleep 5 while ($suspend_output > 0);
@@ -6016,12 +6035,23 @@ sub dmrefresh {
next;
}
# For background refresh (interactive=0), use unread flag detection
# For background refresh (interactive=0), use unread flag detection with local tracking fallback
if (!$interactive && !$sent_dm) {
my $is_unread = $j->{'unread'} || 0;
print $stdout "-- DEBUG: DM #$i unread flag: " . ($is_unread ? "true" : "false") . "\n" if ($verbose);
my $conversation_id = $j->{'id'};
my $last_status_id = $j->{'last_status'}->{'id'} || $j->{'last_status'}->{'id_str'};
my $tracking_key = "${conversation_id}:${last_status_id}";
if (!$is_unread) {
print $stdout "-- DEBUG: DM #$i unread flag: " . ($is_unread ? "true" : "false") . ", tracking_key: $tracking_key\n" if ($verbose);
# Check if we've already seen this exact conversation+status combination
if ($dm_seen_status{$tracking_key}) {
print $stdout "-- DEBUG: Skipping DM #$i - already seen locally (key: $tracking_key)\n" if ($verbose);
next;
}
# For servers that support unread flag, also check that
if (!$is_unread && !$dm_seen_status{$tracking_key}) {
print $stdout "-- DEBUG: Skipping DM #$i - already read (unread=false)\n" if ($verbose);
next;
}
@@ -7251,9 +7281,19 @@ sub defaultdmhandle {
print $stdout "-- DEBUG: DM displayed: " . substr($dm_content, 0, 50) . "...\n" if ($verbose);
&senddmnotifies($dm_ref) if ($sns ne $whoami);
# Mark conversation as read if it was unread
if ($dm_ref->{'unread'}) {
&mark_conversation_read($dm_ref->{'id'});
# Mark conversation as read if it was unread (can be disabled with dmmarkread=0)
if ($dm_ref->{'unread'} && (!defined($dmmarkread) || $dmmarkread)) {
my $mark_result = &mark_conversation_read($dm_ref->{'id'});
# If server-side mark-as-read failed, track locally to prevent re-showing
if (!$mark_result) {
my $conversation_id = $dm_ref->{'id'};
my $last_status_id = $dm_ref->{'last_status'}->{'id'} || $dm_ref->{'last_status'}->{'id_str'};
my $tracking_key = "${conversation_id}:${last_status_id}";
$dm_seen_status{$tracking_key} = time(); # Store timestamp when seen
print $stdout "-- DEBUG: Marked DM as seen locally (key: $tracking_key)\n" if ($verbose);
&save_dm_seen_status(); # Persist the change
}
}
return 1;
@@ -7277,15 +7317,46 @@ sub mark_conversation_read {
print $stdout "-- DEBUG: Marking conversation $conversation_id as read\n" if ($verbose);
# Build the URL for marking conversation as read
my $read_url = "$baseurl/api/v1/conversations/$conversation_id/read";
my $read_url = "${apibase}/conversations/$conversation_id/read";
print $stdout "-- DEBUG: Mark-as-read URL: $read_url\n" if ($verbose);
# Make POST request with shorter timeout for mark-as-read
my $old_timeout = $timeout;
my $old_exception = $exception;
$timeout = 5; # Short timeout for non-critical operation
# Use a custom exception handler to capture detailed error info
$exception = sub {
my ($severity, $message) = @_;
print $stdout "-- DEBUG: Mark-as-read API call failed (severity=$severity): $message" if ($verbose);
# Don't show user warning for this - it's not critical, but log the error
};
# Make POST request with empty data to mark as read
my $result = &postjson($read_url, "");
# Restore original handlers
$timeout = $old_timeout;
$exception = $old_exception;
if ($result) {
print $stdout "-- DEBUG: Successfully marked conversation $conversation_id as read\n" if ($verbose);
return 1;
} else {
print $stdout "-- DEBUG: Failed to mark conversation $conversation_id as read\n" if ($verbose);
print $stdout "-- DEBUG: Failed to mark conversation $conversation_id as read - trying alternative method\n" if ($verbose);
# Fallback: Some servers might need different approach
# Try sending empty message to conversation (some implementations mark as read this way)
my $alt_url = "${apibase}/conversations/$conversation_id";
print $stdout "-- DEBUG: Trying alternative approach: GET $alt_url\n" if ($verbose);
my $alt_result = &grabjson($alt_url, 0, 0, 1, undef, 1);
if ($alt_result) {
print $stdout "-- DEBUG: Alternative method succeeded (conversation fetched)\n" if ($verbose);
return 1;
} else {
print $stdout "-- DEBUG: All methods failed - server may not support conversation read API\n" if ($verbose);
return 0;
}
}
}
@@ -8227,8 +8298,14 @@ sub updatecheck {
} elsif ($latest_version eq $current_version) {
$vs .= "-- your version of TTYverse is up to date ($current_version)\n";
} else {
$vs .= "-- you appear to have a development version ($current_version)\n";
$vs .= "-- latest stable release: $latest_version\n";
# Local version is newer - check if we're in a git repo
if (-d '.git') {
$vs .= "-- your version ($current_version) is newer than latest remote ($latest_version)\n";
$vs .= "-- you may have unpushed changes or unreleased version\n";
} else {
$vs .= "-- you appear to have a development version ($current_version)\n";
$vs .= "-- latest stable release: $latest_version\n";
}
}
} else {
$vs .= "-- warning: unable to determine latest version\n";
@@ -8736,10 +8813,14 @@ sub normalizejson {
print $stdout "-- DEBUG: Found poll in main post\n" if ($verbose);
}
# Store poll data for display
if ($poll_data) {
# Store poll data for display - but only if it's a valid poll with options
if ($poll_data && ref($poll_data) eq 'HASH' && exists($poll_data->{'options'}) && @{$poll_data->{'options'}}) {
$i->{'poll'} = $poll_data;
print $stdout "-- DEBUG: Poll data stored for display\n" if ($verbose);
} else {
# Clear any false poll data
delete $i->{'poll'} if exists($i->{'poll'});
print $stdout "-- DEBUG: No valid poll data found, cleared poll flag\n" if ($verbose && $poll_data);
}
return $i;
@@ -9818,4 +9899,59 @@ sub signrequest {
return "-H \"Authorization: Bearer $tokenkey\"";
}
# Load locally tracked DM seen status from persistent storage
sub load_dm_seen_status {
my $seen_file = "$config/dm_seen_status";
return unless (-r $seen_file);
if (open(SEEN, '<', $seen_file)) {
print $stdout "-- DEBUG: Loading DM seen status from $seen_file\n" if ($verbose);
my $count = 0;
while (my $line = <SEEN>) {
chomp($line);
next unless ($line =~ /^(.+):(\d+)$/);
my ($tracking_key, $timestamp) = ($1, $2);
# Skip entries older than 30 days to prevent infinite growth
if (time() - $timestamp < 30 * 24 * 3600) {
$dm_seen_status{$tracking_key} = $timestamp;
$count++;
}
}
close(SEEN);
print $stdout "-- DEBUG: Loaded $count DM seen entries\n" if ($verbose);
}
}
# Save locally tracked DM seen status to persistent storage
sub save_dm_seen_status {
my $seen_file = "$config/dm_seen_status";
# Ensure config directory exists
unless (-d $config) {
mkdir($config, 0700) || do {
print $stdout "-- DEBUG: Could not create config directory $config: $!\n" if ($verbose);
return;
};
}
if (open(SEEN, '>', $seen_file)) {
print $stdout "-- DEBUG: Saving DM seen status to $seen_file\n" if ($superverbose);
my $count = 0;
for my $key (keys %dm_seen_status) {
my $timestamp = $dm_seen_status{$key};
# Only save entries from last 30 days
if (time() - $timestamp < 30 * 24 * 3600) {
print SEEN "$key:$timestamp\n";
$count++;
}
}
close(SEEN);
chmod(0600, $seen_file); # Keep private
print $stdout "-- DEBUG: Saved $count DM seen entries\n" if ($superverbose);
} else {
print $stdout "-- DEBUG: Could not save DM seen status to $seen_file: $!\n" if ($verbose);
}
}
}