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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c2a0a0fd093c29b07a62a7259c773df5343c4c2c
4
- data.tar.gz: 03110733e1ba66da173b5ad852ea3668dcbc7f4a
3
+ metadata.gz: f8bd5053a6c2b6e07ba04dca54f782a865efd5d4
4
+ data.tar.gz: c163efc8390f5ae215b7bec747401360ee7095d1
5
5
  SHA512:
6
- metadata.gz: c06455d2aad3610b7321dffd54f88f6d426087872083d96ae3284d21e6853936d883d76eff11390f7ffd8774ff0177126edce6460bec03288d1ad1789e6ec89d
7
- data.tar.gz: 6b2a108af177c4b6096ef55152b233319893a7cd967e1e1a11daea8006f76933ecc783a44b585fdceb29f0dd32e446b0865a363c553fe20e7d027536d46e8fd4
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 showname [String] TV show name.
9
+ # @attr show [String] TV show name.
10
10
  # @attr season [Numeric] Season number.
11
- # @attr episode [Numeric] Episode number in the season.
11
+ # @attr number [Numeric] Episode number in the season.
12
12
 
13
13
  class Episode
14
- attr_reader :showname, :season, :episode
14
+ attr_reader :show, :season, :number
15
15
 
16
16
  # Creates a new instance of {Episode}.
17
17
  #
18
- # @param showname [String] TV show name, as extracted from the video file name
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 episode [Numeric] Episode number in the season
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
- # # @episode=9,
26
+ # # @number=9,
27
27
  # # @season=6,
28
- # # @showname="Game.of.Thrones",
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(showname, season, episode)
33
- @showname = showname
34
- @season = season
35
- @episode = episode
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 a list of all available {Subtitle}s for this {Episode} in the given +language+.
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 returned {Subtitle}s to be in.
42
+ # @param language [String] Language code we want the webpage to list subtitles in.
42
43
  #
43
- # @return [Array<Subtitle>] List of {Subtitle}s available on Addic7ed for the given +language+.
44
+ # @return [String] Fully qualified URL of the webpage on Addic7ed.
44
45
  #
45
46
  # @example
46
- # Addic7ed::Episode.new("Game.of.Thrones", 3, 9).subtitles(:fr)
47
- # #=> [
48
- # # #<Addic7ed::Subtitle
49
- # # @comment="works with ctrlhd",
50
- # # @downloads=28130,
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 subtitles(language)
78
- @subtitles[language] ||= Addic7ed::ParsePage.call(page_url(language))
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 the URL of the Addic7ed webpage listing subtitles for this {Episode}
82
- # in the given +language+.
58
+ # Returns all available subtitles for this episode.
83
59
  #
84
- # @param language [String] Language code we want the webpage to list subtitles in.
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).page_url
90
- # #=> "http://www.addic7ed.com/serie/Game_of_Thrones/6/9/8"
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 page_url(language)
93
- localized_urls[language]
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(showname)
84
+ @url_encoded_showname ||= URLEncodeShowName.call(show)
104
85
  end
105
86
 
106
- def localized_url(lang)
107
- "http://www.addic7ed.com/serie/#{url_encoded_showname}/#{season}/#{episode}/#{lang}"
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 hi [Boolean] Hearing-impaired support.
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
- # * +hi+: hearing-impaired support
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
- # # @hi=false
61
- # # @downloads=10335
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 inherits from {Array} so it behaves exaclty like it,
7
- # but it also provides some methods to filter, order and choose the best subtitle.
8
- class SubtitlesCollection < Array
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 select
62
- SubtitlesCollection.new(super)
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 = URI.escape(location_header)
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 { |subtitle_node| Addic7ed::ParseSubtitle.call(subtitle_node) }
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Addic7ed
4
- VERSION = "4.0.0-beta.6".freeze # rubocop:disable Style/RedundantFreeze
4
+ VERSION = "4.0.0-beta.7".freeze # rubocop:disable Style/RedundantFreeze
5
5
  end
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.6
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: 2017-08-13 00:00:00.000000000 Z
11
+ date: 2018-01-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rspec
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: rake
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: webmock
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: pry
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: inch
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/parse_subtitle.rb
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.11
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