mangdown 0.15.1 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/mangdown/adapter/mangareader.rb +21 -20
- data/lib/mangdown/adapter/no_adapter_error.rb +4 -1
- data/lib/mangdown/adapter/not_implemented_error.rb +8 -0
- data/lib/mangdown/adapter/proxy.rb +16 -6
- data/lib/mangdown/adapter.rb +19 -16
- data/lib/mangdown/chapter.rb +13 -15
- data/lib/mangdown/client.rb +17 -11
- data/lib/mangdown/error.rb +7 -0
- data/lib/mangdown/manga.rb +24 -30
- data/lib/mangdown/manga_list.rb +8 -5
- data/lib/mangdown/md_hash.rb +11 -12
- data/lib/mangdown/page.rb +12 -13
- data/lib/mangdown/support/cbz.rb +10 -7
- data/lib/mangdown/support/equality.rb +5 -2
- data/lib/mangdown/support/logging.rb +3 -1
- data/lib/mangdown/support/properties.rb +9 -6
- data/lib/mangdown/support/tools.rb +14 -10
- data/lib/mangdown/version.rb +3 -1
- data/lib/mangdown.rb +17 -9
- data/test/lib/mangdown/chapter_test.rb +0 -12
- data/test/lib/mangdown/manga_test.rb +0 -14
- data/test/lib/mangdown_test.rb +6 -6
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 238181d8ba1817789cb0a1dc8a69a3dafd6cf811
|
4
|
+
data.tar.gz: 26f7195a357234d613f65ebb98779d2643ccf0f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7df1eb96cd3eb36838ae7b2551a3ccd54dc7a17fb9ab4925ecc4f3989cd5fa0b9f1d5579ec0c819eb42ddd419916524ec67007a2ad6c15c6eeca565adf96bdf4
|
7
|
+
data.tar.gz: 7ff2cd14861ac3bce9b72f06050cc679cd8638bcb630af5096b14c35c1f86f40e031149f6db3529d4ea96989ad7503b968785276e28706c48447e67e102e9997
|
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'cgi'
|
2
4
|
|
3
5
|
module Mangdown
|
6
|
+
# Mangdown adapter for mangareader
|
4
7
|
class Mangareader < Adapter::Base
|
5
|
-
|
6
8
|
site :mangareader
|
7
9
|
|
8
10
|
attr_reader :root
|
@@ -31,12 +33,12 @@ module Mangdown
|
|
31
33
|
|
32
34
|
# Only valid mangas should be returned (using is_manga?(uri))
|
33
35
|
def manga_list
|
34
|
-
doc.css('ul.series_alpha li a').map
|
36
|
+
doc.css('ul.series_alpha li a').map do |a|
|
35
37
|
uri = "#{root}#{a[:href]}"
|
36
38
|
manga = { uri: uri, name: a.text.strip, site: site }
|
37
39
|
|
38
40
|
manga if is_manga?(uri)
|
39
|
-
|
41
|
+
end.compact
|
40
42
|
end
|
41
43
|
|
42
44
|
def manga
|
@@ -45,17 +47,17 @@ module Mangdown
|
|
45
47
|
|
46
48
|
# Only valid chapters should be returned (using is_chapter?(uri))
|
47
49
|
def chapter_list
|
48
|
-
doc.css('div#chapterlist td a').map
|
50
|
+
doc.css('div#chapterlist td a').map do |a|
|
49
51
|
uri = root + a[:href].sub(root, '')
|
50
52
|
chapter = { uri: uri, name: a.text.strip, site: site }
|
51
53
|
|
52
54
|
chapter if is_chapter?(uri)
|
53
|
-
|
55
|
+
end.compact
|
54
56
|
end
|
55
57
|
|
56
58
|
def chapter
|
57
|
-
{ uri: uri,
|
58
|
-
manga: manga_name,
|
59
|
+
{ uri: uri,
|
60
|
+
manga: manga_name,
|
59
61
|
name: chapter_name,
|
60
62
|
chapter: chapter_number,
|
61
63
|
site: site }
|
@@ -63,20 +65,20 @@ module Mangdown
|
|
63
65
|
|
64
66
|
def page_list
|
65
67
|
last_page = doc.css('select')[1].css('option').length
|
66
|
-
(1..last_page).map
|
67
|
-
slug = manga_name.
|
68
|
+
(1..last_page).map do |page|
|
69
|
+
slug = manga_name.tr(' ', '-').gsub(/[:,!]/, '')
|
68
70
|
uri = "#{root}/#{slug}/#{chapter_number}/#{page}"
|
69
|
-
uri =
|
70
|
-
|
71
|
-
|
71
|
+
uri = CGI.escape(uri).downcase
|
72
|
+
{ uri: uri, name: page, site: site }
|
73
|
+
end
|
72
74
|
end
|
73
75
|
|
74
76
|
def page
|
75
77
|
page_image = doc.css('img')[0]
|
76
78
|
uri = page_image[:src]
|
77
|
-
name = page_image[:alt].sub(/([^\d]*)(\d+)(\.\w+)?$/)
|
79
|
+
name = page_image[:alt].sub(/([^\d]*)(\d+)(\.\w+)?$/) do
|
78
80
|
Regexp.last_match[1].to_s + Regexp.last_match[2].to_s.rjust(3, '0')
|
79
|
-
|
81
|
+
end
|
80
82
|
|
81
83
|
{ uri: uri, name: name, site: site }
|
82
84
|
end
|
@@ -97,25 +99,24 @@ module Mangdown
|
|
97
99
|
if @name
|
98
100
|
@name.sub(/\s(\d+)$/) { |num| ' ' + num.to_i.to_s.rjust(5, '0') }
|
99
101
|
else
|
100
|
-
doc.css(
|
102
|
+
doc.css('').text # Not implimented
|
101
103
|
end
|
102
104
|
end
|
103
105
|
|
104
106
|
def chapter_manga_name
|
105
107
|
if @name
|
106
|
-
@name.slice(/(^.+)\s/, 1)
|
108
|
+
@name.slice(/(^.+)\s/, 1)
|
107
109
|
else
|
108
|
-
doc.css(
|
110
|
+
doc.css('').text # Not implimented
|
109
111
|
end
|
110
112
|
end
|
111
113
|
|
112
114
|
def chapter_number
|
113
115
|
if @name
|
114
|
-
@name.slice(/\d+\z/).to_i
|
116
|
+
@name.slice(/\d+\z/).to_i
|
115
117
|
else
|
116
|
-
doc.css(
|
118
|
+
doc.css('').text # Not implimented
|
117
119
|
end
|
118
120
|
end
|
119
121
|
end
|
120
122
|
end
|
121
|
-
|
@@ -1,6 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Mangdown
|
2
4
|
module Adapter
|
3
|
-
|
5
|
+
# No matching Mangdown adpter found
|
6
|
+
class NoAdapterError < Mangdown::Error
|
4
7
|
def initialize(site)
|
5
8
|
super("Bad Site: No Adapter Specified for Site: #{site.inspect}")
|
6
9
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Mangdown
|
2
4
|
module Adapter
|
3
5
|
# Wraps Adapters to provide error reporting
|
@@ -17,17 +19,25 @@ module Mangdown
|
|
17
19
|
|
18
20
|
adapter.public_send(method, *args, &block)
|
19
21
|
rescue => e
|
20
|
-
logger.error(
|
22
|
+
logger.error(debug_error)
|
23
|
+
raise Mangdown::Error, "Adapter failed: #{e.message}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def respond_to_missing?(method, include_all)
|
27
|
+
@adapter.respond_to?(method, include_all)
|
28
|
+
end
|
29
|
+
|
30
|
+
def debug_error(error)
|
31
|
+
{
|
21
32
|
msg: 'Adapter method failed',
|
22
33
|
adapter: adapter.class,
|
23
34
|
uri: adapter.uri,
|
24
35
|
doc: adapter.doc.to_s,
|
25
36
|
method: method,
|
26
|
-
error:
|
27
|
-
error_msg:
|
28
|
-
backtrace:
|
29
|
-
}.to_s
|
30
|
-
raise Mangdown::Error, "Adapter failed: #{e.message}"
|
37
|
+
error: error,
|
38
|
+
error_msg: error.message,
|
39
|
+
backtrace: error.backtrace
|
40
|
+
}.to_s
|
31
41
|
end
|
32
42
|
end
|
33
43
|
end
|
data/lib/mangdown/adapter.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Mangdown
|
2
4
|
module Adapter
|
5
|
+
# Abstract Adapter class
|
3
6
|
class Base
|
4
|
-
# Returns something truthy if this adapter should be used for the
|
7
|
+
# Returns something truthy if this adapter should be used for the
|
5
8
|
# given url or adapter name
|
6
9
|
def self.for?(url_or_adapter_name)
|
7
10
|
url_or_adapter_name[site.to_s]
|
@@ -10,7 +13,7 @@ module Mangdown
|
|
10
13
|
def self.site(site = nil)
|
11
14
|
site ? @_site = site : @_site
|
12
15
|
end
|
13
|
-
|
16
|
+
|
14
17
|
attr_reader :uri, :name
|
15
18
|
def initialize(uri, doc, name)
|
16
19
|
@uri = uri
|
@@ -27,53 +30,53 @@ module Mangdown
|
|
27
30
|
end
|
28
31
|
|
29
32
|
# Overwrite if you want to check the uri if it belongs to a manga list
|
30
|
-
def is_manga_list?(
|
31
|
-
raise NotImplementedError
|
33
|
+
def is_manga_list?(_uri = @uri)
|
34
|
+
raise Adapter::NotImplementedError
|
32
35
|
end
|
33
36
|
|
34
37
|
# Must return true/false if uri represents a manga for adapter
|
35
|
-
def is_manga?(
|
36
|
-
raise NotImplementedError
|
38
|
+
def is_manga?(_uri = @uri)
|
39
|
+
raise Adapter::NotImplementedError
|
37
40
|
end
|
38
41
|
|
39
42
|
# Must return true/false if uri represents a chapter for adapter
|
40
|
-
def is_chapter?(
|
41
|
-
raise NotImplementedError
|
43
|
+
def is_chapter?(_uri = @uri)
|
44
|
+
raise Adapter::NotImplementedError
|
42
45
|
end
|
43
46
|
|
44
47
|
# Must return true/false if uri represents a page for adapter
|
45
|
-
def is_page?(
|
46
|
-
raise NotImplementedError
|
48
|
+
def is_page?(_uri = @uri)
|
49
|
+
raise Adapter::NotImplementedError
|
47
50
|
end
|
48
51
|
|
49
52
|
# Return Array of Hash with keys: :uri, :name, :site
|
50
53
|
def manga_list
|
51
|
-
raise NotImplementedError
|
54
|
+
raise Adapter::NotImplementedError
|
52
55
|
end
|
53
56
|
|
54
57
|
# Return Hash with keys: :uri, :name, :site
|
55
58
|
def manga
|
56
|
-
raise NotImplementedError
|
59
|
+
raise Adapter::NotImplementedError
|
57
60
|
end
|
58
61
|
|
59
62
|
# Return Array of Hash with keys: :uri, :name, :site
|
60
63
|
def chapter_list
|
61
|
-
raise NotImplementedError
|
64
|
+
raise Adapter::NotImplementedError
|
62
65
|
end
|
63
66
|
|
64
67
|
# Return Hash with keys: :uri, :name, :chapter, :manga, :site
|
65
68
|
def chapter
|
66
|
-
raise NotImplementedError
|
69
|
+
raise Adapter::NotImplementedError
|
67
70
|
end
|
68
71
|
|
69
72
|
# Return Array of Hash with keys: :uri, :name, :site
|
70
73
|
def page_list
|
71
|
-
raise NotImplementedError
|
74
|
+
raise Adapter::NotImplementedError
|
72
75
|
end
|
73
76
|
|
74
77
|
# Return Hash with keys: :uri, :name, :site
|
75
78
|
def page
|
76
|
-
raise NotImplementedError
|
79
|
+
raise Adapter::NotImplementedError
|
77
80
|
end
|
78
81
|
|
79
82
|
def doc
|
data/lib/mangdown/chapter.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Mangdown
|
4
|
+
# Mangdown chapter object, which holds pages
|
2
5
|
class Chapter
|
3
6
|
include Equality
|
4
7
|
include Enumerable
|
@@ -7,20 +10,13 @@ module Mangdown
|
|
7
10
|
attr_accessor :adapter
|
8
11
|
|
9
12
|
def initialize(uri, name, manga, chapter = nil)
|
10
|
-
@name = name
|
13
|
+
@name = name
|
11
14
|
@manga = manga
|
12
15
|
@chapter = chapter
|
13
|
-
@uri =
|
16
|
+
@uri = CGI.escape(uri)
|
14
17
|
@pages = []
|
15
18
|
end
|
16
19
|
|
17
|
-
def inspect
|
18
|
-
"#<#{self.class} @name=#{name} @uri=#{uri} " +
|
19
|
-
"@pages=[#{pages.first(3).join(',')}" +
|
20
|
-
"#{",..." if pages.length > 3}]>"
|
21
|
-
end
|
22
|
-
alias_method :to_s, :inspect
|
23
|
-
|
24
20
|
def each(&block)
|
25
21
|
@pages.each(&block)
|
26
22
|
end
|
@@ -79,7 +75,7 @@ module Mangdown
|
|
79
75
|
def load_pages
|
80
76
|
return @pages if @pages.any?
|
81
77
|
|
82
|
-
fetch_each_page
|
78
|
+
fetch_each_page { |page| @pages << page }
|
83
79
|
@pages.sort_by!(&:name)
|
84
80
|
end
|
85
81
|
|
@@ -87,13 +83,13 @@ module Mangdown
|
|
87
83
|
|
88
84
|
def setup_download_dir!(dir)
|
89
85
|
set_path(dir)
|
90
|
-
FileUtils.mkdir_p(to_path) unless Dir.
|
86
|
+
FileUtils.mkdir_p(to_path) unless Dir.exist?(to_path)
|
91
87
|
end
|
92
88
|
|
93
89
|
def fetch_each_page
|
94
90
|
pages = build_page_hashes
|
95
|
-
page_data = Hash.new { |h, k| h[k] =
|
96
|
-
Tools.hydra_streaming(pages, adapter.hydra_opts) do |status, page, data=nil|
|
91
|
+
page_data = Hash.new { |h, k| h[k] = +'' }
|
92
|
+
Tools.hydra_streaming(pages, adapter.hydra_opts) do |status, page, data = nil|
|
97
93
|
case status
|
98
94
|
when :before
|
99
95
|
true
|
@@ -108,7 +104,8 @@ module Mangdown
|
|
108
104
|
|
109
105
|
def build_page_hashes
|
110
106
|
adapter.page_list.map do |page|
|
111
|
-
page
|
107
|
+
page[:chapter] = name
|
108
|
+
page[:manga] = manga
|
112
109
|
MDHash.new(page)
|
113
110
|
end
|
114
111
|
end
|
@@ -116,7 +113,8 @@ module Mangdown
|
|
116
113
|
def get_page(uri, doc)
|
117
114
|
adapter = Mangdown.adapter!(uri, nil, doc)
|
118
115
|
page = adapter.page
|
119
|
-
page
|
116
|
+
page[:chapter] = name
|
117
|
+
page[:manga] = manga
|
120
118
|
|
121
119
|
MDHash.new(page)
|
122
120
|
end
|
data/lib/mangdown/client.rb
CHANGED
@@ -1,14 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative '../mangdown'
|
2
4
|
|
5
|
+
# Simple client for Mangdown
|
3
6
|
module M
|
4
|
-
|
7
|
+
module_function
|
5
8
|
|
6
9
|
DATA_FILE_PATH = Dir.home + '/.manga_list.yml'
|
7
10
|
HELP_FILE_PATH = File.expand_path(
|
8
11
|
'../../README.md', File.dirname(__FILE__)
|
9
12
|
)
|
10
13
|
|
11
|
-
MANGA_PAGES = ['http://www.mangareader.net/alphabetical']
|
14
|
+
MANGA_PAGES = ['http://www.mangareader.net/alphabetical'].freeze
|
12
15
|
|
13
16
|
# return a list of hash with :uri and :name of mangas found in list
|
14
17
|
def find(search)
|
@@ -19,7 +22,9 @@ module M
|
|
19
22
|
|
20
23
|
# cbz all subdirectories in a directory
|
21
24
|
def cbz(dir)
|
22
|
-
|
25
|
+
Mangdown::CBZ.all(dir)
|
26
|
+
rescue => error
|
27
|
+
raise Mangdown::Error, "Failed to package #{dir}: #{error.message}"
|
23
28
|
end
|
24
29
|
|
25
30
|
# display help file
|
@@ -33,6 +38,7 @@ module M
|
|
33
38
|
end
|
34
39
|
|
35
40
|
private
|
41
|
+
|
36
42
|
# convenience method to access the data file path
|
37
43
|
def path
|
38
44
|
DATA_FILE_PATH
|
@@ -40,12 +46,12 @@ module M
|
|
40
46
|
|
41
47
|
# check if the data file is current
|
42
48
|
def file_current?(f)
|
43
|
-
File.
|
49
|
+
File.exist?(f) && File.mtime(f) > (Time.now - 604_800)
|
44
50
|
end
|
45
51
|
|
46
52
|
# attempt to get the list from the data file
|
47
53
|
def data_from_file
|
48
|
-
YAML.
|
54
|
+
YAML.safe_load(File.read(path)) if file_current?(path)
|
49
55
|
end
|
50
56
|
|
51
57
|
# get saved current manga list, if data is less than a week old
|
@@ -54,13 +60,13 @@ module M
|
|
54
60
|
data = data_from_file
|
55
61
|
return Mangdown::MangaList.from_data(data) if data
|
56
62
|
|
57
|
-
list = MANGA_PAGES.inject([])
|
63
|
+
list = MANGA_PAGES.inject([]) do |manga, uri|
|
58
64
|
list = Mangdown::MDHash.new(uri: uri).to_manga_list
|
59
|
-
list.merge(manga)
|
60
|
-
|
65
|
+
list.merge(manga)
|
66
|
+
end
|
67
|
+
File.open(path, 'w+') { |f| f.write(list.to_yaml) }
|
61
68
|
list
|
62
|
-
rescue
|
63
|
-
|
64
|
-
raise
|
69
|
+
rescue => error
|
70
|
+
raise Mangdown::Error, "#{path} may be corrupt: #{error.message}"
|
65
71
|
end
|
66
72
|
end
|
data/lib/mangdown/manga.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Mangdown
|
2
|
-
#
|
4
|
+
# Mangdown manga object, which holds chapters
|
3
5
|
class Manga
|
4
6
|
include Equality
|
5
7
|
include Enumerable
|
@@ -10,17 +12,10 @@ module Mangdown
|
|
10
12
|
|
11
13
|
def initialize(uri, name)
|
12
14
|
@name = name
|
13
|
-
@uri =
|
15
|
+
@uri = CGI.escape(uri)
|
14
16
|
@chapters = []
|
15
17
|
end
|
16
18
|
|
17
|
-
def inspect
|
18
|
-
"#<#{self.class} @name=#{name} @uri=#{uri} " +
|
19
|
-
"@chapters=[#{chapters.first(3).join(',')}" +
|
20
|
-
"#{",..." if chapters.length > 3}]>"
|
21
|
-
end
|
22
|
-
alias_method :to_s, :inspect
|
23
|
-
|
24
19
|
def cbz
|
25
20
|
CBZ.all(to_path)
|
26
21
|
end
|
@@ -28,7 +23,7 @@ module Mangdown
|
|
28
23
|
def download(*args)
|
29
24
|
download_to(nil, *args)
|
30
25
|
end
|
31
|
-
|
26
|
+
|
32
27
|
# download using enumerable
|
33
28
|
def download_to(dir, start = 0, stop = -1, opts = { force_download: false })
|
34
29
|
start, stop = validate_indeces!(start, stop)
|
@@ -40,7 +35,7 @@ module Mangdown
|
|
40
35
|
chapters[start..stop].each do |md_hash|
|
41
36
|
chapter = md_hash.to_chapter
|
42
37
|
chapter_result = chapter.download_to(to_path, opts)
|
43
|
-
|
38
|
+
|
44
39
|
if chapter_result[:failed].any?
|
45
40
|
failed << chapter
|
46
41
|
elsif chapter_result[:succeeded].any?
|
@@ -48,18 +43,17 @@ module Mangdown
|
|
48
43
|
elsif chapter_result[:skipped].any?
|
49
44
|
skipped << chapter
|
50
45
|
end
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
end
|
46
|
+
next unless chapter_result[:failed].any?
|
47
|
+
logger.error({
|
48
|
+
msg: 'Chapter was not fully downloaded',
|
49
|
+
uri: chapter.uri,
|
50
|
+
chapter: chapter.name
|
51
|
+
}.to_s)
|
58
52
|
end
|
59
53
|
{ failed: failed, succeeded: succeeded, skipped: skipped }
|
60
54
|
end
|
61
55
|
|
62
|
-
def to_manga
|
56
|
+
def to_manga
|
63
57
|
self
|
64
58
|
end
|
65
59
|
|
@@ -68,19 +62,19 @@ module Mangdown
|
|
68
62
|
end
|
69
63
|
|
70
64
|
def set_path(dir = nil)
|
71
|
-
dir ||= DOWNLOAD_DIR
|
65
|
+
dir ||= DOWNLOAD_DIR
|
72
66
|
path = File.join(dir, name)
|
73
67
|
@path = Tools.relative_or_absolute_path(path)
|
74
68
|
end
|
75
69
|
|
76
70
|
def each(&block)
|
77
71
|
@chapters.each(&block)
|
78
|
-
end
|
72
|
+
end
|
79
73
|
|
80
74
|
def load_chapters
|
81
75
|
@chapters += adapter.chapter_list.map do |chapter|
|
82
|
-
|
83
|
-
|
76
|
+
chapter[:manga] = name
|
77
|
+
MDHash.new(chapter)
|
84
78
|
end
|
85
79
|
end
|
86
80
|
|
@@ -88,26 +82,26 @@ module Mangdown
|
|
88
82
|
|
89
83
|
def chapter_indeces(start, stop)
|
90
84
|
length = chapters.length
|
91
|
-
[start, stop].map { |i| i
|
85
|
+
[start, stop].map { |i| i.negative? ? length + i : i }
|
92
86
|
end
|
93
87
|
|
94
88
|
def setup_download_dir!(dir)
|
95
|
-
set_path(dir)
|
89
|
+
set_path(dir)
|
96
90
|
FileUtils.mkdir_p(to_path) unless Dir.exist?(to_path)
|
97
91
|
end
|
98
92
|
|
99
93
|
def validate_indeces!(start, stop)
|
100
|
-
chapter_indeces(start, stop).tap
|
94
|
+
chapter_indeces(start, stop).tap do |i_start, i_stop|
|
101
95
|
last = chapters.length - 1
|
102
96
|
|
103
97
|
if i_start > last || i_stop > last
|
104
98
|
error = "This manga has chapters in the range (0..#{last})"
|
105
|
-
raise
|
99
|
+
raise Mangdown::Error, error
|
106
100
|
elsif i_stop < i_start
|
107
101
|
error = 'Last index must be greater than or equal to first index'
|
108
|
-
raise
|
109
|
-
end
|
110
|
-
|
102
|
+
raise Mangdown::Error, error
|
103
|
+
end
|
104
|
+
end
|
111
105
|
end
|
112
106
|
end
|
113
107
|
end
|
data/lib/mangdown/manga_list.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Mangdown
|
4
|
+
# Mangdown manga list, which holds manga
|
2
5
|
class MangaList
|
3
6
|
include Enumerable
|
4
7
|
|
5
8
|
def self.from_data(manga)
|
6
|
-
new(manga)
|
9
|
+
new(manga)
|
7
10
|
end
|
8
11
|
|
9
12
|
attr_reader :manga
|
@@ -17,7 +20,7 @@ module Mangdown
|
|
17
20
|
|
18
21
|
def each(&block)
|
19
22
|
manga.each(&block)
|
20
|
-
end
|
23
|
+
end
|
21
24
|
|
22
25
|
def to_yaml
|
23
26
|
@manga.map(&:to_hash).to_yaml
|
@@ -26,15 +29,15 @@ module Mangdown
|
|
26
29
|
def load_manga(uri)
|
27
30
|
adapter = Mangdown.adapter!(uri)
|
28
31
|
|
29
|
-
manga = adapter.manga_list.map { |
|
30
|
-
|
32
|
+
manga = adapter.manga_list.map { |m| MDHash.new(m) }
|
33
|
+
|
31
34
|
merge(manga)
|
32
35
|
end
|
33
36
|
|
34
37
|
def merge(other)
|
35
38
|
@manga += other.to_ary
|
36
39
|
|
37
|
-
|
40
|
+
self
|
38
41
|
end
|
39
42
|
end
|
40
43
|
end
|
data/lib/mangdown/md_hash.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Mangdown
|
4
|
+
# Mangdown hash like object that can be converted to other Mangdown objects.
|
2
5
|
class MDHash
|
3
6
|
include Equality
|
4
7
|
include Properties
|
5
8
|
|
9
|
+
attr_reader :adapter
|
10
|
+
|
6
11
|
properties :name, :uri, :manga, :chapter, :site
|
7
12
|
|
8
13
|
def initialize(options = {})
|
@@ -15,7 +20,7 @@ module Mangdown
|
|
15
20
|
|
16
21
|
@adapter = Mangdown.adapter!(uri, site, nil, name)
|
17
22
|
|
18
|
-
@uri =
|
23
|
+
@uri = CGI.escape(uri)
|
19
24
|
@site = adapter.site
|
20
25
|
end
|
21
26
|
|
@@ -29,10 +34,8 @@ module Mangdown
|
|
29
34
|
|
30
35
|
def to_manga
|
31
36
|
type_error('manga') unless adapter.is_manga?
|
32
|
-
|
33
|
-
if name.to_s.empty?
|
34
|
-
fill_properties(adapter.manga)
|
35
|
-
end
|
37
|
+
|
38
|
+
fill_properties(adapter.manga) if name.to_s.empty?
|
36
39
|
|
37
40
|
manga = Manga.new(uri, name)
|
38
41
|
manga.adapter = adapter
|
@@ -55,20 +58,16 @@ module Mangdown
|
|
55
58
|
chapter
|
56
59
|
end
|
57
60
|
|
58
|
-
def to_page
|
61
|
+
def to_page
|
59
62
|
type_error('page') unless adapter.is_page?
|
60
63
|
|
61
64
|
Page.new(uri, name, manga, chapter)
|
62
|
-
end
|
65
|
+
end
|
63
66
|
|
64
67
|
private
|
65
68
|
|
66
|
-
def adapter
|
67
|
-
@adapter
|
68
|
-
end
|
69
|
-
|
70
69
|
def type_error(type)
|
71
|
-
raise
|
70
|
+
raise Mangdown::Error, "This is not a known #{type} type"
|
72
71
|
end
|
73
72
|
end
|
74
73
|
end
|
data/lib/mangdown/page.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Mangdown
|
4
|
+
# Mangdown page
|
2
5
|
class Page
|
3
6
|
include Equality
|
4
7
|
include Logging
|
@@ -9,13 +12,13 @@ module Mangdown
|
|
9
12
|
@name = Tools.valid_path_name(name)
|
10
13
|
@chapter = chapter
|
11
14
|
@manga = manga
|
12
|
-
@uri =
|
15
|
+
@uri = CGI.escape(uri)
|
13
16
|
end
|
14
17
|
|
15
|
-
# explicit conversion to page
|
18
|
+
# explicit conversion to page
|
16
19
|
def to_page
|
17
20
|
self
|
18
|
-
end
|
21
|
+
end
|
19
22
|
|
20
23
|
def to_path
|
21
24
|
@path ||= set_path
|
@@ -27,16 +30,13 @@ module Mangdown
|
|
27
30
|
def set_path(dir = nil)
|
28
31
|
dir ||= File.join(manga, chapter)
|
29
32
|
dir = Tools.valid_path_name(dir)
|
30
|
-
if Dir.exist?(dir)
|
31
|
-
file = Dir.entries(dir).find { |f| f[name] }
|
32
|
-
end
|
33
|
+
file = Dir.entries(dir).find { |f| f[name] } if Dir.exist?(dir)
|
33
34
|
path = File.join(dir, file || name)
|
34
35
|
@path = Tools.relative_or_absolute_path(path)
|
35
36
|
end
|
36
37
|
|
37
38
|
# downloads to specified directory
|
38
|
-
def download_to(dir = Dir.pwd,
|
39
|
-
# cleanup existing file (all extensions)
|
39
|
+
def download_to(dir = Dir.pwd, force_download: false)
|
40
40
|
delete_files!(dir) if opts[:force_download]
|
41
41
|
|
42
42
|
return if file_exist?(dir)
|
@@ -56,8 +56,8 @@ module Mangdown
|
|
56
56
|
}.to_s)
|
57
57
|
end
|
58
58
|
|
59
|
-
def append_file_data(
|
60
|
-
File.open(to_path, 'ab') { |file| file.write(data) }
|
59
|
+
def append_file_data(_dir, data)
|
60
|
+
File.open(to_path, 'ab') { |file| file.write(data) }
|
61
61
|
end
|
62
62
|
|
63
63
|
def append_file_ext(dir = nil)
|
@@ -75,10 +75,9 @@ module Mangdown
|
|
75
75
|
Dir.entries(dir).any? { |file| file.to_s[to_path.basename.to_s] }
|
76
76
|
end
|
77
77
|
|
78
|
+
# cleanup existing file (all extensions)
|
78
79
|
def delete_files!(dir)
|
79
|
-
while set_path(dir) && File.exist?(to_path)
|
80
|
-
File.delete(to_path)
|
81
|
-
end
|
80
|
+
File.delete(to_path) while set_path(dir) && File.exist?(to_path)
|
82
81
|
end
|
83
82
|
end
|
84
83
|
end
|
data/lib/mangdown/support/cbz.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Mangdown
|
4
|
+
# Package manga or chapter directories into .cbz archive files
|
2
5
|
module CBZ
|
3
6
|
class << self
|
4
7
|
extend Tools
|
@@ -6,7 +9,7 @@ module Mangdown
|
|
6
9
|
def all(main_dir)
|
7
10
|
main_dir = String(main_dir)
|
8
11
|
main_dir = validate_file_or_dir_names(main_dir)
|
9
|
-
each_dir_or_page(main_dir) { |dir| validate_file_or_dir_names(dir)}
|
12
|
+
each_dir_or_page(main_dir) { |dir| validate_file_or_dir_names(dir) }
|
10
13
|
cbz_sub_dirs(main_dir)
|
11
14
|
end
|
12
15
|
|
@@ -19,14 +22,14 @@ module Mangdown
|
|
19
22
|
private
|
20
23
|
|
21
24
|
def cbz_dir(dir)
|
22
|
-
dir = dir.to_s.sub(/\/*$/,
|
23
|
-
|
25
|
+
dir = dir.to_s.sub(/\/*$/, '')
|
26
|
+
|
24
27
|
zip_filename = dir + '.cbz'
|
25
28
|
return if File.exist?(zip_filename)
|
26
29
|
|
27
30
|
::Zip::File.open(zip_filename, ::Zip::File::CREATE) do |zip|
|
28
31
|
file_matcher = File.join(dir, '**', '**')
|
29
|
-
dir <<
|
32
|
+
dir << '/'
|
30
33
|
|
31
34
|
Dir.glob(file_matcher).each do |file|
|
32
35
|
filename = file.sub(dir, '')
|
@@ -39,14 +42,14 @@ module Mangdown
|
|
39
42
|
each_dir_or_page(dir) do |sub_dir|
|
40
43
|
cbz_dir(sub_dir)
|
41
44
|
end
|
42
|
-
end
|
45
|
+
end
|
43
46
|
|
44
47
|
def each_dir_or_page(dir)
|
45
|
-
Dir.glob(dir + '/*').each do |filename|
|
48
|
+
Dir.glob(dir + '/*').each do |filename|
|
46
49
|
next if filename.include?('.cbz')
|
47
50
|
yield(filename)
|
48
51
|
end
|
49
|
-
end
|
52
|
+
end
|
50
53
|
|
51
54
|
def validate_file_or_dir_names(dir)
|
52
55
|
each_dir_or_page(dir) do |filename|
|
@@ -1,11 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Mangdown
|
4
|
+
# Provide hash-like access for object attributes
|
2
5
|
module Properties
|
3
6
|
def self.included(base)
|
4
7
|
base.extend(ClassMethods)
|
5
8
|
end
|
6
9
|
|
7
10
|
def properties
|
8
|
-
keys = self.class.
|
11
|
+
keys = self.class.properties
|
9
12
|
values = keys.map { |name| self[name] }
|
10
13
|
Hash[keys.zip(values)]
|
11
14
|
end
|
@@ -33,15 +36,15 @@ module Mangdown
|
|
33
36
|
properties.to_s
|
34
37
|
end
|
35
38
|
|
39
|
+
# Macro for setting property names
|
36
40
|
module ClassMethods
|
37
41
|
def properties(*names)
|
38
|
-
@properties
|
42
|
+
@properties ||= []
|
43
|
+
return @properties if names.empty?
|
44
|
+
|
45
|
+
@properties.concat(names).uniq!
|
39
46
|
attr_accessor(*names)
|
40
47
|
end
|
41
|
-
|
42
|
-
def property_names
|
43
|
-
@properties || []
|
44
|
-
end
|
45
48
|
end
|
46
49
|
end
|
47
50
|
end
|
@@ -1,15 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'pathname'
|
2
4
|
require 'typhoeus'
|
3
5
|
|
4
6
|
Typhoeus::Config.verbose = $DEBUG
|
5
7
|
|
6
8
|
module Mangdown
|
9
|
+
# Common helpers
|
7
10
|
module Tools
|
8
11
|
class << self
|
9
|
-
|
10
12
|
def get_doc(uri)
|
11
13
|
data = get(uri)
|
12
|
-
@doc =
|
14
|
+
@doc = Nokogiri::HTML(data)
|
13
15
|
end
|
14
16
|
|
15
17
|
def get(uri)
|
@@ -17,7 +19,7 @@ module Mangdown
|
|
17
19
|
end
|
18
20
|
|
19
21
|
def get_root(uri)
|
20
|
-
uri =
|
22
|
+
uri = URI.parse(uri)
|
21
23
|
@root = "#{uri.scheme}://#{uri.host}"
|
22
24
|
end
|
23
25
|
|
@@ -28,9 +30,9 @@ module Mangdown
|
|
28
30
|
def valid_path_name(name)
|
29
31
|
name.to_s.sub(/(\d+)(\.\w+)*\Z/) do
|
30
32
|
digits, ext = Regexp.last_match[1..2]
|
31
|
-
digits.to_i.to_s.rjust(5,
|
33
|
+
digits.to_i.to_s.rjust(5, '0') + ext.to_s
|
32
34
|
end
|
33
|
-
end
|
35
|
+
end
|
34
36
|
|
35
37
|
def image_extension(path)
|
36
38
|
path = path.to_s
|
@@ -44,7 +46,7 @@ module Mangdown
|
|
44
46
|
def hydra_streaming(objects, hydra_opts = {})
|
45
47
|
hydra = Typhoeus::Hydra.new(hydra_opts)
|
46
48
|
|
47
|
-
requests = objects.map
|
49
|
+
requests = objects.map do |obj|
|
48
50
|
next unless yield(:before, obj)
|
49
51
|
|
50
52
|
request = typhoeus(obj.uri)
|
@@ -53,15 +55,15 @@ module Mangdown
|
|
53
55
|
yield(status, obj)
|
54
56
|
end
|
55
57
|
request.on_body do |chunk|
|
56
|
-
yield(:body, obj, chunk)
|
58
|
+
yield(:body, obj, chunk)
|
57
59
|
end
|
58
|
-
request.on_complete do |
|
60
|
+
request.on_complete do |_response|
|
59
61
|
yield(:complete, obj)
|
60
62
|
end
|
61
63
|
|
62
64
|
hydra.queue(request)
|
63
65
|
request
|
64
|
-
|
66
|
+
end.compact
|
65
67
|
|
66
68
|
hydra.run
|
67
69
|
requests
|
@@ -73,7 +75,9 @@ module Mangdown
|
|
73
75
|
|
74
76
|
def typhoeus_options
|
75
77
|
{
|
76
|
-
headers: {
|
78
|
+
headers: {
|
79
|
+
'User-Agent' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36'
|
80
|
+
}
|
77
81
|
}
|
78
82
|
end
|
79
83
|
|
data/lib/mangdown/version.rb
CHANGED
data/lib/mangdown.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'uri'
|
2
4
|
require 'nokogiri'
|
3
5
|
require 'yaml'
|
4
6
|
require 'zip'
|
5
7
|
require 'filemagic'
|
8
|
+
require 'cgi'
|
9
|
+
|
10
|
+
require_relative 'mangdown/error'
|
6
11
|
|
7
12
|
require_relative 'mangdown/support/logging'
|
8
13
|
require_relative 'mangdown/support/equality'
|
@@ -18,31 +23,34 @@ require_relative 'mangdown/md_hash'
|
|
18
23
|
require_relative 'mangdown/adapter'
|
19
24
|
require_relative 'mangdown/adapter/proxy'
|
20
25
|
require_relative 'mangdown/adapter/no_adapter_error'
|
26
|
+
require_relative 'mangdown/adapter/not_implemented_error'
|
21
27
|
require_relative 'mangdown/adapter/mangareader.rb'
|
22
28
|
|
29
|
+
# Find, download and package manga from the web
|
23
30
|
module Mangdown
|
24
|
-
ADAPTERS = {}
|
25
|
-
|
26
31
|
DOWNLOAD_DIR ||= Dir.home + '/manga'
|
27
32
|
|
28
|
-
|
29
|
-
|
33
|
+
module_function
|
34
|
+
|
35
|
+
def register_adapter(name, adapter)
|
36
|
+
adapters[name] = adapter
|
30
37
|
end
|
31
38
|
|
32
|
-
def
|
33
|
-
|
39
|
+
def adapter(name)
|
40
|
+
adapters[name]
|
34
41
|
end
|
35
42
|
|
36
|
-
def
|
43
|
+
def adapter!(uri, site = nil, doc = nil, name = nil)
|
37
44
|
adapter_name = (uri || site).to_s
|
38
|
-
klass =
|
45
|
+
klass = adapters.values.find { |adapter| adapter.for?(adapter_name) }
|
39
46
|
|
40
47
|
raise Adapter::NoAdapterError, adapter_name unless klass
|
41
48
|
|
42
49
|
Adapter::Proxy.new(klass.new(uri, doc, name))
|
43
50
|
end
|
44
51
|
|
45
|
-
|
52
|
+
def adapters
|
53
|
+
@adapters ||= {}
|
46
54
|
end
|
47
55
|
end
|
48
56
|
|
@@ -22,18 +22,6 @@ module Mangdown
|
|
22
22
|
assert_equal 'adapter', @chapter.adapter
|
23
23
|
end
|
24
24
|
|
25
|
-
def test_inspect_differs_from_object_inspect
|
26
|
-
unbound_inspect = Object.instance_method(:inspect)
|
27
|
-
|
28
|
-
refute_equal unbound_inspect.bind(@chapter).call(), @chapter.inspect
|
29
|
-
end
|
30
|
-
|
31
|
-
def test_to_s_differs_from_object_to_s
|
32
|
-
unbound_to_s = Object.instance_method(:to_s)
|
33
|
-
|
34
|
-
refute_equal unbound_to_s.bind(@chapter).call(), @chapter.to_s
|
35
|
-
end
|
36
|
-
|
37
25
|
def test_cbz
|
38
26
|
CBZ.class_eval do
|
39
27
|
class << self
|
@@ -17,20 +17,6 @@ module Mangdown
|
|
17
17
|
assert_equal 'adapter', manga.adapter
|
18
18
|
end
|
19
19
|
|
20
|
-
def test_inspect_differs_from_object_inspect
|
21
|
-
unbound_inspect = Object.instance_method(:inspect)
|
22
|
-
manga = Manga.new('uri', 'name')
|
23
|
-
|
24
|
-
refute_equal unbound_inspect.bind(manga).call(), manga.inspect
|
25
|
-
end
|
26
|
-
|
27
|
-
def test_to_s_differs_from_object_to_s
|
28
|
-
unbound_to_s = Object.instance_method(:to_s)
|
29
|
-
manga = Manga.new('uri', 'name')
|
30
|
-
|
31
|
-
refute_equal unbound_to_s.bind(manga).call(), manga.to_s
|
32
|
-
end
|
33
|
-
|
34
20
|
def test_cbz
|
35
21
|
CBZ.class_eval do
|
36
22
|
class << self
|
data/test/lib/mangdown_test.rb
CHANGED
@@ -7,15 +7,15 @@ class MangdownTest < Minitest::Test
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def test_register_adapter
|
10
|
-
adapters_before = Mangdown
|
10
|
+
adapters_before = Mangdown.adapters.length
|
11
11
|
|
12
12
|
bogus = Class.new(Mangdown::Adapter::Base)
|
13
13
|
|
14
14
|
Mangdown.register_adapter(:bogus_adapter, bogus)
|
15
15
|
|
16
|
-
assert Mangdown
|
16
|
+
assert Mangdown.adapters.length == adapters_before + 1
|
17
17
|
|
18
|
-
Mangdown
|
18
|
+
Mangdown.adapters.delete(:bogus_adapter)
|
19
19
|
end
|
20
20
|
|
21
21
|
def test_adapter
|
@@ -32,13 +32,13 @@ class MangdownTest < Minitest::Test
|
|
32
32
|
"test", nil, doc, "test"
|
33
33
|
).adapter
|
34
34
|
|
35
|
-
adapters = Mangdown
|
36
|
-
Mangdown
|
35
|
+
adapters = Mangdown.adapters.dup
|
36
|
+
Mangdown.adapters.clear
|
37
37
|
|
38
38
|
assert_raises(Mangdown::Adapter::NoAdapterError) {
|
39
39
|
Mangdown.adapter!(nil)
|
40
40
|
}
|
41
41
|
|
42
|
-
Mangdown
|
42
|
+
Mangdown.adapters.merge!(adapters)
|
43
43
|
end
|
44
44
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mangdown
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.16.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jphager2
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-10-
|
11
|
+
date: 2017-10-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: typhoeus
|
@@ -134,9 +134,11 @@ files:
|
|
134
134
|
- lib/mangdown/adapter.rb
|
135
135
|
- lib/mangdown/adapter/mangareader.rb
|
136
136
|
- lib/mangdown/adapter/no_adapter_error.rb
|
137
|
+
- lib/mangdown/adapter/not_implemented_error.rb
|
137
138
|
- lib/mangdown/adapter/proxy.rb
|
138
139
|
- lib/mangdown/chapter.rb
|
139
140
|
- lib/mangdown/client.rb
|
141
|
+
- lib/mangdown/error.rb
|
140
142
|
- lib/mangdown/manga.rb
|
141
143
|
- lib/mangdown/manga_list.rb
|
142
144
|
- lib/mangdown/md_hash.rb
|