summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bin/pinboard_export86
-rw-r--r--lib/WWW/Pinboard.pm69
2 files changed, 155 insertions, 0 deletions
diff --git a/bin/pinboard_export b/bin/pinboard_export
new file mode 100644
index 0000000..5876809
--- /dev/null
+++ b/bin/pinboard_export
@@ -0,0 +1,86 @@
+#!perl
+use strict;
+use warnings;
+
+use DBI;
+use Getopt::Long qw(:config pass_through);
+use WWW::Pinboard;
+use Term::ProgressBar;
+
+my ($dsn, $token, $quiet);
+GetOptions(
+ 'dsn=s' => \$dsn,
+ 'token=s' => \$token,
+ 'quiet' => \$quiet,
+);
+die "--dsn is required" unless $dsn;
+die "--token is required" unless $token;
+
+my $dbh = DBI->connect($dsn, '', '', { RaiseError => 1, AutoCommit => 0 });
+my $fromdt = '1970-01-01T00:00:00Z';
+if (!$dbh->tables(undef, undef, 'posts')) {
+ $dbh->do(<<'');
+ CREATE TABLE `posts` (
+ href TEXT NOT NULL,
+ description TEXT NOT NULL,
+ extended TEXT NOT NULL,
+ tags TEXT NOT NULL,
+ time TEXT NOT NULL,
+ toread TEXT NOT NULL
+ );
+
+}
+else {
+ ($fromdt) = $dbh->selectrow_array(
+ 'SELECT time FROM posts ORDER BY strftime("%s", time) DESC LIMIT 1'
+ );
+}
+
+my $api = WWW::Pinboard->new(token => $token);
+
+if ($fromdt ge $api->update->{update_time}) {
+ $dbh->disconnect;
+ exit(0);
+}
+
+my $progress;
+
+my $sth = $dbh->prepare(
+ 'INSERT INTO posts (href, description, extended, tags, time, toread) VALUES (?, ?, ?, ?, ?, ?)'
+);
+
+my $posts = $api->all(fromdt => $fromdt, progress => sub {
+ my ($chunk, $res) = @_;
+ if (!$progress && !$quiet && defined $res->{headers}{'content-length'}) {
+ $progress = Term::ProgressBar->new({
+ count => $res->{headers}{'content-length'},
+ ETA => 'linear',
+ });
+ $progress->message("downloading new posts...");
+ }
+ $res->{content} .= $chunk;
+ $progress->update(length($res->{content})) if $progress;
+});
+
+if (!$quiet) {
+ $progress = Term::ProgressBar->new({
+ count => scalar(@$posts),
+ ETA => 'linear',
+ });
+ $progress->message('importing posts...');
+}
+
+for my $post (@$posts) {
+ $sth->execute(
+ $post->{href},
+ $post->{description},
+ $post->{extended},
+ $post->{tags},
+ $post->{time},
+ $post->{toread},
+ );
+ $progress->update if $progress;
+}
+
+$dbh->commit;
+$dbh->disconnect;
diff --git a/lib/WWW/Pinboard.pm b/lib/WWW/Pinboard.pm
index e69de29..39e1c63 100644
--- a/lib/WWW/Pinboard.pm
+++ b/lib/WWW/Pinboard.pm
@@ -0,0 +1,69 @@
+package WWW::Pinboard;
+use Moose;
+
+use HTTP::Tiny;
+use JSON::PP;
+use URI;
+
+has token => (
+ is => 'ro',
+ isa => 'Str',
+);
+
+has _endpoint => (
+ is => 'ro',
+ isa => 'Str',
+ init_arg => 'endpoint',
+ default => 'https://api.pinboard.in/v1/',
+);
+
+has endpoint => (
+ is => 'ro',
+ isa => 'URI',
+ lazy => 1,
+ default => sub {
+ my $self = shift;
+ my $uri = URI->new($self->_endpoint);
+ $uri->query_form(auth_token => $self->token, format => 'json');
+ return $uri;
+ },
+);
+
+has ua => (
+ is => 'ro',
+ isa => 'HTTP::Tiny',
+ lazy => 1,
+ default => sub { HTTP::Tiny->new },
+);
+
+has json => (
+ is => 'ro',
+ isa => 'JSON::PP',
+ lazy => 1,
+ default => sub { JSON::PP->new },
+);
+
+for my $method (qw(update add delete get recent dates all suggest)) {
+ __PACKAGE__->meta->add_method($method => sub {
+ my $self = shift;
+ my (%args) = @_;
+
+ my $progress = delete $args{progress};
+
+ my $uri = $self->endpoint->clone;
+ # XXX eventually support other parts of the api
+ $uri->path($uri->path . 'posts/' . $method);
+ $uri->query_form($uri->query_form, %args);
+
+ my $res = $self->ua->get(
+ $uri, { $progress ? (data_callback => $progress) : () }
+ );
+ die $res->{content} unless $res->{success};
+ return $self->json->decode($res->{content});
+ });
+}
+
+__PACKAGE__->meta->make_immutable;
+no Moose;
+
+1;