download_tv 2.6.0 → 2.6.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -12,18 +12,27 @@ module DownloadTV
12
12
  Thread.abort_on_exception = true
13
13
  end
14
14
 
15
+ ##
16
+ # Tries to download episodes in order for a given season,
17
+ # until it can't find any
18
+ def download_entire_season(show, season)
19
+ t = Torrent.new(@config.content[:grabber])
20
+ season.insert(0, '0') if season.size == 1
21
+ episode = "#{show} s#{season}e01"
22
+ loop do
23
+ link = get_link(t, episode)
24
+ break if link.empty?
25
+
26
+ download(link)
27
+ episode = episode.next
28
+ end
29
+ end
30
+
15
31
  def download_single_show(show, season = nil)
16
32
  t = Torrent.new(@config.content[:grabber])
17
33
  show = fix_names([show]).first
18
34
  if season
19
- season.insert(0, '0') if season.size == 1
20
- episode = "#{show} s#{season}e01"
21
- loop do
22
- link = get_link(t, episode)
23
- break if link.empty?
24
- download(link)
25
- episode = episode.next
26
- end
35
+ download_entire_season(show, season)
27
36
  else
28
37
  download(get_link(t, show))
29
38
  end
@@ -44,96 +53,82 @@ module DownloadTV
44
53
  end
45
54
  end
46
55
 
56
+ ##
57
+ # Returns the date from which to check shows
58
+ def date_to_check_from(offset)
59
+ return @config.content[:date] if offset.zero?
60
+
61
+ Date.today - offset
62
+ end
63
+
47
64
  ##
48
65
  # Finds download links for all new episodes aired since
49
66
  # the last run of the program
50
67
  # It connects to MyEpisodes in order to find which shows
51
68
  # to track and which new episodes aired.
52
- def run(dont_update_last_run, offset = 0)
69
+ # The param +dont_update_last_run+ prevents changing the configuration's date value
70
+ # The param +offset+ can be used to move the date back that many days in the check
71
+ # The param +include_tomorrow+ will add the current day to the list of dates to search
72
+ def run(dont_update_last_run, offset = 0, include_tomorrow: false)
53
73
  pending = @config.content[:pending].clone
54
74
  @config.content[:pending].clear
55
75
  pending ||= []
56
- date = check_date(offset)
76
+ date = date_to_check_from(offset)
57
77
 
58
- pending.concat shows_to_download(date) if date
78
+ pending.concat shows_to_download(date) if date < Date.today
79
+ pending.concat today_shows_to_download if include_tomorrow && date < Date.today.next
59
80
 
60
81
  if pending.empty?
61
82
  puts 'Nothing to download'
62
83
  else
63
- find_and_download(pending)
84
+ find_and_download(pending.uniq)
64
85
  puts 'Completed. Exiting...'
65
86
  end
66
87
 
67
- @config.content[:date] = [Date.today, @config.content[:date]].max unless dont_update_last_run
88
+ unless dont_update_last_run
89
+ @config.content[:date] = if include_tomorrow
90
+ Date.today.next
91
+ else
92
+ [Date.today, @config.content[:date]].max
93
+ end
94
+ end
68
95
  @config.serialize
69
96
  rescue InvalidLoginError
70
97
  warn 'Wrong username/password combination'
71
98
  end
72
99
 
73
- ##
74
- # Finds download links for all the episodes set to air today.
75
- # TODO: Refactor with #run()
76
- def run_ahead(dont_update_last_run)
77
- pending = @config.content[:pending].clone
78
- @config.content[:pending].clear
79
- pending ||= []
80
-
81
- # Make normal run first if necessary
82
- if @config.content[:date] < Date.today
83
- pending.concat shows_to_download(@config.content[:date])
84
- end
85
-
86
- # Only do --tomorrow run if it hasn't happened already
87
- if @config.content[:date] < Date.today.next
88
- pending.concat today_shows_to_download
100
+ def find_links(torrent, shows, queue)
101
+ Thread.new do
102
+ shows.each { |show| queue << get_link(torrent, show, save_pending: true) }
103
+ queue.close
89
104
  end
105
+ end
90
106
 
91
- if pending.empty?
92
- puts 'Nothing to download'
93
- else
94
- find_and_download(pending)
95
- puts 'Completed. Exiting...'
107
+ def download_from_queue(queue)
108
+ Thread.new do
109
+ until queue.closed?
110
+ magnet = queue.pop
111
+ download(magnet) if magnet # Doesn't download if no torrents are found
112
+ end
96
113
  end
97
-
98
- @config.content[:date] = Date.today.next unless dont_update_last_run
99
- @config.serialize
100
- rescue InvalidLoginError
101
- warn 'Wrong username/password combination'
102
114
  end
103
115
 
104
116
  def find_and_download(shows)
105
117
  t = Torrent.new
106
118
  queue = Queue.new
107
119
 
108
- # Adds a link (or empty string to the queue)
109
- link_t = Thread.new do
110
- shows.each { |show| queue << get_link(t, show, true) }
111
- end
120
+ link_t = find_links(t, shows, queue)
112
121
 
113
122
  # Downloads the links as they are added
114
- download_t = Thread.new do
115
- shows.size.times do
116
- magnet = queue.pop
117
- next if magnet == '' # Doesn't download if no torrents are found
118
-
119
- download(magnet)
120
- end
121
- end
122
-
123
- # Downloading the subtitles
124
- # subs_t = @config.content[:subs] and Thread.new do
125
- # shows.each { |show| @s.get_subs(show) }
126
- # end
123
+ download_t = download_from_queue(queue)
127
124
 
128
125
  link_t.join
129
126
  download_t.join
130
- # subs_t.join
131
127
  end
132
128
 
133
129
  def shows_to_download(date)
134
130
  myepisodes = MyEpisodes.new(@config.content[:myepisodes_user],
135
131
  @config.content[:cookie])
136
- # Log in using cookie by default
137
132
  myepisodes.load_cookie
138
133
  shows = myepisodes.get_shows_since(date)
139
134
  shows = reject_ignored(shows)
@@ -154,18 +149,17 @@ module DownloadTV
154
149
  # When :auto is true it will try to find the best match
155
150
  # based on a set of filters.
156
151
  # When it's false it will prompt the user to select the preferred result
157
- # Returns either a magnet link or an emptry string
158
- def get_link(torrent, show, save_pending = false)
152
+ # Returns either a magnet link or nil
153
+ def get_link(torrent, show, save_pending: false)
159
154
  links = torrent.get_links(show)
160
155
 
161
156
  if links.empty?
162
157
  @config.content[:pending] << show if save_pending
163
- return ''
158
+ return
164
159
  end
165
160
 
166
161
  if @config.content[:auto]
167
- links = filter_shows(links)
168
- links.first[1]
162
+ filter_shows(links).first[1]
169
163
  else
170
164
  prompt_links(links)
171
165
  get_link_from_user(links)
@@ -180,7 +174,7 @@ module DownloadTV
180
174
  i = $stdin.gets.chomp.to_i
181
175
  end
182
176
 
183
- i == -1 ? '' : links[i][1]
177
+ i == -1 ? nil : links[i][1]
184
178
  end
185
179
 
186
180
  def prompt_links(links)
@@ -190,19 +184,6 @@ module DownloadTV
190
184
  print 'Select the torrent you want to download [-1 to skip]: '
191
185
  end
192
186
 
193
- ##
194
- # Returns the date from which to check shows
195
- # or nil if the program was already ran today
196
- # Passing an offset skips this check
197
- def check_date(offset)
198
- if offset.zero?
199
- last = @config.content[:date]
200
- last if last < Date.today
201
- else
202
- Date.today - offset
203
- end
204
- end
205
-
206
187
  ##
207
188
  # Given a list of shows and episodes:
208
189
  #
@@ -228,13 +209,12 @@ module DownloadTV
228
209
  # Runs until no filters are left to be applied or applying
229
210
  # a filter would leave no results
230
211
  def filter_shows(links)
231
- f = Filterer.new(@config.content[:filters])
232
- f.filter(links)
212
+ @filterer ||= Filterer.new(@config.content[:filters])
213
+ @filterer.filter(links)
233
214
  end
234
215
 
235
216
  ##
236
217
  # Spawns a silent process to download a given magnet link
237
- # Uses xdg-open (not portable)
238
218
  def download(link)
239
219
  @cmd ||= detect_os
240
220
 
@@ -250,7 +230,7 @@ module DownloadTV
250
230
  when /darwin/
251
231
  'open'
252
232
  else
253
- warn "You're using an unsupported platform."
233
+ warn "You're using an unsupported platform (#{RbConfig::CONFIG['host_os']})."
254
234
  exit 1
255
235
  end
256
236
  end
@@ -9,28 +9,17 @@ module DownloadTV
9
9
  end
10
10
 
11
11
  def get_links(show)
12
- # Format the url
13
- search = format(@url, show)
14
-
15
- data = @agent.get(search).search('a.magnet')
16
-
17
- # Torrent name in data[i].attribute 'title'
18
- # 'Suits S04E01 HDTV x264-LOL Torrent: Magnet Link'
12
+ raw_data = @agent.get(format(@url, show))
13
+ raw_seeders = raw_data.search('td.forum_thread_post_end').map { |e| e.children[0].text.to_i }
14
+ raw_links = raw_data.search('a.magnet').sort_by.with_index { |_, index| raw_seeders[index] }.reverse
19
15
 
20
16
  # EZTV shows 50 latest releases if it can't find the torrent
21
- raise NoTorrentsError if data.size == 50
17
+ raise NoTorrentsError if raw_links.size == 50
22
18
 
23
- names = data.collect do |i|
24
- i.attribute('title')
25
- .text
26
- .chomp(' Magnet Link')
19
+ raw_links.collect do |i|
20
+ [i.attribute('title').text.chomp(' Magnet Link'),
21
+ i.attribute('href').text]
27
22
  end
28
- links = data.collect do |i|
29
- i.attribute('href')
30
- .text
31
- end
32
-
33
- names.zip(links)
34
23
  end
35
24
  end
36
25
  end
@@ -5,29 +5,30 @@ module DownloadTV
5
5
  # TorrentAPI.org grabber
6
6
  # Interfaces with http://torrentapi.org/apidocs_v2.txt
7
7
  class TorrentAPI < LinkGrabber
8
- attr_accessor :token
9
- attr_reader :wait
8
+ TOKEN_EXPIRED_ERROR = 4
9
+ TOO_MANY_REQUESTS_ERROR = 5 # 1req/2s
10
10
 
11
11
  def initialize
12
12
  super('https://torrentapi.org/pubapi_v2.php?'\
13
13
  'mode=search&search_string=%s&token=%s&'\
14
14
  'app_id=DownloadTV&sort=seeders')
15
- @wait = 0.1
15
+ @wait = 0.5
16
+ @token = nil
16
17
  end
17
18
 
18
19
  ##
19
20
  # Specific implementation for TorrentAPI (requires token)
20
21
  def online?
21
- @agent.read_timeout = 2
22
22
  renew_token
23
23
  true
24
- rescue Mechanize::ResponseCodeError, Net::HTTP::Persistent::Error => e
24
+ rescue Mechanize::ResponseCodeError => e
25
25
  if e.response_code == '429'
26
26
  sleep(@wait)
27
27
  retry
28
- else
29
- false
30
28
  end
29
+ false
30
+ rescue Net::HTTP::Persistent::Error
31
+ false
31
32
  end
32
33
 
33
34
  ##
@@ -50,19 +51,19 @@ module DownloadTV
50
51
  end
51
52
 
52
53
  def get_links(show)
53
- @token ||= renew_token
54
+ renew_token if @token.nil?
54
55
 
55
56
  search = format(@url, show, @token)
56
57
 
57
58
  obj = request_and_parse(search)
58
59
 
59
- if obj['error_code'] == 4 # Token expired
60
+ if obj['error_code'] == TOKEN_EXPIRED_ERROR
60
61
  renew_token
61
62
  search = format(@url, show, @token)
62
63
  obj = request_and_parse(search)
63
64
  end
64
65
 
65
- while obj['error_code'] == 5 # Violate 1req/2s limit
66
+ while obj['error_code'] == TOO_MANY_REQUESTS_ERROR
66
67
  sleep(@wait)
67
68
  obj = request_and_parse(search)
68
69
  end
@@ -77,9 +78,6 @@ module DownloadTV
77
78
  if e.response_code == '429'
78
79
  sleep(@wait)
79
80
  retry
80
- else
81
- warn 'An unexpected error has occurred. Try updating the gem.'
82
- exit 1
83
81
  end
84
82
  end
85
83
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DownloadTV
4
+ ##
5
+ # EZTV.ag grabber
6
+ class Torrentz < LinkGrabber
7
+ def initialize
8
+ super('https://torrentzeu.org/kick.php?q=%s')
9
+ end
10
+
11
+ def get_links(show)
12
+ raw_data = @agent.get(format(@url, show))
13
+ results = raw_data.search('tbody tr')
14
+
15
+ # require 'byebug'; byebug
16
+
17
+ raise NoTorrentsError if results.empty?
18
+
19
+ data = results.sort_by { |e| e.search('td[data-title="Last Updated"]')[1].text.to_i }.reverse
20
+
21
+ data.collect do |i|
22
+ [i.children[1].text.strip,
23
+ i.children[11].children[1].attribute('href').text]
24
+ end
25
+ end
26
+ end
27
+ end
@@ -8,12 +8,13 @@ module DownloadTV
8
8
 
9
9
  def initialize(url)
10
10
  @url = url
11
- @agent = Mechanize.new
12
- @agent.user_agent = DownloadTV::USER_AGENT
11
+ @agent = Mechanize.new do |a|
12
+ a.user_agent = DownloadTV::USER_AGENT
13
+ a.read_timeout = 10
14
+ end
13
15
  end
14
16
 
15
17
  def online?
16
- @agent.read_timeout = 2
17
18
  url = if @url.include? '%s'
18
19
  format(@url, 'test')
19
20
  else
@@ -32,11 +32,11 @@ module DownloadTV
32
32
  def prompt_user_data
33
33
  if !@user || @user == ''
34
34
  print 'Enter your MyEpisodes username: '
35
- @user = STDIN.gets.chomp
35
+ @user = $stdin.gets.chomp
36
36
  end
37
37
 
38
38
  print 'Enter your MyEpisodes password: '
39
- pass = STDIN.noecho(&:gets).chomp
39
+ pass = $stdin.noecho(&:gets).chomp
40
40
  puts
41
41
  pass
42
42
  end
@@ -7,8 +7,7 @@ module DownloadTV
7
7
  attr_reader :g_instances, :tries
8
8
 
9
9
  def grabbers
10
- # %w[TorrentAPI ThePirateBay Eztv KAT]
11
- %w[TorrentAPI ThePirateBay Eztv]
10
+ %w[TorrentAPI Torrentz Eztv]
12
11
  end
13
12
 
14
13
  def initialize(default_grabber = nil)
@@ -39,31 +38,23 @@ module DownloadTV
39
38
  end
40
39
 
41
40
  def change_grabbers
42
- # Rotates the instantiated grabbers
41
+ @tries -= 1
43
42
  @g_instances.rotate!
44
43
  check_grabber_online
45
44
  end
46
45
 
47
46
  def get_links(show)
48
- links = @g_instances.first.get_links(show)
49
-
50
- reset_grabbers_order
51
- reset_tries
52
-
53
- links
47
+ @g_instances.first.get_links(show)
54
48
  rescue NoTorrentsError
55
- # Use next grabber
56
49
  if @tries.positive?
57
- @tries -= 1
58
50
  change_grabbers
59
51
  retry
60
-
61
- else
62
- reset_grabbers_order
63
- reset_tries
64
- puts "No torrents found for #{show}"
65
- []
66
52
  end
53
+ # We're out of grabbers to try
54
+ puts "No torrents found for #{show}"
55
+ []
56
+ ensure
57
+ reset_grabbers_order
67
58
  end
68
59
 
69
60
  def reset_tries
@@ -72,6 +63,7 @@ module DownloadTV
72
63
 
73
64
  def reset_grabbers_order
74
65
  @g_instances.rotate!(@tries + 1)
66
+ reset_tries
75
67
  end
76
68
  end
77
69
  end