Dotfiles, utilities, and other apparatus.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

172 lines
3.5 KiB

  1. #!/usr/bin/env perl
  2. =pod
  3. =head1 NAME
  4. pinboard - get some stuff from a pinboard account
  5. =head1 USAGE
  6. F<~/.pinboardrc> must contain a username in the format C<username:token>.
  7. # Show some recent stuff from today (empty if nothing):
  8. pinboard
  9. # List all tags:
  10. pinboard tags
  11. # Everything for a specific tag:
  12. pinboard by-tag some-tag
  13. =head1 DESCRIPTION
  14. A wrapper for some Pinboard API calls I use routinely.
  15. Pretty crap.
  16. =head1 AUTHOR
  17. L<Brennen Bearnes|https://p1k3.com/>
  18. =cut
  19. use strict;
  20. use warnings;
  21. use 5.10.0;
  22. use Carp;
  23. use Data::Dumper;
  24. use File::HomeDir;
  25. use Getopt::Long;
  26. use LWP::Simple;
  27. use Pod::Usage;
  28. use JSON;
  29. use Time::Piece;
  30. use utf8;
  31. use open qw(:std :utf8);
  32. # Handle options, including help generated from the POD above
  33. # (there's nothing else here at the moment, but it's a good place
  34. # to hang things if I want options):
  35. GetOptions(
  36. 'help' => sub { pod2usage(0) },
  37. ) or pod2usage(2);
  38. if (defined $ARGV[0] && $ARGV[0] eq 'tags') {
  39. print tags();
  40. } elsif (defined $ARGV[0] && $ARGV[0] eq 'by-tag') {
  41. croak "Must supply a tag name"
  42. unless defined $ARGV[1];
  43. say format_posts(by_tag($ARGV[1]));
  44. } else {
  45. my $today = localtime;
  46. say format_posts(recent($today));
  47. }
  48. sub tags {
  49. my $token = get_token();
  50. my $url = 'https://api.pinboard.in/v1/tags/get?format=json&auth_token=' . $token;
  51. my $pinboard_json = get($url);
  52. # https://stackoverflow.com/questions/45941522/parsing-utf-8-json-with-perl
  53. # Strip byte order mark:
  54. # $pinboard_json =~ s/^\N{BOM}//g;
  55. $pinboard_json =~ s/^[^\x00-\x7f]+//;
  56. my $JSON = JSON->new->utf8->pretty;
  57. my $pinboard_hashref = $JSON->decode($pinboard_json);
  58. my %tags = %{ $pinboard_hashref };
  59. my $output = '';
  60. foreach my $tag (keys %tags) {
  61. $output .= "$tag\n";
  62. }
  63. return $output;
  64. }
  65. sub by_tag {
  66. my $tag = shift;
  67. my $token = get_token();
  68. # lol this is terrible
  69. my $url = 'https://api.pinboard.in/v1/posts/all?tag='
  70. . $tag
  71. . '&format=json&auth_token=' . $token;
  72. my $pinboard_json = get($url);
  73. # print $url;
  74. # print $pinboard_json;
  75. my $JSON = JSON->new->utf8->pretty;
  76. my $pinboard_hashref = $JSON->decode($pinboard_json);
  77. return @{ $pinboard_hashref };
  78. }
  79. sub recent {
  80. my ($day) = @_;
  81. my $token = get_token();
  82. my $url = $day->strftime(
  83. 'https://api.pinboard.in/v1/posts/get?dt=%Y-%m-%d&meta=yes&format=json&auth_token='
  84. . $token
  85. );
  86. my $pinboard_json = get($url);
  87. my $JSON = JSON->new->utf8->pretty;
  88. my $pinboard_hashref = $JSON->decode($pinboard_json);
  89. return @{ $pinboard_hashref->{posts} };
  90. }
  91. # Take a list of posts and format them for display
  92. sub format_posts {
  93. my @output;
  94. foreach my $post (@_)
  95. {
  96. # push @output, Dumper($post);
  97. push @output,
  98. "$post->{time}\t$post->{href}\t$post->{description}\t$post->{tags}";
  99. }
  100. if (@output > 0) {
  101. return join "\n", @output;
  102. }
  103. return;
  104. }
  105. # PHP-style file-content grabbing:
  106. sub file_get_contents {
  107. my ($file) = @_;
  108. open my $fh, '<', $file
  109. or croak "Couldn't open $file: $!\n";
  110. my $contents;
  111. {
  112. # line separator:
  113. local $/ = undef;
  114. $contents = <$fh>;
  115. }
  116. close $fh or croak "Couldn't close $file: $!";
  117. return $contents;
  118. }
  119. sub get_token {
  120. # See the bit about auth here:
  121. # https://pinboard.in/api/
  122. my $home = File::HomeDir->my_home;
  123. my $rc_path = "${home}/.pinboardrc";
  124. my $token;
  125. if (-e $rc_path) {
  126. $token = file_get_contents($rc_path);
  127. } else {
  128. die("No $rc_path found - do you need to create a file with credentials?");
  129. }
  130. chomp($token);
  131. return $token;
  132. }