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.

194 lines
4.5 KiB

  1. #!/usr/bin/env perl
  2. =pod
  3. =head1 NAME
  4. timeslice - aggregate CLI history, notes, blog entries, etc. for a given time
  5. =head1 SYNOPSIS
  6. # Find items for January 1st, 2019:
  7. timeslice 2019-01-01
  8. # Find items corresponding to a file's time - special cases some files
  9. # with an embedded date, like a blog entry or a vimwiki diary page,
  10. # otherwise falls back to mtime:
  11. timeslice --file ~/notes/vimwiki/diary/2019-01-02.wiki
  12. timeslice --file ~/screenshots/foo.png
  13. =head1 DESCRIPTION
  14. timeslice is a utility, for now extremely specific to my personal setup, for
  15. aggregating info from various systems by date. It currently looks up entries
  16. in vimwiki, p1k3 (my blog), pinboard, and command line history using
  17. commandlog.
  18. This code is hot garbage.
  19. =head1 AUTHOR
  20. Brennen Bearnes
  21. =cut
  22. use warnings;
  23. use strict;
  24. use 5.10.0;
  25. use Carp;
  26. use Data::Dumper;
  27. use File::Find;
  28. use File::HomeDir;
  29. use File::Spec;
  30. use Getopt::Long;
  31. use JSON;
  32. use LWP::Simple;
  33. use Pod::Usage;
  34. use Text::Wrap;
  35. use Time::Piece;
  36. use Time::Seconds;
  37. $Text::Wrap::columns = 72;
  38. my $ISO_8601_FMT = '%Y-%m-%d';
  39. # Handle options, including help generated from the POD above:
  40. my $date_from_file = 0;
  41. GetOptions(
  42. 'file' => \$date_from_file,
  43. 'help' => sub { pod2usage(0) },
  44. ) or pod2usage(2);
  45. # If --file was invoked, get time from targetted file instead of taking
  46. # the first param as a date:
  47. my $date;
  48. if ($date_from_file) {
  49. my $file = File::Spec->rel2abs($ARGV[0]);
  50. say "Date from file: $file";
  51. if ($file =~ m{^.*?/diary/(\d{4}-\d{2}-\d{2})[.]wiki$}) {
  52. # Handle vimwiki diary entries:
  53. $date = $1;
  54. } elsif ($file =~ m{^.*?/p1k3/archives/(\d{4})/(\d+)/(\d+)(/index)?$}) {
  55. # Handle p1k3 entries:
  56. $date = sprintf('%d-%02d-%02d', $1, $2, $3);
  57. } else {
  58. # Just use the file's modification time:
  59. $date = get_mtime_day($ARGV[0]);
  60. }
  61. } else {
  62. $date = $ARGV[0];
  63. }
  64. my $day = Time::Piece->strptime($date, $ISO_8601_FMT);
  65. my $next_day = $day + ONE_DAY;
  66. say "Day: ${day}";
  67. my @things = grep { defined $_ } (
  68. # "\n[ vimwiki entries ]\n",
  69. # vimwiki($day),
  70. "\np1k3 entries {{{",
  71. p1k3($day),
  72. "}}}",
  73. "\nshell history {{{",
  74. commandlog($day, $next_day),
  75. "}}}",
  76. "\npinboard {{{",
  77. pinboard($day),
  78. "}}}"
  79. );
  80. foreach my $thing (@things) {
  81. say $thing;
  82. }
  83. sub vimwiki {
  84. my ($day) = @_;
  85. my $daypath = $day->strftime(
  86. File::HomeDir->my_home . "/notes/vimwiki/diary/%Y-%m-%d.wiki"
  87. );
  88. return file_get_contents($daypath) if -e $daypath;
  89. }
  90. sub commandlog {
  91. my ($day, $next_day) = @_;
  92. my $after = $day->strftime('%Y-%m-%d 00:00:00');
  93. my $before = $next_day->strftime('%Y-%m-%d 00:00:00');
  94. return join "", `commandlog log --after="${after} 00:00:00" --before="${before}"`
  95. }
  96. sub p1k3 {
  97. my ($day) = @_;
  98. my $daypath = $day->strftime(
  99. "%Y/%-m/%-d"
  100. );
  101. if (-e File::HomeDir->my_home . '/p1k3/archives/' . $daypath) {
  102. return join "", `cd ~/p1k3 && wrt display ${daypath} | lynx -stdin -dump`
  103. }
  104. }
  105. sub pinboard {
  106. my ($day) = @_;
  107. my $JSON = JSON->new->utf8->pretty;
  108. my $url = $day->strftime(
  109. 'https://api.pinboard.in/v1/posts/get?dt=%Y-%m-%d&meta=yes&format=json'
  110. );
  111. my $home = File::HomeDir->my_home;
  112. my $pinboard_hashref = $JSON->decode(`curl -s -K ${home}/.pinboardrc '${url}'`);
  113. my @posts = @{ $pinboard_hashref->{posts} };
  114. my @output;
  115. foreach my $post (@posts) {
  116. my $display = wrap("", "", $post->{description}) . "\n"
  117. if length($post->{description});
  118. $display .= wrap("\t", "\t", $post->{extended}) . "\n"
  119. if length($post->{extended});
  120. $display .= "\t" . $post->{href} . "\n";
  121. $display .= wrap("\t", "\t", $post->{tags}) . "\n"
  122. if length($post->{tags});
  123. push @output, $display;
  124. }
  125. return join "\n", @output;
  126. }
  127. # PHP-style file-content grabbing:
  128. sub file_get_contents {
  129. my ($file) = @_;
  130. open my $fh, '<', $file
  131. or croak "Couldn't open $file: $!\n";
  132. my $contents;
  133. {
  134. # line separator:
  135. local $/ = undef;
  136. $contents = <$fh>;
  137. }
  138. close $fh or croak "Couldn't close $file: $!";
  139. # TODO: _May_ want to assume here that any file is UTF-8 text.
  140. # http://perldoc.perl.org/perlunitut.html
  141. # return decode('UTF-8', $contents);
  142. return $contents;
  143. }
  144. # Horked from WRT::Date.
  145. sub get_mtime_day
  146. {
  147. use POSIX qw(strftime);
  148. my ($file) = @_;
  149. # my( $dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
  150. # $atime, $mtime, $ctime, $blksize, $blocks )
  151. # = stat( $filename );
  152. my $mtime = (stat $file)[9];
  153. # return strftime("%Y-%m-%dT%H:%M:%SZ", localtime($mtime));
  154. return strftime("%Y-%m-%d", localtime($mtime));
  155. }