#!/usr/bin/perl -w use strict; use FindBin; use lib "$FindBin::RealBin/../lib"; use YAML; use Getopt::Long qw{GetOptions GetOptionsFromArray :config pass_through}; use Bookmarks; GetOptions( 'file|f=s' => \my $DBNAME, ); my $dbname = $DBNAME || $ENV{BKMK_DBNAME} || 'bookmarks.db'; die "Usage: $0 --file \n" unless $dbname; my $bookmarks = Bookmarks->new({ dbname => $dbname, }); my $command = shift; my %action_for = ( init => sub { my $src_file = shift; $bookmarks->create_tables; load_bookmarks($src_file) if $src_file; }, get => sub { my $identifier = shift; my $bookmark = find_bookmark($identifier); print $bookmark ? Dump($bookmark->to_hashref) : "Not Found\n"; }, add => sub { GetOptionsFromArray( \@_, 'title=s' => \my $TITLE, ); my ($uri, @tags) = @_; my $title = defined $TITLE ? $TITLE : fetch_title($uri); my $bookmark = $bookmarks->add({ uri => $uri, title => $title, tags => \@tags }); print Dump($bookmark->to_hashref); }, list => sub { GetOptionsFromArray( \@_, 'query|q=s' => \my $QUERY, ); my @tags = @_; my $resources = $bookmarks->search({ query => $QUERY, tags => \@tags }); # TODO: list by tags, date, etc. # TODO: coordinate this commandline script with the CGI app print Dump([ map { $_->to_hashref } @{ $resources->results } ]); }, tag => sub { my ($identifier, @tags) = @_; my $bookmark = find_bookmark($identifier); if ($bookmark) { $bookmark->tags(\@tags); $bookmarks->update($bookmark); print Dump($bookmark->to_hashref); } else { die "Not found\n"; } }, # interactive editing of a bookmark edit => sub { my ($identifier) = @_; my $bookmark = find_bookmark($identifier) or die "Not found\n"; my $editor = $ENV{VISUAL} || $ENV{EDITOR} || 'vi'; # create a temp file and open it in the user's preferred editor use File::Temp qw{tempfile}; my ($fh, $filename) = tempfile(UNLINK => 1); YAML::DumpFile($filename, $bookmark->to_hashref); system($editor, $filename); # abort on empty file die "Edit canceled\n" unless -s $filename; # update and save the bookmark $bookmark = Bookmark->new(YAML::LoadFile($filename)); $bookmarks->update($bookmark); print Dump($bookmark->to_hashref); }, # bulk loading load => sub { my ($src_file) = @_; load_bookmarks($src_file); }, # bulk dumping dump => sub { my ($dump_file) = @_; my $dump = [ map { $_->to_hashref } @{ $bookmarks->search->results } ]; $dump_file ? YAML::DumpFile($dump_file, $dump) : print Dump($dump); }, # scanning for current status scan => sub { GetOptionsFromArray( \@_, 'csv' => \my $CSV, 'timeout=i' => \my $TIMEOUT, ); require LWP::UserAgent; require Text::CSV; $TIMEOUT ||= 10; my $ua = LWP::UserAgent->new; $ua->timeout($TIMEOUT); my $csv = Text::CSV->new; for my $bookmark (@{ $bookmarks->search->results }) { printf "%3d %s\n", $bookmark->id, $bookmark->uri unless $CSV; my $response = $ua->head($bookmark->uri); printf " -> %s\n", $response->status_line unless $CSV; $csv->combine( $bookmark->id, $bookmark->uri, $response->code, $response->message, ); print $csv->string . "\n" if $CSV; } }, ); $action_for{$command}->(@ARGV); sub find_bookmark { my $identifier = shift; my $query = $identifier =~ /^\d+$/ ? { id => $identifier } : { uri => $identifier }; return $bookmarks->get_bookmark($query); } sub fetch_title { my $uri = shift; require WWW::Mechanize; my $mech = WWW::Mechanize->new; $mech->get($uri); return $mech->title || $uri; } sub load_bookmarks { my $src_file = shift; my $src_bookmarks = YAML::LoadFile($src_file); for my $bookmark (@{ $src_bookmarks }) { $bookmarks->add($bookmark); } }