Extend Octopress With Link Generator for Pocket

Wie bereits berichtet habe ich eine neue Kategorie eingefuehrt. Die weekly Pocket Links.

Einleitend moechte ich bemerken, dass ich bewusst den Weg ueber das Rakefile gewaehlt habe. Ich haette auch ein Plugin schreiben koennen in dem ich mit einem Shortcut Links automatisch erzeugen lasse. Dabei geht aber ein Stueck weit die Dynamik verloren. Der Rake Task generiert im Grunde einen neuen Blogpost den ich im Nachhinein noch bearbeiten kann.

Um das zu bewerkstelligen habe ich das Rakefile aus Octopress ein wenig erweitert. Ich habe mich erst intensiv mir der API von Pocket beschaeftigt und dann festgestellt, dass es bereits einen Gem fuer Ruby gibt, der mir die Arbeit abnimmt. https://github.com/Geknowm/pocket-ruby/

Um diesen zu nutzen habe ich ihn in das Octopress Gemfile eingetragen. active_support und i18n sind notwendig fuer die Angaben der Zeitraeume zum generieren der Linklisten.

1
2
3
4
5
6
7
8
9
--- a/Gemfile
+++ b/Gemfile
@@ -17,3 +17,6 @@ group :development do
 end

 gem 'sinatra', '~> 1.4.2'
+gem 'pocket-ruby'
+gem 'active_support'
+gem 'i18n'

Um mit dem Pocket Account zu kommunizieren wird noch ein consumer_key und ein access_token benoetigt. Den consumer_key generiert man auf der Webseite von Pocket.

http://getpocket.com/developer/apps/

Mit einem Klick auf “Create an Application” wird eine neue App erstellt. Nach Angabe von Namen und Beschreibung erwartet Pocket noch die Einstellung der Berechtigungen. In unserem Fall reicht “Retrieve” aus, da nur Daten abgefragt werden. Also Plattform wird Web angegeben (sollte aber eigentlich egal sein). Nach dem erstellen der Applikation gibt die Webseite den consumer_key aus. Dieser wird im Skript gegen 'yourconsumerkey' ausgetauscht.

Um einen access_token zu generieren wird ein sogenannter request_token benoetigt. Das Pocket-Ruby Gem bringt alle noetigen Funktionen mit um die noetigen Token zu generieren. Ich habe mir ein Script auf Basis des demo-server.rb aus dem Repository vom Pocket-Ruby Gem geschrieben. Dieses macht die Generierung der Token mit Hilfe von sinatra denkbar einfach.

generate_token.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
require "rubygems"
require "sinatra"
require "pocket"

enable :sessions

CALLBACK_URL = "http://localhost:4567/oauth/callback"

Pocket.configure do |config|
  config.consumer_key = 'yourconsumerkey'
end

get '/reset' do
  puts "GET /reset"
  session.clear
  redirect "/"
end

get "/" do
  puts "GET /"
  puts "session: #{session}"

  if session[:access_token]
    'Access token: ' + session[:access_token] +
    '<br /><a href="/reset">Reset session</a>'
  else
    '<a href="/oauth/connect">Connect with Pocket</a>'
  end
end

get "/oauth/connect" do
  puts "OAUTH CONNECT"
  session[:code] = Pocket.get_code(:redirect_uri => CALLBACK_URL)
  new_url = Pocket.authorize_url(:code => session[:code], :redirect_uri => CALLBACK_URL)
  puts "new_url: #{new_url}"
  puts "session: #{session}"
  redirect new_url
end

get "/oauth/callback" do
  puts "OAUTH CALLBACK"
  puts "request.url: #{request.url}"
  puts "request.body: #{request.body.read}"
  access_token = Pocket.get_access_token(session[:code], :redirect_uri => CALLBACK_URL)
  session[:access_token] = access_token
  puts "#{access_token}"
  puts "session: #{session}"
  redirect "/"
end

Das Script wird auf der Kommandozeile mit ruby generate_token.rb gestartet. Sinatra startet eine lokale Webserversession mit Port 4567. Mit dem Browser der Wahl rufen wir localhost:4567/ auf.

Im Browser muessen wir nur noch den Anweisungen folgen:

  • Mit Pocket verbinden
  • App authorisieren

Im Anschluss wird der generierte access_token ausgegeben. Diesen setzen wir spaeter im Rakefile ein.

Im Diff des Rakefiles sieht man die Zeilen die ich neu hinzugefuegt habe. yourconsumerkey und youraccesstoken muessen entsprechend gegen die erzeugten Keys ersetzt werden.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
--- a/Rakefile
+++ b/Rakefile
@@ -1,6 +1,8 @@
 require "rubygems"
 require "bundler/setup"
 require "stringex"
+require "active_support/all"
+require "pocket"

 ## -- Rsync Deploy config -- ##
 # Be sure your public key is listed in your server's ~/.ssh/authorized_keys file
@@ -27,6 +29,10 @@ new_post_ext    = "markdown"  # default new post file extension when using the n
 new_page_ext    = "markdown"  # default new page file extension when using the new_page task
 server_port     = "4000"      # port for preview server eg. localhost:4000

+## Pocket Configuration
+consumer_key = 'yourconsumerkey'
+access_token = 'youraccesstoken'
+

 desc "Initial setup for Octopress: copies the default theme into the path of Jekyll's generator. Rake install defaults to rake install[classic] to install a different theme run rake install[some_theme_name]"
 task :install, :theme do |t, args|
@@ -115,6 +121,50 @@ task :new_post, :title do |t, args|
   end
 end

+desc "Generate blogpost with Pocket links for your blog. e.g. weekly, monthly linklists"
+task :new_pocket, :timerange do |t, args|
+  if args.timerange
+    timerange = args.timerange
+  else
+    timerange = get_stdin("Enter timerange in days: ")
+  end
+  raise "### You haven't set anything up yet. First run `rake install` to set up an Octopress theme." unless File.directory?(source_dir)
+  mkdir_p "#{source_dir}/#{posts_dir}"
+  title = "Pocket links from #{timerange.to_i.days.ago.strftime('%Y-%m-%d')} to #{Time.now.strftime('%Y-%m-%d')}"
+  filename = "#{source_dir}/#{posts_dir}/#{Time.now.strftime('%Y-%m-%d')}-#{title.to_url}.#{new_post_ext}"
+  if File.exist?(filename)
+    abort("rake aborted!") if ask("#{filename} already exists. Do you want to overwrite?", ['y', 'n']) == 'n'
+  end
+
+  Pocket.configure do |config|
+    config.consumer_key = consumer_key
+  end
+
+  client = Pocket.client(:access_token => access_token)
+  info = client.retrieve :detailType => :article
+
+  puts "Creating new post: #{filename}"
+  open(filename, 'w') do |post|
+    post.puts "---"
+    post.puts "layout: post"
+    post.puts "title: \"#{title.gsub(/&/,'&amp;')}\""
+    post.puts "date: #{Time.now.strftime('%Y-%m-%d %H:%M')}"
+    post.puts "comments: true"
+    post.puts "categories: [Pocket, Links, Favorites]"
+    post.puts "---"
+    info["list"].each do |k,v|
+      unless v["time_added"].to_i < timerange.to_i.days.ago.to_i
+        post.puts "*   #{v["resolved_title"].to_s}"
+        post.puts "    "
+        post.puts "    >#{v["excerpt"].to_s}"
+        post.puts "    "
+        post.puts "    #{v["resolved_url"].to_s}"
+        post.puts "    "
+      end
+    end
+  end
+end
+
 # usage rake new_page[my-new-page] or rake new_page[my-new-page.html] or rake new_page (defaults to "new-page.markdown")
 desc "Create a new page in #{source_dir}/(filename)/index.#{new_page_ext}"
 task :new_page, :filename do |t, args|

Das um die Funktion “new_pocket” erweiterte Rakefile erwartet beim Aufruf ein weiteres Argument. Die Anzahl der Tage ab dem Zeitpunkt des Erstellens. Der vollstaendige Aufruf lautet also:

1
rake new_pocket['DAYS']

Fuer DAYS wird die Anzahl der Tage angegeben.

Mein new_pocket Task gibt derzeit den Titel, den Teaser und den Link zur Seite des gespeicherten Pocket Artkels aus. Jeder ist gern angehalten den Task dynamischer zu gestalten oder nach seinen Wuenschen anzupassen. In den Hash info speichert die Pocket Anfrage alle Artikel mit den entsprechenden Attributen. Die vollstaendige Liste der Attribute ist auf den Seiten von Pocket zu finden.

Alle Scripts und Hinweise sind auch in einem Github Repository zu finden.

Comments

GitHub Repos

  • Status updating...