addic7ed 4.0.0.pre.beta.6 → 4.0.0.pre.beta.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|