ZMediumToMarkdown 2.0.11 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3605356973101df17419ca4232f870a0bab0062f04409c78b0a267c1b799a911
4
- data.tar.gz: 10506a2d7f3a699059869ecc7e070c63939a361ccf13007308acb7596d73b130
3
+ metadata.gz: 439f4734a4dde11659f6dede1e220f9edfd2203c0a025599c8c5ca78e2e91aab
4
+ data.tar.gz: c83396525f04b9313ed53b23d2bdf5b7b4ca5d8a7257c5364d9988c802160bcc
5
5
  SHA512:
6
- metadata.gz: 950325be2b1088bef87a36ceffdabce9be5d9800a9ba5d47fbeb09f2d8ff90c2a01a827b7272af5ef4ac9285a06b4de86cea2ea03e81b0984aa2a49f78a269ff
7
- data.tar.gz: 3a448256e99ad7eb6da7a28b89be0e6984430466b04b3d0eec25a9eed24026f6b29f90f25a226f487ce0639d49192fd41e0045b597d2ef1129f505fab67a65de
6
+ metadata.gz: 5b14cc13afd0e3b16ab5195465067ba98b61827171dc38412ca75467670010c4ff0753c7ad94996d29dd3fca5d489de9f055986c0fdbc81b74e83a16bbf9a53f
7
+ data.tar.gz: 7f9745e8c4608bea3cdf613d262c709d317a5fe1a3e3731d27db990d639e8c1e8b162f453ecded98e6dd6c7a1b4ed54c05262b264ce8b27acecefbbcc4bbdddb
data/lib/Helper.rb CHANGED
@@ -14,9 +14,9 @@ class Helper
14
14
 
15
15
  def self.fetchOGImage(url)
16
16
  html = Request.html(Request.URL(url))
17
- content = html.search("meta[property='og:image']").attribute('content')
18
-
19
- content
17
+ return "" unless html
18
+ image = html.search("meta[property='og:image']")
19
+ image.attribute('content') || ""
20
20
  end
21
21
 
22
22
  def self.escapeMarkdown(text)
@@ -9,8 +9,8 @@ class ImageDownloader
9
9
  Helper.createDirIfNotExist(dir.join("/"))
10
10
 
11
11
  begin
12
- imageResponse = open(url)
13
- File.write(path, imageResponse.read, {mode: 'wb'})
12
+ imageResponse = URI.open(url)
13
+ File.write(path, imageResponse.read)
14
14
  true
15
15
  rescue
16
16
  false
@@ -5,7 +5,7 @@ require 'Parsers/PParser'
5
5
  require 'securerandom'
6
6
 
7
7
  class Paragraph
8
- attr_accessor :postID, :name, :orgText, :text, :type, :href, :metadata, :mixtapeMetadata, :iframe, :oliIndex, :markups, :markupLinks
8
+ attr_accessor :postID, :name, :orgText, :text, :type, :href, :metadata, :mixtapeMetadata, :iframe, :oliIndex, :markups, :markupLinks, :codeBlockMetadata
9
9
 
10
10
  class Iframe
11
11
  attr_accessor :id, :title, :type, :src
@@ -49,6 +49,13 @@ class Paragraph
49
49
  end
50
50
  end
51
51
 
52
+ class CodeBlockMetadata
53
+ attr_accessor :lang
54
+ def initialize(json)
55
+ @lang = json['lang']
56
+ end
57
+ end
58
+
52
59
  def self.makeBlankParagraph(postID)
53
60
  json = {
54
61
  "name" => "fakeBlankParagraph_#{SecureRandom.uuid}",
@@ -72,13 +79,19 @@ class Paragraph
72
79
  @metadata = MetaData.new(json['metadata'])
73
80
  end
74
81
 
82
+ if json['codeBlockMetadata'].nil?
83
+ @codeBlockMetadata = nil
84
+ else
85
+ @codeBlockMetadata = CodeBlockMetadata.new(json['codeBlockMetadata'])
86
+ end
87
+
75
88
  if json['mixtapeMetadata'].nil?
76
89
  @mixtapeMetadata = nil
77
90
  else
78
91
  @mixtapeMetadata = MixtapeMetadata.new(json['mixtapeMetadata'])
79
92
  end
80
93
 
81
- if json['iframe'].nil?
94
+ if json['iframe'].nil? || !json['iframe'] || !json['iframe']['mediaResource']
82
95
  @iframe = nil
83
96
  else
84
97
  @iframe = Iframe.new(json['iframe']['mediaResource'])
@@ -16,7 +16,11 @@ class BQParser < Parser
16
16
 
17
17
  def parse(paragraph)
18
18
  if BQParser.isBQ(paragraph)
19
- result = "> #{paragraph.text} \n\n"
19
+ result = "\r\n\r\n"
20
+ paragraph.text.each_line do |p|
21
+ result += "> #{p} \n\n"
22
+ end
23
+ result += "\r\n\r\n"
20
24
  result
21
25
  else
22
26
  if !nextParser.nil?
@@ -26,7 +26,7 @@ class IframeParser < Parser
26
26
  end
27
27
 
28
28
  if paragraph.type == 'IFRAME'
29
-
29
+ return unless paragraph.iframe
30
30
  if !paragraph.iframe.src.nil? && paragraph.iframe.src != ""
31
31
  url = paragraph.iframe.src
32
32
  else
@@ -65,9 +65,11 @@ class IframeParser < Parser
65
65
  end
66
66
  else
67
67
  html = Request.html(Request.URL(url))
68
- src = html.search('script').first.attribute('src')
68
+ return "" unless html
69
+ src = html.search('script').first
70
+ srce = src.attribute('src') if src
69
71
  result = nil
70
- if !src.to_s[/^(https\:\/\/gist\.github\.com)/].nil?
72
+ if !srce.to_s[/^(https\:\/\/gist\.github\.com)/].nil?
71
73
  # is gist
72
74
  gist = Request.body(Request.URL(src)).scan(/(document\.write\('){1}(.*)(\)){1}/)[1][1]
73
75
  gist.gsub! '\n', ''
@@ -20,7 +20,13 @@ class PREParser < Parser
20
20
 
21
21
  def parse(paragraph)
22
22
  if PREParser.isPRE(paragraph)
23
- result = "```\n"
23
+
24
+ lang = ""
25
+ if !paragraph.codeBlockMetadata.nil?
26
+ lang = paragraph.codeBlockMetadata.lang
27
+ end
28
+
29
+ result = "```#{lang}\n"
24
30
 
25
31
  paragraph.text.each_line do |p|
26
32
  result += p
data/lib/Post.rb CHANGED
@@ -23,13 +23,12 @@ class Post
23
23
 
24
24
  def self.getPostPathFromPostURLString(postURLString)
25
25
  uri = URI.parse(postURLString)
26
- postPath = uri.path.split('/').last
27
-
28
- URI.decode(postPath)
26
+ uri.path.split('/').last
29
27
  end
30
28
 
31
29
  def self.parsePostContentFromHTML(html)
32
30
  json = nil
31
+ return "" unless html
33
32
  html.search('script').each do |script|
34
33
  match = script.to_s[/(<script>window\.__APOLLO_STATE__ \= ){1}(.*)(<\/script>){1}/,2]
35
34
  if !match.nil? && match != ""
@@ -47,7 +46,7 @@ class Post
47
46
  "variables": {
48
47
  "postId": postID
49
48
  },
50
- "query": "query PostViewerEdgeContentQuery($postId: ID!, $postMeteringOptions: PostMeteringOptions) {\n post(id: $postId) {\n ... on Post {\n id\n viewerEdge {\n id\n fullContent(postMeteringOptions: $postMeteringOptions) {\n isLockedPreviewOnly\n validatedShareKey\n bodyModel {\n ...PostBody_bodyModel\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}\n\nfragment PostBody_bodyModel on RichText {\n sections {\n name\n startIndex\n textLayout\n imageLayout\n backgroundImage {\n id\n originalHeight\n originalWidth\n __typename\n }\n videoLayout\n backgroundVideo {\n videoId\n originalHeight\n originalWidth\n previewImageId\n __typename\n }\n __typename\n }\n paragraphs {\n id\n ...PostBodySection_paragraph\n __typename\n }\n ...normalizedBodyModel_richText\n __typename\n}\n\nfragment PostBodySection_paragraph on Paragraph {\n name\n ...PostBodyParagraph_paragraph\n __typename\n id\n}\n\nfragment PostBodyParagraph_paragraph on Paragraph {\n name\n type\n ...ImageParagraph_paragraph\n ...TextParagraph_paragraph\n ...IframeParagraph_paragraph\n ...MixtapeParagraph_paragraph\n __typename\n id\n}\n\nfragment ImageParagraph_paragraph on Paragraph {\n href\n layout\n metadata {\n id\n originalHeight\n originalWidth\n focusPercentX\n focusPercentY\n alt\n __typename\n }\n ...Markups_paragraph\n ...ParagraphRefsMapContext_paragraph\n ...PostAnnotationsMarker_paragraph\n __typename\n id\n}\n\nfragment Markups_paragraph on Paragraph {\n name\n text\n hasDropCap\n dropCapImage {\n ...MarkupNode_data_dropCapImage\n __typename\n id\n }\n markups {\n type\n start\n end\n href\n anchorType\n userId\n linkMetadata {\n httpStatus\n __typename\n }\n __typename\n }\n __typename\n id\n}\n\nfragment MarkupNode_data_dropCapImage on ImageMetadata {\n ...DropCap_image\n __typename\n id\n}\n\nfragment DropCap_image on ImageMetadata {\n id\n originalHeight\n originalWidth\n __typename\n}\n\nfragment ParagraphRefsMapContext_paragraph on Paragraph {\n id\n name\n text\n __typename\n}\n\nfragment PostAnnotationsMarker_paragraph on Paragraph {\n ...PostViewNoteCard_paragraph\n __typename\n id\n}\n\nfragment PostViewNoteCard_paragraph on Paragraph {\n name\n __typename\n id\n}\n\nfragment TextParagraph_paragraph on Paragraph {\n type\n hasDropCap\n ...Markups_paragraph\n ...ParagraphRefsMapContext_paragraph\n __typename\n id\n}\n\nfragment IframeParagraph_paragraph on Paragraph {\n iframe {\n mediaResource {\n id\n iframeSrc\n iframeHeight\n iframeWidth\n title\n __typename\n }\n __typename\n }\n layout\n ...getEmbedlyCardUrlParams_paragraph\n ...Markups_paragraph\n __typename\n id\n}\n\nfragment getEmbedlyCardUrlParams_paragraph on Paragraph {\n type\n iframe {\n mediaResource {\n iframeSrc\n __typename\n }\n __typename\n }\n __typename\n id\n}\n\nfragment MixtapeParagraph_paragraph on Paragraph {\n type\n mixtapeMetadata {\n href\n mediaResource {\n mediumCatalog {\n id\n __typename\n }\n __typename\n }\n __typename\n }\n ...GenericMixtapeParagraph_paragraph\n __typename\n id\n}\n\nfragment GenericMixtapeParagraph_paragraph on Paragraph {\n text\n mixtapeMetadata {\n href\n thumbnailImageId\n __typename\n }\n markups {\n start\n end\n type\n href\n __typename\n }\n __typename\n id\n}\n\nfragment normalizedBodyModel_richText on RichText {\n paragraphs {\n markups {\n type\n __typename\n }\n ...getParagraphHighlights_paragraph\n ...getParagraphPrivateNotes_paragraph\n __typename\n }\n sections {\n startIndex\n ...getSectionEndIndex_section\n __typename\n }\n ...getParagraphStyles_richText\n ...getParagraphSpaces_richText\n __typename\n}\n\nfragment getParagraphHighlights_paragraph on Paragraph {\n name\n __typename\n id\n}\n\nfragment getParagraphPrivateNotes_paragraph on Paragraph {\n name\n __typename\n id\n}\n\nfragment getSectionEndIndex_section on Section {\n startIndex\n __typename\n}\n\nfragment getParagraphStyles_richText on RichText {\n paragraphs {\n text\n type\n __typename\n }\n sections {\n ...getSectionEndIndex_section\n __typename\n }\n __typename\n}\n\nfragment getParagraphSpaces_richText on RichText {\n paragraphs {\n layout\n metadata {\n originalHeight\n originalWidth\n __typename\n }\n type\n ...paragraphExtendsImageGrid_paragraph\n __typename\n }\n ...getSeriesParagraphTopSpacings_richText\n ...getPostParagraphTopSpacings_richText\n __typename\n}\n\nfragment paragraphExtendsImageGrid_paragraph on Paragraph {\n layout\n type\n __typename\n id\n}\n\nfragment getSeriesParagraphTopSpacings_richText on RichText {\n paragraphs {\n id\n __typename\n }\n sections {\n startIndex\n __typename\n }\n __typename\n}\n\nfragment getPostParagraphTopSpacings_richText on RichText {\n paragraphs {\n layout\n text\n __typename\n }\n sections {\n startIndex\n __typename\n }\n __typename\n}\n"
49
+ "query": "query PostViewerEdgeContentQuery($postId: ID!, $postMeteringOptions: PostMeteringOptions) {\n post(id: $postId) {\n ... on Post {\n id\n viewerEdge {\n id\n fullContent(postMeteringOptions: $postMeteringOptions) {\n isLockedPreviewOnly\n validatedShareKey\n bodyModel {\n ...PostBody_bodyModel\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}\n\nfragment PostBody_bodyModel on RichText {\n sections {\n name\n startIndex\n textLayout\n imageLayout\n backgroundImage {\n id\n originalHeight\n originalWidth\n __typename\n }\n videoLayout\n backgroundVideo {\n videoId\n originalHeight\n originalWidth\n previewImageId\n __typename\n }\n __typename\n }\n paragraphs {\n id\n ...PostBodySection_paragraph\n __typename\n }\n ...normalizedBodyModel_richText\n __typename\n}\n\nfragment PostBodySection_paragraph on Paragraph {\n name\n ...PostBodyParagraph_paragraph\n __typename\n id\n}\n\nfragment PostBodyParagraph_paragraph on Paragraph {\n name\n type\n ...ImageParagraph_paragraph\n ...TextParagraph_paragraph\n ...IframeParagraph_paragraph\n ...MixtapeParagraph_paragraph\n ...CodeBlockParagraph_paragraph\n __typename\n id\n}\n\nfragment ImageParagraph_paragraph on Paragraph {\n href\n layout\n metadata {\n id\n originalHeight\n originalWidth\n focusPercentX\n focusPercentY\n alt\n __typename\n }\n ...Markups_paragraph\n ...ParagraphRefsMapContext_paragraph\n ...PostAnnotationsMarker_paragraph\n __typename\n id\n}\n\nfragment Markups_paragraph on Paragraph {\n name\n text\n hasDropCap\n dropCapImage {\n ...MarkupNode_data_dropCapImage\n __typename\n id\n }\n markups {\n type\n start\n end\n href\n anchorType\n userId\n linkMetadata {\n httpStatus\n __typename\n }\n __typename\n }\n __typename\n id\n}\n\nfragment MarkupNode_data_dropCapImage on ImageMetadata {\n ...DropCap_image\n __typename\n id\n}\n\nfragment DropCap_image on ImageMetadata {\n id\n originalHeight\n originalWidth\n __typename\n}\n\nfragment ParagraphRefsMapContext_paragraph on Paragraph {\n id\n name\n text\n __typename\n}\n\nfragment PostAnnotationsMarker_paragraph on Paragraph {\n ...PostViewNoteCard_paragraph\n __typename\n id\n}\n\nfragment PostViewNoteCard_paragraph on Paragraph {\n name\n __typename\n id\n}\n\nfragment TextParagraph_paragraph on Paragraph {\n type\n hasDropCap\n codeBlockMetadata {\n mode\n lang\n __typename\n }\n ...Markups_paragraph\n ...ParagraphRefsMapContext_paragraph\n __typename\n id\n}\n\nfragment IframeParagraph_paragraph on Paragraph {\n iframe {\n mediaResource {\n id\n iframeSrc\n iframeHeight\n iframeWidth\n title\n __typename\n }\n __typename\n }\n layout\n ...getEmbedlyCardUrlParams_paragraph\n ...Markups_paragraph\n __typename\n id\n}\n\nfragment getEmbedlyCardUrlParams_paragraph on Paragraph {\n type\n iframe {\n mediaResource {\n iframeSrc\n __typename\n }\n __typename\n }\n __typename\n id\n}\n\nfragment MixtapeParagraph_paragraph on Paragraph {\n type\n mixtapeMetadata {\n href\n mediaResource {\n mediumCatalog {\n id\n __typename\n }\n __typename\n }\n __typename\n }\n ...GenericMixtapeParagraph_paragraph\n __typename\n id\n}\n\nfragment GenericMixtapeParagraph_paragraph on Paragraph {\n text\n mixtapeMetadata {\n href\n thumbnailImageId\n __typename\n }\n markups {\n start\n end\n type\n href\n __typename\n }\n __typename\n id\n}\n\nfragment CodeBlockParagraph_paragraph on Paragraph {\n codeBlockMetadata {\n lang\n mode\n __typename\n }\n __typename\n id\n}\n\nfragment normalizedBodyModel_richText on RichText {\n paragraphs {\n markups {\n type\n __typename\n }\n codeBlockMetadata {\n lang\n mode\n __typename\n }\n ...getParagraphHighlights_paragraph\n ...getParagraphPrivateNotes_paragraph\n __typename\n }\n sections {\n startIndex\n ...getSectionEndIndex_section\n __typename\n }\n ...getParagraphStyles_richText\n ...getParagraphSpaces_richText\n __typename\n}\n\nfragment getParagraphHighlights_paragraph on Paragraph {\n name\n __typename\n id\n}\n\nfragment getParagraphPrivateNotes_paragraph on Paragraph {\n name\n __typename\n id\n}\n\nfragment getSectionEndIndex_section on Section {\n startIndex\n __typename\n}\n\nfragment getParagraphStyles_richText on RichText {\n paragraphs {\n text\n type\n __typename\n }\n sections {\n ...getSectionEndIndex_section\n __typename\n }\n __typename\n}\n\nfragment getParagraphSpaces_richText on RichText {\n paragraphs {\n layout\n metadata {\n originalHeight\n originalWidth\n id\n __typename\n }\n type\n ...paragraphExtendsImageGrid_paragraph\n __typename\n }\n ...getSeriesParagraphTopSpacings_richText\n ...getPostParagraphTopSpacings_richText\n __typename\n}\n\nfragment paragraphExtendsImageGrid_paragraph on Paragraph {\n layout\n type\n __typename\n id\n}\n\nfragment getSeriesParagraphTopSpacings_richText on RichText {\n paragraphs {\n id\n __typename\n }\n sections {\n startIndex\n __typename\n }\n __typename\n}\n\nfragment getPostParagraphTopSpacings_richText on RichText {\n paragraphs {\n layout\n text\n codeBlockMetadata {\n lang\n mode\n __typename\n }\n __typename\n }\n sections {\n startIndex\n __typename\n }\n __typename\n}\n"
51
50
  }
52
51
  ]
53
52
 
data/lib/Request.rb CHANGED
@@ -22,34 +22,40 @@ class Request
22
22
  end
23
23
  end
24
24
 
25
- response = https.request(request)
26
-
27
- # 3XX Redirect
28
- if response.code.to_i >= 300 && response.code.to_i <= 399 && !response['location'].nil? && response['location'] != ''
29
- if retryCount >= 10
30
- raise "Error: Retry limit reached. path: #{url}"
31
- else
32
- location = response['location']
33
- if !location.match? /^(http)/
34
- location = "#{uri.scheme}://#{uri.host}#{location}"
35
- end
36
- response = self.URL(location, method, data)
37
- end
25
+ begin
26
+ response = https.request(request)
27
+ # 3XX Redirect
28
+ if response.code.to_i >= 300 && response.code.to_i <= 399 && !response['location'].nil? && response['location'] != ''
29
+ if retryCount >= 10
30
+ raise "Error: Retry limit reached. path: #{url}"
31
+ else
32
+ location = response['location']
33
+ if !location.match? /^(http)/
34
+ location = "#{uri.scheme}://#{uri.host}#{location}"
35
+ end
36
+ response = self.URL(location, method, data)
37
+ end
38
+ end
39
+ rescue
40
+
38
41
  end
42
+
39
43
  response
40
44
  end
41
45
 
42
46
  def self.html(response)
43
- if response.code.to_i != 200
44
- nil
45
- end
47
+ if response.nil? || (response && response.code.to_i != 200)
48
+ nil
49
+ else
46
50
  Nokogiri::HTML(response.read_body)
51
+ end
47
52
  end
48
53
 
49
54
  def self.body(response)
50
- if response.code.to_i != 200
51
- nil
52
- end
55
+ if response.nil? || (response && response.code.to_i != 200)
56
+ nil
57
+ else
53
58
  response.read_body
59
+ end
54
60
  end
55
61
  end
@@ -26,6 +26,14 @@ require "Request"
26
26
  require "Post"
27
27
  require "User"
28
28
  require 'date'
29
+ require "uri"
30
+
31
+ module URI
32
+ def self.decode url
33
+ url ? URI.decode_www_form_component(url).gsub(" ", "%20") : ""
34
+ end
35
+ end
36
+
29
37
 
30
38
  class ZMediumFetcher
31
39
 
@@ -128,7 +136,7 @@ class ZMediumFetcher
128
136
  imagePathPolicy = PathPolicy.new(postPathPolicy.getAbsolutePath("assets"), "assets")
129
137
  end
130
138
 
131
- progress.postPath = postPath
139
+ progress.postPath = URI.decode(postPath)
132
140
  progress.message = "Downloading Post..."
133
141
  progress.printLog()
134
142
 
@@ -154,6 +162,7 @@ class ZMediumFetcher
154
162
  previousParagraph = nil
155
163
  preTypeParagraphs = []
156
164
  sourceParagraphs.each do |sourcParagraph|
165
+ return if (!sourcParagraph || !postID)
157
166
  paragraph = Paragraph.new(sourcParagraph, postID)
158
167
  if OLIParser.isOLI(paragraph)
159
168
  oliIndex += 1
@@ -223,8 +232,7 @@ class ZMediumFetcher
223
232
  progress.printLog()
224
233
 
225
234
  postWithDatePath = "#{postInfo.firstPublishedAt.strftime("%Y-%m-%d")}-#{postPath}"
226
-
227
- absolutePath = postPathPolicy.getAbsolutePath("#{postWithDatePath}.md")
235
+ absolutePath = URI.decode(postPathPolicy.getAbsolutePath("#{postWithDatePath}")) + ".md"
228
236
 
229
237
  fileLatestPublishedAt = nil
230
238
 
@@ -287,7 +295,7 @@ class ZMediumFetcher
287
295
 
288
296
  def downloadPostsByUsername(username, pathPolicy)
289
297
  progress.username = username
290
- progress.message = "Fetching infromation..."
298
+ progress.message = "Fetching posts..."
291
299
  progress.printLog()
292
300
 
293
301
  userID = User.convertToUserIDFromUsername(username)
@@ -295,9 +303,6 @@ class ZMediumFetcher
295
303
  raise "Medium's Username:#{username} not found!"
296
304
  end
297
305
 
298
- progress.message = "Fetching posts..."
299
- progress.printLog()
300
-
301
306
  postURLS = []
302
307
  nextID = nil
303
308
  begin
@@ -321,14 +326,19 @@ class ZMediumFetcher
321
326
  downloadPathPolicy = PathPolicy.new(pathPolicy.getAbsolutePath("users/#{username}"), pathPolicy.getRelativePath("users/#{username}"))
322
327
  end
323
328
 
324
- index = 0
329
+ index = 1
325
330
  postURLS.each do |postURL|
326
- downloadPost(postURL, downloadPathPolicy)
327
-
328
- index += 1
329
- progress.currentPostIndex = index
330
- progress.message = "Downloading posts..."
331
- progress.printLog()
331
+ begin
332
+ # todo: unless File.exists? Post.getPostPathFromPostURLString(postURL) +".md"
333
+ downloadPost(postURL, downloadPathPolicy)
334
+ rescue => e
335
+ puts e
336
+ end
337
+
338
+ index += 1
339
+ progress.currentPostIndex = index
340
+ progress.message = "Downloading posts..."
341
+ progress.printLog()
332
342
  end
333
343
 
334
344
  progress.message = "All posts has been downloaded!, Total posts: #{postURLS.length}"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ZMediumToMarkdown
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.11
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ZhgChgLi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-07-23 00:00:00.000000000 Z
11
+ date: 2023-02-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri