Instapaper Kindle Two way Sync
Well today might not be the best day for Marco of Instapaper with the introduction of Reading List feature in iOS and Mac OS X by Apple. But I love Instapaper nonetheless. But one of the annoyances I have is that there is no two way sync with the Kindle. Well there is http://goephemera.com/ but it is unmaintained and no longer works for multiple articles.
So in a binge of insomniac coding I decided to write such a sync. Now, I realize that I am not going to be putting a lot of work into maintaing this so take it as is and improve it as you like.
Somethings you will need:
Leave a comment if you need help. But this does assume you have knowledge of the command line.
require 'rubygems' require 'oauth' require 'json' require "sqlite3" # Get your key here. http://www.instapaper.com/main/request_oauth_consumer_token INSTAPAPER_CONSUMER_KEY = 'getyourownkey' INSTAPAPER_CONSUMER_SECRET = 'getyourownkey' INSTAPAPER_USERNAME = 'user@mail.com' INSTAPAPER_PASSWORD = 'password' KINDLEGEN = "~/Dropbox/KindleGen/kindlegen" class Instapaper Url = "http://www.instapaper.com" def initialize(consumer_key, consumer_secret) @consumer_key = consumer_key @consumer_secret = consumer_secret end def authorize(username, password) @consumer = OAuth::Consumer.new(@consumer_key, @consumer_secret, { :site => "https://www.instapaper.com", :access_token_path => "/api/1/oauth/access_token", :http_method => :post }) access_token = @consumer.get_access_token(nil, {}, { :x_auth_username => username, :x_auth_password => password, :x_auth_mode => "client_auth", }) @access_token = OAuth::AccessToken.new(@consumer, access_token.token, access_token.secret) end def request(path, params={}) @access_token.request(:post, "#{Url}#{path}", params) end end $instapaper = Instapaper.new(INSTAPAPER_CONSUMER_KEY, INSTAPAPER_CONSUMER_SECRET) $instapaper.authorize(INSTAPAPER_USERNAME, INSTAPAPER_PASSWORD) $db = SQLite3::Database.new('i2ksync.db') $db.results_as_hash = true # status 1. download, 2. still_there 3. archived $db.execute(%{ create table if not exists bookmarks ( id integer PRIMARY KEY, title text, status text, UNIQUE(id)) }) # Create the path if it doesn't exist path = File.join("/Volumes/Kindle/documents", "_instapaper") Dir.mkdir(path) unless File.exists?(path) num_not_there = 0 still_there_ids = [] still_there = $db.execute("select * from bookmarks where status = 2") still_there.each do |bookmark| unless File.exists?(File.join(path, "#{bookmark['title']}.mobi")) $instapaper.request("/api/1/bookmarks/archive?bookmark_id=#{bookmark['id']}") $db.execute("update bookmarks set status = 3 where id = #{bookmark['id']}") num_not_there += 1 else still_there_ids << bookmark['id'] end end articles = JSON.parse($instapaper.request("/api/1/bookmarks/list?limit=#{25 - num_not_there}&have=#{still_there_ids.join(',')}").body) articles.each do |article| next unless article.has_key?('title') filename = article['title'] filename = "Article #{article['bookmark_id']}" unless article['title'] file_path = "#{filename}.html" File.open(File.join(path, file_path), 'w') do |f| f << $instapaper.request("/api/1/bookmarks/get_text?bookmark_id=#{article['bookmark_id']}").body end $db.execute("insert or ignore into bookmarks (id, title, status) values (?,?,?)", article['bookmark_id'], filename, 2) end `cd #{path} && find . -name "*html" -exec #{KINDLEGEN} {} \\;` `cd #{path} && find . -name "*html" -exec rm {} \\;`
