autosub 0.4.0
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.
- data/.gitignore +27 -0
- data/LICENSE +20 -0
- data/README.markdown +38 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/asset/failure.png +0 -0
- data/asset/srt.png +0 -0
- data/autosub.gemspec +75 -0
- data/bin/autosub +26 -0
- data/lib/episode.rb +89 -0
- data/lib/inspector.rb +104 -0
- data/lib/sites/betaseries.rb +140 -0
- data/lib/sites/podnapisi.rb +101 -0
- data/lib/sites/seriessub.rb +122 -0
- data/lib/sites/tvsubtitle.rb +81 -0
- metadata +139 -0
data/.gitignore
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
## MAC OS
|
2
|
+
.DS_Store
|
3
|
+
|
4
|
+
## TEXTMATE
|
5
|
+
*.tmproj
|
6
|
+
tmtags
|
7
|
+
|
8
|
+
## EMACS
|
9
|
+
*~
|
10
|
+
\#*
|
11
|
+
.\#*
|
12
|
+
|
13
|
+
## VIM
|
14
|
+
*.swp
|
15
|
+
|
16
|
+
## PROJECT::GENERAL
|
17
|
+
coverage
|
18
|
+
rdoc
|
19
|
+
pkg
|
20
|
+
|
21
|
+
## PROJECT::SPECIFIC
|
22
|
+
pkg
|
23
|
+
doc
|
24
|
+
tasks
|
25
|
+
test
|
26
|
+
rep
|
27
|
+
fixtures
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Pirate
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# AutoSub
|
2
|
+
|
3
|
+
Ruby tool to automatically download subtitles (srt) inside your TV Shows folder.
|
4
|
+
Currently only english and french subtitles are supported.
|
5
|
+
|
6
|
+
## Install
|
7
|
+
|
8
|
+
sudo gem install pirate-autosub --source http://gems.github.com
|
9
|
+
|
10
|
+
## Usage
|
11
|
+
|
12
|
+
In your terminal:
|
13
|
+
|
14
|
+
autosub -p /path/of/your/TV Shows/folder -lang fr,en
|
15
|
+
|
16
|
+
more details with:
|
17
|
+
|
18
|
+
autosub -h
|
19
|
+
|
20
|
+
## Folder Name Convention
|
21
|
+
|
22
|
+
AutoNZB use (and needs) specific folders/episodes name for your TV Shows:
|
23
|
+
|
24
|
+
+ TV Shows
|
25
|
+
+ Dexter (TV Show's name needs to be 'clean')
|
26
|
+
+ Season 01
|
27
|
+
- Dexter S01E01.mkv (.mkv for 720p HD episode)
|
28
|
+
- Dexter 1x02.avi (.avi for SD episode)
|
29
|
+
- S01E03.mkv (TV Show's name in episode file's name not needed)
|
30
|
+
- S01E03.fr.srt (.fr.srt used to define subtitle's language)
|
31
|
+
+ Fringe
|
32
|
+
- (season folder not needed)
|
33
|
+
- Fringe S01E01.mkv
|
34
|
+
- 1x01.avi
|
35
|
+
|
36
|
+
## Copyright
|
37
|
+
|
38
|
+
Copyright (c) 2009 Pirate
|
data/Rakefile
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "autosub"
|
8
|
+
gem.summary = "Automatically download srt for your TV Shows"
|
9
|
+
gem.description = "Ruby tool to automatically download subtitles (srt) inside your TV Shows folder"
|
10
|
+
gem.email = "pirate.2061@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/pirate/autosub"
|
12
|
+
gem.authors = ["Pirate"]
|
13
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
gem.add_dependency "hpricot", ">= 0.8.1"
|
16
|
+
gem.add_dependency "httparty", ">= 0.4.5"
|
17
|
+
gem.add_dependency "optiflag", ">= 0.7"
|
18
|
+
gem.add_dependency "rubyzip", ">= 0.9.1"
|
19
|
+
gem.add_dependency "mechanize", ">= 0.9.3"
|
20
|
+
gem.add_dependency "simple-rss", ">= 1.2.2"
|
21
|
+
gem.default_executable = "bin/autosub"
|
22
|
+
end
|
23
|
+
Jeweler::GemcutterTasks.new
|
24
|
+
rescue LoadError
|
25
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
26
|
+
end
|
27
|
+
|
28
|
+
require 'spec/rake/spectask'
|
29
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
30
|
+
spec.libs << 'lib' << 'spec'
|
31
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
35
|
+
spec.libs << 'lib' << 'spec'
|
36
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
37
|
+
spec.rcov = true
|
38
|
+
end
|
39
|
+
|
40
|
+
task :spec => :check_dependencies
|
41
|
+
|
42
|
+
task :default => :spec
|
43
|
+
|
44
|
+
require 'rake/rdoctask'
|
45
|
+
Rake::RDocTask.new do |rdoc|
|
46
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
47
|
+
|
48
|
+
rdoc.rdoc_dir = 'rdoc'
|
49
|
+
rdoc.title = "autosub #{version}"
|
50
|
+
rdoc.rdoc_files.include('README*')
|
51
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
52
|
+
end
|
53
|
+
|
54
|
+
Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.4.0
|
data/asset/failure.png
ADDED
Binary file
|
data/asset/srt.png
ADDED
Binary file
|
data/autosub.gemspec
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{autosub}
|
8
|
+
s.version = "0.4.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Pirate"]
|
12
|
+
s.date = %q{2009-11-06}
|
13
|
+
s.default_executable = %q{bin/autosub}
|
14
|
+
s.description = %q{Ruby tool to automatically download subtitles (srt) inside your TV Shows folder}
|
15
|
+
s.email = %q{pirate.2061@gmail.com}
|
16
|
+
s.executables = ["autosub"]
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"LICENSE",
|
19
|
+
"README.markdown"
|
20
|
+
]
|
21
|
+
s.files = [
|
22
|
+
".gitignore",
|
23
|
+
"LICENSE",
|
24
|
+
"README.markdown",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"asset/failure.png",
|
28
|
+
"asset/srt.png",
|
29
|
+
"autosub.gemspec",
|
30
|
+
"bin/autosub",
|
31
|
+
"lib/episode.rb",
|
32
|
+
"lib/inspector.rb",
|
33
|
+
"lib/sites/betaseries.rb",
|
34
|
+
"lib/sites/podnapisi.rb",
|
35
|
+
"lib/sites/seriessub.rb",
|
36
|
+
"lib/sites/tvsubtitle.rb"
|
37
|
+
]
|
38
|
+
s.homepage = %q{http://github.com/pirate/autosub}
|
39
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
40
|
+
s.require_paths = ["lib"]
|
41
|
+
s.rubygems_version = %q{1.3.5}
|
42
|
+
s.summary = %q{Automatically download srt for your TV Shows}
|
43
|
+
|
44
|
+
if s.respond_to? :specification_version then
|
45
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
46
|
+
s.specification_version = 3
|
47
|
+
|
48
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
49
|
+
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
50
|
+
s.add_runtime_dependency(%q<hpricot>, [">= 0.8.1"])
|
51
|
+
s.add_runtime_dependency(%q<httparty>, [">= 0.4.5"])
|
52
|
+
s.add_runtime_dependency(%q<optiflag>, [">= 0.7"])
|
53
|
+
s.add_runtime_dependency(%q<rubyzip>, [">= 0.9.1"])
|
54
|
+
s.add_runtime_dependency(%q<mechanize>, [">= 0.9.3"])
|
55
|
+
s.add_runtime_dependency(%q<simple-rss>, [">= 1.2.2"])
|
56
|
+
else
|
57
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
58
|
+
s.add_dependency(%q<hpricot>, [">= 0.8.1"])
|
59
|
+
s.add_dependency(%q<httparty>, [">= 0.4.5"])
|
60
|
+
s.add_dependency(%q<optiflag>, [">= 0.7"])
|
61
|
+
s.add_dependency(%q<rubyzip>, [">= 0.9.1"])
|
62
|
+
s.add_dependency(%q<mechanize>, [">= 0.9.3"])
|
63
|
+
s.add_dependency(%q<simple-rss>, [">= 1.2.2"])
|
64
|
+
end
|
65
|
+
else
|
66
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
67
|
+
s.add_dependency(%q<hpricot>, [">= 0.8.1"])
|
68
|
+
s.add_dependency(%q<httparty>, [">= 0.4.5"])
|
69
|
+
s.add_dependency(%q<optiflag>, [">= 0.7"])
|
70
|
+
s.add_dependency(%q<rubyzip>, [">= 0.9.1"])
|
71
|
+
s.add_dependency(%q<mechanize>, [">= 0.9.3"])
|
72
|
+
s.add_dependency(%q<simple-rss>, [">= 1.2.2"])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
data/bin/autosub
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optiflag'
|
4
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'inspector')
|
5
|
+
|
6
|
+
module AutoSub extend OptiFlagSet
|
7
|
+
flag "p" do
|
8
|
+
description "Directory path with many TV Shows directories"
|
9
|
+
end
|
10
|
+
optional_flag "lang" do
|
11
|
+
description "Language(s) you want for your subtitles, default: fr,en
|
12
|
+
(Order is important to define if a srt is needed)"
|
13
|
+
end
|
14
|
+
optional_flag "log" do
|
15
|
+
description "path for log file"
|
16
|
+
end
|
17
|
+
|
18
|
+
and_process!
|
19
|
+
end
|
20
|
+
|
21
|
+
begin
|
22
|
+
inspector = Inspector.new(ARGV.flags.p, :lang => ARGV.flags.lang, :log_path => ARGV.flags.log)
|
23
|
+
rescue => e
|
24
|
+
p e.to_s
|
25
|
+
Inspector.growl("AutoSub Error!", 'look into the console log', 'failure.png')
|
26
|
+
end
|
data/lib/episode.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
class Episode
|
2
|
+
|
3
|
+
attr_accessor :path, :name, :ext, :format, :srt, :tv_show, :season, :number
|
4
|
+
|
5
|
+
def initialize(tv_show, path)
|
6
|
+
@path = path
|
7
|
+
@ext = File.extname(@path)
|
8
|
+
@name = File.basename(path, @ext)
|
9
|
+
@tv_show = tv_show.gsub(/\s\([0-9]{4}\)/,'').chomp(' ')
|
10
|
+
@srt = []
|
11
|
+
|
12
|
+
search_existing_srt
|
13
|
+
define_format
|
14
|
+
define_season_and_episode_number
|
15
|
+
end
|
16
|
+
|
17
|
+
def filename
|
18
|
+
@name + @ext
|
19
|
+
end
|
20
|
+
|
21
|
+
def episode_name
|
22
|
+
"#{@tv_show} S#{@season < 10 ? "0#{@season}" : @season}E#{@number < 10 ? "0#{@number}" : @number}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def episode_name_with_format
|
26
|
+
episode_name + "#{format == 'hd' ? ' 720p' : ''}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def need_srt?(langs)
|
30
|
+
need = -1
|
31
|
+
langs = langs.reverse
|
32
|
+
langs.each do |lang|
|
33
|
+
need = langs.index(lang) if @srt.include?(lang) && need < langs.index(lang)
|
34
|
+
end
|
35
|
+
need != langs.size - 1
|
36
|
+
end
|
37
|
+
|
38
|
+
def srt_filename(lang)
|
39
|
+
"#{File.dirname(path)}/#{name}.#{lang}.srt"
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.valid?(filename)
|
43
|
+
filename.match(/.*(([0-9]{1,2}X[0-9]{1,2})|(S[0-9][0-9]E[0-9][0-9])).*((\.avi)|(\.mkv))$/i)
|
44
|
+
end
|
45
|
+
|
46
|
+
def good_format?(filename)
|
47
|
+
case @format
|
48
|
+
when 'hd'
|
49
|
+
filename.include?('720p') || filename.include?('720')
|
50
|
+
when 'sd'
|
51
|
+
!filename.include?('720p')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def search_existing_srt
|
58
|
+
dir = Dir.new(File.dirname(@path))
|
59
|
+
dir.select { |el| File.extname(el) == '.srt' && el.include?(@name) && !el.include?('._') }.each do |srt|
|
60
|
+
case srt
|
61
|
+
when /\.(french|fr|fre|fra)\.srt/i
|
62
|
+
@srt << 'fr'
|
63
|
+
when /\.(english|en|eng)\.srt/i
|
64
|
+
@srt << 'en'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def define_format
|
70
|
+
case @ext
|
71
|
+
when '.mkv'
|
72
|
+
@format = 'hd'
|
73
|
+
when '.avi'
|
74
|
+
@format = 'sd'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def define_season_and_episode_number
|
79
|
+
case @name
|
80
|
+
when /S[0-9][0-9]E[0-9][0-9]/i # S02E03
|
81
|
+
@season = @name.match(/.*S([0-9]{1,2})E.*$/i)[1].to_i
|
82
|
+
@number = @name.match(/.*E([0-9]{1,2}).*$/i)[1].to_i
|
83
|
+
when /[0-9]{1,2}X[0-9]{1,2}/i # 2X03
|
84
|
+
@season = @name.match(/.*([0-9]{1,2})X[0-9]{1,2}.*$/i)[1].to_i
|
85
|
+
@number = @name.match(/.*[0-9]{1,2}X([0-9]{1,2}).*$/i)[1].to_i
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
data/lib/inspector.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'episode')
|
2
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'sites', 'betaseries')
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'sites', 'seriessub')
|
4
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'sites', 'tvsubtitle')
|
5
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'sites', 'podnapisi')
|
6
|
+
require 'logger'
|
7
|
+
require "pathname"
|
8
|
+
|
9
|
+
class Inspector
|
10
|
+
|
11
|
+
attr_accessor :tv_shows, :episodes, :langs, :log
|
12
|
+
|
13
|
+
def initialize(path , options = {})
|
14
|
+
@path = Pathname.new(path).realpath.to_s
|
15
|
+
@langs = options[:lang] ? options[:lang].split(',') : ['fr','en']
|
16
|
+
|
17
|
+
# Initialize Logger
|
18
|
+
@log = Logger.new(options[:log_path] || "#{@path}/_autosub_.log" )
|
19
|
+
@log.datetime_format = "%Y-%m-%d %H:%M:%S "
|
20
|
+
log.info "Begin searching for '#{langs.join(',')}' subtitles..."
|
21
|
+
|
22
|
+
$stdout.print "--- Searching for '#{langs.join(',')}' subtitles ---\n"
|
23
|
+
@tv_shows = [] # {:name => ..., :path => ...}
|
24
|
+
initialize_tv_shows
|
25
|
+
$stdout.print "Found #{@tv_shows.size} TV Show(s) in #{@path}\n"
|
26
|
+
|
27
|
+
@episodes = []
|
28
|
+
initialize_episodes
|
29
|
+
# keep only episodes who needs srt
|
30
|
+
$stdout.print "Found #{@episodes.select { |e| e.need_srt?(@langs) }.size} episode(s) who need(s) srt\n"
|
31
|
+
|
32
|
+
# Find new srt
|
33
|
+
begin
|
34
|
+
BetaSeries.new(self)
|
35
|
+
rescue => e
|
36
|
+
log.fatal "Problem with BetaSeries: #{e}"
|
37
|
+
end
|
38
|
+
# begin
|
39
|
+
# TVSubtitle.new(self)
|
40
|
+
# rescue => e
|
41
|
+
# log.fatal "Problem with TVSubtitle: #{e}"
|
42
|
+
# end
|
43
|
+
# begin
|
44
|
+
# SeriesSub.new(self)
|
45
|
+
# rescue => e
|
46
|
+
# log.fatal "Problem with SeriesSub: #{e}"
|
47
|
+
# end
|
48
|
+
# begin
|
49
|
+
# Podnapisi.new(self)
|
50
|
+
# rescue => e
|
51
|
+
# log.fatal "Problem with Podnapisi: #{e}"
|
52
|
+
# end
|
53
|
+
end
|
54
|
+
|
55
|
+
def growl_episode(episode, lang)
|
56
|
+
Inspector.growl episode.episode_name_with_format, "#{lang_name(lang)} srt added", "srt.png"
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.growl(title, msg, icon, pri = 0)
|
60
|
+
system("/usr/local/bin/growlnotify -w -n autosub --image #{File.dirname(__FILE__) + "/../asset/#{icon}"} -p #{pri} -m #{msg.inspect} #{title} &")
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def initialize_tv_shows
|
66
|
+
# path is a dir with many tv_shows dir
|
67
|
+
base_dir = clean_dir(Dir.new(@path))
|
68
|
+
base_dir.each do |tv_show_name|
|
69
|
+
@tv_shows << { :name => tv_show_name, :path => "#{@path}/#{tv_show_name}" }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def initialize_episodes
|
74
|
+
@tv_shows.each do |tv_show|
|
75
|
+
search_episodes(tv_show[:name], tv_show[:path])
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def search_episodes(tv_show_name, path)
|
80
|
+
elements = clean_dir(Dir.new(path))
|
81
|
+
elements.each do |el|
|
82
|
+
el_path = "#{path}/#{el}"
|
83
|
+
if File.directory?(el_path)
|
84
|
+
search_episodes(tv_show_name, el_path)
|
85
|
+
elsif Episode.valid?(el)
|
86
|
+
episodes << Episode.new(tv_show_name, el_path)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def clean_dir(dir)
|
92
|
+
dir.select { |e| !["..", ".", ".DS_Store", ".com.apple.timemachine.supported", "Icon\r", "autosub.log", "_autosub_.log"].include?(e) }
|
93
|
+
end
|
94
|
+
|
95
|
+
def lang_name(lang)
|
96
|
+
case lang
|
97
|
+
when 'en'
|
98
|
+
'English'
|
99
|
+
when 'fr'
|
100
|
+
'French'
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'hpricot'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'zip/zip'
|
4
|
+
|
5
|
+
# http://www.betaseries.com/
|
6
|
+
class BetaSeries
|
7
|
+
|
8
|
+
def initialize(inspector)
|
9
|
+
@inspector = inspector
|
10
|
+
episodes = @inspector.episodes.select { |e| e.need_srt?(@inspector.langs) }
|
11
|
+
|
12
|
+
$stdout.print "------------------------------------------\n"
|
13
|
+
$stdout.print "Start srt searching from www.betaseries.com\n"
|
14
|
+
$stdout.print "------------------------------------------\n"
|
15
|
+
episodes.each do |e|
|
16
|
+
@inspector.langs.each do |l|
|
17
|
+
unless e.srt.include?(l)
|
18
|
+
$stdout.print "#{e.episode_name_with_format} [#{l}]: "
|
19
|
+
if get_srt(e, l)
|
20
|
+
inspector.log.info "#{e.episode_name_with_format} [#{l}] // BetaSeries // #{@srt_name}"
|
21
|
+
$stdout.print "FOUND\n"
|
22
|
+
e.srt << l
|
23
|
+
@inspector.growl_episode(e, l)
|
24
|
+
break
|
25
|
+
else
|
26
|
+
$stdout.print "NOT FOUND\n"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def get_srt(episode, lang)
|
36
|
+
found = false
|
37
|
+
agent = WWW::Mechanize.new
|
38
|
+
doc = Hpricot(open(url(episode)))
|
39
|
+
doc.search("div.episode").each do |el|
|
40
|
+
title = el.search("div.titreep").inner_text
|
41
|
+
if good_episode?(episode, title)
|
42
|
+
el.search("ul.srt li a") do |srt_link|
|
43
|
+
title = srt_link.inner_text
|
44
|
+
if !found && good_language?(title, lang) && good_format?(episode, title) && no_tag?(title)
|
45
|
+
Tempfile.open("tv.zip") do |tempfile|
|
46
|
+
tempfile.write(agent.get_file(srt_link[:href])) # download the zip
|
47
|
+
tempfile.close # tempfile need to be closed for unzip it
|
48
|
+
Zip::ZipFile.open(tempfile.path) do |zip_file|
|
49
|
+
if zip_file.size == 1
|
50
|
+
file = zip_file.first
|
51
|
+
else
|
52
|
+
zip_file.each do |f|
|
53
|
+
if f.size > 5000 && good_episode?(episode, f.name) && good_language?(f.name, lang) && episode.good_format?(f.name) && no_tag?(f.name)
|
54
|
+
file = f
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
if file
|
59
|
+
@srt_name = file.name
|
60
|
+
zip_file.extract(file, episode.srt_filename(lang))
|
61
|
+
found = true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
rescue => e
|
70
|
+
@inspector.log.fatal "BetaSeries // #{episode.episode_name_with_format} [#{lang}] // #{e}"
|
71
|
+
found = false
|
72
|
+
else
|
73
|
+
found
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
def url(episode)
|
78
|
+
"http://www.betaseries.com/ajax/planning_serie.php?url=#{tv_show(episode)}&saison=#{episode.season}"
|
79
|
+
end
|
80
|
+
|
81
|
+
def tv_show(episode)
|
82
|
+
case episode.tv_show
|
83
|
+
when "Terminator The Sarah Connor Chronicles"
|
84
|
+
"thesarahconnorchronicles"
|
85
|
+
when "CSI New York"
|
86
|
+
"csiny"
|
87
|
+
when "The IT Crowd"
|
88
|
+
"itcrowd"
|
89
|
+
else
|
90
|
+
episode.tv_show
|
91
|
+
end.downcase.gsub(/\s/, '')
|
92
|
+
end
|
93
|
+
|
94
|
+
def lang_version(lang)
|
95
|
+
case lang
|
96
|
+
when 'fr'
|
97
|
+
"VF"
|
98
|
+
when 'en'
|
99
|
+
"VO"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def num(episode)
|
104
|
+
"#{episode.season}#{episode.number < 10 ? "0#{episode.number}" : episode.number}"
|
105
|
+
end
|
106
|
+
|
107
|
+
def good_episode?(episode, name)
|
108
|
+
num2 = "S#{episode.season < 10 ? "0#{episode.season}" : episode.season}E#{episode.number < 10 ? "0#{episode.number}" : episode.number}"
|
109
|
+
name.include?(num(episode)) || name.include?(num2)
|
110
|
+
end
|
111
|
+
|
112
|
+
def good_language?(name, lang)
|
113
|
+
case lang
|
114
|
+
when 'fr'
|
115
|
+
name.include?("VF") || name.include?("fr")
|
116
|
+
when 'en'
|
117
|
+
name.include?("VO") || name.include?("en")
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def good_format?(episode, name)
|
122
|
+
if name.include?("VO") || name.include?("VF")
|
123
|
+
true
|
124
|
+
else
|
125
|
+
episode.good_format?(name)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def no_tag?(filename)
|
130
|
+
case filename
|
131
|
+
when /no.?tag/i
|
132
|
+
true
|
133
|
+
when /tag/i
|
134
|
+
false
|
135
|
+
else
|
136
|
+
true
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'hpricot'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'zip/zip'
|
4
|
+
require 'cgi'
|
5
|
+
|
6
|
+
# http://www.podnapisi.net/ | http://www.sub-titles.net/
|
7
|
+
class Podnapisi
|
8
|
+
|
9
|
+
def initialize(inspector)
|
10
|
+
@inspector = inspector
|
11
|
+
episodes = @inspector.episodes.select { |e| e.need_srt?(@inspector.langs) }
|
12
|
+
|
13
|
+
$stdout.print "------------------------------------------\n"
|
14
|
+
$stdout.print "Start srt searching from www.podnapisi.net\n"
|
15
|
+
$stdout.print "------------------------------------------\n"
|
16
|
+
episodes.each do |e|
|
17
|
+
@inspector.langs.each do |l|
|
18
|
+
unless e.srt.include?(l)
|
19
|
+
$stdout.print "#{e.episode_name_with_format} [#{l}]: "
|
20
|
+
if get_srt(e, l)
|
21
|
+
@inspector.log.info "#{e.episode_name_with_format} [#{l}] // Podnapisi // #{@srt_name}"
|
22
|
+
$stdout.print "FOUND\n"
|
23
|
+
e.srt << l
|
24
|
+
@inspector.growl_episode(e, l)
|
25
|
+
break
|
26
|
+
else
|
27
|
+
$stdout.print "NOT FOUND\n"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def get_srt(episode, lang)
|
37
|
+
found = false
|
38
|
+
doc = Hpricot(open(url(episode, lang)))
|
39
|
+
doc.search("table.list tr").each do |el|
|
40
|
+
if !found && have_srt_format?(el) && !hearing_impaired?(el) && url = open(download_url(el))
|
41
|
+
Tempfile.open("tv.zip") do |tempfile|
|
42
|
+
tempfile.write(open(url).read) # download the zip
|
43
|
+
tempfile.close # tempfile need to be closed for unzip it
|
44
|
+
Zip::ZipFile.open(tempfile.path) do |zip_file|
|
45
|
+
zip_file.each do |f|
|
46
|
+
if f.size > 5000
|
47
|
+
@srt_name = f.name
|
48
|
+
zip_file.extract(f, episode.srt_filename(lang))
|
49
|
+
found = true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
rescue => e
|
57
|
+
@inspector.log.fatal "Podnapisi // #{episode.episode_name_with_format} [#{lang}] // #{e}"
|
58
|
+
found = false
|
59
|
+
else
|
60
|
+
found
|
61
|
+
end
|
62
|
+
|
63
|
+
def url(episode, lang)
|
64
|
+
"http://simple.podnapisi.net/ppodnapisi/search?tbsl=3&asdp=1&sK=#{tv_show(episode)}&sJ=#{lang_num(lang)}&sO=desc&sS=time&submit=Search&sTS=#{episode.season}&sTE=#{episode.number}&sY=&sR=#{format(episode)}&sT=1"
|
65
|
+
end
|
66
|
+
|
67
|
+
def tv_show(episode)
|
68
|
+
CGI.escape(episode.tv_show)
|
69
|
+
end
|
70
|
+
|
71
|
+
def format(episode)
|
72
|
+
case episode.format
|
73
|
+
when 'hd'
|
74
|
+
"720"
|
75
|
+
when 'sd'
|
76
|
+
""
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def lang_num(lang)
|
81
|
+
case lang
|
82
|
+
when 'fr'
|
83
|
+
8
|
84
|
+
when 'en'
|
85
|
+
2
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def have_srt_format?(el)
|
90
|
+
!el.search("td[text()*='SubRip']").empty?
|
91
|
+
end
|
92
|
+
|
93
|
+
def hearing_impaired?(el)
|
94
|
+
!el.search("img[@title='Subtitle is for hearing impaired']").empty?
|
95
|
+
end
|
96
|
+
|
97
|
+
def download_url(el)
|
98
|
+
"http://simple.podnapisi.net#{el.search("a[text()*='download subtitle']").first[:href]}"
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'hpricot'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'zip/zip'
|
4
|
+
|
5
|
+
# http://www.seriessub.com/
|
6
|
+
class SeriesSub
|
7
|
+
|
8
|
+
def initialize(inspector)
|
9
|
+
@inspector = inspector
|
10
|
+
episodes = @inspector.episodes.select { |e| e.need_srt?(@inspector.langs) }
|
11
|
+
|
12
|
+
$stdout.print "------------------------------------------\n"
|
13
|
+
$stdout.print "Start srt searching from www.seriessub.com\n"
|
14
|
+
$stdout.print "------------------------------------------\n"
|
15
|
+
episodes.each do |e|
|
16
|
+
@inspector.langs.each do |l|
|
17
|
+
unless e.srt.include?(l)
|
18
|
+
$stdout.print "#{e.episode_name_with_format} [#{l}]: "
|
19
|
+
if get_srt(e, l)
|
20
|
+
inspector.log.info "#{e.episode_name_with_format} [#{l}] // SeriesSub // #{@srt_name}"
|
21
|
+
$stdout.print "FOUND\n"
|
22
|
+
e.srt << l
|
23
|
+
@inspector.growl_episode(e, l)
|
24
|
+
break
|
25
|
+
else
|
26
|
+
$stdout.print "NOT FOUND\n"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def get_srt(episode, lang)
|
36
|
+
found = false
|
37
|
+
doc = Hpricot(open(url(episode)))
|
38
|
+
doc.search("td.gst_fichier a").each do |el|
|
39
|
+
text = el.inner_text.gsub(/(\_|\.)/, ' ')
|
40
|
+
if good_episode?(episode, text) && text.include?(lang_version(lang))
|
41
|
+
if text.include?('zip')
|
42
|
+
Tempfile.open("tv.zip") do |tempfile|
|
43
|
+
tempfile.write(open(el[:href]).read) # download the zip
|
44
|
+
tempfile.close # tempfile need to be closed for unzip it
|
45
|
+
Zip::ZipFile.open(tempfile.path) do |zip_file|
|
46
|
+
zip_file.each do |f|
|
47
|
+
if f.size > 5000 && good_episode?(episode, f.name) && f.name.include?(lang_version(lang)) && episode.good_format?(f.name) && no_tag?(f.name)
|
48
|
+
@srt_name = f.name
|
49
|
+
zip_file.extract(f, episode.srt_filename(lang))
|
50
|
+
found = true
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
elsif episode.good_format?(text) && no_tag?(text) # just a single srt file
|
56
|
+
@srt_name = text
|
57
|
+
Tempfile.open("tv.srt") do |tempfile|
|
58
|
+
tempfile.write(open(el[:href]).read) # download the zip
|
59
|
+
tempfile.close
|
60
|
+
File.move(tempfile.path, episode.srt_filename(lang))
|
61
|
+
found = true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
rescue => e
|
67
|
+
@inspector.log.fatal "SeriesSub // #{episode.episode_name_with_format} [#{lang}] // #{e}"
|
68
|
+
found = false
|
69
|
+
else
|
70
|
+
found
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
def url(episode)
|
75
|
+
"http://www.seriessub.com/sous-titres/#{tv_show(episode)}/#{season(episode)}"
|
76
|
+
end
|
77
|
+
|
78
|
+
def tv_show(episode)
|
79
|
+
case episode.tv_show
|
80
|
+
when "Terminator The Sarah Connor Chronicles"
|
81
|
+
"The Sarah Connor Chronicles"
|
82
|
+
when "The IT Crowd"
|
83
|
+
"IT Crowd"
|
84
|
+
else
|
85
|
+
episode.tv_show
|
86
|
+
end.downcase.gsub(/\s/, '_')
|
87
|
+
end
|
88
|
+
|
89
|
+
def season(episode)
|
90
|
+
"saison_#{episode.season}"
|
91
|
+
end
|
92
|
+
|
93
|
+
def lang_version(lang)
|
94
|
+
case lang
|
95
|
+
when 'fr'
|
96
|
+
"VF"
|
97
|
+
when 'en'
|
98
|
+
"VO"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def num(episode)
|
103
|
+
"#{episode.season}#{episode.number < 10 ? "0#{episode.number}" : episode.number}"
|
104
|
+
end
|
105
|
+
|
106
|
+
def good_episode?(episode, name)
|
107
|
+
num2 = "S#{episode.season < 10 ? "0#{episode.season}" : episode.season}E#{episode.number < 10 ? "0#{episode.number}" : episode.number}"
|
108
|
+
name.include?(num(episode)) || name.include?(num2)
|
109
|
+
end
|
110
|
+
|
111
|
+
def no_tag?(filename)
|
112
|
+
case filename
|
113
|
+
when /notag/i
|
114
|
+
true
|
115
|
+
when /tag/i
|
116
|
+
false
|
117
|
+
else
|
118
|
+
true
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'simple-rss'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'zip/zip'
|
4
|
+
require 'cgi'
|
5
|
+
require 'mechanize'
|
6
|
+
|
7
|
+
# http://www.tvsubtitles.net/
|
8
|
+
class TVSubtitle
|
9
|
+
|
10
|
+
def initialize(inspector)
|
11
|
+
@inspector = inspector
|
12
|
+
episodes = @inspector.episodes.select { |e| e.need_srt?(@inspector.langs) }
|
13
|
+
|
14
|
+
$stdout.print "--------------------------------------------\n"
|
15
|
+
$stdout.print "Searching for srt in www.tvsubtitles.net RSS\n"
|
16
|
+
$stdout.print "--------------------------------------------\n"
|
17
|
+
@inspector.langs.each do |l|
|
18
|
+
rss(l).items.each do |item|
|
19
|
+
episodes.each do |e|
|
20
|
+
unless e.srt.include?(l)
|
21
|
+
if episode_title(e, l) == item_title(item)
|
22
|
+
download_srt(item, e, l)
|
23
|
+
inspector.log.info "#{e.episode_name_with_format} [#{l}] // TVSubtitle // #{@srt_name}"
|
24
|
+
$stdout.print "FOUND: #{e.episode_name_with_format} [#{l}]\n"
|
25
|
+
e.srt << l
|
26
|
+
@inspector.growl_episode(e, l)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def download_srt(item, episode, lang)
|
37
|
+
found = false
|
38
|
+
agent = WWW::Mechanize.new
|
39
|
+
id = item_id(item)
|
40
|
+
Tempfile.open("srt") do |tempfile|
|
41
|
+
agent.get("http://www.tvsubtitles.net/subtitle-#{id}.html") # set cookie
|
42
|
+
tempfile.write(agent.get_file("http://www.tvsubtitles.net/download-#{id}.html")) # download the srt
|
43
|
+
tempfile.close
|
44
|
+
Zip::ZipFile.open(tempfile.path) do |zip_file|
|
45
|
+
zip_file.each do |f|
|
46
|
+
if f.size > 5000
|
47
|
+
@srt_name = f.name
|
48
|
+
zip_file.extract(f, episode.srt_filename(lang))
|
49
|
+
found = true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
rescue => e
|
55
|
+
@inspector.log.fatal "TVSubtitle // #{episode.episode_name_with_format} [#{lang}] // #{e}"
|
56
|
+
found = false
|
57
|
+
else
|
58
|
+
found
|
59
|
+
end
|
60
|
+
|
61
|
+
def rss(lang)
|
62
|
+
SimpleRSS.parse open("http://fr.tvsubtitles.net/rss#{lang}.xml")
|
63
|
+
end
|
64
|
+
|
65
|
+
def num(episode)
|
66
|
+
"#{episode.season}X#{episode.number < 10 ? "0#{episode.number}" : episode.number}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def episode_title(episode, lang)
|
70
|
+
"#{episode.tv_show} #{num(episode)} #{lang} #{episode.format}".downcase
|
71
|
+
end
|
72
|
+
|
73
|
+
def item_title(item)
|
74
|
+
"#{item.title} #{item.description.include?('720p') ? 'hd' : 'sd'}".downcase
|
75
|
+
end
|
76
|
+
|
77
|
+
def item_id(item)
|
78
|
+
item.link.match(/([0-9]+)/)[1]
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
metadata
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: autosub
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Pirate
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-11-06 00:00:00 +01:00
|
13
|
+
default_executable: bin/autosub
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.2.9
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: hpricot
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.8.1
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: httparty
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.4.5
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: optiflag
|
47
|
+
type: :runtime
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0.7"
|
54
|
+
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubyzip
|
57
|
+
type: :runtime
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 0.9.1
|
64
|
+
version:
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: mechanize
|
67
|
+
type: :runtime
|
68
|
+
version_requirement:
|
69
|
+
version_requirements: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 0.9.3
|
74
|
+
version:
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: simple-rss
|
77
|
+
type: :runtime
|
78
|
+
version_requirement:
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: 1.2.2
|
84
|
+
version:
|
85
|
+
description: Ruby tool to automatically download subtitles (srt) inside your TV Shows folder
|
86
|
+
email: pirate.2061@gmail.com
|
87
|
+
executables:
|
88
|
+
- autosub
|
89
|
+
extensions: []
|
90
|
+
|
91
|
+
extra_rdoc_files:
|
92
|
+
- LICENSE
|
93
|
+
- README.markdown
|
94
|
+
files:
|
95
|
+
- .gitignore
|
96
|
+
- LICENSE
|
97
|
+
- README.markdown
|
98
|
+
- Rakefile
|
99
|
+
- VERSION
|
100
|
+
- asset/failure.png
|
101
|
+
- asset/srt.png
|
102
|
+
- autosub.gemspec
|
103
|
+
- bin/autosub
|
104
|
+
- lib/episode.rb
|
105
|
+
- lib/inspector.rb
|
106
|
+
- lib/sites/betaseries.rb
|
107
|
+
- lib/sites/podnapisi.rb
|
108
|
+
- lib/sites/seriessub.rb
|
109
|
+
- lib/sites/tvsubtitle.rb
|
110
|
+
has_rdoc: true
|
111
|
+
homepage: http://github.com/pirate/autosub
|
112
|
+
licenses: []
|
113
|
+
|
114
|
+
post_install_message:
|
115
|
+
rdoc_options:
|
116
|
+
- --charset=UTF-8
|
117
|
+
require_paths:
|
118
|
+
- lib
|
119
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: "0"
|
124
|
+
version:
|
125
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - ">="
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: "0"
|
130
|
+
version:
|
131
|
+
requirements: []
|
132
|
+
|
133
|
+
rubyforge_project:
|
134
|
+
rubygems_version: 1.3.5
|
135
|
+
signing_key:
|
136
|
+
specification_version: 3
|
137
|
+
summary: Automatically download srt for your TV Shows
|
138
|
+
test_files: []
|
139
|
+
|