Skip to content

Instantly share code, notes, and snippets.

@niw
Created March 7, 2012 11:58
Show Gist options
  • Save niw/1992719 to your computer and use it in GitHub Desktop.
Save niw/1992719 to your computer and use it in GitHub Desktop.
A tiny script to import items from Instapaper to Readability
#!/usr/bin/env ruby
require 'csv'
require 'net/smtp'
require 'resolv'
# We need a specific version of eventmachine due to apply a patch.
gem 'eventmachine', '0.12.10'
require 'eventmachine'
# Patch EventMachine::Protocol::SmtpClient to use HELO instead.
# Readability SMTP server doesn't understand EHLO.
# See lib/em/protocols/smtpclient.rb
module EventMachine
module Protocols
class SmtpClient
def receive_signon
return invoke_error unless @range == 2
send_data "HELO #{@args[:domain]}\r\n"
@responder = :receive_ehlo_response
end
end
end
end
class ImportInstapaperToReadability
MAX_URLS_IN_MAIL = 20.freeze
DUMMY_FROM = "foo@bar".freeze
def run!
readability_email_address = ARGV.shift
instapaper_csv_file = ARGV.shift
unless readability_email_address && instapaper_csv_file
usage
exit
end
urls = parse_instapaper_csv(instapaper_csv_file)
import_urls_to_readability(readability_email_address, urls)
end
private
def usage
puts "Usage: #{$0} <readability email address> <instapaper csv>"
end
def parse_instapaper_csv(path)
CSV.read(path).map do |line|
line[0]
end.reverse
end
def import_urls_to_readability(email_address, urls)
domain = domain_for_email_address(email_address)
host = host_for_domain(domain)
run_event_machine do
urls.each_slice(MAX_URLS_IN_MAIL) do |urls_in_mail|
puts "Importing #{urls_in_mail.size} URLs..."
add_smtp_send({
:verbose => true,
:domain => domain,
:host => host,
:from => DUMMY_FROM,
:to => email_address,
:header => {:From => DUMMY_FROM, :To => email_address},
:body => urls_in_mail.join("\r\n")
},
lambda {
puts urls_in_mail.map{|url| "Imported #{url}"}
},
lambda {
puts urls_in_mail.map{|url| "Failed #{url}"}
})
end
end
# Net::SMTP.start(host, 25) do |smtp|
# urls.each_slice(MAX_URLS_IN_MAIL) do |urls_in_mail|
# puts "Importing #{urls_in_mail.size} URLs..."
# smtp.send_message(email_body_for_urls(DUMMY_FROM, email_address, urls_in_mail), DUMMY_FROM, email_address)
# puts urls_in_mail.map{|url| "Imported #{url}"}
# end
# end
end
module EventMachineHelper
def run_event_machine
EventMachine.run do
@count = 0
yield
end
end
def add_smtp_send(options, callback = nil, errback = nil)
@count += 1
EM::Protocols::SmtpClient.send(options).tap do |smtp|
smtp.callback do
callback.call if callback
stop_event_machine_if_last_job
end
smtp.errback do
errback.call if errback
stop_event_machine_if_last_job
end
end
end
def stop_event_machine_if_last_job
@count -= 1
EventMachine.stop unless @count > 0
end
end
include EventMachineHelper
def domain_for_email_address(email_address)
$1 if /@([^@]+)$/ === email_address
end
def host_for_domain(domain)
resource = Resolv::DNS.new.getresource(domain, Resolv::DNS::Resource::IN::MX)
if Resolv::DNS::Resource::IN::MX === resource
resource.exchange.to_s
end
end
# def email_body_for_urls(from, to, urls)
# <<-END_OF_EMAIL
#From: <#{from}>
#To: <#{to}>
#
##{urls.join("\r\n")}
# END_OF_EMAIL
# end
end
ImportInstapaperToReadability.new.run!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment