suby 0.0.4 → 0.0.5

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.
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: