bunto-import 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE +21 -21
- data/README.markdown +33 -33
- data/lib/bunto-import.rb +49 -49
- data/lib/bunto-import/importer.rb +26 -26
- data/lib/bunto-import/importers.rb +10 -10
- data/lib/bunto-import/importers/behance.rb +80 -80
- data/lib/bunto-import/importers/blogger.rb +330 -264
- data/lib/bunto-import/importers/csv.rb +96 -96
- data/lib/bunto-import/importers/drupal6.rb +53 -139
- data/lib/bunto-import/importers/drupal7.rb +54 -111
- data/lib/bunto-import/importers/drupal_common.rb +157 -0
- data/lib/bunto-import/importers/easyblog.rb +96 -96
- data/lib/bunto-import/importers/enki.rb +74 -74
- data/lib/bunto-import/importers/ghost.rb +68 -68
- data/lib/bunto-import/importers/google_reader.rb +64 -64
- data/lib/bunto-import/importers/joomla.rb +92 -90
- data/lib/bunto-import/importers/joomla3.rb +91 -91
- data/lib/bunto-import/importers/jrnl.rb +125 -125
- data/lib/bunto-import/importers/marley.rb +72 -72
- data/lib/bunto-import/importers/mephisto.rb +99 -99
- data/lib/bunto-import/importers/mt.rb +257 -257
- data/lib/bunto-import/importers/posterous.rb +130 -130
- data/lib/bunto-import/importers/rss.rb +62 -62
- data/lib/bunto-import/importers/s9y.rb +60 -60
- data/lib/bunto-import/importers/s9y_database.rb +363 -0
- data/lib/bunto-import/importers/textpattern.rb +70 -70
- data/lib/bunto-import/importers/tumblr.rb +300 -289
- data/lib/bunto-import/importers/typo.rb +88 -88
- data/lib/bunto-import/importers/wordpress.rb +372 -372
- data/lib/bunto-import/importers/wordpressdotcom.rb +207 -207
- data/lib/bunto-import/util.rb +76 -76
- data/lib/bunto-import/version.rb +3 -3
- data/lib/bunto/commands/import.rb +79 -79
- metadata +84 -54
@@ -1,130 +1,130 @@
|
|
1
|
-
module BuntoImport
|
2
|
-
module Importers
|
3
|
-
class Posterous < Importer
|
4
|
-
|
5
|
-
def self.specify_options(c)
|
6
|
-
c.option 'email', '--email EMAIL', 'Posterous email address'
|
7
|
-
c.option 'password', '--password PW', 'Posterous password'
|
8
|
-
c.option 'api_token', '--token TOKEN', 'Posterous API Token'
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.require_deps
|
12
|
-
BuntoImport.require_with_fallback(%w[
|
13
|
-
rubygems
|
14
|
-
bunto
|
15
|
-
fileutils
|
16
|
-
uri
|
17
|
-
json
|
18
|
-
net/http
|
19
|
-
])
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.fetch(uri_str, limit = 10)
|
23
|
-
# You should choose better exception.
|
24
|
-
raise ArgumentError, 'Stuck in a redirect loop. Please double check your email and password' if limit == 0
|
25
|
-
|
26
|
-
response = nil
|
27
|
-
Net::HTTP.start('posterous.com') do |http|
|
28
|
-
req = Net::HTTP::Get.new(uri_str)
|
29
|
-
req.basic_auth @email, @pass
|
30
|
-
response = http.request(req)
|
31
|
-
end
|
32
|
-
|
33
|
-
case response
|
34
|
-
when Net::HTTPSuccess then response
|
35
|
-
when Net::HTTPRedirection then fetch(response['location'], limit - 1)
|
36
|
-
else response.error!
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def self.fetch_images(directory, imgs)
|
41
|
-
def self.fetch_one(url, limit = 10)
|
42
|
-
raise ArgumentError, 'HTTP redirect too deep' if limit == 0
|
43
|
-
response = Net::HTTP.get_response(URI.parse(url))
|
44
|
-
case response
|
45
|
-
when Net::HTTPSuccess then response.body
|
46
|
-
when Net::HTTPRedirection then self.fetch_one(response['location'], limit - 1)
|
47
|
-
else
|
48
|
-
response.error!
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
FileUtils.mkdir_p directory
|
53
|
-
urls = Array.new
|
54
|
-
imgs.each do |img|
|
55
|
-
fullurl = img["full"]["url"]
|
56
|
-
uri = URI.parse(fullurl)
|
57
|
-
imgname = uri.path.split("/")[-1]
|
58
|
-
imgdata = self.fetch_one(fullurl)
|
59
|
-
open(directory + "/" + imgname, "wb") do |file|
|
60
|
-
file.write imgdata
|
61
|
-
end
|
62
|
-
urls.push(directory + "/" + imgname)
|
63
|
-
end
|
64
|
-
|
65
|
-
return urls
|
66
|
-
end
|
67
|
-
|
68
|
-
def self.process(options)
|
69
|
-
email = options.fetch('email')
|
70
|
-
pass = options.fetch('password')
|
71
|
-
api_token = options.fetch('api_token')
|
72
|
-
|
73
|
-
@email, @pass, @api_token = email, pass, api_token
|
74
|
-
defaults = { :include_imgs => false, :blog => 'primary', :base_path => '/' }
|
75
|
-
opts = defaults.merge(opts)
|
76
|
-
FileUtils.mkdir_p "_posts"
|
77
|
-
|
78
|
-
posts = JSON.parse(self.fetch("/api/v2/users/me/sites/#{opts[:blog]}/posts?api_token=#{@api_token}").body)
|
79
|
-
page = 1
|
80
|
-
|
81
|
-
while posts.any?
|
82
|
-
posts.each do |post|
|
83
|
-
title = post["title"]
|
84
|
-
slug = title.gsub(/[^[:alnum:]]+/, '-').downcase
|
85
|
-
date = Date.parse(post["display_date"])
|
86
|
-
content = post["body_html"]
|
87
|
-
published = !post["is_private"]
|
88
|
-
basename = "%02d-%02d-%02d-%s" % [date.year, date.month, date.day, slug]
|
89
|
-
name = basename + '.html'
|
90
|
-
|
91
|
-
# Images:
|
92
|
-
if opts[:include_imgs]
|
93
|
-
post_imgs = post["media"]["images"]
|
94
|
-
if post_imgs.any?
|
95
|
-
img_dir = "imgs/%s" % basename
|
96
|
-
img_urls = self.fetch_images(img_dir, post_imgs)
|
97
|
-
|
98
|
-
img_urls.map! do |url|
|
99
|
-
'<li><img src="' + opts[:base_path] + url + '"></li>'
|
100
|
-
end
|
101
|
-
imgcontent = "<ol>\n" + img_urls.join("\n") + "</ol>\n"
|
102
|
-
|
103
|
-
# filter out "posterous-content", replacing with imgs:
|
104
|
-
content = content.sub(/\<p\>\[\[posterous-content:[^\]]+\]\]\<\/p\>/, imgcontent)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
# Get the relevant fields as a hash, delete empty fields and convert
|
109
|
-
# to YAML for the header
|
110
|
-
data = {
|
111
|
-
'layout' => 'post',
|
112
|
-
'title' => title.to_s,
|
113
|
-
'published' => published
|
114
|
-
}.delete_if { |k,v| v.nil? || v == ''}.to_yaml
|
115
|
-
|
116
|
-
# Write out the data and content to file
|
117
|
-
File.open("_posts/#{name}", "w") do |f|
|
118
|
-
f.puts data
|
119
|
-
f.puts "---"
|
120
|
-
f.puts content
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
page += 1
|
125
|
-
posts = JSON.parse(self.fetch("/api/v2/users/me/sites/#{opts[:blog]}/posts?api_token=#{@api_token}&page=#{page}").body)
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
1
|
+
module BuntoImport
|
2
|
+
module Importers
|
3
|
+
class Posterous < Importer
|
4
|
+
|
5
|
+
def self.specify_options(c)
|
6
|
+
c.option 'email', '--email EMAIL', 'Posterous email address'
|
7
|
+
c.option 'password', '--password PW', 'Posterous password'
|
8
|
+
c.option 'api_token', '--token TOKEN', 'Posterous API Token'
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.require_deps
|
12
|
+
BuntoImport.require_with_fallback(%w[
|
13
|
+
rubygems
|
14
|
+
bunto
|
15
|
+
fileutils
|
16
|
+
uri
|
17
|
+
json
|
18
|
+
net/http
|
19
|
+
])
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.fetch(uri_str, limit = 10)
|
23
|
+
# You should choose better exception.
|
24
|
+
raise ArgumentError, 'Stuck in a redirect loop. Please double check your email and password' if limit == 0
|
25
|
+
|
26
|
+
response = nil
|
27
|
+
Net::HTTP.start('posterous.com') do |http|
|
28
|
+
req = Net::HTTP::Get.new(uri_str)
|
29
|
+
req.basic_auth @email, @pass
|
30
|
+
response = http.request(req)
|
31
|
+
end
|
32
|
+
|
33
|
+
case response
|
34
|
+
when Net::HTTPSuccess then response
|
35
|
+
when Net::HTTPRedirection then fetch(response['location'], limit - 1)
|
36
|
+
else response.error!
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.fetch_images(directory, imgs)
|
41
|
+
def self.fetch_one(url, limit = 10)
|
42
|
+
raise ArgumentError, 'HTTP redirect too deep' if limit == 0
|
43
|
+
response = Net::HTTP.get_response(URI.parse(url))
|
44
|
+
case response
|
45
|
+
when Net::HTTPSuccess then response.body
|
46
|
+
when Net::HTTPRedirection then self.fetch_one(response['location'], limit - 1)
|
47
|
+
else
|
48
|
+
response.error!
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
FileUtils.mkdir_p directory
|
53
|
+
urls = Array.new
|
54
|
+
imgs.each do |img|
|
55
|
+
fullurl = img["full"]["url"]
|
56
|
+
uri = URI.parse(fullurl)
|
57
|
+
imgname = uri.path.split("/")[-1]
|
58
|
+
imgdata = self.fetch_one(fullurl)
|
59
|
+
open(directory + "/" + imgname, "wb") do |file|
|
60
|
+
file.write imgdata
|
61
|
+
end
|
62
|
+
urls.push(directory + "/" + imgname)
|
63
|
+
end
|
64
|
+
|
65
|
+
return urls
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.process(options)
|
69
|
+
email = options.fetch('email')
|
70
|
+
pass = options.fetch('password')
|
71
|
+
api_token = options.fetch('api_token')
|
72
|
+
|
73
|
+
@email, @pass, @api_token = email, pass, api_token
|
74
|
+
defaults = { :include_imgs => false, :blog => 'primary', :base_path => '/' }
|
75
|
+
opts = defaults.merge(opts)
|
76
|
+
FileUtils.mkdir_p "_posts"
|
77
|
+
|
78
|
+
posts = JSON.parse(self.fetch("/api/v2/users/me/sites/#{opts[:blog]}/posts?api_token=#{@api_token}").body)
|
79
|
+
page = 1
|
80
|
+
|
81
|
+
while posts.any?
|
82
|
+
posts.each do |post|
|
83
|
+
title = post["title"]
|
84
|
+
slug = title.gsub(/[^[:alnum:]]+/, '-').downcase
|
85
|
+
date = Date.parse(post["display_date"])
|
86
|
+
content = post["body_html"]
|
87
|
+
published = !post["is_private"]
|
88
|
+
basename = "%02d-%02d-%02d-%s" % [date.year, date.month, date.day, slug]
|
89
|
+
name = basename + '.html'
|
90
|
+
|
91
|
+
# Images:
|
92
|
+
if opts[:include_imgs]
|
93
|
+
post_imgs = post["media"]["images"]
|
94
|
+
if post_imgs.any?
|
95
|
+
img_dir = "imgs/%s" % basename
|
96
|
+
img_urls = self.fetch_images(img_dir, post_imgs)
|
97
|
+
|
98
|
+
img_urls.map! do |url|
|
99
|
+
'<li><img src="' + opts[:base_path] + url + '"></li>'
|
100
|
+
end
|
101
|
+
imgcontent = "<ol>\n" + img_urls.join("\n") + "</ol>\n"
|
102
|
+
|
103
|
+
# filter out "posterous-content", replacing with imgs:
|
104
|
+
content = content.sub(/\<p\>\[\[posterous-content:[^\]]+\]\]\<\/p\>/, imgcontent)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Get the relevant fields as a hash, delete empty fields and convert
|
109
|
+
# to YAML for the header
|
110
|
+
data = {
|
111
|
+
'layout' => 'post',
|
112
|
+
'title' => title.to_s,
|
113
|
+
'published' => published
|
114
|
+
}.delete_if { |k,v| v.nil? || v == ''}.to_yaml
|
115
|
+
|
116
|
+
# Write out the data and content to file
|
117
|
+
File.open("_posts/#{name}", "w") do |f|
|
118
|
+
f.puts data
|
119
|
+
f.puts "---"
|
120
|
+
f.puts content
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
page += 1
|
125
|
+
posts = JSON.parse(self.fetch("/api/v2/users/me/sites/#{opts[:blog]}/posts?api_token=#{@api_token}&page=#{page}").body)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -1,62 +1,62 @@
|
|
1
|
-
module BuntoImport
|
2
|
-
module Importers
|
3
|
-
class RSS < Importer
|
4
|
-
def self.specify_options(c)
|
5
|
-
c.option 'source', '--source NAME', 'The RSS file or URL to import'
|
6
|
-
end
|
7
|
-
|
8
|
-
def self.validate(options)
|
9
|
-
if options['source'].nil?
|
10
|
-
abort "Missing mandatory option --source."
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.require_deps
|
15
|
-
BuntoImport.require_with_fallback(%w[
|
16
|
-
rss
|
17
|
-
rss/1.0
|
18
|
-
rss/2.0
|
19
|
-
open-uri
|
20
|
-
fileutils
|
21
|
-
safe_yaml
|
22
|
-
])
|
23
|
-
end
|
24
|
-
|
25
|
-
# Process the import.
|
26
|
-
#
|
27
|
-
# source - a URL or a local file String.
|
28
|
-
#
|
29
|
-
# Returns nothing.
|
30
|
-
def self.process(options)
|
31
|
-
source = options.fetch('source')
|
32
|
-
|
33
|
-
content = ""
|
34
|
-
open(source) { |s| content = s.read }
|
35
|
-
rss = ::RSS::Parser.parse(content, false)
|
36
|
-
|
37
|
-
raise "There doesn't appear to be any RSS items at the source (#{source}) provided." unless rss
|
38
|
-
|
39
|
-
rss.items.each do |item|
|
40
|
-
formatted_date = item.date.strftime('%Y-%m-%d')
|
41
|
-
post_name = item.title.split(%r{ |!|/|:|&|-|$|,}).map do |i|
|
42
|
-
i.downcase if i != ''
|
43
|
-
end.compact.join('-')
|
44
|
-
name = "#{formatted_date}-#{post_name}"
|
45
|
-
|
46
|
-
header = {
|
47
|
-
'layout' => 'post',
|
48
|
-
'title' => item.title
|
49
|
-
}
|
50
|
-
|
51
|
-
FileUtils.mkdir_p("_posts")
|
52
|
-
|
53
|
-
File.open("_posts/#{name}.html", "w") do |f|
|
54
|
-
f.puts header.to_yaml
|
55
|
-
f.puts "---\n\n"
|
56
|
-
f.puts item.description
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
1
|
+
module BuntoImport
|
2
|
+
module Importers
|
3
|
+
class RSS < Importer
|
4
|
+
def self.specify_options(c)
|
5
|
+
c.option 'source', '--source NAME', 'The RSS file or URL to import'
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.validate(options)
|
9
|
+
if options['source'].nil?
|
10
|
+
abort "Missing mandatory option --source."
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.require_deps
|
15
|
+
BuntoImport.require_with_fallback(%w[
|
16
|
+
rss
|
17
|
+
rss/1.0
|
18
|
+
rss/2.0
|
19
|
+
open-uri
|
20
|
+
fileutils
|
21
|
+
safe_yaml
|
22
|
+
])
|
23
|
+
end
|
24
|
+
|
25
|
+
# Process the import.
|
26
|
+
#
|
27
|
+
# source - a URL or a local file String.
|
28
|
+
#
|
29
|
+
# Returns nothing.
|
30
|
+
def self.process(options)
|
31
|
+
source = options.fetch('source')
|
32
|
+
|
33
|
+
content = ""
|
34
|
+
open(source) { |s| content = s.read }
|
35
|
+
rss = ::RSS::Parser.parse(content, false)
|
36
|
+
|
37
|
+
raise "There doesn't appear to be any RSS items at the source (#{source}) provided." unless rss
|
38
|
+
|
39
|
+
rss.items.each do |item|
|
40
|
+
formatted_date = item.date.strftime('%Y-%m-%d')
|
41
|
+
post_name = item.title.split(%r{ |!|/|:|&|-|$|,}).map do |i|
|
42
|
+
i.downcase if i != ''
|
43
|
+
end.compact.join('-')
|
44
|
+
name = "#{formatted_date}-#{post_name}"
|
45
|
+
|
46
|
+
header = {
|
47
|
+
'layout' => 'post',
|
48
|
+
'title' => item.title
|
49
|
+
}
|
50
|
+
|
51
|
+
FileUtils.mkdir_p("_posts")
|
52
|
+
|
53
|
+
File.open("_posts/#{name}.html", "w") do |f|
|
54
|
+
f.puts header.to_yaml
|
55
|
+
f.puts "---\n\n"
|
56
|
+
f.puts item.description
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -1,60 +1,60 @@
|
|
1
|
-
module BuntoImport
|
2
|
-
module Importers
|
3
|
-
class S9Y < Importer
|
4
|
-
def self.specify_options(c)
|
5
|
-
c.option 'source', '--source SOURCE', 'The URL of the S9Y RSS feed'
|
6
|
-
end
|
7
|
-
|
8
|
-
def self.validate(options)
|
9
|
-
if options['source'].nil?
|
10
|
-
abort "Missing mandatory option --source, e.g. --source \"http://blog.example.com/rss.php?version=2.0&all=1\""
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.require_deps
|
15
|
-
BuntoImport.require_with_fallback(%w[
|
16
|
-
open-uri
|
17
|
-
rss
|
18
|
-
fileutils
|
19
|
-
safe_yaml
|
20
|
-
])
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.process(options)
|
24
|
-
source = options.fetch('source')
|
25
|
-
|
26
|
-
FileUtils.mkdir_p("_posts")
|
27
|
-
|
28
|
-
text = ''
|
29
|
-
open(source) { |line| text = line.read }
|
30
|
-
rss = ::RSS::Parser.parse(text)
|
31
|
-
|
32
|
-
rss.items.each do |item|
|
33
|
-
post_url = item.link.match('.*(/archives/.*)')[1]
|
34
|
-
categories = item.categories.collect { |c| c.content }
|
35
|
-
content = item.content_encoded.strip
|
36
|
-
date = item.date
|
37
|
-
slug = item.link.match('.*/archives/[0-9]+-(.*)\.html')[1]
|
38
|
-
name = "%02d-%02d-%02d-%s.markdown" % [date.year, date.month, date.day,
|
39
|
-
slug]
|
40
|
-
|
41
|
-
data = {
|
42
|
-
'layout' => 'post',
|
43
|
-
'title' => item.title,
|
44
|
-
'categories' => categories,
|
45
|
-
'permalink' => post_url,
|
46
|
-
's9y_link' => item.link,
|
47
|
-
'date' => item.date,
|
48
|
-
}.delete_if { |k,v| v.nil? || v == '' }.to_yaml
|
49
|
-
|
50
|
-
# Write out the data and content to file
|
51
|
-
File.open("_posts/#{name}", "w") do |f|
|
52
|
-
f.puts data
|
53
|
-
f.puts "---"
|
54
|
-
f.puts content
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
1
|
+
module BuntoImport
|
2
|
+
module Importers
|
3
|
+
class S9Y < Importer
|
4
|
+
def self.specify_options(c)
|
5
|
+
c.option 'source', '--source SOURCE', 'The URL of the S9Y RSS feed'
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.validate(options)
|
9
|
+
if options['source'].nil?
|
10
|
+
abort "Missing mandatory option --source, e.g. --source \"http://blog.example.com/rss.php?version=2.0&all=1\""
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.require_deps
|
15
|
+
BuntoImport.require_with_fallback(%w[
|
16
|
+
open-uri
|
17
|
+
rss
|
18
|
+
fileutils
|
19
|
+
safe_yaml
|
20
|
+
])
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.process(options)
|
24
|
+
source = options.fetch('source')
|
25
|
+
|
26
|
+
FileUtils.mkdir_p("_posts")
|
27
|
+
|
28
|
+
text = ''
|
29
|
+
open(source) { |line| text = line.read }
|
30
|
+
rss = ::RSS::Parser.parse(text)
|
31
|
+
|
32
|
+
rss.items.each do |item|
|
33
|
+
post_url = item.link.match('.*(/archives/.*)')[1]
|
34
|
+
categories = item.categories.collect { |c| c.content }
|
35
|
+
content = item.content_encoded.strip
|
36
|
+
date = item.date
|
37
|
+
slug = item.link.match('.*/archives/[0-9]+-(.*)\.html')[1]
|
38
|
+
name = "%02d-%02d-%02d-%s.markdown" % [date.year, date.month, date.day,
|
39
|
+
slug]
|
40
|
+
|
41
|
+
data = {
|
42
|
+
'layout' => 'post',
|
43
|
+
'title' => item.title,
|
44
|
+
'categories' => categories,
|
45
|
+
'permalink' => post_url,
|
46
|
+
's9y_link' => item.link,
|
47
|
+
'date' => item.date,
|
48
|
+
}.delete_if { |k,v| v.nil? || v == '' }.to_yaml
|
49
|
+
|
50
|
+
# Write out the data and content to file
|
51
|
+
File.open("_posts/#{name}", "w") do |f|
|
52
|
+
f.puts data
|
53
|
+
f.puts "---"
|
54
|
+
f.puts content
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|