-
Notifications
You must be signed in to change notification settings - Fork 318
/
posterous.rb
131 lines (114 loc) · 4.28 KB
/
posterous.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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
module JekyllImport
module Importers
class Posterous < Importer
def self.specify_options(c)
c.option "email", "--email EMAIL", "Posterous email address"
c.option "password", "--password PW", "Posterous password"
c.option "api_token", "--token TOKEN", "Posterous API Token"
end
def self.require_deps
JekyllImport.require_with_fallback(%w(
rubygems
jekyll
fileutils
uri
json
net/http
))
end
def self.fetch(uri_str, limit = 10)
# You should choose better exception.
raise ArgumentError, "Stuck in a redirect loop. Please double check your email and password" if limit.zero?
response = nil
Net::HTTP.start("posterous.com") do |http|
req = Net::HTTP::Get.new(uri_str)
req.basic_auth @email, @pass
response = http.request(req)
end
case response
when Net::HTTPSuccess then response
when Net::HTTPRedirection then fetch(response["location"], limit - 1)
else response.error!
end
end
def self.fetch_images(directory, imgs)
def self.fetch_one(url, limit = 10)
raise ArgumentError, "HTTP redirect too deep" if limit.zero?
response = Net::HTTP.get_response(URI.parse(url))
case response
when Net::HTTPSuccess then response.body
when Net::HTTPRedirection then self.fetch_one(response["location"], limit - 1)
else
response.error!
end
end
FileUtils.mkdir_p directory
urls = []
imgs.each do |img|
fullurl = img["full"]["url"]
uri = URI.parse(fullurl)
imgname = uri.path.split("/")[-1]
imgdata = self.fetch_one(fullurl)
open(directory + "/" + imgname, "wb") do |file|
file.write imgdata
end
urls.push(directory + "/" + imgname)
end
return urls
end
def self.process(options)
email = options.fetch("email")
pass = options.fetch("password")
api_token = options.fetch("api_token")
@email = email
@pass = pass
@api_token = api_token
defaults = { :include_imgs => false, :blog => "primary", :base_path => "/" }
opts = defaults.merge(opts)
FileUtils.mkdir_p "_posts"
posts = JSON.parse(self.fetch("/api/v2/users/me/sites/#{opts[:blog]}/posts?api_token=#{@api_token}").body)
page = 1
while posts.any?
posts.each do |post|
title = post["title"]
slug = title.gsub(%r![^[:alnum:]]+!, "-").downcase
date = Date.parse(post["display_date"])
content = post["body_html"]
published = !post["is_private"]
basename = format("%02d-%02d-%02d-%s", date.year, date.month, date.day, slug)
name = basename + ".html"
# Images:
if opts[:include_imgs]
post_imgs = post["media"]["images"]
if post_imgs.any?
img_dir = format("imgs/%s", basename)
img_urls = self.fetch_images(img_dir, post_imgs)
img_urls.map! do |url|
'<li><img src="' + opts[:base_path] + url + '"></li>'
end
imgcontent = "<ol>\n" + img_urls.join("\n") + "</ol>\n"
# filter out "posterous-content", replacing with imgs:
content = content.sub(%r!\<p\>\[\[posterous-content:[^\]]+\]\]\<\/p\>!, imgcontent)
end
end
# Get the relevant fields as a hash, delete empty fields and convert
# to YAML for the header
data = {
"layout" => "post",
"title" => title.to_s,
"published" => published,
}.delete_if { |_k, v| v.nil? || v == "" }.to_yaml
# Write out the data and content to file
File.open("_posts/#{name}", "w") do |f|
f.puts data
f.puts "---"
f.puts content
end
end
page += 1
posts = JSON.parse(self.fetch("/api/v2/users/me/sites/#{opts[:blog]}/posts?api_token=#{@api_token}&page=#{page}").body)
end
end
end
end
end