download_tv 2.2.1 → 2.2.2
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 +4 -4
- data/Gemfile +3 -2
- data/Rakefile +8 -8
- data/bin/tv +76 -76
- data/download_tv.gemspec +18 -17
- data/lib/download_tv.rb +13 -13
- data/lib/download_tv/configuration.rb +64 -64
- data/lib/download_tv/downloader.rb +184 -191
- data/lib/download_tv/grabbers/addic7ed.rb +48 -53
- data/lib/download_tv/grabbers/eztv.rb +19 -22
- data/lib/download_tv/grabbers/kat.rb +21 -25
- data/lib/download_tv/grabbers/torrentapi.rb +60 -66
- data/lib/download_tv/grabbers/tpb.rb +22 -26
- data/lib/download_tv/linkgrabber.rb +25 -31
- data/lib/download_tv/myepisodes.rb +78 -86
- data/lib/download_tv/subtitles.rb +14 -19
- data/lib/download_tv/torrent.rb +69 -83
- data/lib/download_tv/version.rb +1 -1
- data/test/config_test.rb +168 -170
- data/test/downloader_test.rb +166 -182
- data/test/grabbers_test.rb +38 -44
- data/test/test_helper.rb +15 -15
- data/test/torrent_test.rb +22 -25
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bd060f362bcaa6f8150f6e766ff4f8d882666b8d
|
|
4
|
+
data.tar.gz: ddc3287c2df8cfb98d5bc5b39b8e559099721bee
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 68b70848a669d493ec77c5e12d5d82acb4627161cc5ca975d8c0650d5ea17a82bce1c56657ad278bfff903680e0c0b11f668d7ce3c2031e51abfc1452fc44859
|
|
7
|
+
data.tar.gz: 8cd0a1e1732d280c842c867c0f6ae5227fb8fd7d495481b5e7a147cf3c06956a96100ce31c25be734143cd498c4ebdc89f645d028eedf43095e4375dfcdf950a
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
require
|
|
2
|
-
require
|
|
1
|
+
require 'bundler/gem_tasks'
|
|
2
|
+
require 'rake/testtask'
|
|
3
3
|
|
|
4
|
-
task :
|
|
4
|
+
task default: :test
|
|
5
5
|
|
|
6
6
|
Rake::TestTask.new do |t|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
end
|
|
7
|
+
t.libs << 'lib'
|
|
8
|
+
t.libs << 'test'
|
|
9
|
+
t.test_files = FileList['test/**/*_test.rb']
|
|
10
|
+
t.verbose = false
|
|
11
|
+
end
|
data/bin/tv
CHANGED
|
@@ -6,88 +6,88 @@ require 'download_tv'
|
|
|
6
6
|
options = {}
|
|
7
7
|
options[:offset] = 0
|
|
8
8
|
options[:dry] = false
|
|
9
|
-
options[:cmd] =
|
|
9
|
+
options[:cmd] = 'run'
|
|
10
10
|
config = {}
|
|
11
11
|
|
|
12
12
|
opt_parser = OptionParser.new do |opts|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
13
|
+
opts.banner = 'Usage: tv [options]'
|
|
14
|
+
|
|
15
|
+
opts.separator ''
|
|
16
|
+
opts.separator 'Specific options:'
|
|
17
|
+
|
|
18
|
+
opts.on('-o', '--offset OFFSET', Integer, 'Move back the last run offset') do |o|
|
|
19
|
+
options[:offset] = o
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
opts.on('-f', '--file PATH', 'Download shows from a file') do |f|
|
|
23
|
+
options[:cmd] = 'file'
|
|
24
|
+
options[:arg] = f
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
opts.on('-d', '--download SHOW', 'Downloads given show') do |s|
|
|
28
|
+
options[:cmd] = 'dl'
|
|
29
|
+
options[:arg] = s
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
opts.on('-c', '--configure', 'Configures defaults') do
|
|
33
|
+
options[:cmd] = 'config'
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
opts.on('--show-config', 'Show current configuration values') do
|
|
37
|
+
options[:cmd] = 'showconfig'
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
opts.on('--dry-run', "Don't write to the date file") do |n|
|
|
41
|
+
options[:dry] = n
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
opts.on('-a', '--[no-]auto', 'Automatically find links') do |n|
|
|
45
|
+
config[:auto] = n
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
opts.on('-s', '--[no-]subtitles', 'Download subtitles') do |n|
|
|
49
|
+
config[:subs] = n
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
opts.on('-g', '--grabber GRABBER', 'Use given grabber as first option') do |g|
|
|
53
|
+
config[:grabber] = g
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
opts.on('--show-grabbers', 'List available grabbers') do
|
|
57
|
+
puts DownloadTV::Torrent.new.grabbers
|
|
58
|
+
exit
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
opts.on('-v', '--version', 'Print version') do
|
|
62
|
+
puts DownloadTV::VERSION
|
|
63
|
+
exit
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
|
67
|
+
puts opts
|
|
68
|
+
exit
|
|
69
|
+
end
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
opt_parser.parse!(ARGV)
|
|
73
73
|
|
|
74
74
|
begin
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
75
|
+
case options[:cmd]
|
|
76
|
+
when 'run'
|
|
77
|
+
dl = DownloadTV::Downloader.new(options[:offset], config)
|
|
78
|
+
dl.run(options[:dry])
|
|
79
|
+
when 'dl'
|
|
80
|
+
dl = DownloadTV::Downloader.new(options[:offset], config)
|
|
81
|
+
dl.download_single_show(options[:arg])
|
|
82
|
+
when 'file'
|
|
83
|
+
dl = DownloadTV::Downloader.new(options[:offset], config)
|
|
84
|
+
dl.download_from_file(options[:arg])
|
|
85
|
+
when 'config'
|
|
86
|
+
DownloadTV::Configuration.new(config, true)
|
|
87
|
+
when 'showconfig'
|
|
88
|
+
DownloadTV::Configuration.new(config).print_config
|
|
89
|
+
end
|
|
90
90
|
rescue Interrupt
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
end
|
|
91
|
+
puts 'Interrupt signal detected. Exiting...'
|
|
92
|
+
exit 1
|
|
93
|
+
end
|
data/download_tv.gemspec
CHANGED
|
@@ -1,34 +1,35 @@
|
|
|
1
1
|
# coding: utf-8
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
-
require
|
|
5
|
+
require 'download_tv/version'
|
|
5
6
|
|
|
6
7
|
Gem::Specification.new do |s|
|
|
7
|
-
s.name =
|
|
8
|
+
s.name = 'download_tv'
|
|
8
9
|
s.version = DownloadTV::VERSION
|
|
9
|
-
s.authors = [
|
|
10
|
-
s.email = [
|
|
10
|
+
s.authors = ['guille']
|
|
11
|
+
s.email = ['guillerg96@gmail.com']
|
|
11
12
|
|
|
12
|
-
s.summary =
|
|
13
|
-
s.homepage =
|
|
13
|
+
s.summary = 'DownloadTV 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.'
|
|
14
|
+
s.homepage = 'https://github.com/guille/download_tv'
|
|
14
15
|
|
|
15
16
|
s.files = `git ls-files -z`.split("\x0").reject do |f|
|
|
16
17
|
f.match(%r{^(test)/})
|
|
17
18
|
end
|
|
18
19
|
|
|
19
|
-
s.test_files
|
|
20
|
-
s.require_paths = [
|
|
20
|
+
s.test_files = `git ls-files -- test/*`.split($/)
|
|
21
|
+
s.require_paths = ['lib']
|
|
21
22
|
|
|
22
|
-
s.executables
|
|
23
|
+
s.executables = ['tv']
|
|
23
24
|
s.default_executable = 'tv'
|
|
24
25
|
|
|
25
|
-
s.add_development_dependency
|
|
26
|
-
s.add_development_dependency
|
|
27
|
-
s.add_development_dependency
|
|
26
|
+
s.add_development_dependency 'bundler', '~> 1.15'
|
|
27
|
+
s.add_development_dependency 'rake', '~> 10.0'
|
|
28
|
+
s.add_development_dependency 'minitest', '~> 5.0'
|
|
28
29
|
|
|
29
|
-
s.add_dependency(
|
|
30
|
-
s.add_dependency(
|
|
30
|
+
s.add_dependency('json')
|
|
31
|
+
s.add_dependency('mechanize')
|
|
31
32
|
|
|
32
33
|
s.has_rdoc = false
|
|
33
|
-
s.license =
|
|
34
|
-
end
|
|
34
|
+
s.license = 'MIT'
|
|
35
|
+
end
|
data/lib/download_tv.rb
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
require
|
|
2
|
-
require
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'mechanize'
|
|
3
|
+
require 'date'
|
|
4
|
+
require 'io/console'
|
|
5
|
+
require 'fileutils'
|
|
6
6
|
|
|
7
|
-
require
|
|
8
|
-
require
|
|
9
|
-
require
|
|
10
|
-
require
|
|
11
|
-
require
|
|
12
|
-
require
|
|
13
|
-
require
|
|
14
|
-
Dir[File.join(__dir__, 'download_tv', 'grabbers', '*.rb')].each {|file| require file }
|
|
7
|
+
require 'download_tv/version'
|
|
8
|
+
require 'download_tv/configuration'
|
|
9
|
+
require 'download_tv/downloader'
|
|
10
|
+
require 'download_tv/torrent'
|
|
11
|
+
require 'download_tv/myepisodes'
|
|
12
|
+
require 'download_tv/linkgrabber'
|
|
13
|
+
require 'download_tv/subtitles'
|
|
14
|
+
Dir[File.join(__dir__, 'download_tv', 'grabbers', '*.rb')].each { |file| require file }
|
|
@@ -1,77 +1,77 @@
|
|
|
1
1
|
module DownloadTV
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
2
|
+
class Configuration
|
|
3
|
+
attr_reader :content, :config_path
|
|
4
|
+
|
|
5
|
+
def initialize(content={}, force_change=false)
|
|
6
|
+
FileUtils.mkdir_p(File.join(ENV["HOME"], ".config", "download_tv"))
|
|
7
|
+
@config_path = content[:path] || File.join(ENV["HOME"], ".config", "download_tv", "config")
|
|
8
|
+
|
|
9
|
+
if File.exist? @config_path
|
|
10
|
+
load_config
|
|
11
|
+
@content.merge!(content) unless content.empty?
|
|
12
|
+
@content[:ignored]&.map!(&:downcase)
|
|
13
|
+
change_configuration if force_change
|
|
14
|
+
else
|
|
15
|
+
@content = content
|
|
16
|
+
change_configuration
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
def change_configuration
|
|
22
|
+
if @content[:myepisodes_user]
|
|
23
|
+
print "Enter your MyEpisodes username (#{@content[:myepisodes_user]}) : "
|
|
24
|
+
else
|
|
25
|
+
print "Enter your MyEpisodes username: "
|
|
26
|
+
end
|
|
27
|
+
@content[:myepisodes_user] = STDIN.gets.chomp
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
print "Save cookie? (y)/n: "
|
|
30
|
+
@content[:cookie] = STDIN.gets.chomp.downcase != "n"
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
if @content[:ignored]
|
|
33
|
+
puts "Enter a comma-separated list of shows to ignore: (#{@content[:ignored]})"
|
|
34
|
+
else
|
|
35
|
+
puts "Enter a comma-separated list of shows to ignore: "
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
@content[:ignored] = STDIN.gets.chomp.split(",").map(&:strip).map(&:downcase)
|
|
39
|
+
STDOUT.flush
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
41
|
+
# When modifying existing config, keeps previous values
|
|
42
|
+
# When creating new one, sets defaults
|
|
43
|
+
@content[:auto] ||= true
|
|
44
|
+
@content[:subs] ||= true
|
|
45
|
+
@content[:grabber] ||= "TorrentAPI"
|
|
46
|
+
@content[:date] ||= Date.today-1
|
|
47
|
+
@content[:version] = DownloadTV::VERSION
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
serialize
|
|
50
|
+
end
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
def serialize
|
|
54
|
+
File.open(@config_path, "wb") { |f| Marshal.dump(@content, f) }
|
|
55
|
+
end
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
def load_config
|
|
58
|
+
@content = File.open(@config_path, "rb") { |f| Marshal.load(f) }
|
|
59
|
+
if !@content[:version] || breaking_changes?(@content[:version])
|
|
60
|
+
change_configuration
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
64
|
+
##
|
|
65
|
+
# Returns true if a major or minor update has been detected
|
|
66
|
+
# Returns false if a patch has been detected
|
|
67
|
+
# Returns nil if it's the same version
|
|
68
|
+
def breaking_changes?(version)
|
|
69
|
+
DownloadTV::VERSION.split(".").zip(version.split(".")).find_index { |x, y| y > x }&.< 2
|
|
70
|
+
end
|
|
71
|
+
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
def print_config
|
|
74
|
+
@content.each {|k, v| puts "#{k}: #{v}"}
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
77
|
end
|
|
@@ -1,193 +1,186 @@
|
|
|
1
1
|
module DownloadTV
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
"open"
|
|
187
|
-
else
|
|
188
|
-
warn "You're using an unsupported platform."
|
|
189
|
-
exit 1
|
|
190
|
-
end
|
|
191
|
-
end
|
|
192
|
-
end
|
|
2
|
+
##
|
|
3
|
+
# Entry point of the application
|
|
4
|
+
class Downloader
|
|
5
|
+
attr_reader :offset, :config
|
|
6
|
+
|
|
7
|
+
def initialize(offset = 0, config = {})
|
|
8
|
+
@offset = offset.abs
|
|
9
|
+
@config = Configuration.new(config) # Load configuration
|
|
10
|
+
|
|
11
|
+
@filters = [
|
|
12
|
+
->(n) { n.include?('2160p') },
|
|
13
|
+
->(n) { n.include?('1080p') },
|
|
14
|
+
->(n) { n.include?('720p') },
|
|
15
|
+
->(n) { n.include?('WEB') },
|
|
16
|
+
->(n) { !n.include?('PROPER') && !n.include?('REPACK') }
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
Thread.abort_on_exception = true
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def download_single_show(show)
|
|
23
|
+
t = Torrent.new(@config.content[:grabber])
|
|
24
|
+
download(get_link(t, show))
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
##
|
|
28
|
+
# Given a file containing a list of episodes (one per line), it tries to find download links for each
|
|
29
|
+
def download_from_file(filename)
|
|
30
|
+
if !File.exist? filename
|
|
31
|
+
puts "Error: #{filename} not found"
|
|
32
|
+
exit 1
|
|
33
|
+
end
|
|
34
|
+
filename = File.realpath(filename)
|
|
35
|
+
t = Torrent.new(@config.content[:grabber])
|
|
36
|
+
File.readlines(filename).each { |show| download(get_link(t, show)) }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
##
|
|
40
|
+
# Finds download links for all new episodes aired since the last run of the program
|
|
41
|
+
# It connects to MyEpisodes in order to find which shows to track and which new episodes aired.
|
|
42
|
+
def run(dont_update_last_run)
|
|
43
|
+
date = check_date
|
|
44
|
+
|
|
45
|
+
myepisodes = MyEpisodes.new(@config.content[:myepisodes_user], @config.content[:cookie])
|
|
46
|
+
# Log in using cookie by default
|
|
47
|
+
myepisodes.load_cookie
|
|
48
|
+
shows = myepisodes.get_shows(date)
|
|
49
|
+
|
|
50
|
+
if shows.empty?
|
|
51
|
+
puts 'Nothing to download'
|
|
52
|
+
|
|
53
|
+
else
|
|
54
|
+
t = Torrent.new(@config.content[:grabber])
|
|
55
|
+
to_download = fix_names(shows)
|
|
56
|
+
|
|
57
|
+
queue = Queue.new
|
|
58
|
+
|
|
59
|
+
# Adds a link (or empty string to the queue)
|
|
60
|
+
link_t = Thread.new do
|
|
61
|
+
to_download.each { |show| queue << get_link(t, show) }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Downloads the links as they are added
|
|
65
|
+
download_t = Thread.new do
|
|
66
|
+
to_download.size.times do
|
|
67
|
+
magnet = queue.pop
|
|
68
|
+
next if magnet == '' # Doesn't download if no torrents are found
|
|
69
|
+
download(magnet)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Downloading the subtitles
|
|
74
|
+
# subs_t = @config.content[:subs] and Thread.new do
|
|
75
|
+
# to_download.each { |show| @s.get_subs(show) }
|
|
76
|
+
# end
|
|
77
|
+
|
|
78
|
+
link_t.join
|
|
79
|
+
download_t.join
|
|
80
|
+
# subs_t.join
|
|
81
|
+
|
|
82
|
+
puts 'Completed. Exiting...'
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
@config.content[:date] = Date.today unless dont_update_last_run
|
|
86
|
+
@config.serialize
|
|
87
|
+
rescue InvalidLoginError
|
|
88
|
+
warn 'Wrong username/password combination'
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
##
|
|
92
|
+
# Uses a Torrent object to obtain links to the given tv show
|
|
93
|
+
# When :auto is true it will try to find the best match based on a set of filters
|
|
94
|
+
# When it's false it will prompt the user to select the preferred result
|
|
95
|
+
# Returns either a magnet link or an emptry string
|
|
96
|
+
def get_link(t, show)
|
|
97
|
+
links = t.get_links(show)
|
|
98
|
+
|
|
99
|
+
return '' if links.empty?
|
|
100
|
+
|
|
101
|
+
if @config.content[:auto]
|
|
102
|
+
links = filter_shows(links)
|
|
103
|
+
links.first[1]
|
|
104
|
+
else
|
|
105
|
+
puts "Collecting links for #{show}"
|
|
106
|
+
links.each_with_index { |data, i| puts "#{i}\t\t#{data[0]}" }
|
|
107
|
+
|
|
108
|
+
puts
|
|
109
|
+
print 'Select the torrent you want to download [-1 to skip]: '
|
|
110
|
+
|
|
111
|
+
i = $stdin.gets.chomp.to_i
|
|
112
|
+
|
|
113
|
+
while i >= links.size || i < -1
|
|
114
|
+
puts 'Index out of bounds. Try again [-1 to skip]: '
|
|
115
|
+
i = $stdin.gets.chomp.to_i
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Use -1 to skip the download
|
|
119
|
+
i == -1 ? '' : links[i][1]
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def check_date
|
|
124
|
+
last = @config.content[:date]
|
|
125
|
+
if last - @offset != Date.today
|
|
126
|
+
last - @offset
|
|
127
|
+
else
|
|
128
|
+
puts 'Everything up to date'
|
|
129
|
+
exit
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
##
|
|
134
|
+
# Given a list of shows and episodes:
|
|
135
|
+
#
|
|
136
|
+
# * Removes ignored shows
|
|
137
|
+
# * Removes apostrophes, colons and parens
|
|
138
|
+
def fix_names(shows)
|
|
139
|
+
# Ignored shows
|
|
140
|
+
s = shows.reject do |i|
|
|
141
|
+
# Remove season+episode
|
|
142
|
+
@config.content[:ignored].include?(i.split(' ')[0..-2].join(' ').downcase)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
s.map { |i| i.gsub(/ \(.+\)|[':]/, '') }
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
##
|
|
149
|
+
# Iteratively applies filters until they've all been applied or applying the next filter would result in no results
|
|
150
|
+
# These filters are defined at @filters
|
|
151
|
+
def filter_shows(links)
|
|
152
|
+
@filters.each do |f| # Apply each filter
|
|
153
|
+
new_links = links.reject { |name, _link| f.call(name) }
|
|
154
|
+
# Stop if the filter removes every release
|
|
155
|
+
break if new_links.empty?
|
|
156
|
+
|
|
157
|
+
links = new_links
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
links
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
##
|
|
164
|
+
# Spawns a silent process to download a given magnet link
|
|
165
|
+
# Uses xdg-open (not portable)
|
|
166
|
+
def download(link)
|
|
167
|
+
@cmd ||= detect_os
|
|
168
|
+
|
|
169
|
+
exec = "#{@cmd} \"#{link}\""
|
|
170
|
+
|
|
171
|
+
Process.detach(Process.spawn(exec, %i[out err] => '/dev/null'))
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def detect_os
|
|
175
|
+
case RbConfig::CONFIG['host_os']
|
|
176
|
+
when /linux/
|
|
177
|
+
'xdg-open'
|
|
178
|
+
when /darwin/
|
|
179
|
+
'open'
|
|
180
|
+
else
|
|
181
|
+
warn "You're using an unsupported platform."
|
|
182
|
+
exit 1
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
193
186
|
end
|