addic7ed 4.0.0.pre.beta.6 → 4.0.0.pre.beta.7
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/lib/addic7ed/models/episode.rb +42 -61
- data/lib/addic7ed/models/subtitle.rb +14 -9
- data/lib/addic7ed/models/subtitles_collection.rb +40 -7
- data/lib/addic7ed/services/download_subtitle.rb +5 -3
- data/lib/addic7ed/services/parse_page.rb +3 -1
- data/lib/addic7ed/services/parse_subtitle_node.rb +33 -0
- data/lib/addic7ed/services/parse_subtitle_node_child_fields.rb +52 -0
- data/lib/addic7ed/services/parse_subtitle_node_root_fields.rb +42 -0
- data/lib/addic7ed/version.rb +1 -1
- metadata +20 -11
- data/lib/addic7ed/models/search.rb +0 -92
- data/lib/addic7ed/services/parse_subtitle.rb +0 -81
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f8bd5053a6c2b6e07ba04dca54f782a865efd5d4
|
4
|
+
data.tar.gz: c163efc8390f5ae215b7bec747401360ee7095d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c4400b776ae11341b98684bbd19d93b01cde852e2ad7a33df6286a0a9b53b540c62311002ad1ddd14c4a5325f3ee3b76df7768105eafa21244c71887a8a9bd16
|
7
|
+
data.tar.gz: 72331b362831a3cc49af9b2a4e67a4595af1063ebc264582f8731d1fcc02417e3659234a57a14e9a3af2ea8207d05441f57289fc558a997d210503f62c2f1dd2
|
@@ -6,91 +6,72 @@ require "open-uri"
|
|
6
6
|
module Addic7ed
|
7
7
|
# Represents a TV show episode.
|
8
8
|
#
|
9
|
-
# @attr
|
9
|
+
# @attr show [String] TV show name.
|
10
10
|
# @attr season [Numeric] Season number.
|
11
|
-
# @attr
|
11
|
+
# @attr number [Numeric] Episode number in the season.
|
12
12
|
|
13
13
|
class Episode
|
14
|
-
attr_reader :
|
14
|
+
attr_reader :show, :season, :number
|
15
15
|
|
16
16
|
# Creates a new instance of {Episode}.
|
17
17
|
#
|
18
|
-
# @param
|
18
|
+
# @param show [String] TV show name
|
19
19
|
# (_e.g._ both +"Game.of.Thrones"+ and +"Game of Thrones"+ are valid)
|
20
20
|
# @param season [Numeric] Season number
|
21
|
-
# @param
|
21
|
+
# @param number [Numeric] Episode number in the season
|
22
22
|
#
|
23
23
|
# @example
|
24
|
-
# Addic7ed::Episode.new("Game of Thrones", 6, 9)
|
24
|
+
# Addic7ed::Episode.new(show: "Game of Thrones", season: 6, number: 9)
|
25
25
|
# #=> #<Addic7ed::Episode
|
26
|
-
# # @
|
26
|
+
# # @number=9,
|
27
27
|
# # @season=6,
|
28
|
-
# # @
|
29
|
-
# # @subtitles={:fr=>nil, :ar=>nil, :az=>nil, ..., :th=>nil, :tr=>nil, :vi=>nil}
|
28
|
+
# # @show="Game.of.Thrones"
|
30
29
|
# # >
|
31
30
|
|
32
|
-
def initialize(
|
33
|
-
@
|
34
|
-
@season
|
35
|
-
@
|
36
|
-
@subtitles = languages_hash { |code, _| { code => nil } }
|
31
|
+
def initialize(show:, season:, number:)
|
32
|
+
@show = show
|
33
|
+
@season = season
|
34
|
+
@number = number
|
37
35
|
end
|
38
36
|
|
39
|
-
# Returns
|
37
|
+
# Returns the URL of the Addic7ed webpage listing subtitles for this {Episode}.
|
38
|
+
# If +language+ is given, it returns the URL of the page with subtitles for this language only.
|
39
|
+
# (_warning:_ despite requesting a language, Addic7ed may display subtitles in all languages
|
40
|
+
# if the requested language has no subtitle)
|
40
41
|
#
|
41
|
-
# @param language [String] Language code we want
|
42
|
+
# @param language [String] Language code we want the webpage to list subtitles in.
|
42
43
|
#
|
43
|
-
# @return [
|
44
|
+
# @return [String] Fully qualified URL of the webpage on Addic7ed.
|
44
45
|
#
|
45
46
|
# @example
|
46
|
-
# Addic7ed::Episode.new("Game
|
47
|
-
# #=>
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
# # @hi=false,
|
52
|
-
# # @language="French",
|
53
|
-
# # @source="http://addic7ed.com",
|
54
|
-
# # @status="Completed",
|
55
|
-
# # @url="http://www.addic7ed.com/updated/8/76081/0",
|
56
|
-
# # @version="EVOLVE">,
|
57
|
-
# # #<Addic7ed::Subtitle
|
58
|
-
# # @comment="la fabrique",
|
59
|
-
# # @downloads=1515,
|
60
|
-
# # @hi=false,
|
61
|
-
# # @language="French",
|
62
|
-
# # @source="http://sous-titres.eu",
|
63
|
-
# # @status="Completed",
|
64
|
-
# # @url="http://www.addic7ed.com/original/76081/11",
|
65
|
-
# # @version="EVOLVE">,
|
66
|
-
# # #<Addic7ed::Subtitle
|
67
|
-
# # @comment="la fabrique",
|
68
|
-
# # @downloads=917,
|
69
|
-
# # @hi=false,
|
70
|
-
# # @language="French",
|
71
|
-
# # @source="http://sous-titres.eu",
|
72
|
-
# # @status="Completed",
|
73
|
-
# # @url="http://www.addic7ed.com/original/76081/12",
|
74
|
-
# # @version="WEB,DL,NTB,&,YFN">
|
75
|
-
# # ]
|
47
|
+
# Addic7ed::Episode.new("Game of Thrones", 6, 9).page_url
|
48
|
+
# #=> "http://www.addic7ed.com/serie/Game_of_Thrones/6/9/0"
|
49
|
+
#
|
50
|
+
# Addic7ed::Episode.new("Game of Thrones", 6, 9).page_url(:fr)
|
51
|
+
# #=> "http://www.addic7ed.com/serie/Game_of_Thrones/6/9/8"
|
76
52
|
|
77
|
-
def
|
78
|
-
|
53
|
+
def page_url(language = nil)
|
54
|
+
return localized_url(0) if language.nil?
|
55
|
+
localized_urls[language]
|
79
56
|
end
|
80
57
|
|
81
|
-
# Returns
|
82
|
-
# in the given +language+.
|
58
|
+
# Returns all available subtitles for this episode.
|
83
59
|
#
|
84
|
-
# @
|
85
|
-
#
|
86
|
-
# @return [String] Fully qualified URL of the webpage on Addic7ed.
|
60
|
+
# @return [SubtitlesCollection] the collection of subtitles.
|
87
61
|
#
|
88
62
|
# @example
|
89
|
-
# Addic7ed::Episode.new("Game of Thrones", 6, 9)
|
90
|
-
# #=>
|
63
|
+
# Addic7ed::Episode.new("Game of Thrones", 6, 9)
|
64
|
+
# #=> #<Addic7ed::SubtitlesCollection
|
65
|
+
# # @subtitles=[
|
66
|
+
# # #<Addic7ed::Subtitle ... >,
|
67
|
+
# # #<Addic7ed::Subtitle ... >,
|
68
|
+
# # #<Addic7ed::Subtitle ... >
|
69
|
+
# # ]
|
91
70
|
|
92
|
-
def
|
93
|
-
|
71
|
+
def subtitles
|
72
|
+
@subtitles ||= SubtitlesCollection.new(
|
73
|
+
Addic7ed::ParsePage.call(page_url)
|
74
|
+
)
|
94
75
|
end
|
95
76
|
|
96
77
|
private
|
@@ -100,11 +81,11 @@ module Addic7ed
|
|
100
81
|
end
|
101
82
|
|
102
83
|
def url_encoded_showname
|
103
|
-
@url_encoded_showname ||= URLEncodeShowName.call(
|
84
|
+
@url_encoded_showname ||= URLEncodeShowName.call(show)
|
104
85
|
end
|
105
86
|
|
106
|
-
def localized_url(
|
107
|
-
"http://www.addic7ed.com/serie/#{url_encoded_showname}/#{season}/#{
|
87
|
+
def localized_url(lang_id)
|
88
|
+
"http://www.addic7ed.com/serie/#{url_encoded_showname}/#{season}/#{number}/#{lang_id}"
|
108
89
|
end
|
109
90
|
|
110
91
|
def languages_hash(&block)
|
@@ -16,13 +16,14 @@ module Addic7ed
|
|
16
16
|
# @attr downloads [Numeric] Number of times this subtitle has been downloaded.
|
17
17
|
# @attr comment [String] Comment manually added by the subtitle author/publisher
|
18
18
|
# (usually related to extra-compatibilities or resync source).
|
19
|
-
# @attr
|
19
|
+
# @attr corrected [Boolean] Indicates if the subtitle has been corrected.
|
20
|
+
# @attr hi [Boolean] Indicates if the subtitle embeds hearing-impaired sequences.
|
20
21
|
# @attr url [String] Download URL of actual subtitle file (warning: Addic7ed servers
|
21
22
|
# won't serve a subtite file without a proper +Referer+ HTTP header which can be
|
22
23
|
# retrieved from +episode.page_url+).
|
23
24
|
|
24
25
|
class Subtitle
|
25
|
-
attr_reader :version, :language, :status, :source, :downloads, :comment, :hi
|
26
|
+
attr_reader :version, :language, :status, :source, :downloads, :comment, :corrected, :hi
|
26
27
|
attr_accessor :url
|
27
28
|
|
28
29
|
# Creates a new instance of {Subtitle} created using +options+,
|
@@ -35,7 +36,8 @@ module Addic7ed
|
|
35
36
|
# * +source+: URL of website the subtitle was originally published on
|
36
37
|
# * +downloads+: number of times the subtitle has been downloaded
|
37
38
|
# * +comment+: manually added comment from the author or publisher
|
38
|
-
# * +
|
39
|
+
# * +corrected+: indicates if subtitle has been corrected
|
40
|
+
# * +hi+: indicates if subtitle embeds hearing-impaired sequences
|
39
41
|
# * +url+: download URL for the subtitle file
|
40
42
|
#
|
41
43
|
# @param options [Hash] subtitle information as a {Hash}
|
@@ -48,17 +50,19 @@ module Addic7ed
|
|
48
50
|
# source: "http://sous-titres.eu",
|
49
51
|
# downloads: 10335,
|
50
52
|
# comment: "works with 1080p.BATV",
|
53
|
+
# corrected: true,
|
51
54
|
# hi: false,
|
52
55
|
# url: "http://www.addic7ed.com/original/113643/4"
|
53
56
|
# )
|
54
57
|
# #=> #<Addic7ed::Subtitle
|
55
58
|
# # @version="KILLERS,AVS",
|
56
|
-
# # @language="French"
|
57
|
-
# # @status="Completed"
|
58
|
-
# # @url="http://www.addic7ed.com/original/113643/4"
|
59
|
-
# # @source="http://sous-titres.eu"
|
60
|
-
# # @
|
61
|
-
# # @
|
59
|
+
# # @language="French",
|
60
|
+
# # @status="Completed",
|
61
|
+
# # @url="http://www.addic7ed.com/original/113643/4",
|
62
|
+
# # @source="http://sous-titres.eu",
|
63
|
+
# # @corrected=true,
|
64
|
+
# # @hi=false,
|
65
|
+
# # @downloads=10335,
|
62
66
|
# # @comment="works with 1080p.batv"
|
63
67
|
# # >
|
64
68
|
|
@@ -68,6 +72,7 @@ module Addic7ed
|
|
68
72
|
@status = options[:status]
|
69
73
|
@url = options[:url]
|
70
74
|
@source = options[:source]
|
75
|
+
@corrected = options[:corrected]
|
71
76
|
@hi = options[:hi]
|
72
77
|
@downloads = options[:downloads].to_i || 0
|
73
78
|
@comment = NormalizeComment.call(options[:comment])
|
@@ -3,9 +3,25 @@
|
|
3
3
|
module Addic7ed
|
4
4
|
# Represents a collection of {Subtitle} objects.
|
5
5
|
#
|
6
|
-
# This collection
|
7
|
-
#
|
8
|
-
class SubtitlesCollection
|
6
|
+
# This collection is a custom {Enumerable} which provides
|
7
|
+
# some methods to filter, order and choose the best subtitle.
|
8
|
+
class SubtitlesCollection
|
9
|
+
include Enumerable
|
10
|
+
|
11
|
+
# @!visibility private
|
12
|
+
def each(&block)
|
13
|
+
@subtitles.each(&block)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Creates a filterable, sortable collection of subtitles
|
17
|
+
# @param subtitles [Enumerable] List of subtitles to initialize the collection with
|
18
|
+
#
|
19
|
+
# @return [SubtitleCollection] the initialized subtitles collection
|
20
|
+
|
21
|
+
def initialize(subtitles = [])
|
22
|
+
@subtitles = subtitles
|
23
|
+
end
|
24
|
+
|
9
25
|
# Returns only subtitles that are compatible with +group+.
|
10
26
|
# @param group [String] Release group we want the returned subtitles to be compatible with
|
11
27
|
#
|
@@ -21,7 +37,7 @@ module Addic7ed
|
|
21
37
|
# #=> [#<Addic7ed::Subtitle @version="LOL">, #<Addic7ed::Subtitle @version="DIMENSION">]
|
22
38
|
|
23
39
|
def compatible_with(group)
|
24
|
-
select { |subtitle| CheckCompatibility.call(subtitle, group) }
|
40
|
+
chainable(select { |subtitle| CheckCompatibility.call(subtitle, group) })
|
25
41
|
end
|
26
42
|
|
27
43
|
# Returns only completed subtitles.
|
@@ -37,7 +53,24 @@ module Addic7ed
|
|
37
53
|
# #=> [#<Addic7ed::Subtitle @status="Completed">]
|
38
54
|
|
39
55
|
def completed
|
40
|
-
select(&:completed?)
|
56
|
+
chainable(select(&:completed?))
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns only subtitles for given +language_code+.
|
60
|
+
#
|
61
|
+
# @return [SubtitleCollection] Copy of collection filtered by +language+
|
62
|
+
#
|
63
|
+
# @example
|
64
|
+
# english_subtitle = Addic7ed::Subtitle.new(language: "English")
|
65
|
+
# french_subtitle = Addic7ed::Subtitle.new(language: "French")
|
66
|
+
# collection = Addic7ed::SubtitlesCollection.new([english_subtitle, french_subtitle])
|
67
|
+
#
|
68
|
+
# collection.for_language(:en)
|
69
|
+
# #=> [#<Addic7ed::Subtitle @language="English">]
|
70
|
+
|
71
|
+
def for_language(language_code)
|
72
|
+
raise LanguageNotSupported unless LANGUAGES.key? language_code.to_sym
|
73
|
+
chainable(select { |subtitle| subtitle.language == LANGUAGES[language_code.to_sym][:name] })
|
41
74
|
end
|
42
75
|
|
43
76
|
# Returns the most downloaded subtitle.
|
@@ -58,8 +91,8 @@ module Addic7ed
|
|
58
91
|
|
59
92
|
private
|
60
93
|
|
61
|
-
def
|
62
|
-
|
94
|
+
def chainable(array)
|
95
|
+
self.class.new(array)
|
63
96
|
end
|
64
97
|
end
|
65
98
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# TODO: move to the CLI codebase and use HTTParty
|
4
|
+
|
3
5
|
module Addic7ed
|
4
6
|
class DownloadSubtitle
|
5
7
|
include Service
|
@@ -39,20 +41,20 @@ module Addic7ed
|
|
39
41
|
request["User-Agent"] = USER_AGENTS.sample
|
40
42
|
http.request(request)
|
41
43
|
end
|
42
|
-
rescue
|
44
|
+
rescue StandardError
|
43
45
|
raise DownloadError, "A network error occured"
|
44
46
|
end
|
45
47
|
|
46
48
|
def follow_redirection(location_header)
|
47
49
|
# Addic7ed is serving redirection URL not-encoded,
|
48
50
|
# but Ruby does not support it (see http://bugs.ruby-lang.org/issues/7396)
|
49
|
-
new_url =
|
51
|
+
new_url = CGI.escape(location_header)
|
50
52
|
DownloadSubtitle.call(new_url, filename, url, redirect_count + 1)
|
51
53
|
end
|
52
54
|
|
53
55
|
def write(content)
|
54
56
|
Kernel.open(filename, "w") { |f| f << content }
|
55
|
-
rescue
|
57
|
+
rescue StandardError
|
56
58
|
raise DownloadError, "Cannot write to disk"
|
57
59
|
end
|
58
60
|
end
|
@@ -16,7 +16,9 @@ module Addic7ed
|
|
16
16
|
|
17
17
|
def call
|
18
18
|
raise NoSubtitleFound unless subtitles_found?
|
19
|
-
subtitles_nodes.map
|
19
|
+
subtitles_nodes.map do |subtitle_node|
|
20
|
+
Addic7ed::ParseSubtitleNode.call(subtitle_node)
|
21
|
+
end.flatten
|
20
22
|
end
|
21
23
|
|
22
24
|
private
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "oga"
|
4
|
+
|
5
|
+
module Addic7ed
|
6
|
+
class ParseSubtitleNode
|
7
|
+
include Service
|
8
|
+
|
9
|
+
attr_reader :subtitle_node
|
10
|
+
|
11
|
+
def initialize(subtitle_node)
|
12
|
+
@subtitle_node = subtitle_node
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
children_fields.map do |child_fields|
|
17
|
+
Addic7ed::Subtitle.new(root_fields.merge(child_fields))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def root_fields
|
24
|
+
@root_fields ||= ParseSubtitleNodeRootFields.call(subtitle_node)
|
25
|
+
end
|
26
|
+
|
27
|
+
def children_fields
|
28
|
+
@children_fields ||= subtitle_node.css(".language").map do |language_node|
|
29
|
+
ParseSubtitleNodeChildFields.call(language_node)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Addic7ed
|
4
|
+
class ParseSubtitleNodeChildFields
|
5
|
+
include Service
|
6
|
+
|
7
|
+
attr_reader :language_node
|
8
|
+
|
9
|
+
FIELDS = %i[language status url corrected hi downloads].freeze
|
10
|
+
|
11
|
+
def initialize(language_node)
|
12
|
+
@language_node = language_node
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
FIELDS.map do |field|
|
17
|
+
{ field => send(field) }
|
18
|
+
end.reduce(:merge)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def language
|
24
|
+
@language ||= language_node.text.gsub(/\A\W*/, "").gsub(/[^\w\)]*\z/, "")
|
25
|
+
end
|
26
|
+
|
27
|
+
def status
|
28
|
+
@status ||= language_node.css("~ td b").first.text.strip
|
29
|
+
end
|
30
|
+
|
31
|
+
def url
|
32
|
+
@url ||= "http://www.addic7ed.com" + language_node.css("~ td a.buttonDownload").first[:href]
|
33
|
+
end
|
34
|
+
|
35
|
+
def corrected
|
36
|
+
return @corrected if defined? @corrected
|
37
|
+
@corrected = language_node.parent.css("~ tr td.newsDate img")[0][:title] == "Corrected"
|
38
|
+
end
|
39
|
+
|
40
|
+
def hi
|
41
|
+
return @hi if defined? @hi
|
42
|
+
@hi = language_node.parent.css("~ tr td.newsDate img")[1][:title] == "Hearing Impaired"
|
43
|
+
end
|
44
|
+
|
45
|
+
def downloads
|
46
|
+
@downloads ||= begin
|
47
|
+
text = language_node.parent.css("~ tr td.newsDate").text
|
48
|
+
/(?<downloads>\d*) Downloads/.match(text)[:downloads]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Addic7ed
|
4
|
+
class ParseSubtitleNodeRootFields
|
5
|
+
include Service
|
6
|
+
|
7
|
+
attr_reader :subtitle_node
|
8
|
+
|
9
|
+
FIELDS = %i[version source comment].freeze
|
10
|
+
|
11
|
+
def initialize(subtitle_node)
|
12
|
+
@subtitle_node = subtitle_node
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
FIELDS.map do |field|
|
17
|
+
{ field => send(field) }
|
18
|
+
end.reduce(:merge)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def version
|
24
|
+
return @version if defined? @version
|
25
|
+
@version = subtitle_node.css(".NewsTitle").first.text
|
26
|
+
end
|
27
|
+
|
28
|
+
def source
|
29
|
+
return @source if defined? @source
|
30
|
+
@source = subtitle_node.css("tr:nth-child(3) td:first-child a").first.tap do |node|
|
31
|
+
break node[:href] if node
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def comment
|
36
|
+
return @comment if defined? @comment
|
37
|
+
@comment = subtitle_node.css("tr:nth-child(2) td.newsDate").first.tap do |node|
|
38
|
+
break node.text.strip if node
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/addic7ed/version.rb
CHANGED
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: addic7ed
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.0.pre.beta.
|
4
|
+
version: 4.0.0.pre.beta.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Baudino
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-01-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: inch
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
@@ -25,7 +25,7 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: pry
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
@@ -53,7 +53,7 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: rspec
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
@@ -81,7 +81,7 @@ dependencies:
|
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: webmock
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - ">="
|
@@ -134,7 +134,6 @@ files:
|
|
134
134
|
- lib/addic7ed/config.json
|
135
135
|
- lib/addic7ed/errors.rb
|
136
136
|
- lib/addic7ed/models/episode.rb
|
137
|
-
- lib/addic7ed/models/search.rb
|
138
137
|
- lib/addic7ed/models/subtitle.rb
|
139
138
|
- lib/addic7ed/models/subtitles_collection.rb
|
140
139
|
- lib/addic7ed/models/video_file.rb
|
@@ -145,14 +144,23 @@ files:
|
|
145
144
|
- lib/addic7ed/services/normalize_comment.rb
|
146
145
|
- lib/addic7ed/services/normalize_version.rb
|
147
146
|
- lib/addic7ed/services/parse_page.rb
|
148
|
-
- lib/addic7ed/services/
|
147
|
+
- lib/addic7ed/services/parse_subtitle_node.rb
|
148
|
+
- lib/addic7ed/services/parse_subtitle_node_child_fields.rb
|
149
|
+
- lib/addic7ed/services/parse_subtitle_node_root_fields.rb
|
149
150
|
- lib/addic7ed/services/url_encode_show_name.rb
|
150
151
|
- lib/addic7ed/version.rb
|
151
152
|
homepage: https://github.com/michaelbaudino/addic7ed-ruby
|
152
153
|
licenses:
|
153
154
|
- MIT
|
154
155
|
metadata: {}
|
155
|
-
post_install_message:
|
156
|
+
post_install_message: |2+
|
157
|
+
|
158
|
+
Important update if you're upgrading from 3.x to 4.x:
|
159
|
+
|
160
|
+
This gem is not providing a CLI tool anymore.
|
161
|
+
If you're using it as a Ruby API for Addic7ed, you're all good, ignore this message.
|
162
|
+
If you're expecting the `addic7ed` binary, we've moved it to the `addic7ed-cli` gem.
|
163
|
+
|
156
164
|
rdoc_options: []
|
157
165
|
require_paths:
|
158
166
|
- lib
|
@@ -168,8 +176,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
168
176
|
version: 1.3.1
|
169
177
|
requirements: []
|
170
178
|
rubyforge_project:
|
171
|
-
rubygems_version: 2.6.
|
179
|
+
rubygems_version: 2.6.14
|
172
180
|
signing_key:
|
173
181
|
specification_version: 4
|
174
182
|
summary: Addic7ed auto-downloader
|
175
183
|
test_files: []
|
184
|
+
has_rdoc:
|
@@ -1,92 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Addic7ed
|
4
|
-
# Represents a subtitle search for a +video_filename+ in a +language+ with
|
5
|
-
# multiple search +criterias+.
|
6
|
-
#
|
7
|
-
# @attr video_filename [String] Video file name we're searching subtitles for.
|
8
|
-
# @attr language [String] ISO code of language (_e.g._ "en", "fr", "es").
|
9
|
-
# @attr criterias [Hash] List of search criterias as a {Hash}.
|
10
|
-
|
11
|
-
class Search
|
12
|
-
attr_reader :video_filename, :language, :criterias
|
13
|
-
|
14
|
-
# Creates a new instance of {Search}.
|
15
|
-
#
|
16
|
-
# Currently supported search criterias are:
|
17
|
-
# * +no_hi+: do not include hearing impaired subtitles (defaults to +false+)
|
18
|
-
#
|
19
|
-
# @param video_filename [String] Path to the video file for which we search subtitles
|
20
|
-
# (either relative or absolute path)
|
21
|
-
# @param language [String] ISO code of target subtitles language
|
22
|
-
# @param criterias [Hash] List of search criterias the subtitles must match
|
23
|
-
# (will be merged with default criterias as described above)
|
24
|
-
#
|
25
|
-
# @example
|
26
|
-
# Addic7ed::Search.new("Game.of.Thrones.S06E09.720p.HDTV.x264-AVS.mkv", :fr)
|
27
|
-
# #=> #<Addic7ed::Search
|
28
|
-
# # @criterias={:no_hi=>false},
|
29
|
-
# # @language=:fr,
|
30
|
-
# # @video_filename="Game.of.Thrones.S06E09.720p.HDTV.x264-AVS.mkv"
|
31
|
-
# # >
|
32
|
-
|
33
|
-
def initialize(video_filename, language, criterias = {})
|
34
|
-
@video_filename = video_filename
|
35
|
-
@language = language
|
36
|
-
@criterias = default_criterias.merge(criterias)
|
37
|
-
end
|
38
|
-
|
39
|
-
# Returns the {VideoFile} object representing the video file we're searching subtitles for.
|
40
|
-
#
|
41
|
-
# @return [VideoFile] the {VideoFile} associated with this {Search}
|
42
|
-
|
43
|
-
def video_file
|
44
|
-
@video_file ||= VideoFile.new(video_filename)
|
45
|
-
end
|
46
|
-
|
47
|
-
# Returns the {Episode} object we're searching subtitles for.
|
48
|
-
#
|
49
|
-
# @return [Episode] the {Episode} associated with this {Search}
|
50
|
-
|
51
|
-
def episode
|
52
|
-
@episode ||= Episode.new(video_file.showname, video_file.season, video_file.episode)
|
53
|
-
end
|
54
|
-
|
55
|
-
# Returns the list of all available subtitles for this search,
|
56
|
-
# regardless of completeness, compatibility or search +criterias+.
|
57
|
-
#
|
58
|
-
# @return [SubtitlesCollection] all subtitles for the searched episode
|
59
|
-
|
60
|
-
def all_subtitles
|
61
|
-
@all_subtitles ||= SubtitlesCollection.new(episode.subtitles(language))
|
62
|
-
end
|
63
|
-
|
64
|
-
# Returns the list of subtitles completed and compatible with the episode we're searching
|
65
|
-
# subtitles for, regardless of search +criterias+.
|
66
|
-
#
|
67
|
-
# @return [SubtitlesCollection] subtitles completed and compatible with the searched episode
|
68
|
-
|
69
|
-
def matching_subtitles
|
70
|
-
@matching_subtitles ||= all_subtitles.completed.compatible_with(video_file.group)
|
71
|
-
end
|
72
|
-
|
73
|
-
# Returns the best subtitle for the episode we're searching subtitles for.
|
74
|
-
#
|
75
|
-
# The best subtitle means the more popular (_i.e._ most downloaded) subtitle among completed,
|
76
|
-
# compatible subtitles for the episode we're searching subtitles for.
|
77
|
-
#
|
78
|
-
# @return [SubtitlesCollection] subtitles completed and compatible with the searched episode
|
79
|
-
|
80
|
-
def best_subtitle
|
81
|
-
@best_subtitle ||= matching_subtitles.most_popular
|
82
|
-
end
|
83
|
-
|
84
|
-
private
|
85
|
-
|
86
|
-
def default_criterias
|
87
|
-
{
|
88
|
-
no_hi: false
|
89
|
-
}
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
@@ -1,81 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "oga"
|
4
|
-
|
5
|
-
module Addic7ed
|
6
|
-
class ParseSubtitle
|
7
|
-
include Service
|
8
|
-
|
9
|
-
attr_reader :subtitle_node
|
10
|
-
|
11
|
-
FIELDS = %i[version language status url source hi downloads comment].freeze
|
12
|
-
|
13
|
-
def initialize(subtitle_node)
|
14
|
-
@subtitle_node = subtitle_node
|
15
|
-
end
|
16
|
-
|
17
|
-
def call
|
18
|
-
Addic7ed::Subtitle.new(extract_fields)
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
def extract_fields
|
24
|
-
FIELDS.map do |field|
|
25
|
-
{ field => send(:"extract_#{field}") }
|
26
|
-
end.reduce(:merge)
|
27
|
-
end
|
28
|
-
|
29
|
-
def extract_field(selector, options = { required: true })
|
30
|
-
node = subtitle_node.css(selector).first
|
31
|
-
raise Addic7ed::ParsingError if options[:required] && node.nil?
|
32
|
-
yield node
|
33
|
-
end
|
34
|
-
|
35
|
-
def extract_version
|
36
|
-
extract_field(".NewsTitle", &:text)
|
37
|
-
end
|
38
|
-
|
39
|
-
def extract_language
|
40
|
-
extract_field(".language") do |node|
|
41
|
-
node.text.gsub(/\A\W*/, "").gsub(/[^\w\)]*\z/, "")
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def extract_status
|
46
|
-
extract_field("tr:nth-child(3) td:nth-child(4) b") do |node|
|
47
|
-
node.text.strip
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def extract_url
|
52
|
-
extract_field("a.buttonDownload:last-of-type") do |node|
|
53
|
-
"http://www.addic7ed.com#{node["href"]}"
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def extract_source
|
58
|
-
extract_field("tr:nth-child(3) td:first-child a", required: false) do |node|
|
59
|
-
node["href"] unless node.nil?
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def extract_hi
|
64
|
-
extract_field("tr:nth-child(4) td.newsDate img:last-of-type") do |node|
|
65
|
-
node.attribute("title") == "Hearing Impaired"
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def extract_downloads
|
70
|
-
extract_field("tr:nth-child(4) td.newsDate") do |node|
|
71
|
-
/(?<downloads>\d*) Downloads/.match(node.text)[:downloads]
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def extract_comment
|
76
|
-
extract_field("tr:nth-child(2) td.newsDate") do |node|
|
77
|
-
node.text.gsub(/<img[^>]+\>/i, "")
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|