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