dotfiles

My personal shell configs and stuff
git clone git://git.alex.balgavy.eu/dotfiles.git
Log | Files | Refs | Submodules | README | LICENSE

libpocket.rb (3475B)


      1 # frozen_string_literal: true
      2 # https://getpocket.com/developer/docs/overview
      3 require 'open-uri'
      4 require 'json'
      5 require 'net/http'
      6 
      7 def die(message)
      8   warn "error: #{message}"
      9   exit 1
     10 end
     11 
     12 # The Pocket API authentication system
     13 class PocketAuth
     14   def initialize
     15     die 'Please set the POCKET_CONSUMER_KEY environment variable.' unless ENV['POCKET_CONSUMER_KEY']
     16     @consumer_key = ENV['POCKET_CONSUMER_KEY']
     17     @base = 'https://getpocket.com/v3'
     18     @headers = { 'Content-Type' => 'application/json; charset=UTF8', 'X-Accept' => 'application/json' }
     19     @access_token = read_access_token
     20   end
     21 
     22   def credentials
     23     { consumer_key: @consumer_key, access_token: @access_token }
     24   end
     25 
     26   private
     27 
     28   ACCESS_TOKEN_FILE = "#{ENV['HOME']}/.cache/pocket-access-token"
     29 
     30   def read_access_token
     31     if File.exist? ACCESS_TOKEN_FILE
     32       @access_token = File.read ACCESS_TOKEN_FILE
     33     else
     34       @access_token = request_access_token
     35       puts "Writing access token to #{ACCESS_TOKEN_FILE}, remove this file to revoke authorization."
     36       File.write ACCESS_TOKEN_FILE, @access_token
     37     end
     38   end
     39 
     40   def generate_auth_uri
     41     query = { consumer_key: @consumer_key, redirect_uri: 'https://example.com' }
     42     response = Net::HTTP.post URI("#{@base}/oauth/request"), query.to_json, @headers
     43     if response.code == '200'
     44       @pocket_code = JSON.parse(response.body)['code']
     45     else
     46       die 'Could not retrieve code.'
     47     end
     48     "https://getpocket.com/auth/authorize?request_token=#{@pocket_code}&redirect_uri=#{query['redirect_uri']}"
     49   end
     50 
     51   def authenticate
     52     query = { consumer_key: @consumer_key, code: @pocket_code }
     53     response = Net::HTTP.post URI("#{@base}/oauth/authorize"), query.to_json, @headers
     54     return nil unless response.code == '200'
     55 
     56     JSON.parse(response.body)
     57   end
     58 
     59   def request_access_token
     60     puts "Please open: #{generate_auth_uri}"
     61     # TODO: start a temp server, react when receive request (URL passed in redirect_uri above)
     62     print 'Press enter when done.'
     63     STDIN.getc
     64     auth_response = authenticate
     65     die 'Could not authenticate' unless auth_response
     66     puts "Authenticated for username #{body['username']}"
     67     @access_token = body['access_token']
     68   end
     69 end
     70 
     71 # The Pocket API interface class
     72 class Pocket
     73   def initialize
     74     @base = 'https://getpocket.com/v3'
     75     @headers = { 'Content-Type' => 'application/json; charset=UTF8', 'X-Accept' => 'application/json' }
     76     @security_params = PocketAuth.new.credentials
     77   end
     78 
     79   def api_call(endpoint, params)
     80     response = Net::HTTP.post URI(@base+endpoint), params.merge(@security_params).to_json, @headers
     81     if response.code == '200'
     82       block_given? ? (yield JSON.load(response.body)) : (return JSON.load(response.body))
     83     else
     84       die "Could not add, code #{response.code}"
     85     end
     86   end
     87 
     88   def archive_all_pocketbook
     89     tagged_pocketbook = api_call('/get', { tag: 'pocketbook', state: :any })
     90     ids = tagged_pocketbook['list'].map(&:first)
     91     actions = ids.map { |id| [{action: :tags_remove, item_id: id, tags: 'pocketbook'}, {action: :archive, item_id: id}]}.flatten
     92     result = api_call('/send', { actions: })
     93     warn "Some errors, ids #{ids}" unless result['action_results'].all?
     94   end
     95 
     96   def save(url)
     97     api_call("/add", url: url)
     98   end
     99 
    100   def retrieve_list(query)
    101     # merge overwrites sort key if needed
    102     api_call("/get", { sort: 'newest' }.merge(query)) do |response_body|
    103       response_body['list'].map { |_id, data| data }
    104     end
    105   end
    106 end
    107