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 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