diff --git a/ttyverse.pl b/ttyverse.pl index 935f4c9..b5a89d5 100755 --- a/ttyverse.pl +++ b/ttyverse.pl @@ -87,7 +87,7 @@ BEGIN { # pause=auto # Auto-refresh rate (seconds, or 'auto') # backload=30 # Number of posts to load initially # wrap=120 # Text wrapping width -# timestamp=0 # Show timestamps on posts +# timestamp=0 # Show timestamps on posts (0=off, 1=relative, 2=both) # noreblogs=0 # Hide boost/reblog posts # === DISPLAY SETTINGS === @@ -6023,6 +6023,15 @@ sub standardpost { $post = "[$ts] $post"; } + # Add relative time and client info + my $relative_time = &format_relative_time($ref->{'created_at'}); + my $client_info = &format_client_info($ref); + + my $metadata = ''; + $metadata .= " ($relative_time)" if ($relative_time); + $metadata .= " via $client_info" if ($client_info); + $post .= $metadata if ($metadata); + # pull it all together $post = &wwrap($post, ($wrapseq <= 1) ? ((&$prompt(1))[1]) : 0) if ($wrap); # remember to account for prompt length on #1 @@ -6098,6 +6107,89 @@ sub format_poll_display { return $poll_text; } +# format relative time (e.g., "5 minutes ago", "2 hours ago") +sub format_relative_time { + my $created_at = shift; + return '' unless ($created_at); + + # Parse the fediverse timestamp format (ISO 8601) + # Example: "2025-07-26T12:34:56.000Z" + my ($year, $month, $day, $hour, $min, $sec); + if ($created_at =~ /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})/) { + ($year, $month, $day, $hour, $min, $sec) = ($1, $2, $3, $4, $5, $6); + } else { + return ''; + } + + # Convert to Unix timestamp + my $post_time = eval { + require Time::Local; + Time::Local::timegm($sec, $min, $hour, $day, $month - 1, $year); + }; + return '' if (!defined($post_time) || $@); + + my $now = time(); + my $diff = $now - $post_time; + + # Handle future timestamps (clock skew) + return "just now" if ($diff < 0); + + # Calculate relative time + if ($diff < 60) { + return "just now"; + } elsif ($diff < 3600) { # Less than 1 hour + my $minutes = int($diff / 60); + return "${minutes}m ago"; + } elsif ($diff < 86400) { # Less than 1 day + my $hours = int($diff / 3600); + return "${hours}h ago"; + } elsif ($diff < 604800) { # Less than 1 week + my $days = int($diff / 86400); + return "${days}d ago"; + } elsif ($diff < 2629746) { # Less than 1 month (30.44 days) + my $weeks = int($diff / 604800); + return "${weeks}w ago"; + } elsif ($diff < 31556952) { # Less than 1 year + my $months = int($diff / 2629746); + return "${months}mo ago"; + } else { + my $years = int($diff / 31556952); + return "${years}y ago"; + } +} + +# format client application info +sub format_client_info { + my $ref = shift; + + # For boost posts, show client of original post + my $app_data; + if (exists($ref->{'reblog'}) && $ref->{'reblog'} && exists($ref->{'reblog'}->{'application'})) { + $app_data = $ref->{'reblog'}->{'application'}; + } elsif (exists($ref->{'application'})) { + $app_data = $ref->{'application'}; + } + + return '' unless ($app_data && ref($app_data) eq 'HASH'); + + my $client_name = $app_data->{'name'} || ''; + return '' unless ($client_name); + + # Clean up common client names for better display + if ($client_name =~ /^mastodon/i) { + return "Web" if ($client_name =~ /web/i); + return "Mobile" if ($client_name =~ /mobile|android|ios/i); + } + + # Handle common clients + $client_name = "Tusky" if ($client_name =~ /tusky/i); + $client_name = "Subway Tooter" if ($client_name =~ /subway.*tooter/i); + $client_name = "Fedilab" if ($client_name =~ /fedilab/i); + $client_name = "TTYverse" if ($client_name =~ /ttyverse/i); + + return $client_name; +} + # format a DM based on standard user options sub standarddm { my $ref = shift;