hpanot

hpanot: get your annotations in Markdown from Hypothes.is (https://hypothes.is)
git clone git://git.alex.balgavy.eu/hpanot.git
Log | Files | Refs | README

commit c31c8afd06151806edb874d1a25bc61274dd2c48
Author: Alex Balgavy <a.balgavy@gmail.com>
Date:   Wed,  7 Oct 2020 20:02:01 +0200

Initial commit

Diffstat:
AMakefile | 21+++++++++++++++++++++
AREADME.md | 11+++++++++++
Ahpanot | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 152 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile @@ -0,0 +1,21 @@ +prefix=/usr/local +datarootdir=$(prefix)/share +etcdir=$(prefix)/etc/hpanot +datadir=$(datarootdir) +exec_prefix=$(prefix) +bindir=$(exec_prefix)/bin +mandir=$(datarootdir)/man +man1dir=$(mandir)/man1 + +all: + @echo "Targets: install, uninstall" + +install: hpanot + cp hpanot $(bindir)/ + mkdir -p $(etcdir) + cp urls $(etcdir)/ + +uninstall: + rm $(bindir)/hpanot + rm $(etcdir)/urls + rmdir $(etcdir) diff --git a/README.md b/README.md @@ -0,0 +1,11 @@ +# hpanot: get your annotations in Markdown from [hypothes.is](https://hypothes.is) + +Requires Ruby. +Make sure to set the environment variables: +* `HYPOTHESIS_API_KEY`: your Hypothes.is API key, find it in your account under "developer" +* `HYPOTHESIS_USERNAME`: your Hypothes.is username (not email) + +## Installation +* Homebrew: `brew install thezeroalpha/formulae/hpanot` +* Makefile: `make install` +* Manual: download the `hpanot` script, make it executable, and put it in your `$PATH` diff --git a/hpanot b/hpanot @@ -0,0 +1,120 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require 'open-uri' +require 'json' + +# hypothes.is interface +class Hypothesis + # a hypothes.is annotation + class Annotation + def initialize(text:, comment:, title:, uri:) + @text = text + @comment = comment.empty? ? nil : comment + @title = title + @uri = uri + end + + def to_markdown + str = @text.split("\n").reduce('') { |acc, line| acc + "> #{line}\n" } + str += "\n" + str += "#{@comment}\n" if @comment + str + end + + def to_markdown_title_url + "[#{@title}](#{@uri})\n" + end + end + + def initialize + %w[HYPOTHESIS_API_KEY HYPOTHESIS_USERNAME].each do |var| + die "Please set the #{var} environment variable" if ENV[var].nil? + end + + @apikey = ENV['HYPOTHESIS_API_KEY'] + @username = ENV['HYPOTHESIS_USERNAME'] + @headers = { 'Host' => 'hypothes.is', 'Accept' => 'application/json', 'Authorization' => "Bearer #{@apikey}" } + @baseurl = 'https://hypothes.is/api' + + ping || die("Could not access the API #{@baseurl}") + end + + def search_host(host) + annotations "wildcard_uri=http://#{host}/*" + end + + def search_uri(uri) + annotations "uri=#{uri}" + end + + private + + def ping + URI.open("#{@baseurl}/", @headers) + true + rescue OpenURI::HTTPError + false + end + + def die(msg) + warn msg + exit 1 + end + + def request(endpoint) + URI.open(@baseurl + endpoint, @headers) do |response| + JSON.parse(response.read)['rows'] + end + rescue OpenURI::HTTPError + warn "Error getting data from #{endpoint}" + [] + end + + def annotations(uri_search_str) + data = request "/search?user=acct:#{@username}@hypothes.is&#{uri_search_str}&limit=200&order=asc" + data.reduce([]) do |arr, annot| + arr << Annotation.new(text: annot['target'].first['selector'] + .select { |f| f['type'] == 'TextQuoteSelector' }.first['exact'], + comment: annot['text'], + title: annot['document']['title'].first, + uri: annot['uri']) + end + end +end + +def print_usage + puts <<~HEREDOC + Usage: hpanot [command] [arg1, [arg2...]] + + Commands: + site [URL] get annotations for a website + + HEREDOC +end + +ARGV.each do |opt| + case opt + when '-h' || '--help' + print_usage + exit 0 + end +end + +params = ARGV.reject { |arg| arg.start_with? '-' } +if params.empty? + print_usage + exit 1 +end + +case params[0] +when 'site' + die 'No website specified, use pass -h to print usage.' unless params[1] + h = Hypothesis.new + site = params[1] + annotations = site.start_with?('http') ? h.search_uri(site) : h.search_host(site) + puts annotations.first.to_markdown_title_url + "\n" + annotations.reduce('') { |str, annot| str + annot.to_markdown } +else + print_usage + exit 1 +end