#!/usr/bin/env perl

# vl-twitget - simple command-line Twitter client to get one's latest
# tweets and retweets as plain text.
# Copyright 2010-2017 Vincent Lefevre <vincent@vinc17.net>.

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA

# To register an application and get a consumer key/secret pair:
#   https://apps.twitter.com/

# The consumer key and the consumer secret must be stored in
# a ~/.twitget file on two lines.

# See https://developer.twitter.com/en/docs for the API, in particular:
#   https://developer.twitter.com/en/docs/tweets/tweet-updates

use strict;
use open OUT => ':locale';
use TwitGet;
use Date::Parse;
use POSIX;

my ($proc) = '$Id: twitget 103810 2017-11-25 03:14:25Z vinc17/zira $'
  =~ /^.Id: (\S+) \d+ / or die;

my $rev = $ARGV[0] eq '-r' and shift;
my $ss = $rev ? sub { $b cmp $a } : sub { $a cmp $b };
my %param;
foreach (@ARGV)
  { /^(\w+)=(.*)/ or die "Usage: $proc [-r] [ key=value ... ]\n";
    $param{$1} = $2; }

STDERR->autoflush(1);

my $eol = -t STDERR ? eval
  {
    require Term::Cap;
    my $terminal = Tgetent Term::Cap;
    $terminal->Tputs('ce');
  } || "\n" : "";

my $nt = TwitGet::init();

$param{include_rts} = 1;
$param{tweet_mode} = 'extended';

my ($ntweets,$nrts) = (0,0);
my @timeline;

sub src ($)
  {
    my $s = $_[0]->{source};
    $s =~ s:^<a href=".*?" rel="nofollow">(.*?)</a>$:$1:;
    return $s;
  }

sub pl ($$)
  { "@_".($_[0] > 1 ? 's' : '') }

my $tget = sub (\%)
  {
    my $param = $_[0];
    my ($minid,$maxid);
    print STDERR "$proc: request...\r" if $eol;
    my @t = sort $ss map {
      $ntweets++;
      my $status = $_;
      my $id = $status->{id};
      defined $minid && $id >= $minid or $minid = $id;
      defined $maxid && $id <= $maxid or $maxid = $id;
      my $created = str2time($status->{created_at});
      defined $created or die "$proc: can't parse date for id $id\n";
      my $text = $status->{full_text};
      my $rf = '';
      my $rt = $status->{retweeted_status};
      if (defined $rt)
        {
          $nrts++;
          # Note: $status->{truncated} now seems to be always false.
          # So, no longer check it.
          $text = "RT @".$rt->{user}{screen_name}.": $rt->{full_text}";
          $rt = " [RT of $rt->{id} from ".src($rt)."]";
        }
      else
        {
          my $rc = $status->{retweet_count};
          my $fc = $status->{favorite_count};
          if ($rc + $fc > 1)
            {
              my @rf;
              $rc and push @rf, pl($rc,"retweet");
              $fc and push @rf, pl($fc,"favorite");
              $rf = "{".join(" / ",@rf)."}\n";
            }
        }
      $text =~ s/\n/ /g;
      $text =~ s/&lt;/</g;
      $text =~ s/&gt;/>/g;
      $text =~ s/&amp;/&/g;
      foreach my $u (@{$status->{entities}{urls}})
        { $text =~ s/\Q$u->{url}\E/$u->{expanded_url}/g }
      foreach my $u (@{$status->{entities}{media}})
        { $text =~ s/\Q$u->{url}\E/$u->{media_url}/g }
      my $coord = $status->{coordinates};
      my $cstr = '';
      if (defined $coord)
        {
          my $type = $coord->{type};
          if ($type eq 'Point')
            {
              $cstr = "Coordinates: (".join(',',@{$coord->{coordinates}}).")\n";
            }
          else
            {
              warn "Bad coordinates type for $id: $type\n";
            }
        }
      POSIX::strftime("[%FT%TZ] ", gmtime $created).
          "https://twitter.com/$status->{user}{screen_name}/status/$id\n".
            "$text\nSource: ".src($status)."$rt\n$cstr$rf\n";
    } (@{$nt->user_timeline($param)});
    if (@t)
      {
        print STDERR "$proc: got tweets from $minid to $maxid\n";
        if ($rev)
          { push @timeline, @t }
        else
          { unshift @timeline, @t }
        return $minid;
      }
    else
      {
        print STDERR $eol;
        return;
      }
  };

TwitGet::loop($nt,\%param,$tget);
print @timeline, "$ntweets tweets, including $nrts retweets.\n";