Manage your Pinboard links.
This manual corresponds to pin version 0.2.1.
Pinboard is "social bookmarking for introverts"– a social bookmarking web service along the lines of (the now defunct) del.icio.us. pin is a command-line client for Pinboard. With it, you can send links to Pinboard (among other tasks) programmatically, or perform operations that are inconvenient from the web application such as generate a report on your tags.
The author, for instance, uses it, along with Emacs org-protocol, to capture links from the browser and store them simultaneously in his notes and on Pinboard.
The original use case for pin
was sending links to Pinboard
from the command line, or in situations where the only interface
available was process-based.
In Pinboard terms, a link is a “post”, or a “bookmark”, and it has certain attributes. The two mandatory attributes are:
A post has several other optional attributes. pin
supports
the following:
The relevant sub-command is ’send’, with arguments being the link or
links you’d like to send to Pinboard. The links may be given in one of
two ways. The first is simply giving the URL as an argument, in which
case the title will be taken from the -T
or
--title
option (which must be provided, in this case; it is
illegal to send a link with no title):
pin send --title=foo http://foo.com
The other is to give arguments in the form “URL | TITLE” in which
case the title given for each argument will be preferred to the
--title
pin send "http://foo.com | foo"
The latter form happens to be the export format of the One Tab FireFox plugin.
You can tag the links given as arguments as “to be read later” by adding the --read-later. You can tags the links given with the --tag option (which can of course be given more than once).
“Instapaper turns web content – articles, stories, posts, videos, and even long emails – into a great reading experience.” If you have an Instapaper account, you may wish to send your links there at the same time as you send them to Pinboard. You do this with the --with-instapaper option, but you’ll need to provide credentials.
You can give your username & password with --username and --password, but see also Providing Your Credentials.
The send
sub-command offers quite a few options: marking its
arguments “to be read later”, specifying tags, and sending to
Instapaper or not. It is likely that the user will develop certain
commonly-used combinations of these settings: one might mark tech
articles to be “read later”, tag them “@review-tech” and decline
to send them to Instaper, while marking long-form pieces as “read
later”, tagging them “@review-long-form” and sending them to
Instapaper for a more comfortable reading experience.
pin
supports this through the notion of a “target”. One
can, in the configuration file (See Configuration), define any
number of targets:
[targets] [targets.tech] tags = ["@review-tech"] read_later = true send_to_insty = false [targets.long-form] tags = ["@review-long-form"] read_later = true send_to_insty = true
Then, when sending links to Pinboard, one can simply refer to a pre-defined target. Instead of saying, e.g.:
pin send --tag=@review-long-form --read-later --with-instapaper "https://foo.com | Think Piece"
say:
pin send --target=long-form "https://foo.com | Think Piece"
Sometimes, you may want to delete links. The author, for instance, uses Pinboard as a reference library that sometimes includes links to documents only available on an employer’s VPN. Once that employer has been left, those documents are no longer available (or, frankly, of interest).
One can of course delete links directly, simply by saying pin
delete URL...
, but this is likely to prove tedious. Therefore, you
can also delete by tags.
To remove all links with a given tag, say:
pin delete TAG
You can combine tags with the ’+’ symbol; this will select the set of URLs who have all of the tags in the expression:
pin delete TAG1+TAG2+TAG3
will only delete links with all of TAG1, TAG2 and TAG3.
You can freely mix tags & URLs as arguments, like so:
pin delete https://foo.com TAG1+TAG2+TAG3 http://bar.io TAG4
Since the Pinboard API only allows deleting a single post at a time, this sub-command can result in a flood of API invocations subject to rate-limiting, and so this command may take some time to complete. If verbose output has not been requested, a progress bar will be displayed (see Rate Limiting).
If you’d like to just see a list of links that would be deleted, specify the --dry-run flag.
The author has found that without regular curation, his tag collection decays; typos creep in, similar tags are created to name the same abstraction, and so forth. Periodically, one may want to get a report one one’s tags.
pin get-tags
will do so. It will fetch all of the user’s
tags from Pinboard and print them in a a few formats. By default, it
will produce an Emacs Org Mode-like table, but the --csv
option will instead cause it to produce output in Comma-Separated
Values format.
By default, the tags are sorted numerically by use; use the alphabetical option to sort lexicographically.
By default, the tags are sorted in ascending order (whether numerically or lexicographically); use the --descending option to reverse that.
Having discovered a typo in one’s tagging scheme, one may wish to
correct it: just say pin rename-tag OLD NEW
to rename all
instances of the old tag name to the new.
Pinboard API callers may authenticate
using the HTTP Basic Authentication scheme with the credentials
provided in the URL
(i.e. ‘https://username:password@api.pinboard.in/v1/method’) or
with an API key provided in the query parameters
(i.e. ‘https://api.pinboard.in/v1/method?auth_token=user:NNNNNN’).
Given the obvious security concerns in the former, pin
only
supports the latter. You can find your API key
here once you’ve signed-up
& logged-in.
You can provide that token to pin
in one of the following
three ways:
PINBOARD_API_TOKEN
environment variable
600
, for instance).
Instapaper credentials may be provided as parameters to the
send
sub-command, in the environment variables
INSTAPAPER_USERNAME
and INSTAPAPER_PASSWORD
or in the
configuration file (see The Configuration File).
pin
offers many options. The user may find it convenient to
collect some of them in a configuration file (~/.pin
by
default) that will be read by the tool on invocation rather than
specifying them every time on the command line.
The configuration file is in TOML format, and all items are optional:
Targets (see Targets) are specified in their own section “[targets]”, and each target has its own section “[targets.NAME]” (see below for an example). Each target may have one or more of the following attributes:
A complete sample configuration file:
# Instapaper username username = "jdoe@gmail.com" # Pinboard API token token ="jdoe:DECADE90C0DEDDABB1ED" [targets] [targets.tech] tags = ["@review-tech", "tech"] read_later = true send_to_insty = false
All textual entities shall be UTF-8 encoded. The API
docs state that “’characters’
means logical characters rather than bytes”. pin
interprets
that to mean grapheme clusters and uses the
unicode_segmentation
crate to identify them.
Both the Pinboard & Instapaper APIs reserve the right to rate-limit callers. In the case of Pinboard, the advertised acceptable rate for most endpoints is one request every three seconds (much worse for a few selected endpoints), but the author has seen far better than that in the wild. The docs suggest: “Make sure your API clients check for 429 Too Many Requests server errors and back off appropriately. If possible, keep doubling the interval between requests until you stop receiving errors.”
Instapaper is a bit more coy, only alluding to rate-limiting in their documentation for a 400 response code as being returned for “a bad request or exceeded the rate limit”. The rate limit is never defined, and the author has never encountered it in the wild.
Regardless, this implementation will take into account the possibility of rate-limiting by retrying on certain status codes, halving the request rate each time.
pin
is still early code; its version number 0.2.1
is selected to indicate that.
The package is intended to provide an interface organized around user operations, not API endpoints, so new operations will be added when & as they are requested.
Bugs, comments, problems, PRs, feature requests &c welcome at sp1ff@pobox.com, Github or shoot a webmention to me at my web site.
Jump to: | B C D E G I O P R S T U |
---|
Jump to: | B C D E G I O P R S T U |
---|