bathyscaphe 0.1.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 +2 -0
- data/Gemfile +4 -0
- data/README.md +31 -0
- data/Rakefile +1 -0
- data/bathyscaphe.gemspec +24 -0
- data/bin/bathyscaphe +32 -0
- data/lib/bathyscaphe.rb +11 -0
- data/lib/bathyscaphe/addic7ed.rb +83 -0
- data/lib/bathyscaphe/config.rb +102 -0
- data/lib/bathyscaphe/tvdb.rb +19 -0
- data/lib/bathyscaphe/version.rb +3 -0
- metadata +84 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
Bathyscaphe
|
2
|
+
===========
|
3
|
+
|
4
|
+
Bathyscaphe is a command-line tool for downloading subtitles for tv-shows from addic7ed.com. Subtitles are searched based on tv-show file name. Downloaded subtitles are automatically renamed and saved next to corresponding files.
|
5
|
+
|
6
|
+
Existing solutions such as [Periscope](http://code.google.com/p/periscope/) and [Submarine](https://github.com/blazt/submarine) are more powerfull then bathyscaphe, they're using file hashes to search subtitles with API-powered services (Podnapisi, Opensubtitles, etc). And frankly, I use periscope myself most of the time. But they don't work in case of just released episodes of tv-shows. And going to addic7ed.com, every time new episode came out, is pain in the butt. So *bathyscaphe* to the rescue.
|
7
|
+
|
8
|
+
Be aware: there is a limit of 30 subs per day set by addic7ed.com.
|
9
|
+
|
10
|
+
### INSTALL
|
11
|
+
|
12
|
+
$ git clone git://github.com/ilzoff/bathyscaphe.git
|
13
|
+
$ cd bathyscaphe
|
14
|
+
$ gem install bones
|
15
|
+
$ rake gem:install
|
16
|
+
|
17
|
+
### USAGE
|
18
|
+
|
19
|
+
$ bathyscaphe [OPTIONS] TV_SHOW
|
20
|
+
|
21
|
+
#### Options
|
22
|
+
-d, --dry-run Parse filename but do not download anything
|
23
|
+
-h, --help Show usage
|
24
|
+
|
25
|
+
### TODO
|
26
|
+
|
27
|
+
1 Test regexp for matching more tv-show names
|
28
|
+
|
29
|
+
### Authors
|
30
|
+
|
31
|
+
- Ilia Zemskov (nbspace.ru) ilzoff@gmail.com
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bathyscaphe.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "bathyscaphe/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "bathyscaphe"
|
7
|
+
s.version = Bathyscaphe::VERSION
|
8
|
+
s.authors = ["Ilia Zemskov"]
|
9
|
+
s.email = ["il.zoff@gmail.com"]
|
10
|
+
s.homepage = "https://github.com/ilzoff/bathyscaphe"
|
11
|
+
s.summary = %q{Simple gem to download subtitles from addic7ed.com}
|
12
|
+
s.description = %q{Simple gem to download subtitles for tv-show episodes from addic7ed.com. Subtitles are searched based on file name.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "bathyscaphe"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
s.add_runtime_dependency "nokogiri"
|
24
|
+
end
|
data/bin/bathyscaphe
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib bathyscaphe]))
|
4
|
+
|
5
|
+
file_arg = Bathyscaphe::Config.parse_options
|
6
|
+
|
7
|
+
unless File.exist? File.expand_path(file_arg)
|
8
|
+
puts "There's no such file: " + File.expand_path(file_arg)
|
9
|
+
exit 0
|
10
|
+
end
|
11
|
+
|
12
|
+
file_name = File.basename(file_arg)
|
13
|
+
file_dir = File.expand_path(File.dirname(file_arg))
|
14
|
+
|
15
|
+
|
16
|
+
begin
|
17
|
+
tv_show = Bathyscaphe::TVDB.new(file_name)
|
18
|
+
|
19
|
+
puts "TV Show: #{tv_show.name}"
|
20
|
+
puts "Season: #{tv_show.season}"
|
21
|
+
puts "Episode: #{tv_show.episode}"
|
22
|
+
|
23
|
+
rescue Exception => e
|
24
|
+
puts e
|
25
|
+
exit 0
|
26
|
+
end
|
27
|
+
|
28
|
+
exit if Bathyscaphe::Config::OPTIONS[:dry_run]
|
29
|
+
|
30
|
+
sub = Bathyscaphe::Addic7ed.new(tv_show.name, tv_show.season, tv_show.episode)
|
31
|
+
|
32
|
+
sub.save(file_dir + "/" + File.basename(file_name, ".*") + ".srt")
|
data/lib/bathyscaphe.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
module Bathyscaphe
|
2
|
+
def self.require_all_libs_relative_to( fname, dir = nil )
|
3
|
+
dir ||= ::File.basename(fname, '.*')
|
4
|
+
search_me = ::File.expand_path(
|
5
|
+
::File.join(::File.dirname(fname), dir, '**', '*.rb'))
|
6
|
+
|
7
|
+
Dir.glob(search_me).sort.each {|rb| require rb}
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
Bathyscaphe.require_all_libs_relative_to(__FILE__)
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Bathyscaphe
|
2
|
+
require "nokogiri"
|
3
|
+
require "open-uri"
|
4
|
+
require 'net/http'
|
5
|
+
require "uri"
|
6
|
+
require "tempfile"
|
7
|
+
require "fileutils"
|
8
|
+
|
9
|
+
class Addic7ed
|
10
|
+
|
11
|
+
HTTP_HOST = "http://addic7ed.com"
|
12
|
+
HOST = "www.addic7ed.com"
|
13
|
+
|
14
|
+
def initialize(tv_show, season, episode)
|
15
|
+
@tv_show = tv_show
|
16
|
+
@season = season
|
17
|
+
@episode = episode
|
18
|
+
@temp_file = download
|
19
|
+
end
|
20
|
+
|
21
|
+
def download
|
22
|
+
|
23
|
+
uri = URI(HTTP_HOST + sub_link)
|
24
|
+
path = uri.path.empty? ? "/" : uri.path
|
25
|
+
|
26
|
+
headers = { "Host" => HOST,
|
27
|
+
"Referer" => show_page(:referer)
|
28
|
+
}
|
29
|
+
@temp_file = Tempfile.open("bathyscaphe_"+@tv_show+@season+@episode)
|
30
|
+
begin
|
31
|
+
Net::HTTP.start(uri.host, uri.port) { |http|
|
32
|
+
resp = http.get(path, headers)
|
33
|
+
@temp_file.write resp.body
|
34
|
+
raise "Limit exceeded" if resp.code.to_s == "302"
|
35
|
+
}
|
36
|
+
rescue Exception => e
|
37
|
+
puts e
|
38
|
+
ensure
|
39
|
+
@temp_file.close
|
40
|
+
end
|
41
|
+
@temp_file
|
42
|
+
end
|
43
|
+
|
44
|
+
def save local_path
|
45
|
+
@temp_file ||= download
|
46
|
+
FileUtils.mv(@temp_file.path, local_path)
|
47
|
+
end
|
48
|
+
|
49
|
+
def sub_link
|
50
|
+
html = Nokogiri::HTML(open(show_page(:lang)))
|
51
|
+
subtitles = {}
|
52
|
+
html.css(".tabel95 .newsDate").each do |td|
|
53
|
+
if downloads = td.text.match(/\s(\d*)\sDownloads/i)
|
54
|
+
done = false
|
55
|
+
td.parent.parent.xpath("./tr/td/a[@class='buttonDownload']/@href").each do |link|
|
56
|
+
if md = link.value.match(/updated/i)
|
57
|
+
subtitles[downloads[1].to_i] = link.value
|
58
|
+
done = true
|
59
|
+
elsif link.value.match(/original/i) && done == false
|
60
|
+
subtitles[downloads[1].to_i] = link.value
|
61
|
+
done = true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
subtitles = subtitles.sort
|
68
|
+
puts "Found subtitles with #{subtitles.last[0]} downloads: http://www.addic7ed.com#{subtitles.last[1]}"
|
69
|
+
subtitles.last[1]
|
70
|
+
end
|
71
|
+
|
72
|
+
def show_page(type)
|
73
|
+
link = URI::escape("http://www.addic7ed.com/serie/#{@tv_show}/#{@season}/#{@episode}/")
|
74
|
+
link += case type
|
75
|
+
when :referer
|
76
|
+
"addic7ed"
|
77
|
+
when :lang
|
78
|
+
"1"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require "optparse"
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
|
5
|
+
CONFIG_FILENAME = File.expand_path("~/.config/bathyscaphe/bathyscaphe.conf")
|
6
|
+
|
7
|
+
CONFIG_DEFAULTS = {
|
8
|
+
:source => 'http://addic7ed.com'
|
9
|
+
}
|
10
|
+
|
11
|
+
module Bathyscaphe
|
12
|
+
class Config
|
13
|
+
|
14
|
+
OPTIONS = {
|
15
|
+
:dry_run => false
|
16
|
+
}
|
17
|
+
|
18
|
+
def self.parse_options
|
19
|
+
optparser = OptionParser.new do |opts|
|
20
|
+
opts.set_summary_indent(' ')
|
21
|
+
opts.banner = "Usage: #{File.basename($0)} [OPTIONS] TV_SHOW"
|
22
|
+
# opts.on( "-s", "--source SOURCE", String, "Set source to download subtitles from","Current: #{self.source}" ) { |o| self.source = o ; self.save }
|
23
|
+
opts.on( "-d", "--dry-run", "Parse filename but do not download anything") { |o| OPTIONS[:dry_run] = o}
|
24
|
+
|
25
|
+
opts.on_tail( "-h", "--help", "Show usage") do
|
26
|
+
puts opts
|
27
|
+
exit
|
28
|
+
end
|
29
|
+
end
|
30
|
+
# Parse command line
|
31
|
+
begin
|
32
|
+
optparser.parse!
|
33
|
+
if ARGV.empty?
|
34
|
+
puts optparser
|
35
|
+
exit
|
36
|
+
else
|
37
|
+
tv_show = ARGV[0]
|
38
|
+
end
|
39
|
+
rescue OptionParser::ParseError => e
|
40
|
+
puts e
|
41
|
+
puts optparser
|
42
|
+
exit
|
43
|
+
end
|
44
|
+
return tv_show
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
# Loads configuration parameters.
|
49
|
+
#
|
50
|
+
def self.load
|
51
|
+
@params = CONFIG_DEFAULTS
|
52
|
+
if File.exists? config_filename
|
53
|
+
@params.merge! YAML::load_file( config_filename )
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Writes configuration parameters, creating config directory and file
|
59
|
+
# if they do not exist.
|
60
|
+
#
|
61
|
+
def self.save
|
62
|
+
unless File.directory? config_dir
|
63
|
+
system "mkdir -p #{config_dir}"
|
64
|
+
end
|
65
|
+
File.open( config_filename, "w" ) do |f|
|
66
|
+
YAML::dump( @params, f )
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# Returns a property with the given name.
|
72
|
+
#
|
73
|
+
def self.method_missing( name, *args )
|
74
|
+
if m = /^(.+)=$/.match(name.to_s)
|
75
|
+
# set
|
76
|
+
@params[m[1].to_sym] = args[0]
|
77
|
+
else
|
78
|
+
# get
|
79
|
+
@params[name.to_sym]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
#
|
84
|
+
# Returns full path to config file.
|
85
|
+
#
|
86
|
+
def self.config_filename
|
87
|
+
File.expand_path( CONFIG_FILENAME )
|
88
|
+
end
|
89
|
+
|
90
|
+
#
|
91
|
+
# Returns full path to the directory where config file is located.
|
92
|
+
#
|
93
|
+
def self.config_dir
|
94
|
+
File.dirname( config_filename )
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
Config.load
|
100
|
+
Config.save # creates default config on a fresh installation
|
101
|
+
|
102
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Bathyscaphe
|
2
|
+
class TVDB
|
3
|
+
|
4
|
+
TVREGEXP1 = /(.*)S([0-9]{2})E([0-9]{2}).*/i
|
5
|
+
TVREGEXP2 = /(.*).([0-9]{1,2})x([0-9]{1,2}).*/i
|
6
|
+
|
7
|
+
attr_accessor :name, :season, :episode
|
8
|
+
|
9
|
+
def initialize filename
|
10
|
+
if md = filename.match(TVREGEXP1) || md = filename.match(TVREGEXP2)
|
11
|
+
@name = md[1].gsub(".", " ").strip
|
12
|
+
@season = md[2].to_i.to_s
|
13
|
+
@episode = md[3].to_i.to_s
|
14
|
+
else
|
15
|
+
raise("Cant't parse filename")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bathyscaphe
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Ilia Zemskov
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2012-05-08 00:00:00 +04:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: nokogiri
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :runtime
|
31
|
+
version_requirements: *id001
|
32
|
+
description: Simple gem to download subtitles for tv-show episodes from addic7ed.com. Subtitles are searched based on file name.
|
33
|
+
email:
|
34
|
+
- il.zoff@gmail.com
|
35
|
+
executables:
|
36
|
+
- bathyscaphe
|
37
|
+
extensions: []
|
38
|
+
|
39
|
+
extra_rdoc_files: []
|
40
|
+
|
41
|
+
files:
|
42
|
+
- .gitignore
|
43
|
+
- Gemfile
|
44
|
+
- README.md
|
45
|
+
- Rakefile
|
46
|
+
- bathyscaphe.gemspec
|
47
|
+
- bin/bathyscaphe
|
48
|
+
- lib/bathyscaphe.rb
|
49
|
+
- lib/bathyscaphe/addic7ed.rb
|
50
|
+
- lib/bathyscaphe/config.rb
|
51
|
+
- lib/bathyscaphe/tvdb.rb
|
52
|
+
- lib/bathyscaphe/version.rb
|
53
|
+
has_rdoc: true
|
54
|
+
homepage: https://github.com/ilzoff/bathyscaphe
|
55
|
+
licenses: []
|
56
|
+
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options: []
|
59
|
+
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
segments:
|
67
|
+
- 0
|
68
|
+
version: "0"
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
segments:
|
74
|
+
- 0
|
75
|
+
version: "0"
|
76
|
+
requirements: []
|
77
|
+
|
78
|
+
rubyforge_project: bathyscaphe
|
79
|
+
rubygems_version: 1.3.6
|
80
|
+
signing_key:
|
81
|
+
specification_version: 3
|
82
|
+
summary: Simple gem to download subtitles from addic7ed.com
|
83
|
+
test_files: []
|
84
|
+
|