suby 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/bin/suby +5 -99
  2. data/lib/suby.rb +100 -0
  3. metadata +2 -1
data/bin/suby CHANGED
@@ -1,11 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'suby'
3
4
  require 'optparse'
4
5
 
5
- options = {
6
- lang: 'en'
7
- }
8
-
6
+ options = {}
9
7
  option_parser = OptionParser.new do |opts|
10
8
  opts.banner = "#{File.basename $0} [options] video"
11
9
  opts.separator ' Find and download subtitles for the given video file'
@@ -23,100 +21,8 @@ end
23
21
 
24
22
  option_parser.parse!
25
23
 
26
- if ARGV.empty?
27
- puts option_parser
28
- exit
29
- end
30
-
31
- require 'net/http'
32
- require 'nokogiri'
33
-
34
- SUB_EXTENSIONS = %w[srt sub]
35
- archive = '__archive__'
36
- site = 'www.tvsubtitles.net'
37
- search_url = '/search.php'
24
+ puts option_parser if ARGV.empty?
38
25
 
39
- def extract_subs_from_archive(archive)
40
- case `file #{archive}`
41
- when /Zip archive data/
42
- subs = `unzip -qql #{archive}`.scan(/\d{2}:\d{2} (.+?(?:#{SUB_EXTENSIONS.join '|'}))$/).map(&:first)
43
- raise "no subtitles in #{archive}" if subs.empty?
44
- subs_for_unzip = subs.map { |sub| sub.gsub(/(\[|\])/) { "\\#{$1}" } }
45
- system 'unzip', archive, *subs_for_unzip, 1 => :close
46
- puts "found subtitles: #{subs.join(', ')}"
47
- else
48
- raise "unknown archive type (#{archive})"
49
- end
50
-
51
- # Cleaning
52
- File.unlink archive
53
- subs
26
+ ARGV.each do |file|
27
+ Suby.download_subtitles file, options
54
28
  end
55
-
56
- # cache
57
- show_urls = {}
58
- show_pages = {}
59
-
60
- ARGV.each { |file|
61
- next if SUB_EXTENSIONS.include? File.extname(file)
62
- next(puts "Skipping: #{file}") if SUB_EXTENSIONS.any? { |ext|
63
- File.exist? File.basename(file, File.extname(file)) + ".#{ext}" }
64
-
65
- unless /^(?<show>.+) (?<season>\d{1,2})x(?<episode>\d{1,2}) - .+\.[a-z]+?$/ =~ file
66
- next puts "wrong file format (#{file}). Must be:\n<show> <season>x<episode> - <title>.<ext>"
67
- end
68
- season, episode = [season, episode].map(&:to_i)
69
- puts "Searching subtitles for #{file}:"
70
- puts "Show: #{show}, Season: #{season}, Episode: #{episode}"
71
-
72
- Net::HTTP.start(site) { |tvsubtitles|
73
- # search show
74
- show_url = (show_urls[show] ||= begin
75
- post = Net::HTTP::Post.new(search_url)
76
- post.form_data = { 'q' => show }
77
- results = Nokogiri tvsubtitles.request(post).body
78
- url = results.css('ul li div a').first[:href]
79
-
80
- raise 'could not find the show' unless /^\/tvshow-(\d+)\.html$/ =~ url
81
- "/tvshow-#{$1}-#{season}.html"
82
- end)
83
- puts "show url: #{show_url}"
84
-
85
- # search episode
86
- show = (show_pages[show] ||= Nokogiri tvsubtitles.get(show_url).body)
87
- tr = show.css('div.left_articles table tr').find { |tr|
88
- tr.children.find { |td| td.name == 'td' && td.text =~ /\A#{season}x0?#{episode}\z/ }
89
- }
90
- episode_url = nil
91
- tr.children.find { |td|
92
- td.children.find { |a|
93
- a.name == 'a' && a[:href].start_with?('episode') && episode_url = a[:href]
94
- }
95
- }
96
-
97
- raise "invalid episode url: #{episode_url}" unless episode_url =~ /^episode-(\d+)\.html$/
98
- episode_url = "/episode-#{$1}-#{options[:lang]}.html"
99
- puts "episode url: #{episode_url}"
100
-
101
- # subtitles
102
- subtitles = Nokogiri tvsubtitles.get(episode_url).body
103
-
104
- # TODO: choose 720p or most downloaded instead of first found
105
- subtitle_url = subtitles.css('div.left_articles a').find { |a| a.name == 'a' && a[:href].start_with?('/subtitle') }[:href]
106
- raise 'invalid subtitle url' unless subtitle_url =~ /^\/subtitle-(\d+)\.html/
107
- puts "subtitle url: #{subtitle_url}"
108
-
109
- # download
110
- download_url = tvsubtitles.get("/download-#{$1}.html")['Location']
111
- download_url = URI.escape('/'+download_url)
112
- puts "download url: #{download_url}"
113
-
114
- # extract
115
- zip = tvsubtitles.get(download_url).body
116
- open(archive, 'wb') { |f| f.write zip }
117
- subs = extract_subs_from_archive(archive)
118
- new_name = File.basename(file, File.extname(file))+File.extname(subs.first)
119
- File.rename(subs.first, new_name)
120
- puts "Renaming to #{new_name}"
121
- }
122
- }
data/lib/suby.rb ADDED
@@ -0,0 +1,100 @@
1
+ require 'net/http'
2
+ require 'nokogiri'
3
+
4
+ module Suby
5
+ extend self
6
+
7
+ DEFAULT_OPTIONS = {
8
+ lang: 'en'
9
+ }
10
+
11
+ SUB_EXTENSIONS = %w[srt sub]
12
+ TEMP_ARCHIVE_NAME = '__archive__'
13
+ SITE = 'www.tvsubtitles.net'
14
+ SEARCH_URL = '/search.php'
15
+
16
+ # cache
17
+ SHOW_URLS = {}
18
+ SHOW_PAGES = {}
19
+
20
+ def download_subtitles(file, options = {})
21
+ options = DEFAULT_OPTIONS.merge options
22
+ return if SUB_EXTENSIONS.include? File.extname(file)
23
+ return puts "Skipping: #{file}" if SUB_EXTENSIONS.any? { |ext|
24
+ File.exist? File.basename(file, File.extname(file)) + ".#{ext}" }
25
+
26
+ unless /^(?<show>.+) (?<season>\d{1,2})x(?<episode>\d{1,2}) - .+\.[a-z]+?$/ =~ file
27
+ return puts "wrong file format (#{file}). Must be:\n<show> <season>x<episode> - <title>.<ext>"
28
+ end
29
+ season, episode = [season, episode].map(&:to_i)
30
+ puts "Searching subtitles for #{file}:"
31
+ puts "Show: #{show}, Season: #{season}, Episode: #{episode}"
32
+
33
+ Net::HTTP.start(SITE) { |tvsubtitles|
34
+ # search show
35
+ show_url = (SHOW_URLS[show] ||= begin
36
+ post = Net::HTTP::Post.new(SEARCH_URL)
37
+ post.form_data = { 'q' => show }
38
+ results = Nokogiri tvsubtitles.request(post).body
39
+ url = results.css('ul li div a').first[:href]
40
+
41
+ raise 'could not find the show' unless /^\/tvshow-(\d+)\.html$/ =~ url
42
+ "/tvshow-#{$1}-#{season}.html"
43
+ end)
44
+ puts "show url: #{show_url}"
45
+
46
+ # search episode
47
+ show = (SHOW_PAGES[show] ||= Nokogiri tvsubtitles.get(show_url).body)
48
+ episode_url = nil
49
+ show.css('div.left_articles table tr').find { |tr|
50
+ tr.children.find { |td| td.name == 'td' && td.text =~ /\A#{season}x0?#{episode}\z/ }
51
+ }.children.find { |td|
52
+ td.children.find { |a|
53
+ a.name == 'a' && a[:href].start_with?('episode') && episode_url = a[:href]
54
+ }
55
+ }
56
+
57
+ raise "invalid episode url: #{episode_url}" unless episode_url =~ /^episode-(\d+)\.html$/
58
+ episode_url = "/episode-#{$1}-#{options[:lang]}.html"
59
+ puts "episode url: #{episode_url}"
60
+
61
+ # subtitles
62
+ subtitles = Nokogiri tvsubtitles.get(episode_url).body
63
+
64
+ # TODO: choose 720p or most downloaded instead of first found
65
+ subtitle_url = subtitles.css('div.left_articles a').find { |a| a.name == 'a' && a[:href].start_with?('/subtitle') }[:href]
66
+ raise 'invalid subtitle url' unless subtitle_url =~ /^\/subtitle-(\d+)\.html/
67
+ puts "subtitle url: #{subtitle_url}"
68
+
69
+ # download
70
+ download_url = tvsubtitles.get("/download-#{$1}.html")['Location']
71
+ download_url = URI.escape('/'+download_url)
72
+ puts "download url: #{download_url}"
73
+
74
+ # extract
75
+ zip = tvsubtitles.get(download_url).body
76
+ open(TEMP_ARCHIVE_NAME, 'wb') { |f| f.write zip }
77
+ subs = extract_subs_from_archive(TEMP_ARCHIVE_NAME)
78
+ new_name = File.basename(file, File.extname(file))+File.extname(subs.first)
79
+ File.rename(subs.first, new_name)
80
+ puts "Renaming to #{new_name}"
81
+ }
82
+ end
83
+
84
+ def extract_subs_from_archive(archive)
85
+ case `file #{archive}`
86
+ when /Zip archive data/
87
+ subs = `unzip -qql #{archive}`.scan(/\d{2}:\d{2} (.+?(?:#{SUB_EXTENSIONS.join '|'}))$/).map(&:first)
88
+ raise "no subtitles in #{archive}" if subs.empty?
89
+ subs_for_unzip = subs.map { |sub| sub.gsub(/(\[|\])/) { "\\#{$1}" } }
90
+ system 'unzip', archive, *subs_for_unzip, 1 => :close
91
+ puts "found subtitles: #{subs.join(', ')}"
92
+ else
93
+ raise "unknown archive type (#{archive})"
94
+ end
95
+
96
+ # Cleaning
97
+ File.unlink archive
98
+ subs
99
+ end
100
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: suby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -19,6 +19,7 @@ extensions: []
19
19
  extra_rdoc_files: []
20
20
  files:
21
21
  - bin/suby
22
+ - lib/suby.rb
22
23
  homepage:
23
24
  licenses: []
24
25
  post_install_message: