Experimental updates, this may be the first of a batchto be reverted only time will tell.

This commit is contained in:
Storm Dragon
2025-07-27 19:58:24 -04:00
parent 6bbd2ab263
commit fc736cfc9a
+181 -26
View File
@@ -169,7 +169,7 @@ BEGIN {
# notrack=0 # Disable tracking
# filterusers= # Filter posts from specific users
# filterats= # Filter posts with specific @mentions
# filterrts= # Filter retweets/boosts
# filterrts= # Filter boosts
# filteratonly= # Only show posts with @mentions
# filterflags= # Filter flags
# nofilter=0 # Disable all filtering
@@ -193,7 +193,7 @@ BEGIN {
# === ADVANCED/TECHNICAL ===
# runcommand= # Command to run on startup
# twarg= # Legacy Twitter argument (unused)
# twarg= # Legacy argument (unused)
# user= # Username override
# leader= # Command leader character
@@ -2908,6 +2908,7 @@ EOF
print $stdout "-- /refresh in streaming mode is pretty impatient\n"
if ($dostream);
&thump;
&dmthump_no_skip if ($dmpause); # Also refresh DMs but don't skip timeline
return 0;
}
if (m#^/a(gain)?(\s+\+\d+)?$#) { # the asynchronous form
@@ -3105,7 +3106,7 @@ EOF
# grab all the IDs
my $ids_ref = &grabjson(
"$mode?count=${countmaybe}&screen_name=${who}&stringify_ids=true",
"$mode?limit=${countmaybe}&screen_name=${who}",
0, 0, 0, undef, 1);
return 0 if (!$ids_ref || ref($ids_ref) ne 'HASH' ||
!$ids_ref->{'ids'});
@@ -3173,7 +3174,7 @@ EOF
if(!scalar(@usarray)) {
last FABIO if ($nofetch);
$json_ref = &grabjson(
"${mode}?count=${countper}&cursor=${cursor}${user}",
"${mode}?limit=${countper}&cursor=${cursor}${user}",
0, 0, 0, undef, 1);
@usarray = @{ $json_ref->{'users'} };
last FABIO if (!scalar(@usarray));
@@ -3835,8 +3836,8 @@ EOF
my $my_json_ref = &grabjson($timeline_url, 0, 0, $countmaybe || 20, undef, 1);
if ($timeline_name eq 'notifications') {
# Notifications have a different structure, need special handling
&dt_tdisplay($my_json_ref, "notifications");
# Notifications need individual type mapping for sound alerts
&notifications_tdisplay($my_json_ref);
} else {
&dt_tdisplay($my_json_ref, $timeline_name);
}
@@ -3886,7 +3887,7 @@ EOF
$countmaybe = sprintf("%03i", $countmaybe);
print $stdout "-- background request sent\n" unless ($synch);
$mode = ($mode =~ /^s/) ? 's' : 'd';
$mode = ($mode eq 'sent') ? 's' : 'd';
print C "${mode}mreset${countmaybe}---------\n";
&sync_semaphore;
return 0;
@@ -4153,7 +4154,7 @@ EOF
if(!scalar(@usarray)) {
last LABIO if ($nofetch);
$json_ref = &grabjson(
"${furl}&count=${countper}&cursor=${cursor}", 0, 0, 0,
"${furl}&limit=${countper}&cursor=${cursor}", 0, 0, 0,
undef, 1);
@usarray = @{ ((length($lname)) ?
$json_ref->{'users'} :
@@ -4585,6 +4586,9 @@ $interactive = $previous_last_id = $we_got_signal = 0;
$suspend_output = -1;
$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
$stuck_stdin = 0;
# tell the foreground we are ready
@@ -4605,10 +4609,14 @@ for(;;) {
&dmrefresh(0);
$dmcount = $dmpause;
} elsif (!$interactive) {
print $stdout "-- DEBUG: DM countdown: $dmcount -> " . ($dmcount - 1) . "\n" if ($verbose);
if (!--$dmcount) {
print $stdout "-- DEBUG: Triggering background DM refresh\n" if ($verbose);
&dmrefresh($interactive); # using dm_first_time
$dmcount = $dmpause;
}
} else {
print $stdout "-- DEBUG: Skipping DM countdown (interactive=$interactive)\n" if ($verbose);
}
}
DONT_REFRESH:
@@ -4919,15 +4927,31 @@ EOF
if ($rout =~ /^reset(\d+)/);
($dmfetchwanted = 0+$1, $last_dm = 0)
if ($rout =~ /^dmreset(\d+)/);
if ($rout =~ /^smreset/) { # /dmsent
if ($rout =~ /^dmreset/) { # /dms (received)
$dmfetchwanted = 0+$1
if ($rout =~ /(\d+)/);
&dmrefresh(1, 1);
$dm_display_only = 1; # Suppress notifications for user-initiated /dms
&dmrefresh(1, 0); # interactive=1, sent_dm=0
$dm_display_only = 0; # Reset flag
&send_repaint if ($termrl);
# we do not want to force a refresh.
goto DONT_REFRESH;
} elsif ($rout =~ /^smreset/) { # /dmsent
$dmfetchwanted = 0+$1
if ($rout =~ /(\d+)/);
$dm_display_only = 1; # Suppress notifications for user-initiated /dmsent
&dmrefresh(1, 1); # interactive=1, sent_dm=1
$dm_display_only = 0; # Reset flag
&send_repaint if ($termrl);
# we do not want to force a refresh.
goto DONT_REFRESH;
}
if ($rout =~ /^dm/) {
if ($rout =~ /^dmthump_no_skip/) {
&dmrefresh(0); # Force background-style refresh to update last_dm
&send_repaint if ($termrl);
$dmcount = $dmpause;
# Don't skip - let timeline refresh continue
} elsif ($rout =~ /^dm/) {
&dmrefresh($interactive);
&send_repaint if ($termrl);
$dmcount = $dmpause;
@@ -5018,7 +5042,7 @@ sub update_effpause {
if ($effpause > 120) {
$effpause = 120; # Maximum 2 minutes for fediverse
}
# this will usually be 75s (Twitter) or 120s (fediverse cap)
# this will usually be 120s (fediverse rate limit cap)
# for lists, however, we have to drain the list bucket faster, so for every
# list AFTER THE FIRST ONE we subscribe to, add rate_limit_rate to slow.
# for search, it has 180 requests, so we don't care so much. if this
@@ -5777,7 +5801,7 @@ sub tdisplay { # used by both synchronous /again and asynchronous refreshes
$wrapseq++;
$printed += scalar(&$handle($j,
($class || (($id <= $relative_last_id) ? 'again' :
($class || (($id le $relative_last_id) ? 'again' :
undef))));
}
}
@@ -5823,12 +5847,46 @@ $my_json_ref->[(&min($print_max,scalar(@{ $my_json_ref }))-1)]->{'created_at'});
}
}
sub notifications_tdisplay {
my $my_json_ref = shift;
if (defined($my_json_ref)
&& ref($my_json_ref) eq 'ARRAY'
&& scalar(@{ $my_json_ref })) {
# Process each notification with proper type mapping
for my $notification (@{ $my_json_ref }) {
my $type = $notification->{'type'} || 'default';
# Map Mastodon notification types to sound categories
my $sound_class = $type;
$sound_class = 'mention' if ($type eq 'mention');
$sound_class = 'boost' if ($type eq 'reblog');
$sound_class = 'favourite' if ($type eq 'favourite');
$sound_class = 'follow' if ($type eq 'follow');
# Process as individual post with proper class
&$handle($notification, $sound_class);
}
unless ($timestamp) {
my ($time, $ts1) = &$wraptime(
$my_json_ref->[(&min($print_max,scalar(@{ $my_json_ref }))-1)]->{'created_at'});
my ($time, $ts2) = &$wraptime($my_json_ref->[0]->{'created_at'});
print $stdout &wwrap(
"-- update covers $ts1 thru $ts2\n");
}
&$conclude;
}
}
# thump for DMs
sub dmrefresh {
my $interactive = shift;
my $sent_dm = shift;
# for streaming API to inject DMs it receives
my $my_json_ref = shift;
# Reset notification flag for this refresh cycle
$dm_notification_sent = 0;
if ($anonymous) {
print $stdout
@@ -5859,6 +5917,8 @@ sub dmrefresh {
my $g;
my $key;
print $stdout "-- DEBUG: DM response: " . scalar(@{ $my_json_ref }) . " conversations, disp_max=$disp_max\n" if ($verbose);
if ($disp_max) { # an empty list can be valid
if ($dm_first_time) {
sleep 5 while ($suspend_output > 0);
@@ -5867,13 +5927,39 @@ sub dmrefresh {
"-- checking for most recent direct messages:\n";
$disp_max = 2;
$interactive = 1;
print $stdout "-- DEBUG: dm_first_time: disp_max reduced to $disp_max\n" if ($verbose);
}
print $stdout "-- DEBUG: Starting DM display loop: $disp_max conversations\n" if ($verbose);
for($i = $disp_max; $i > 0; $i--) {
$g = ($i-1);
my $j = $my_json_ref->[$g];
next if (!$sent_dm && $j->{'id'} <= $last_dm);
next if (!$j->{'accounts'} || !@{$j->{'accounts'}} ||
!$j->{'last_status'});
print $stdout "-- DEBUG: Processing DM #$i (index $g)\n" if ($verbose);
# Skip if missing data
if (!$j->{'accounts'} || !@{$j->{'accounts'}} || !$j->{'last_status'}) {
print $stdout "-- DEBUG: Skipping DM #$i - missing data (accounts=" . (defined($j->{'accounts'}) ? scalar(@{$j->{'accounts'}}) : 'undef') . ")\n" if ($verbose);
next;
}
# For background refresh (interactive=0), use unread flag detection
if (!$interactive && !$sent_dm) {
my $is_unread = $j->{'unread'} || 0;
print $stdout "-- DEBUG: DM #$i unread flag: " . ($is_unread ? "true" : "false") . "\n" if ($verbose);
if (!$is_unread) {
print $stdout "-- DEBUG: Skipping DM #$i - already read (unread=false)\n" if ($verbose);
next;
}
# Only play sound for the first unread conversation to avoid spam
if ($dm_notification_sent) {
print $stdout "-- DEBUG: Suppressing notification for DM #$i - already notified this cycle\n" if ($verbose);
# Still display the DM but suppress notification
} else {
# Mark that we will send a notification for this unread DM
print $stdout "-- DEBUG: Will send notification for unread DM #$i\n" if ($verbose);
}
}
$key = substr($alphabet, $dm_counter/10, 1) .
$dm_counter % 10;
@@ -5887,7 +5973,10 @@ sub dmrefresh {
&send_removereadline if ($termrl);
$wrapseq++;
$printed += scalar(&$dmhandle($j));
print $stdout "-- DEBUG: Calling dmhandle for DM #$i\n" if ($verbose);
my $dm_result = scalar(&$dmhandle($j));
print $stdout "-- DEBUG: dmhandle returned: $dm_result\n" if ($verbose);
$printed += $dm_result;
}
$max = $my_json_ref->[0]->{'id'};
}
@@ -5899,8 +5988,26 @@ sub dmrefresh {
: "-- sorry, no new direct messages.\n");
$wrapseq = 1;
}
$last_dm = ($sent_dm) ? $orig_last_dm
: &max($last_dm, $max);
# Update last_dm for background refresh AND manual /dms
# Background calls: $interactive=0
# Manual /dms: $interactive=1, $sent_dm=0 (receives messages, should update read marker)
# Manual /dmsent: $interactive=1, $sent_dm=1 (shows sent messages, don't update)
if (!$interactive || $dm_first_time || ($interactive && !$sent_dm)) {
$last_dm = ($sent_dm) ? $orig_last_dm
: &max($last_dm, $max);
# Update content bookmark for the newest DM (index 0)
if (!$sent_dm && scalar(@{ $my_json_ref }) > 0) {
my $newest_dm = $my_json_ref->[0];
if ($newest_dm->{'last_status'}) {
# Track newest DM for next comparison (unread flag handles change detection)
}
}
print $stdout "-- DEBUG: Updated last_dm to $last_dm (interactive=$interactive, dm_first_time=$dm_first_time, sent_dm=$sent_dm)\n" if ($verbose);
} else {
print $stdout "-- DEBUG: NOT updating last_dm (interactive=$interactive, keeping last_dm=$last_dm)\n" if ($verbose);
}
$dm_first_time = 0 if ($last_dm || !scalar(@{ $my_json_ref }));
print $stdout "-- dm bookmark is $last_dm.\n" if ($verbose);
&$dmconclude;
@@ -6111,6 +6218,11 @@ EOF
$lasttwit = $string;
&$postpost($string);
}
# Send "me" notification for outgoing DMs
if ($user_name_dm) {
&notifytype_dispatch('me', $string, undef);
}
return 0;
}
@@ -6328,6 +6440,16 @@ sub standardpost {
}
}
# Add poll indicator if this post has a poll
if (exists($ref->{'poll'}) && $ref->{'poll'}) {
my $poll_indicator = '[Poll]';
if ($nocolour) {
$info_line .= " $poll_indicator";
} else {
$info_line .= " ${GREEN}${poll_indicator}${OFF}";
}
}
# Add content warning/title if present
my $cw_text = '';
if (exists($ref->{'reblog'}) && $ref->{'reblog'} && exists($ref->{'reblog'}->{'spoiler_text'})) {
@@ -7028,15 +7150,47 @@ sub defaultdmhandle {
my $dm_ref = shift;
my $sns = &descape($dm_ref->{'last_status'}->{'account'}->{'username'} || $dm_ref->{'last_status'}->{'account'}->{'acct'});
print $streamout &standarddm($dm_ref);
my $dm_content = &standarddm($dm_ref);
print $streamout $dm_content;
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'});
}
return 1;
}
sub senddmnotifies {
my $dm_ref = shift;
&notifytype_dispatch('dm', &standarddm($dm_ref, 1), $dm_ref)
if ($notify_list{'dm'} && $last_dm);
# Only send notification if we haven't already sent one this refresh cycle
# and we're not in initial load (either timeline or DM first time)
# and we're not in display-only mode (user-initiated /dms commands)
if ($notify_list{'dm'} && !$initial_load_in_progress && !$dm_first_time && !$dm_notification_sent && !$dm_display_only) {
&notifytype_dispatch('dm', &standarddm($dm_ref, 1), $dm_ref);
$dm_notification_sent = 1;
}
}
sub mark_conversation_read {
my $conversation_id = shift;
return unless ($conversation_id);
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";
# Make POST request with empty data to mark as read
my $result = &postjson($read_url, "");
if ($result) {
print $stdout "-- DEBUG: Successfully marked conversation $conversation_id as read\n" if ($verbose);
} else {
print $stdout "-- DEBUG: Failed to mark conversation $conversation_id as read\n" if ($verbose);
}
}
sub defaulteventhandle {
@@ -7386,6 +7540,7 @@ sub thump {
&sync_semaphore;
}
sub dmthump { print C "dmthump------------\n"; &sync_semaphore; }
sub dmthump_no_skip { print C "dmthump_no_skip----\n"; &sync_semaphore; }
sub sync_n_quit {
if ($child) {
@@ -8192,14 +8347,14 @@ sub grabjson {
$url = substr($url, 0, $i);
}
# count needs to be removed for the default case due to show, etc.
push(@xargs, "count=$count") if ($count);
# limit parameter for Mastodon API (replaces Twitter's count parameter)
push(@xargs, "limit=$count") if ($count);
# timeline control. this speeds up parsing since there's less data.
# can't use skip_user: no SN
push (@xargs, "since_id=${last_id}") if ($last_id);
# request entities, which should be supported everywhere now
push (@xargs, "include_entities=1") if ($do_entities);
# include_entities is Twitter-specific, not needed for Mastodon
# push (@xargs, "include_entities=1") if ($do_entities);
my $resource = (scalar(@xargs)) ?
[ $url, join('&', sort @xargs) ] : $url;