jekyll-import 0.20.0 → 0.22.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -16,16 +16,16 @@ module JekyllImport
16
16
  DEFAULTS = {
17
17
  "engine" => "mysql",
18
18
  "password" => "",
19
- "host" => "localhost",
19
+ "host" => "127.0.0.1",
20
20
  "prefix" => "",
21
21
  "port" => "3306",
22
22
  "types" => %w(blog story article),
23
23
  }.freeze
24
24
 
25
25
  def specify_options(c)
26
- c.option "engine", "--engine [mysql|postgresql]", "Database engine (default: #{DEFAULTS["engine"].inspect})"
27
26
  c.option "dbname", "--dbname DB", "Database name"
28
27
  c.option "user", "--user USER", "Database user name"
28
+ c.option "engine", "--engine [mysql|postgresql]", "Database engine (default: #{DEFAULTS["engine"].inspect})"
29
29
  c.option "password", "--password PW", "Database user's password (default: #{DEFAULTS["password"].inspect})"
30
30
  c.option "host", "--host HOST", "Database host name (default: #{DEFAULTS["host"].inspect})"
31
31
  c.option "port", "--port PORT", "Database port name (default: #{DEFAULTS["port"].inspect})"
@@ -47,9 +47,9 @@ module JekyllImport
47
47
  end
48
48
 
49
49
  def process(options)
50
- engine = options.fetch("engine", DEFAULTS["engine"])
51
50
  dbname = options.fetch("dbname")
52
51
  user = options.fetch("user")
52
+ engine = options.fetch("engine", DEFAULTS["engine"])
53
53
  pass = options.fetch("password", DEFAULTS["password"])
54
54
  host = options.fetch("host", DEFAULTS["host"])
55
55
  port = options.fetch("port", DEFAULTS["port"])
@@ -68,6 +68,7 @@ module JekyllImport
68
68
  src_dir = conf["source"]
69
69
 
70
70
  dirs = {
71
+ :_aliases => src_dir,
71
72
  :_posts => File.join(src_dir, "_posts").to_s,
72
73
  :_drafts => File.join(src_dir, "_drafts").to_s,
73
74
  :_layouts => Jekyll.sanitized_path(src_dir, conf["layouts_dir"].to_s),
@@ -146,10 +147,10 @@ module JekyllImport
146
147
 
147
148
  if partition.first.length.positive?
148
149
  dir = "#{partition.first}/"
149
- FileUtils.mkdir_p partition.first
150
+ FileUtils.mkdir_p "#{dirs[:_aliases]}/#{dir}"
150
151
  end
151
152
 
152
- File.open("#{dir}#{file}.md", "w") do |f|
153
+ File.open("#{dirs[:_aliases]}/#{dir}#{file}.md", "w") do |f|
153
154
  f.puts "---"
154
155
  f.puts "layout: refresh"
155
156
  f.puts "permalink: #{dir}#{file}/"
@@ -10,12 +10,12 @@ module JekyllImport
10
10
  end
11
11
 
12
12
  def self.specify_options(c)
13
- c.option "dbname", "--dbname", "Database name"
14
- c.option "user", "--user", "Database user name"
15
- c.option "password", "--password", "Database user's password (default: '')"
16
- c.option "host", "--host", "Database host name"
17
- c.option "section", "--section", "Table prefix name"
18
- c.option "prefix", "--prefix", "Table prefix name"
13
+ c.option "dbname", "--dbname", "Database name."
14
+ c.option "user", "--user", "Database user name."
15
+ c.option "password", "--password", "Database user's password. (default: '')"
16
+ c.option "host", "--host", "Database host name. (default: 'localhost')"
17
+ c.option "section", "--section", "Section ID. (default: '1')"
18
+ c.option "prefix", "--prefix", "Table prefix name. (default: 'jos_')"
19
19
  end
20
20
 
21
21
  def self.require_deps
@@ -32,7 +32,7 @@ module JekyllImport
32
32
  dbname = options.fetch("dbname")
33
33
  user = options.fetch("user")
34
34
  pass = options.fetch("password", "")
35
- host = options.fetch("host", "localhost")
35
+ host = options.fetch("host", "127.0.0.1")
36
36
  section = options.fetch("section", "1")
37
37
  table_prefix = options.fetch("prefix", "jos_")
38
38
 
@@ -20,10 +20,10 @@ module JekyllImport
20
20
  end
21
21
 
22
22
  def self.specify_options(c)
23
- c.option "dbname", "--dbname", "Database name"
24
- c.option "user", "--user", "Database name"
25
- c.option "password", "--password", 'Database name (default: "")'
26
- c.option "host", "--host", "Database name"
23
+ c.option "dbname", "--dbname", "Database name."
24
+ c.option "user", "--user", "User name."
25
+ c.option "password", "--password", "Database password. (default: '')"
26
+ c.option "host", "--host", "Database host name. (default: 'localhost')"
27
27
  end
28
28
 
29
29
  def self.require_deps
@@ -10,13 +10,13 @@ module JekyllImport
10
10
  end
11
11
 
12
12
  def self.specify_options(c)
13
- c.option "dbname", "--dbname", "Database name"
14
- c.option "user", "--user", "Database user name"
15
- c.option "password", "--password", "Database user's password (default: '')"
16
- c.option "host", "--host", "Database host name"
17
- c.option "port", "--port", "Database port"
18
- c.option "section", "--section", "Table prefix name"
19
- c.option "prefix", "--prefix", "Table prefix name"
13
+ c.option "dbname", "--dbname", "Database name."
14
+ c.option "user", "--user", "Database user name."
15
+ c.option "password", "--password", "Database user's password. (default: '')"
16
+ c.option "host", "--host", "Database host name. (default: 'localhost')"
17
+ c.option "port", "--port", "Database port. (default: '3306')"
18
+ c.option "section", "--section", "Section ID. (default: '1')"
19
+ c.option "prefix", "--prefix", "Table prefix name. (default: 'jos_')"
20
20
  end
21
21
 
22
22
  def self.require_deps
@@ -33,7 +33,7 @@ module JekyllImport
33
33
  dbname = options.fetch("dbname")
34
34
  user = options.fetch("user")
35
35
  pass = options.fetch("password", "")
36
- host = options.fetch("host", "localhost")
36
+ host = options.fetch("host", "127.0.0.1")
37
37
  port = options.fetch("port", 3306).to_i
38
38
  section = options.fetch("section", "1")
39
39
  table_prefix = options.fetch("prefix", "jos_")
@@ -10,13 +10,13 @@ module JekyllImport
10
10
  end
11
11
 
12
12
  def self.specify_options(c)
13
- c.option "dbname", "--dbname", "Database name"
14
- c.option "user", "--user", "Database user name"
15
- c.option "password", "--password", "Database user's password (default: '')"
16
- c.option "host", "--host", "Database host name"
17
- c.option "port", "--port", "Database port"
18
- c.option "category", "--category", "ID of the category"
19
- c.option "prefix", "--prefix", "Table prefix name"
13
+ c.option "dbname", "--dbname", "Database name."
14
+ c.option "user", "--user", "Database user name."
15
+ c.option "password", "--password", "Database user's password. (default: '')"
16
+ c.option "host", "--host", "Database host name. (default: 'localhost')"
17
+ c.option "port", "--port", "Database port. (default: '3306')"
18
+ c.option "category", "--category", "ID of the category. (default: '0')"
19
+ c.option "prefix", "--prefix", "Table prefix name. (default: 'jos_')"
20
20
  end
21
21
 
22
22
  def self.require_deps
@@ -33,7 +33,7 @@ module JekyllImport
33
33
  dbname = options.fetch("dbname")
34
34
  user = options.fetch("user")
35
35
  pass = options.fetch("password", "")
36
- host = options.fetch("host", "localhost")
36
+ host = options.fetch("host", "127.0.0.1")
37
37
  port = options.fetch("port", 3306).to_i
38
38
  cid = options.fetch("category", 0)
39
39
  table_prefix = options.fetch("prefix", "jos_")
@@ -12,10 +12,10 @@ module JekyllImport
12
12
  end
13
13
 
14
14
  def self.specify_options(c)
15
- c.option "file", "--file FILENAME", 'Journal file (default: "~/journal.txt")'
16
- c.option "time_format", "--time_format FORMAT", 'Time format of your journal (default: "%Y-%m-%d %H:%M")'
17
- c.option "extension", "--extension EXT", 'Output extension (default: "md")'
18
- c.option "layout", "--layout NAME", 'Output post layout (default: "post")'
15
+ c.option "file", "--file FILENAME", "Journal file. (default: '~/journal.txt')"
16
+ c.option "time_format", "--time_format FORMAT", "Time format of your journal. (default: '%Y-%m-%d %H:%M')"
17
+ c.option "extension", "--extension EXT", "Output extension. (default: 'md')"
18
+ c.option "layout", "--layout NAME", "Output post layout. (default: 'post')"
19
19
  end
20
20
 
21
21
  # Reads a jrnl file and creates a new post for each entry
@@ -28,7 +28,7 @@ module JekyllImport
28
28
  end
29
29
 
30
30
  def self.specify_options(c)
31
- c.option "marley_data_dir", "--marley_data_dir DIR", "The dir containing your marley data"
31
+ c.option "marley_data_dir", "--marley_data_dir DIR", "The dir containing your marley data."
32
32
  end
33
33
 
34
34
  def self.process(options)
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JekyllImport
4
+ module Importers
5
+ class Medium < Importer
6
+ def self.specify_options(c)
7
+ c.option "username", "--username NAME", "Medium username"
8
+ c.option "canonical_link", "--canonical_link", "Copy original link as canonical_url to post (default: false)"
9
+ c.option "render_audio", "--render_audio", "Render <audio> element in posts for the enclosure URLs (default: false)"
10
+ end
11
+
12
+ def self.validate(options)
13
+ abort "Missing mandatory option --username." if options["username"].nil?
14
+ end
15
+
16
+ def self.require_deps
17
+ Importers::RSS.require_deps
18
+ end
19
+
20
+ # Medium posts and associated metadata are exported as an RSS Feed. Hence invoke our RSS Importer to create the
21
+ # Jekyll source directory.
22
+ #
23
+ # "Tags" attached to a Medium post are exported under the markup `<item><category>...</category></item>` in the
24
+ # export feed. Therefore, configure the RSS Importer to always look for tags in the `<category></category>` field
25
+ # of an RSS item.
26
+ def self.process(options)
27
+ Importers::RSS.process({
28
+ "source" => "https://medium.com/feed/@#{options.fetch("username")}",
29
+ "render_audio" => options.fetch("render_audio", false),
30
+ "canonical_link" => options.fetch("canonical_link", false),
31
+ "extract_tags" => "category",
32
+ })
33
+ end
34
+ end
35
+ end
36
+ end
@@ -14,7 +14,7 @@ module JekyllImport
14
14
  COPY jekyll TO STDOUT WITH CSV HEADER;
15
15
  ROLLBACK;
16
16
  SQL
17
- command = %(psql -h #{c[:host] || "localhost"} -c "#{sql.strip}" #{c[:database]} #{c[:username]} -o #{c[:filename] || "posts.csv"})
17
+ command = %(psql -h #{c[:host] || "127.0.0.1"} -c "#{sql.strip}" #{c[:database]} #{c[:username]} -o #{c[:filename] || "posts.csv"})
18
18
  Jekyll.logger.info "Executing:", command
19
19
  `#{command}`
20
20
  CSV.process
@@ -40,7 +40,7 @@ module JekyllImport
40
40
  c.option "dbname", "--dbname DB", "Database name"
41
41
  c.option "user", "--user USER", "Database user name"
42
42
  c.option "password", "--password PW", "Database user's password (default: '')"
43
- c.option "host", "--host HOST", 'Database host name (default: "localhost")'
43
+ c.option "host", "--host HOST", "Database host name (default: 'localhost')"
44
44
  end
45
45
 
46
46
  # This query will pull blog posts from all entries across all blogs. If
@@ -61,7 +61,7 @@ module JekyllImport
61
61
  dbname = options.fetch("dbname")
62
62
  user = options.fetch("user")
63
63
  pass = options.fetch("password", "")
64
- host = options.fetch("host", "localhost")
64
+ host = options.fetch("host", "127.0.0.1")
65
65
 
66
66
  db = Sequel.mysql2(dbname, :user => user,
67
67
  :password => pass,
@@ -32,17 +32,17 @@ module JekyllImport
32
32
  end
33
33
 
34
34
  def self.specify_options(c)
35
- c.option "engine", "--engine ENGINE", "Database engine, (default: 'mysql', postgres also supported)"
36
- c.option "dbname", "--dbname DB", "Database name"
37
- c.option "user", "--user USER", "Database user name"
38
- c.option "password", "--password PW", "Database user's password, (default: '')"
39
- c.option "host", "--host HOST", 'Database host name (default: "localhost")'
40
- c.option "port", "--port PORT", "Custom database port connect to (optional)"
41
- c.option "blog_id", "--blog_id ID", "Specify a single Movable Type blog ID to import (default: all blogs)"
42
- c.option "categories", "--categories", "If true, save post's categories in its YAML front matter. (default: true)"
35
+ c.option "dbname", "--dbname DB", "Database name."
36
+ c.option "user", "--user USER", "Database user name."
37
+ c.option "engine", "--engine ENGINE", "Database engine ('mysql' or 'postgres'). (default: 'mysql')"
38
+ c.option "password", "--password PW", "Database user's password. (default: '')"
39
+ c.option "host", "--host HOST", "Database host name. (default: 'localhost')"
40
+ c.option "port", "--port PORT", "Custom database port connect to. (default: null)"
41
+ c.option "blog_id", "--blog_id ID", "Specify a single Movable Type blog ID to import. (default: null (all blogs))"
42
+ c.option "categories", "--categories", "When true, save post's categories in its YAML front matter. (default: true)"
43
43
  c.option "src_encoding", "--src_encoding ENCODING", "Encoding of strings from database. (default: UTF-8)"
44
44
  c.option "dest_encoding", "--dest_encoding ENCODING", "Encoding of output strings. (default: UTF-8)"
45
- c.option "comments", "--comments", "If true, output comments in _comments directory (default: false)"
45
+ c.option "comments", "--comments", "When true, output comments in `_comments` directory. (default: false)"
46
46
  end
47
47
 
48
48
  # By default this migrator will include posts for all your MovableType blogs.
@@ -242,7 +242,7 @@ module JekyllImport
242
242
  Sequel.sqlite(dbname)
243
243
  when "mysql", "postgres"
244
244
  db_connect_opts = {
245
- :host => options.fetch("host", "localhost"),
245
+ :host => options.fetch("host", "127.0.0.1"),
246
246
  :user => options.fetch("user"),
247
247
  :password => options.fetch("password", ""),
248
248
  }
@@ -12,9 +12,9 @@ module JekyllImport
12
12
  end
13
13
 
14
14
  def self.specify_options(c)
15
- c.option "source", "--source NAME", "The PluXML data directory to import"
16
- c.option "layout", "--layout NAME", "The layout to apply"
17
- c.option "avoid_liquid", "--avoid_liquid true", "Will add render_with_liquid: false in frontmatter"
15
+ c.option "source", "--source NAME", "The PluXml data directory to import."
16
+ c.option "layout", "--layout NAME", "The layout to apply. (default: 'post')"
17
+ c.option "avoid_liquid", "--avoid_liquid", "Will add `render_with_liquid: false` in front matter. (default: false)"
18
18
  end
19
19
 
20
20
  def self.validate(options)
@@ -14,19 +14,19 @@ module JekyllImport
14
14
  end
15
15
 
16
16
  def self.specify_options(c)
17
- c.option "dbname", "--dbname DB", "Database name (default: '')"
18
- c.option "socket", "--socket SOCKET", "Database socket (default: '')"
19
- c.option "user", "--user USER", "Database user name (default: '')"
20
- c.option "password", "--password PW", "Database user's password (default: '')"
21
- c.option "host", "--host HOST", "Database host name (default: 'localhost')"
22
- c.option "port", "--port PORT", "Database port number (default: '3306')"
23
- c.option "clean_entities", "--clean_entities", "Whether to clean entities (default: true)"
24
- c.option "comments", "--comments", "Whether to import comments (default: true)"
25
- c.option "categories", "--categories", "Whether to import categories (default: true)"
26
- c.option "tags", "--tags", "Whether to import tags (default: true)"
17
+ c.option "dbname", "--dbname DB", "Database name."
18
+ c.option "user", "--user USER", "Database user name."
19
+ c.option "password", "--password PW", "Database user's password."
20
+ c.option "socket", "--socket SOCKET", "Database socket. (default: null)"
21
+ c.option "host", "--host HOST", "Database host name. (default: 'localhost')"
22
+ c.option "port", "--port PORT", "Database port number. (default: '3306')"
23
+ c.option "clean_entities", "--clean_entities", "Whether to clean entities. (default: true)"
24
+ c.option "comments", "--comments", "Whether to import comments. (default: true)"
25
+ c.option "categories", "--categories", "Whether to import categories. (default: true)"
26
+ c.option "tags", "--tags", "Whether to import tags. (default: true)"
27
27
 
28
28
  c.option "status", "--status STATUS,STATUS2", Array,
29
- "Array of allowed statuses (default: ['PUBLISHED'], other options: 'DRAFT')"
29
+ "Array of allowed statuses (either ['PUBLISHED'] or ['DRAFT']). (default: ['PUBLISHED'])"
30
30
  end
31
31
 
32
32
  # Main migrator function. Call this to perform the migration.
@@ -64,7 +64,7 @@ module JekyllImport
64
64
  options = {
65
65
  :user => opts.fetch("user", ""),
66
66
  :pass => opts.fetch("password", ""),
67
- :host => opts.fetch("host", "localhost"),
67
+ :host => opts.fetch("host", "127.0.0.1"),
68
68
  :port => opts.fetch("port", "3306"),
69
69
  :socket => opts.fetch("socket", nil),
70
70
  :dbname => opts.fetch("dbname", ""),
@@ -4,12 +4,16 @@ module JekyllImport
4
4
  module Importers
5
5
  class RSS < Importer
6
6
  def self.specify_options(c)
7
- c.option "source", "--source NAME", "The RSS file or URL to import"
8
- c.option "tag", "--tag NAME", "Add a tag to posts"
7
+ c.option "source", "--source NAME", "The RSS file or URL to import."
8
+ c.option "tag", "--tag NAME", "Add a specific tag to all posts."
9
+ c.option "extract_tags", "--extract_tags KEY", "Copies tags from the given subfield on the RSS `<item>` to front matter. (default: null)"
10
+ c.option "render_audio", "--render_audio", "Render `<audio>` element in posts for the enclosure URLs. (default: false)"
11
+ c.option "canonical_link", "--canonical_link", "Add original link as `canonical_url` to post front matter. (default: false)"
9
12
  end
10
13
 
11
14
  def self.validate(options)
12
15
  abort "Missing mandatory option --source." if options["source"].nil?
16
+ abort "Provide either --tag or --extract_tags option." if options["extract_tags"] && options["tag"]
13
17
  end
14
18
 
15
19
  def self.require_deps
@@ -30,49 +34,82 @@ module JekyllImport
30
34
  # Returns nothing.
31
35
  def self.process(options)
32
36
  source = options.fetch("source")
33
- frontmatter = options.fetch("frontmatter", [])
34
- body = options.fetch("body", ["description"])
35
37
 
36
38
  content = ""
37
- open(source) { |s| content = s.read }
39
+ URI.open(source) { |s| content = s.read }
38
40
  rss = ::RSS::Parser.parse(content, false)
39
41
 
40
42
  raise "There doesn't appear to be any RSS items at the source (#{source}) provided." unless rss
41
43
 
42
44
  rss.items.each do |item|
43
- formatted_date = item.date.strftime("%Y-%m-%d")
44
- post_name = Jekyll::Utils.slugify(item.title, :mode => "latin")
45
- name = "#{formatted_date}-#{post_name}"
45
+ write_rss_item(item, options)
46
+ end
47
+ end
46
48
 
47
- header = {
48
- "layout" => "post",
49
- "title" => item.title,
50
- }
49
+ def self.write_rss_item(item, options)
50
+ frontmatter = options.fetch("frontmatter", [])
51
+ body = options.fetch("body", ["description"])
52
+ render_audio = options.fetch("render_audio", false)
51
53
 
52
- header["tag"] = options["tag"] unless options["tag"].nil? || options["tag"].empty?
54
+ formatted_date = item.date.strftime("%Y-%m-%d")
55
+ post_name = Jekyll::Utils.slugify(item.title, :mode => "latin")
56
+ name = "#{formatted_date}-#{post_name}"
57
+ audio = render_audio && item.enclosure.url
58
+ canonical_link = options.fetch("canonical_link", false)
53
59
 
54
- frontmatter.each do |value|
55
- header[value] = item.send(value)
56
- end
60
+ header = {
61
+ "layout" => "post",
62
+ "title" => item.title,
63
+ "canonical_url" => (canonical_link ? item.link : nil),
64
+ "tag" => get_tags(item, options),
65
+ }.compact
57
66
 
58
- output = +""
67
+ frontmatter.each do |value|
68
+ header[value] = item.send(value)
69
+ end
59
70
 
60
- body.each do |row|
61
- output << item.send(row).to_s
62
- end
71
+ output = +""
63
72
 
64
- output.strip!
65
- output = item.content_encoded if output.empty?
73
+ body.each do |row|
74
+ output << item.send(row).to_s
75
+ end
76
+
77
+ output.strip!
78
+ output = item.content_encoded if output.empty?
79
+
80
+ FileUtils.mkdir_p("_posts")
66
81
 
67
- FileUtils.mkdir_p("_posts")
82
+ File.open("_posts/#{name}.html", "w") do |f|
83
+ f.puts header.to_yaml
84
+ f.puts "---\n\n"
68
85
 
69
- File.open("_posts/#{name}.html", "w") do |f|
70
- f.puts header.to_yaml
71
- f.puts "---\n\n"
72
- f.puts output
86
+ if audio
87
+ f.puts <<~HTML
88
+ <audio controls="">
89
+ <source src="#{audio}" type="audio/mpeg">
90
+ Your browser does not support the audio element.
91
+ </audio>
92
+ HTML
73
93
  end
94
+
95
+ f.puts output
74
96
  end
75
97
  end
98
+
99
+ def self.get_tags(item, options)
100
+ explicit_tag = options["tag"]
101
+ return explicit_tag unless explicit_tag.nil? || explicit_tag.empty?
102
+
103
+ tags_reference = options["extract_tags"]
104
+ return unless tags_reference
105
+
106
+ tags_from_feed = item.instance_variable_get("@#{tags_reference}")
107
+ return unless tags_from_feed.is_a?(Array)
108
+
109
+ tags = tags_from_feed.map { |feed_tag| feed_tag.content.downcase }
110
+ tags.empty? ? nil : tags.tap(&:uniq!)
111
+ end
112
+ private_class_method :get_tags
76
113
  end
77
114
  end
78
115
  end