download_tv 2.6.5 → 2.6.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +1 -1
- data/.rspec +1 -0
- data/CHANGELOG.md +17 -0
- data/Gemfile +2 -0
- data/README.md +9 -4
- data/bin/tv +9 -4
- data/lib/download_tv/configuration.rb +107 -81
- data/lib/download_tv/downloader.rb +21 -32
- data/lib/download_tv/filterer.rb +17 -17
- data/lib/download_tv/grabbers/eztv.rb +1 -1
- data/lib/download_tv/grabbers/torrentapi.rb +1 -1
- data/lib/download_tv/grabbers/torrentz.rb +25 -0
- data/lib/download_tv/grabbers/tpb.rb +1 -1
- data/lib/download_tv/linkgrabber.rb +6 -3
- data/lib/download_tv/myepisodes.rb +45 -38
- data/lib/download_tv/torrent.rb +37 -28
- data/lib/download_tv/version.rb +1 -1
- data/lib/download_tv.rb +0 -1
- data/spec/download_tv/configuration_spec.rb +199 -0
- data/spec/download_tv/filterer_spec.rb +107 -0
- data/spec/download_tv/linkgrabber_spec.rb +16 -0
- data/spec/download_tv/myepisodes_spec.rb +38 -0
- data/spec/download_tv/torrent_spec.rb +132 -0
- data/spec/spec_helper.rb +92 -0
- data/test/downloader_test.rb +5 -5
- metadata +11 -11
- data/lib/download_tv/grabbers/addic7ed.rb +0 -65
- data/lib/download_tv/grabbers/kat.rb +0 -49
- data/lib/download_tv/grabbers/torrentz2.rb +0 -27
- data/lib/download_tv/subtitles.rb +0 -17
- data/test/config_test.rb +0 -175
- data/test/torrent_test.rb +0 -41
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2cd494e098abb85a02a4a7182e66aef862aa14a04e73bd0c38f2e3a8991c1954
|
4
|
+
data.tar.gz: 275eccd2336a88bda38cd0711d169b7e95b9fd492164ae033b199b8d08eb4f32
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 884a973095e183b1499839d3b68f01e0ba475ae6ea1220f7a5a98d9f3427892bb78c5404aedc2cbdab6f8f157b9a84729ebd75a1aaef37b5a389670f98e67c40
|
7
|
+
data.tar.gz: 2a1d58fb22524127f7fe42040a652473f0146aaa7ea6a7c45fc6af35800d4c09e45ed821ec6ebd8c343e76952af3ec4a4771dfb5986c9f64bbf764347c0bc267
|
data/.github/workflows/ruby.yml
CHANGED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--require spec_helper
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,22 @@
|
|
1
1
|
# download_tv CHANGELOG
|
2
2
|
|
3
|
+
## 2.6.7 (2022-10-22)
|
4
|
+
|
5
|
+
* Features
|
6
|
+
* Add `--healthcheck` to check the status of all the grabbers (online/offline).
|
7
|
+
|
8
|
+
* Fixes
|
9
|
+
* Better detection for offline grabbers without crashing the app
|
10
|
+
|
11
|
+
* Grabbers
|
12
|
+
* Torrentz: Fix parser
|
13
|
+
|
14
|
+
## 2.6.6 (2022-01-21)
|
15
|
+
|
16
|
+
* Improvements
|
17
|
+
* The `--dry-run` option now prevents from persisting any configuration, including pending shows, not just the last execution date.
|
18
|
+
* Performance improvements when running with the `-t` flag.
|
19
|
+
|
3
20
|
## 2.6.5 (2021-06-10)
|
4
21
|
|
5
22
|
* Fixes
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -6,13 +6,13 @@
|
|
6
6
|
|
7
7
|
**download_tv** is a tool that allows the user to find magnet links for TV show episodes. It accepts shows as arguments, from a file or it can integrate with your MyEpisodes account.
|
8
8
|
|
9
|
-
|
9
|
+
## Installation
|
10
10
|
|
11
11
|
`gem install download_tv`
|
12
12
|
|
13
|
-
|
13
|
+
## Usage
|
14
14
|
|
15
|
-
Once installed, you can launch the binary
|
15
|
+
Once installed, you can launch the binary `tv`
|
16
16
|
|
17
17
|
```
|
18
18
|
Usage: tv [options]
|
@@ -29,6 +29,7 @@ Specific options:
|
|
29
29
|
-a, --[no-]auto Automatically find links
|
30
30
|
-g, --grabber GRABBER Use given grabber as first option
|
31
31
|
--show-grabbers List available grabbers
|
32
|
+
--healthcheck Check status of all the grabbers
|
32
33
|
-p, --pending Show list of pending downloads
|
33
34
|
--clear-pending Clear list of pending downloads
|
34
35
|
-q, --queue SHOW Add show episode to pending downloads list
|
@@ -86,6 +87,10 @@ Upon installation, the default filters exclude 2060p, 1080p or 720p, and include
|
|
86
87
|
|
87
88
|
Keep in mind that this is not a hard filter. The application will sequentially apply as many user-defined filters as possible **while still returning at least one result**.
|
88
89
|
|
89
|
-
|
90
|
+
## Shell completion
|
91
|
+
|
92
|
+
The provided binary will print completion files to STDOUT by passing the options `--*-completion-bash` and `--*-completion-zsh` (you might have to escape the asterisk). Use your shell's manual to find out how to load these files to get completions.
|
93
|
+
|
94
|
+
## License
|
90
95
|
|
91
96
|
This project is released under the terms of the MIT license. See [LICENSE.md](https://github.com/guille/download_tv/blob/master/LICENSE.md) file for details.
|
data/bin/tv
CHANGED
@@ -47,7 +47,7 @@ opt_parser = OptionParser.new do |opts|
|
|
47
47
|
options[:cmd] = 'showconfig'
|
48
48
|
end
|
49
49
|
|
50
|
-
opts.on('--dry-run', "Don't
|
50
|
+
opts.on('--dry-run', "Don't update the persisted configuration") do |n|
|
51
51
|
options[:dry] = n
|
52
52
|
end
|
53
53
|
|
@@ -60,7 +60,12 @@ opt_parser = OptionParser.new do |opts|
|
|
60
60
|
end
|
61
61
|
|
62
62
|
opts.on('--show-grabbers', 'List available grabbers') do
|
63
|
-
puts DownloadTV::Torrent.
|
63
|
+
puts DownloadTV::Torrent.grabbers
|
64
|
+
exit
|
65
|
+
end
|
66
|
+
|
67
|
+
opts.on('--healthcheck', 'Check status of all the grabbers') do
|
68
|
+
DownloadTV::Torrent.healthcheck
|
64
69
|
exit
|
65
70
|
end
|
66
71
|
|
@@ -117,9 +122,9 @@ begin
|
|
117
122
|
when 'config'
|
118
123
|
DownloadTV::Configuration.new(config).change_configuration
|
119
124
|
when 'showconfig'
|
120
|
-
DownloadTV::Configuration.new(config)
|
125
|
+
puts DownloadTV::Configuration.new(config)
|
121
126
|
when 'showpending'
|
122
|
-
DownloadTV::Configuration.new(config)
|
127
|
+
puts DownloadTV::Configuration.new(config)[:pending]
|
123
128
|
when 'clearpending'
|
124
129
|
DownloadTV::Configuration.new(config).clear_pending
|
125
130
|
when 'queue'
|
@@ -4,134 +4,160 @@ module DownloadTV
|
|
4
4
|
##
|
5
5
|
# Class used for managing the configuration of the application
|
6
6
|
class Configuration
|
7
|
-
|
7
|
+
def initialize(user_config = {})
|
8
|
+
load_config(user_config)
|
9
|
+
end
|
10
|
+
|
11
|
+
def [](key)
|
12
|
+
@content[key]
|
13
|
+
end
|
14
|
+
|
15
|
+
def []=(key, value)
|
16
|
+
@content[key] = value
|
17
|
+
end
|
18
|
+
|
19
|
+
def change_configuration
|
20
|
+
prompt_for_new_values
|
21
|
+
set_default_values
|
22
|
+
serialize
|
23
|
+
end
|
24
|
+
|
25
|
+
def serialize
|
26
|
+
self[:pending] = self[:pending].uniq
|
27
|
+
File.write(config_path, JSON.generate(@content))
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
@content.reduce('') do |mem, item|
|
32
|
+
key, val = item
|
33
|
+
"#{mem}#{key}: #{val}\n"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def clear_pending
|
38
|
+
self[:pending].clear
|
39
|
+
serialize
|
40
|
+
end
|
41
|
+
|
42
|
+
def queue_pending(show)
|
43
|
+
self[:pending] << show
|
44
|
+
serialize
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
8
48
|
|
9
|
-
def
|
10
|
-
@
|
11
|
-
|
49
|
+
def content
|
50
|
+
@content ||= {}
|
51
|
+
end
|
12
52
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
@content[:ignored]&.map!(&:downcase)
|
53
|
+
def load_config(user_config)
|
54
|
+
if File.exist? config_path
|
55
|
+
parse_config
|
17
56
|
else
|
18
|
-
|
57
|
+
FileUtils.mkdir_p(File.expand_path('..', config_path))
|
19
58
|
change_configuration
|
20
59
|
end
|
60
|
+
content.merge!(user_config) unless user_config.empty?
|
61
|
+
self[:ignored]&.map!(&:downcase)
|
21
62
|
end
|
22
63
|
|
23
|
-
def
|
64
|
+
def parse_config
|
65
|
+
source = File.read(config_path)
|
66
|
+
@content = JSON.parse(source, symbolize_names: true)
|
67
|
+
|
68
|
+
self[:date] = Date.parse(self[:date]) if self[:date]
|
69
|
+
|
70
|
+
if !self[:version] || breaking_changes?(self[:version])
|
71
|
+
warn 'Change configuration required (version with breaking changes detected)'
|
72
|
+
change_configuration
|
73
|
+
end
|
74
|
+
rescue JSON::ParserError => e
|
75
|
+
warn "Error parsing config file at #{config_path} => #{e.message}"
|
76
|
+
change_configuration
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# Returns true if a major or minor update has been detected, or if the config version is newer
|
81
|
+
# than the installed version. Returns something falsy otherwise
|
82
|
+
def breaking_changes?(version)
|
83
|
+
paired = DownloadTV::VERSION.split('.')
|
84
|
+
.map(&:to_i)
|
85
|
+
.zip(version.split('.').map(&:to_i))
|
86
|
+
# The configuration belongs to a newer version than is installed
|
87
|
+
return true unless paired.find_index { |x, y| x < y }.nil?
|
88
|
+
|
89
|
+
paired.find_index { |x, y| y < x }&.< 2
|
90
|
+
end
|
91
|
+
|
92
|
+
def prompt_for_new_values
|
24
93
|
prompt_for_myep_user
|
25
94
|
prompt_for_cookie
|
26
95
|
prompt_for_ignored
|
27
96
|
prompt_for_filters
|
28
97
|
$stdout.flush
|
29
|
-
|
30
|
-
set_default_values
|
31
|
-
serialize
|
32
98
|
end
|
33
99
|
|
34
100
|
def prompt_for_myep_user
|
35
|
-
existing = "(#{
|
101
|
+
existing = "(#{self[:myepisodes_user]}) " if self[:myepisodes_user]
|
36
102
|
print "Enter your MyEpisodes username #{existing}: "
|
37
103
|
input = $stdin.gets.chomp
|
38
|
-
|
104
|
+
self[:myepisodes_user] = input if input
|
39
105
|
end
|
40
106
|
|
41
107
|
def prompt_for_cookie
|
42
108
|
print 'Save cookie? (y)/n: '
|
43
|
-
|
109
|
+
self[:cookie] = !($stdin.gets.chomp.casecmp? 'n')
|
44
110
|
end
|
45
111
|
|
46
112
|
def prompt_for_ignored
|
47
|
-
existing = "(#{
|
113
|
+
existing = "(#{self[:ignored]})" if self[:ignored]
|
48
114
|
puts "Enter a comma-separated list of shows to ignore: #{existing}"
|
49
115
|
|
50
|
-
|
116
|
+
self[:ignored] = read_and_split_list :downcase
|
51
117
|
end
|
52
118
|
|
53
119
|
def prompt_for_filters
|
54
|
-
puts "Current filters: (#{
|
55
|
-
|
120
|
+
puts "Current filters: (#{self[:filters]})" if self[:filters]
|
121
|
+
self[:filters] = {}
|
56
122
|
|
57
123
|
puts 'Enter a comma-separated list of terms to include: '
|
58
|
-
|
124
|
+
self[:filters][:includes] = read_and_split_list :upcase
|
59
125
|
|
60
126
|
puts 'Enter a comma-separated list of terms to exclude: '
|
61
|
-
|
127
|
+
self[:filters][:excludes] = read_and_split_list :upcase
|
62
128
|
end
|
63
129
|
|
64
|
-
def
|
65
|
-
|
66
|
-
.map(&:strip)
|
67
|
-
.map(&case_method)
|
130
|
+
def config_path
|
131
|
+
(content[:path] || default_config_path)
|
68
132
|
end
|
69
133
|
|
70
|
-
def
|
71
|
-
|
72
|
-
'includes' => %w[PROPER REPACK],
|
73
|
-
'excludes' => %w[2160P 1080P 720P]
|
74
|
-
}
|
134
|
+
def default_config_path
|
135
|
+
File.join(ENV['HOME'], '.config', 'download_tv', 'config')
|
75
136
|
end
|
76
137
|
|
77
138
|
##
|
78
139
|
# Update the +content+ attribute with the defaults, if needed.
|
79
140
|
# Maintains the previous values, in case it's an update from an existing file.
|
80
141
|
def set_default_values
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
end
|
88
|
-
|
89
|
-
def serialize
|
90
|
-
@content[:pending] = @content[:pending].uniq
|
91
|
-
File.write(@config_path, JSON.generate(@content))
|
92
|
-
end
|
93
|
-
|
94
|
-
def load_config
|
95
|
-
source = File.read(@config_path)
|
96
|
-
@content = JSON.parse(source, symbolize_names: true)
|
97
|
-
|
98
|
-
@content[:date] = Date.parse(@content[:date]) if @content[:date]
|
99
|
-
|
100
|
-
change_configuration if !@content[:version] || breaking_changes?(@content[:version])
|
101
|
-
rescue JSON::ParserError
|
102
|
-
@content = {}
|
103
|
-
change_configuration
|
104
|
-
end
|
105
|
-
|
106
|
-
def default_config_path
|
107
|
-
File.join(ENV['HOME'], '.config', 'download_tv', 'config')
|
108
|
-
end
|
109
|
-
|
110
|
-
##
|
111
|
-
# Returns true if a major or minor update has been detected, something falsy otherwise
|
112
|
-
def breaking_changes?(version)
|
113
|
-
DownloadTV::VERSION.split('.')
|
114
|
-
.zip(version.split('.'))
|
115
|
-
.find_index { |x, y| y < x }
|
116
|
-
&.< 2
|
142
|
+
self[:auto] ||= true
|
143
|
+
self[:grabber] ||= 'TorrentAPI'
|
144
|
+
self[:date] ||= Date.today - 1
|
145
|
+
self[:filters] ||= default_filters
|
146
|
+
self[:pending] ||= []
|
147
|
+
self[:version] = DownloadTV::VERSION
|
117
148
|
end
|
118
149
|
|
119
|
-
def
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
puts @content[arg]
|
125
|
-
end
|
126
|
-
|
127
|
-
def clear_pending
|
128
|
-
@content[:pending].clear
|
129
|
-
serialize
|
150
|
+
def default_filters
|
151
|
+
{
|
152
|
+
'includes' => %w[PROPER REPACK],
|
153
|
+
'excludes' => %w[2160P 1080P 720P]
|
154
|
+
}
|
130
155
|
end
|
131
156
|
|
132
|
-
def
|
133
|
-
|
134
|
-
|
157
|
+
def read_and_split_list(case_method)
|
158
|
+
$stdin.gets.chomp.split(',')
|
159
|
+
.map(&:strip)
|
160
|
+
.map(&case_method)
|
135
161
|
end
|
136
162
|
end
|
137
163
|
end
|
@@ -16,7 +16,7 @@ module DownloadTV
|
|
16
16
|
# Tries to download episodes in order for a given season,
|
17
17
|
# until it can't find any
|
18
18
|
def download_entire_season(show, season)
|
19
|
-
t = Torrent.new(@config
|
19
|
+
t = Torrent.new(@config[:grabber])
|
20
20
|
season.insert(0, '0') if season.size == 1
|
21
21
|
episode = "#{show} s#{season}e01"
|
22
22
|
loop do
|
@@ -29,7 +29,7 @@ module DownloadTV
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def download_single_show(show, season = nil)
|
32
|
-
t = Torrent.new(@config
|
32
|
+
t = Torrent.new(@config[:grabber])
|
33
33
|
show = fix_names([show]).first
|
34
34
|
if season
|
35
35
|
download_entire_season(show, season)
|
@@ -44,7 +44,7 @@ module DownloadTV
|
|
44
44
|
def download_from_file(filename)
|
45
45
|
if File.exist? filename
|
46
46
|
filename = File.realpath(filename)
|
47
|
-
t = Torrent.new(@config
|
47
|
+
t = Torrent.new(@config[:grabber])
|
48
48
|
to_download = File.readlines(filename, chomp: true)
|
49
49
|
fix_names(to_download).each { |show| download(get_link(t, show)) }
|
50
50
|
else
|
@@ -56,7 +56,7 @@ module DownloadTV
|
|
56
56
|
##
|
57
57
|
# Returns the date from which to check shows
|
58
58
|
def date_to_check_from(offset)
|
59
|
-
return @config
|
59
|
+
return @config[:date] if offset.zero?
|
60
60
|
|
61
61
|
Date.today - offset
|
62
62
|
end
|
@@ -66,17 +66,16 @@ module DownloadTV
|
|
66
66
|
# the last run of the program
|
67
67
|
# It connects to MyEpisodes in order to find which shows
|
68
68
|
# to track and which new episodes aired.
|
69
|
-
# The param +
|
69
|
+
# The param +dry_run+ prevents changing the persisted configuration
|
70
70
|
# The param +offset+ can be used to move the date back that many days in the check
|
71
71
|
# The param +include_tomorrow+ will add the current day to the list of dates to search
|
72
|
-
def run(
|
73
|
-
pending = @config
|
74
|
-
@config
|
72
|
+
def run(dry_run = false, offset = 0, include_tomorrow: false)
|
73
|
+
pending = @config[:pending].clone
|
74
|
+
@config[:pending].clear
|
75
75
|
pending ||= []
|
76
76
|
date = date_to_check_from(offset)
|
77
77
|
|
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
|
78
|
+
pending.concat shows_to_download(date, include_tomorrow) if date < (include_tomorrow ? Date.today.next : Date.today)
|
80
79
|
|
81
80
|
if pending.empty?
|
82
81
|
puts 'Nothing to download'
|
@@ -85,14 +84,14 @@ module DownloadTV
|
|
85
84
|
puts 'Completed. Exiting...'
|
86
85
|
end
|
87
86
|
|
88
|
-
unless
|
89
|
-
@config
|
87
|
+
unless dry_run
|
88
|
+
@config[:date] = if include_tomorrow
|
90
89
|
Date.today.next
|
91
90
|
else
|
92
|
-
[Date.today, @config
|
91
|
+
[Date.today, @config[:date]].max
|
93
92
|
end
|
93
|
+
@config.serialize
|
94
94
|
end
|
95
|
-
@config.serialize
|
96
95
|
rescue InvalidLoginError
|
97
96
|
warn 'Wrong username/password combination'
|
98
97
|
end
|
@@ -126,20 +125,10 @@ module DownloadTV
|
|
126
125
|
download_t.join
|
127
126
|
end
|
128
127
|
|
129
|
-
def shows_to_download(date)
|
130
|
-
myepisodes = MyEpisodes.new(@config
|
131
|
-
@config
|
132
|
-
myepisodes.
|
133
|
-
shows = myepisodes.get_shows_since(date)
|
134
|
-
shows = reject_ignored(shows)
|
135
|
-
fix_names(shows)
|
136
|
-
end
|
137
|
-
|
138
|
-
def today_shows_to_download
|
139
|
-
myepisodes = MyEpisodes.new(@config.content[:myepisodes_user],
|
140
|
-
@config.content[:cookie])
|
141
|
-
myepisodes.load_cookie
|
142
|
-
shows = myepisodes.today_shows
|
128
|
+
def shows_to_download(date, include_tomorrow)
|
129
|
+
myepisodes = MyEpisodes.new(@config[:myepisodes_user],
|
130
|
+
@config[:cookie])
|
131
|
+
shows = myepisodes.get_shows_since(date, include_tomorrow: include_tomorrow)
|
143
132
|
shows = reject_ignored(shows)
|
144
133
|
fix_names(shows)
|
145
134
|
end
|
@@ -154,11 +143,11 @@ module DownloadTV
|
|
154
143
|
links = torrent.get_links(show)
|
155
144
|
|
156
145
|
if links.empty?
|
157
|
-
@config
|
146
|
+
@config[:pending] << show if save_pending
|
158
147
|
return
|
159
148
|
end
|
160
149
|
|
161
|
-
if @config
|
150
|
+
if @config[:auto]
|
162
151
|
filter_shows(links).first[1]
|
163
152
|
else
|
164
153
|
prompt_links(links)
|
@@ -191,7 +180,7 @@ module DownloadTV
|
|
191
180
|
def reject_ignored(shows)
|
192
181
|
shows.reject do |i|
|
193
182
|
# Remove season+episode
|
194
|
-
@config
|
183
|
+
@config[:ignored]
|
195
184
|
.include?(i.split(' ')[0..-2].join(' ').downcase)
|
196
185
|
end
|
197
186
|
end
|
@@ -209,7 +198,7 @@ module DownloadTV
|
|
209
198
|
# Runs until no filters are left to be applied or applying
|
210
199
|
# a filter would leave no results
|
211
200
|
def filter_shows(links)
|
212
|
-
@filterer ||= Filterer.new(@config
|
201
|
+
@filterer ||= Filterer.new(@config[:filters])
|
213
202
|
@filterer.filter(links)
|
214
203
|
end
|
215
204
|
|
data/lib/download_tv/filterer.rb
CHANGED
@@ -4,28 +4,11 @@ module DownloadTV
|
|
4
4
|
##
|
5
5
|
# Builds and applies filters to the results
|
6
6
|
class Filterer
|
7
|
-
attr_reader :filters
|
8
|
-
|
9
7
|
def initialize(filters_config)
|
10
8
|
@filters = []
|
11
9
|
build_filters(filters_config)
|
12
10
|
end
|
13
11
|
|
14
|
-
def build_include_filter(str)
|
15
|
-
@filters << ->(n) { !n.upcase.include?(str) }
|
16
|
-
end
|
17
|
-
|
18
|
-
def build_exclude_filter(str)
|
19
|
-
@filters << ->(n) { n.upcase.include?(str) }
|
20
|
-
end
|
21
|
-
|
22
|
-
def build_filters(filters_config)
|
23
|
-
return unless filters_config
|
24
|
-
|
25
|
-
filters_config[:includes].map { |i| build_include_filter(i) }
|
26
|
-
filters_config[:excludes].map { |i| build_exclude_filter(i) }
|
27
|
-
end
|
28
|
-
|
29
12
|
##
|
30
13
|
# Iteratively applies filters until they've all been applied
|
31
14
|
# or applying the next filter would result in no results
|
@@ -41,5 +24,22 @@ module DownloadTV
|
|
41
24
|
|
42
25
|
shows
|
43
26
|
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def build_filters(filters_config)
|
31
|
+
return unless filters_config
|
32
|
+
|
33
|
+
filters_config[:includes].map { |i| build_include_filter(i) }
|
34
|
+
filters_config[:excludes].map { |i| build_exclude_filter(i) }
|
35
|
+
end
|
36
|
+
|
37
|
+
def build_include_filter(str)
|
38
|
+
@filters << ->(n) { !n.upcase.include?(str) }
|
39
|
+
end
|
40
|
+
|
41
|
+
def build_exclude_filter(str)
|
42
|
+
@filters << ->(n) { n.upcase.include?(str) }
|
43
|
+
end
|
44
44
|
end
|
45
45
|
end
|
@@ -9,7 +9,7 @@ module DownloadTV
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def get_links(show)
|
12
|
-
raw_data =
|
12
|
+
raw_data = agent.get(format(@url, show))
|
13
13
|
raw_seeders = raw_data.search('td.forum_thread_post_end').map { |e| e.children[0].text.to_i }
|
14
14
|
raw_links = raw_data.search('a.magnet').sort_by.with_index { |_, index| raw_seeders[index] }.reverse
|
15
15
|
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DownloadTV
|
4
|
+
##
|
5
|
+
# Torrentz2 grabber
|
6
|
+
class Torrentz < LinkGrabber
|
7
|
+
def initialize
|
8
|
+
super('https://torrentz2.nz/search?q=%s')
|
9
|
+
end
|
10
|
+
|
11
|
+
def get_links(show)
|
12
|
+
raw_data = agent.get(format(@url, show))
|
13
|
+
results = raw_data.search('dl')
|
14
|
+
|
15
|
+
raise NoTorrentsError if results.empty?
|
16
|
+
|
17
|
+
data = results.sort_by { |e| e.search('dd span')[3].text.to_i }.reverse
|
18
|
+
|
19
|
+
data.collect do |i|
|
20
|
+
[i.children[0].text.strip,
|
21
|
+
i.search('dd span a').first.attribute('href').text]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -8,7 +8,10 @@ module DownloadTV
|
|
8
8
|
|
9
9
|
def initialize(url)
|
10
10
|
@url = url
|
11
|
-
|
11
|
+
end
|
12
|
+
|
13
|
+
def agent
|
14
|
+
@agent ||= Mechanize.new do |a|
|
12
15
|
a.user_agent = DownloadTV::USER_AGENT
|
13
16
|
a.read_timeout = 10
|
14
17
|
end
|
@@ -20,9 +23,9 @@ module DownloadTV
|
|
20
23
|
else
|
21
24
|
@url
|
22
25
|
end
|
23
|
-
|
26
|
+
agent.head(url)
|
24
27
|
true
|
25
|
-
rescue Mechanize::ResponseCodeError, Net::HTTP::Persistent::Error, Errno::ECONNRESET
|
28
|
+
rescue Mechanize::ResponseCodeError, Net::HTTP::Persistent::Error, Errno::ECONNRESET, Net::ReadTimeout, OpenSSL::SSL::SSLError
|
26
29
|
false
|
27
30
|
end
|
28
31
|
|