bathyscaphe 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ .DS_Store
2
+ pkg
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in bathyscaphe.gemspec
4
+ gemspec
@@ -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
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -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
@@ -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")
@@ -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
@@ -0,0 +1,3 @@
1
+ module Bathyscaphe
2
+ VERSION = "0.1.0"
3
+ 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
+