download_tv 2.2.1 → 2.2.2

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: b52ab943213458fa9781f6aa6fc332f80eb42f11
4
- data.tar.gz: 12187f1e431cbb5be09725f6439bb2a27681972d
3
+ metadata.gz: bd060f362bcaa6f8150f6e766ff4f8d882666b8d
4
+ data.tar.gz: ddc3287c2df8cfb98d5bc5b39b8e559099721bee
5
5
  SHA512:
6
- metadata.gz: de173925b0f49d9bc22d76de843c2c86a3d12bb65cffe0613a91ea637f4caac154bae4db652a5a787e449b24b47a626880937d0d1aa980be95fa4c8070d33386
7
- data.tar.gz: 95b903ada7b90ff403347e0a51a4686f332137e4e684ce0a595519e110bf61e56b5d71980bbda1f0794313c6649a92425e84debbdae9fb57e1d2d191b8edbba7
6
+ metadata.gz: 68b70848a669d493ec77c5e12d5d82acb4627161cc5ca975d8c0650d5ea17a82bce1c56657ad278bfff903680e0c0b11f668d7ce3c2031e51abfc1452fc44859
7
+ data.tar.gz: 8cd0a1e1732d280c842c867c0f6ae5227fb8fd7d495481b5e7a147cf3c06956a96100ce31c25be734143cd498c4ebdc89f645d028eedf43095e4375dfcdf950a
data/Gemfile CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
- source "https://rubygems.org"
3
2
 
4
- gemspec
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
data/Rakefile CHANGED
@@ -1,11 +1,11 @@
1
- require "bundler/gem_tasks"
2
- require "rake/testtask"
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
3
 
4
- task :default => :test
4
+ task default: :test
5
5
 
6
6
  Rake::TestTask.new do |t|
7
- t.libs << "lib"
8
- t.libs << "test"
9
- t.test_files = FileList["test/**/*_test.rb"]
10
- t.verbose = false
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] = "run"
9
+ options[:cmd] = 'run'
10
10
  config = {}
11
11
 
12
12
  opt_parser = OptionParser.new do |opts|
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", "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
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
- 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
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
- puts "Interrupt signal detected. Exiting..."
92
- exit 1
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
- lib = File.expand_path("../lib", __FILE__)
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "download_tv/version"
5
+ require 'download_tv/version'
5
6
 
6
7
  Gem::Specification.new do |s|
7
- s.name = "download_tv"
8
+ s.name = 'download_tv'
8
9
  s.version = DownloadTV::VERSION
9
- s.authors = ["guille"]
10
- s.email = ["guillerg96@gmail.com"]
10
+ s.authors = ['guille']
11
+ s.email = ['guillerg96@gmail.com']
11
12
 
12
- s.summary = %q{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.}
13
- s.homepage = "https://github.com/guille/download_tv"
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 = `git ls-files -- test/*`.split($/)
20
- s.require_paths = ["lib"]
20
+ s.test_files = `git ls-files -- test/*`.split($/)
21
+ s.require_paths = ['lib']
21
22
 
22
- s.executables = ["tv"]
23
+ s.executables = ['tv']
23
24
  s.default_executable = 'tv'
24
25
 
25
- s.add_development_dependency "bundler", "~> 1.15"
26
- s.add_development_dependency "rake", "~> 10.0"
27
- s.add_development_dependency "minitest", "~> 5.0"
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("json")
30
- s.add_dependency("mechanize")
30
+ s.add_dependency('json')
31
+ s.add_dependency('mechanize')
31
32
 
32
33
  s.has_rdoc = false
33
- s.license = "MIT"
34
- end
34
+ s.license = 'MIT'
35
+ end
data/lib/download_tv.rb CHANGED
@@ -1,14 +1,14 @@
1
- require "json"
2
- require "mechanize"
3
- require "date"
4
- require "io/console"
5
- require "fileutils"
1
+ require 'json'
2
+ require 'mechanize'
3
+ require 'date'
4
+ require 'io/console'
5
+ require 'fileutils'
6
6
 
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 }
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
- 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
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
- 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
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
- print "Save cookie? (y)/n: "
30
- @content[:cookie] = STDIN.gets.chomp.downcase != "n"
29
+ print "Save cookie? (y)/n: "
30
+ @content[:cookie] = STDIN.gets.chomp.downcase != "n"
31
31
 
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
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
- # 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
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
- serialize
50
- end
49
+ serialize
50
+ end
51
51
 
52
52
 
53
- def serialize
54
- File.open(@config_path, "wb") { |f| Marshal.dump(@content, f) }
55
- end
53
+ def serialize
54
+ File.open(@config_path, "wb") { |f| Marshal.dump(@content, f) }
55
+ end
56
56
 
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
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
- # 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
-
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
- def print_config
74
- @content.each {|k, v| puts "#{k}: #{v}"}
75
- end
76
- end
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
- class Downloader
4
-
5
- attr_reader :offset, :config
6
-
7
- def initialize(offset=0, config={})
8
- @offset = offset.abs
9
- @config = Configuration.new(config).content # 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[:grabber])
24
- download(get_link(t, show))
25
- end
26
-
27
-
28
- ##
29
- # Given a file containing a list of episodes (one per line), it tries to find download links for each
30
- def download_from_file(filename)
31
- if !File.exist? filename
32
- puts "Error: #{filename} not found"
33
- exit 1
34
- end
35
- filename = File.realpath(filename)
36
- t = Torrent.new(@config[:grabber])
37
- File.readlines(filename).each { |show| download(get_link(t, show)) }
38
- end
39
-
40
- ##
41
- # Finds download links for all new episodes aired since the last run of the program
42
- # It connects to MyEpisodes in order to find which shows to track and which new episodes aired.
43
- def run(dont_update_last_run)
44
- date = check_date
45
-
46
- myepisodes = MyEpisodes.new(@config[:myepisodes_user], @config[:cookie])
47
- # Log in using cookie by default
48
- myepisodes.load_cookie
49
- shows = myepisodes.get_shows(date)
50
-
51
- if shows.empty?
52
- puts "Nothing to download"
53
-
54
- else
55
- t = Torrent.new(@config[:grabber])
56
- to_download = fix_names(shows)
57
-
58
- queue = Queue.new
59
-
60
- # Adds a link (or empty string to the queue)
61
- link_t = Thread.new do
62
- to_download.each { |show| queue << get_link(t, show) }
63
- end
64
-
65
- # Downloads the links as they are added
66
- download_t = Thread.new do
67
- to_download.size.times do
68
- magnet = queue.pop
69
- next if magnet == "" # Doesn't download if no torrents are found
70
- download(magnet)
71
- end
72
- end
73
-
74
- # Downloading the subtitles
75
- # subs_t = @config[:subs] and Thread.new do
76
- # to_download.each { |show| @s.get_subs(show) }
77
- # end
78
-
79
- link_t.join
80
- download_t.join
81
- # subs_t.join
82
-
83
- puts "Completed. Exiting..."
84
- end
85
-
86
- @config[:date] = Date.today unless dont_update_last_run
87
-
88
- rescue InvalidLoginError
89
- warn "Wrong username/password combination"
90
- end
91
-
92
- ##
93
- # Uses a Torrent object to obtain links to the given tv show
94
- # When :auto is true it will try to find the best match based on a set of filters
95
- # When it's false it will prompt the user to select the preferred result
96
- # Returns either a magnet link or an emptry string
97
- def get_link(t, show)
98
- links = t.get_links(show)
99
-
100
- return "" if links.empty?
101
-
102
- if @config[:auto]
103
- links = filter_shows(links)
104
- links.first[1]
105
-
106
- else
107
- puts "Collecting links for #{show}"
108
- links.each_with_index { |data, i| puts "#{i}\t\t#{data[0]}" }
109
-
110
- puts
111
- print "Select the torrent you want to download [-1 to skip]: "
112
-
113
- i = $stdin.gets.chomp.to_i
114
-
115
- while i >= links.size || i < -1
116
- puts "Index out of bounds. Try again [-1 to skip]: "
117
- i = $stdin.gets.chomp.to_i
118
- end
119
-
120
- # Use -1 to skip the download
121
- i == -1 ? "" : links[i][1]
122
- end
123
-
124
- end
125
-
126
-
127
- def check_date
128
- last = @config[:date]
129
- if last - @offset != Date.today
130
- last - @offset
131
- else
132
- puts "Everything up to date"
133
- exit
134
- end
135
- end
136
-
137
-
138
- ##
139
- # Given a list of shows and episodes:
140
- #
141
- # * Removes ignored shows
142
- # * Removes apostrophes, colons and parens
143
- def fix_names(shows)
144
- # Ignored shows
145
- s = shows.reject do |i|
146
- # Remove season+episode
147
- @config[:ignored].include?(i.split(" ")[0..-2].join(" ").downcase)
148
- end
149
-
150
- s.map { |i| i.gsub(/ \(.+\)|[':]/, "") }
151
- end
152
-
153
- ##
154
- # Iteratively applies filters until they've all been applied or applying the next filter would result in no results
155
- # These filters are defined at @filters
156
- def filter_shows(links)
157
- @filters.each do |f| # Apply each filter
158
- new_links = links.reject { |name, _link| f.(name) }
159
- # Stop if the filter removes every release
160
- break if new_links.size == 0
161
-
162
- links = new_links
163
- end
164
-
165
- links
166
- end
167
-
168
-
169
- ##
170
- # Spawns a silent process to download a given magnet link
171
- # Uses xdg-open (not portable)
172
- def download(link)
173
- @cmd ||= detect_os
174
-
175
- exec = "#{@cmd} \"#{link}\""
176
-
177
- Process.detach(Process.spawn(exec, [:out, :err]=>"/dev/null"))
178
-
179
- end
180
-
181
- def detect_os
182
- case RbConfig::CONFIG['host_os']
183
- when /linux/
184
- "xdg-open"
185
- when /darwin/
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