suby 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/suby +101 -0
- metadata +46 -0
data/bin/suby
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
if ARGV.include? '-h'
|
4
|
+
puts "#{File.basename $0} video"
|
5
|
+
puts " Find and download subtitles for the given video file"
|
6
|
+
exit
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'net/http'
|
10
|
+
require 'nokogiri'
|
11
|
+
|
12
|
+
SUB_EXTENSIONS = %w[srt sub]
|
13
|
+
archive = '__archive__'
|
14
|
+
site = 'www.tvsubtitles.net'
|
15
|
+
search_url = '/search.php'
|
16
|
+
lang = 'en'
|
17
|
+
|
18
|
+
def extract_subs_from_archive(archive)
|
19
|
+
case `file #{archive}`
|
20
|
+
when /Zip archive data/
|
21
|
+
subs = `unzip -qql #{archive}`.scan(/\d{2}:\d{2} (.+?(?:#{SUB_EXTENSIONS.join '|'}))$/).map(&:first)
|
22
|
+
raise "no subtitles in #{archive}" if subs.empty?
|
23
|
+
subs_for_unzip = subs.map { |sub| sub.gsub(/(\[|\])/) { "\\#{$1}" } }
|
24
|
+
system 'unzip', archive, *subs_for_unzip, 1 => :close
|
25
|
+
puts "found subtitles: #{subs.join(', ')}"
|
26
|
+
else
|
27
|
+
raise "unknown archive type (#{archive})"
|
28
|
+
end
|
29
|
+
|
30
|
+
# Cleaning
|
31
|
+
File.unlink archive
|
32
|
+
subs
|
33
|
+
end
|
34
|
+
|
35
|
+
# cache
|
36
|
+
show_urls = {}
|
37
|
+
show_pages = {}
|
38
|
+
|
39
|
+
ARGV.each { |file|
|
40
|
+
next if SUB_EXTENSIONS.include? File.extname(file)
|
41
|
+
next(puts "Skipping: #{file}") if SUB_EXTENSIONS.any? { |ext|
|
42
|
+
File.exist? File.basename(file, File.extname(file)) + ".#{ext}" }
|
43
|
+
|
44
|
+
unless /^(?<tvshow>.+) (?<season>\d{1,2})x(?<episode>\d{1,2}) - .+\.[a-z]+?$/ =~ file
|
45
|
+
next puts "wrong file format (#{file}). Must be:\n<tvshow> <season>x<episode> - <title>.<ext>"
|
46
|
+
end
|
47
|
+
season, episode = [season, episode].map(&:to_i)
|
48
|
+
puts "Searching subtitles for #{file}:"
|
49
|
+
puts "Show: #{tvshow}, Season: #{season}, Episode: #{episode}"
|
50
|
+
|
51
|
+
Net::HTTP.start(site) { |tvsubtitles|
|
52
|
+
# search tvshow
|
53
|
+
tvshow_url = (show_urls[tvshow] ||= begin
|
54
|
+
post = Net::HTTP::Post.new(search_url)
|
55
|
+
post.form_data = { 'q' => tvshow }
|
56
|
+
results = Nokogiri tvsubtitles.request(post).body
|
57
|
+
url = results.css('ul li div a').first[:href]
|
58
|
+
|
59
|
+
raise 'could not find the show' unless /^\/tvshow-(\d+)\.html$/ =~ url
|
60
|
+
"/tvshow-#{$1}-#{season}.html"
|
61
|
+
end)
|
62
|
+
puts "tvshow url: #{tvshow_url}"
|
63
|
+
|
64
|
+
# search episode
|
65
|
+
tvshow = (show_pages[tvshow] ||= Nokogiri tvsubtitles.get(tvshow_url).body)
|
66
|
+
tr = tvshow.css('div.left_articles table tr').find { |tr|
|
67
|
+
tr.children.find { |td| td.name == 'td' && td.text =~ /\A#{season}x0?#{episode}\z/ }
|
68
|
+
}
|
69
|
+
episode_url = nil
|
70
|
+
tr.children.find { |td|
|
71
|
+
td.children.find { |a|
|
72
|
+
a.name == 'a' && a[:href].start_with?('episode') && episode_url = a[:href]
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
76
|
+
raise "invalid episode url: #{episode_url}" unless episode_url =~ /^episode-(\d+)\.html$/
|
77
|
+
episode_url = "/episode-#{$1}-#{lang}.html"
|
78
|
+
puts "episode url: #{episode_url}"
|
79
|
+
|
80
|
+
# subtitles
|
81
|
+
subtitles = Nokogiri tvsubtitles.get(episode_url).body
|
82
|
+
|
83
|
+
# TODO: choose 720p or most downloaded instead of first found
|
84
|
+
subtitle_url = subtitles.css('div.left_articles a').find { |a| a.name == 'a' && a[:href].start_with?('/subtitle') }[:href]
|
85
|
+
raise 'invalid subtitle url' unless subtitle_url =~ /^\/subtitle-(\d+)\.html/
|
86
|
+
puts "subtitle url: #{subtitle_url}"
|
87
|
+
|
88
|
+
# download
|
89
|
+
download_url = tvsubtitles.get("/download-#{$1}.html")['Location']
|
90
|
+
download_url = URI.escape('/'+download_url)
|
91
|
+
puts "download url: #{download_url}"
|
92
|
+
|
93
|
+
# extract
|
94
|
+
zip = tvsubtitles.get(download_url).body
|
95
|
+
open(archive, 'wb') { |f| f.write zip }
|
96
|
+
subs = extract_subs_from_archive(archive)
|
97
|
+
new_name = File.basename(file, File.extname(file))+File.extname(subs.first)
|
98
|
+
File.rename(subs.first, new_name)
|
99
|
+
puts "Renaming to #{new_name}"
|
100
|
+
}
|
101
|
+
}
|
metadata
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: suby
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- eregon
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-06-15 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Find and download subtitles
|
15
|
+
email:
|
16
|
+
executables:
|
17
|
+
- suby
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- bin/suby
|
22
|
+
homepage:
|
23
|
+
licenses: []
|
24
|
+
post_install_message:
|
25
|
+
rdoc_options: []
|
26
|
+
require_paths:
|
27
|
+
- lib
|
28
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
35
|
+
none: false
|
36
|
+
requirements:
|
37
|
+
- - ! '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
requirements: []
|
41
|
+
rubyforge_project:
|
42
|
+
rubygems_version: 1.8.5
|
43
|
+
signing_key:
|
44
|
+
specification_version: 3
|
45
|
+
summary: Subtitles' downloader
|
46
|
+
test_files: []
|