warlley-subtitle_it 0.6.5 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +8 -1
- data/Manifest.txt +9 -0
- data/README.markdown +1 -1
- data/README.txt +19 -6
- data/bin/subtitle_it +47 -17
- data/lib/subtitle_it/formats/ass.rb +1 -0
- data/lib/subtitle_it/formats/mpl.rb +28 -0
- data/lib/subtitle_it/formats/rsb.rb +3 -4
- data/lib/subtitle_it/formats/srt.rb +12 -2
- data/lib/subtitle_it/formats/sub.rb +18 -4
- data/lib/subtitle_it/movie.rb +4 -4
- data/lib/subtitle_it/movie_hasher.rb +5 -5
- data/lib/subtitle_it/subdown.rb +99 -0
- data/lib/subtitle_it/substyle.rb +0 -0
- data/lib/subtitle_it/subtime.rb +25 -47
- data/lib/subtitle_it/subtitle.rb +29 -6
- data/lib/subtitle_it/version.rb +2 -2
- data/lib/subtitle_it.rb +4 -0
- data/spec/fixtures/puplfiction.mpl +12 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/subtitle_it/formats/mpl_spec.rb +45 -0
- data/spec/subtitle_it/formats/sub_spec.rb +4 -1
- data/spec/subtitle_it/movie_hasher_spec.rb +1 -0
- data/spec/subtitle_it/movie_spec.rb +17 -0
- data/spec/subtitle_it/subdown_spec.rb +46 -0
- data/spec/subtitle_it/substyle_spec.rb +1 -0
- data/spec/subtitle_it/subtime_spec.rb +15 -4
- data/subtitle_it.gemspec +2 -2
- metadata +10 -1
data/History.txt
CHANGED
@@ -27,4 +27,11 @@
|
|
27
27
|
== 0.6.1 2008-09-09
|
28
28
|
|
29
29
|
* 1 major enhancement:
|
30
|
-
* Adds xml tt support
|
30
|
+
* Adds xml tt support
|
31
|
+
|
32
|
+
== 0.7.0 2008-09-10
|
33
|
+
|
34
|
+
* 4 major enhancements:
|
35
|
+
* Adds download opensubtitles support
|
36
|
+
* Fixes various bugs (and adds another ones)
|
37
|
+
* Adds MPL2 support
|
data/Manifest.txt
CHANGED
@@ -10,6 +10,7 @@ config/hoe.rb
|
|
10
10
|
config/requirements.rb
|
11
11
|
lib/subtitle_it.rb
|
12
12
|
lib/subtitle_it/formats/ass.rb
|
13
|
+
lib/subtitle_it/formats/mpl.rb
|
13
14
|
lib/subtitle_it/formats/rsb.rb
|
14
15
|
lib/subtitle_it/formats/srt.rb
|
15
16
|
lib/subtitle_it/formats/sub.rb
|
@@ -17,7 +18,9 @@ lib/subtitle_it/formats/xml.rb
|
|
17
18
|
lib/subtitle_it/formats/yml.rb
|
18
19
|
lib/subtitle_it/movie.rb
|
19
20
|
lib/subtitle_it/movie_hasher.rb
|
21
|
+
lib/subtitle_it/subdown.rb
|
20
22
|
lib/subtitle_it/subline.rb
|
23
|
+
lib/subtitle_it/substyle.rb
|
21
24
|
lib/subtitle_it/subtime.rb
|
22
25
|
lib/subtitle_it/subtitle.rb
|
23
26
|
lib/subtitle_it/version.rb
|
@@ -32,16 +35,22 @@ spec/fixtures/movie.xml
|
|
32
35
|
spec/fixtures/movie.yml
|
33
36
|
spec/fixtures/pseudo.rsb
|
34
37
|
spec/fixtures/pulpfiction.sub
|
38
|
+
spec/fixtures/puplfiction.mpl
|
35
39
|
spec/fixtures/sincity.yml
|
36
40
|
spec/spec.opts
|
37
41
|
spec/spec_helper.rb
|
38
42
|
spec/subtitle_it/formats/ass_spec.rb
|
43
|
+
spec/subtitle_it/formats/mpl_spec.rb
|
39
44
|
spec/subtitle_it/formats/rsb_spec.rb
|
40
45
|
spec/subtitle_it/formats/srt_spec.rb
|
41
46
|
spec/subtitle_it/formats/sub_spec.rb
|
42
47
|
spec/subtitle_it/formats/xml_spec.rb
|
43
48
|
spec/subtitle_it/formats/yml_spec.rb
|
49
|
+
spec/subtitle_it/movie_hasher_spec.rb
|
50
|
+
spec/subtitle_it/movie_spec.rb
|
51
|
+
spec/subtitle_it/subdown_spec.rb
|
44
52
|
spec/subtitle_it/subline_spec.rb
|
53
|
+
spec/subtitle_it/substyle_spec.rb
|
45
54
|
spec/subtitle_it/subtime_spec.rb
|
46
55
|
spec/subtitle_it/subtitle_spec.rb
|
47
56
|
spec/subtitle_it_spec.rb
|
data/README.markdown
CHANGED
data/README.txt
CHANGED
@@ -5,14 +5,13 @@ Ruby tool to work with subtitle files.
|
|
5
5
|
|
6
6
|
== FEATURES:
|
7
7
|
|
8
|
-
*
|
8
|
+
* To and from: SRT, SUB, XML(TT), YML, MPL2, RSB and ASS.
|
9
|
+
* Download from opensubtitles.org
|
9
10
|
* Fixes delays. (SrtResync)
|
10
11
|
|
11
|
-
TODO:
|
12
|
+
== TODO:
|
12
13
|
|
13
14
|
* Compatibility with "sube" (http://github.com/vic/sube)
|
14
|
-
* Download subtitles. (http://github.com/johanlunds/downsub/tree)
|
15
|
-
* Download from http://trac.opensubtitles.org/projects/opensubtitles/wiki/XMLRPC
|
16
15
|
* Fix delays
|
17
16
|
* Convert 1 to 2 CD`s and versa-vice
|
18
17
|
* ASS Format (Yes, for the funny of it...)
|
@@ -52,17 +51,31 @@ MM:SS => N == TEXT | NEWLINE
|
|
52
51
|
Create a template to check it out.
|
53
52
|
|
54
53
|
|
55
|
-
==
|
54
|
+
== DEV:
|
55
|
+
|
56
|
+
To run tests:
|
57
|
+
|
58
|
+
rake spec or autotest
|
59
|
+
|
60
|
+
Documentation => doc
|
61
|
+
Subtitle examples => spec/fixtures
|
62
|
+
|
63
|
+
|
64
|
+
== SUBTITLE EDITORS:
|
65
|
+
|
66
|
+
Try those nice editors too, if SubtitleIt does not fit your need:
|
67
|
+
|
68
|
+
Jubler: http://www.jubler.org/
|
56
69
|
|
57
70
|
Aegisub: http://www.malakith.net/aegiwiki/Main_Page
|
58
71
|
|
59
72
|
|
73
|
+
|
60
74
|
== LICENSE:
|
61
75
|
|
62
76
|
(The MIT License)
|
63
77
|
|
64
78
|
Copyright (c) 2008 Warlley Rezende, Marcos Piccinini
|
65
|
-
Parts of subrip code by Marcin (tiraeth) Chwedziak
|
66
79
|
|
67
80
|
Permission is hereby granted, free of charge, to any person obtaining
|
68
81
|
a copy of this software and associated documentation files (the
|
data/bin/subtitle_it
CHANGED
@@ -55,7 +55,7 @@ BANNER
|
|
55
55
|
|
56
56
|
#FIXME: I gave up... I cant acess the version var from here... missing something.
|
57
57
|
opts.on("-v", "--version",
|
58
|
-
"Show program version") { puts
|
58
|
+
"Show program version") { puts "SubtitleIt v#{SubtitleIt::VERSION::STRING}"; exit }
|
59
59
|
|
60
60
|
opts.parse!(ARGV)
|
61
61
|
|
@@ -69,25 +69,54 @@ if ARGV.empty?
|
|
69
69
|
exit
|
70
70
|
end
|
71
71
|
|
72
|
-
|
72
|
+
|
73
|
+
filein = ARGV[0].split('.')
|
74
|
+
filein_ext = filein.delete_at(-1)
|
75
|
+
filein = filein.join('')
|
73
76
|
fileout, fileout_ext = ARGV[1] ? ARGV[1].split('.') : [filein, filein_ext]
|
77
|
+
|
78
|
+
#time spent
|
74
79
|
t = Time.now
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
#
|
87
|
-
|
80
|
+
|
81
|
+
#FIXME: ugly
|
82
|
+
if %w(3g2 3gp 3gp2 3gpp 60d ajp asf asx avchd avi bik bix box cam dat divx dmf dv dvr-ms evo flc fli flic flv flx gvi gvp h264 m1v m2p m2ts m2v m4e m4v mjp mjpeg mjpg mkv moov mov movhd movie movx mp4 mpe mpeg mpg mpv mpv2 mxf nsv nut ogg ogm omf ps qt ram rm rmvb swf ts vfw vid video viv vivo vob vro wm wmv wmx wrap wvx wx x264 xvid).include?(filein_ext)
|
83
|
+
#we got a video!
|
84
|
+
include SubtitleIt
|
85
|
+
@down = Subdown.new
|
86
|
+
@down.log_in!
|
87
|
+
@movie = Movie.new(ARGV[0])
|
88
|
+
res = @down.search_subtitles(@movie)#.inspect
|
89
|
+
puts "Found #{res.length} result#{"s" if res.length > 1}. Choose one:\n"
|
90
|
+
res.each_with_index do |r,i|
|
91
|
+
puts "#{i+1}) #{r.info["MovieName"]} / #{r.info["MovieYear"]} - #{r.info["SubFileName"]} Dl count: #{r.info["SubDownloadsCnt"]} Rating: #{r.info["SubRating"]}"
|
92
|
+
puts " Language: #{r.info["SubLanguageID"]} Movie rating: #{r.info["MovieImdbRating"]} CD Count: #{r.info["SubSumCD"]}"
|
93
|
+
puts " Comments: #{r.info["SubAuthorComment"]} \n\n"
|
94
|
+
end
|
95
|
+
printf "Choose one: "
|
96
|
+
choose = STDIN.gets.to_i
|
97
|
+
choose = res[choose + 1]
|
98
|
+
puts "Downloading #{choose.info}"
|
99
|
+
out = @down.download_subtitle(choose)
|
100
|
+
format = choose.format
|
101
|
+
@down.log_out!
|
88
102
|
else
|
89
|
-
|
90
|
-
|
103
|
+
#we got files
|
104
|
+
if File.exists?(ARGV[0]) && ( ARGV[1] || OPTIONS[:format] )
|
105
|
+
content = File.open(ARGV[0], 'r')
|
106
|
+
if OPTIONS[:delay]
|
107
|
+
ARGV[1] ||= ARGV[0] + "_new"
|
108
|
+
SubtitleIt.srt_delay(ARGV[0],ARGV[1])
|
109
|
+
else
|
110
|
+
puts "Working on file #{filein}..."
|
111
|
+
sub = Subtitle.new(content, filein_ext)
|
112
|
+
format = OPTIONS[:format]
|
113
|
+
format ||= fileout_ext unless fileout_ext == filein_ext
|
114
|
+
out = sub.send :"to_#{format}"
|
115
|
+
#TODO: rescue format not found....
|
116
|
+
end
|
117
|
+
else
|
118
|
+
format = 'rsb'
|
119
|
+
out = <<GEN
|
91
120
|
- title: #{ARGV[0]}
|
92
121
|
- authors: FIXME
|
93
122
|
- version: FIXME
|
@@ -95,6 +124,7 @@ else
|
|
95
124
|
00:06:00.400 => 00:06:03.400 == worth dying for...
|
96
125
|
00:07:00.300 => 00:07:03.300 == worth going to the hell for...
|
97
126
|
GEN
|
127
|
+
end
|
98
128
|
end
|
99
129
|
|
100
130
|
fout = "#{fileout}.#{format}"
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# SubtitleIt
|
2
|
+
# MPL2 - extension .txt
|
3
|
+
#
|
4
|
+
# [1025][1115]You always say that.|The same thing every time.
|
5
|
+
#
|
6
|
+
# Where N is sec * 10
|
7
|
+
#
|
8
|
+
module SubtitleIt
|
9
|
+
module Formats
|
10
|
+
def parse_mpl
|
11
|
+
@raw.to_a.inject([]) do |i,l|
|
12
|
+
line_data = l.scan(/^\[([0-9]{1,})\]\[([0-9]{1,})\](.+)$/)
|
13
|
+
line_data = line_data.at 0
|
14
|
+
text_on, text_off, text = line_data
|
15
|
+
text_on, text_off = [text_on.to_i, text_off.to_i].map { |t| t.to_i * 1000 }
|
16
|
+
i << Subline.new(text_on, text_off, text.chomp)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_mpl
|
21
|
+
@lines.inject([]) do |i,l|
|
22
|
+
start = l.text_on.to_i / 100
|
23
|
+
stop = l.text_off.to_i / 100
|
24
|
+
i << "[%d][%d]%s" % [start, stop, l.text]
|
25
|
+
end.join("\n")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
# SubtitleIt
|
2
2
|
# RSB - Ruby Subtitle
|
3
3
|
#
|
4
|
-
# 00:32 => 00:33
|
4
|
+
# 00:32 => 00:33
|
5
|
+
# Nice police work! | Thank you!
|
5
6
|
# 00:53 => N == Howdy ho!
|
6
7
|
# MM:SS => N == TEXT | NEWLINE
|
7
8
|
#
|
@@ -28,6 +29,4 @@ module SubtitleIt
|
|
28
29
|
end.join("\n")
|
29
30
|
end
|
30
31
|
end
|
31
|
-
end
|
32
|
-
|
33
|
-
|
32
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# SubtitleIt
|
2
|
-
# SRT format
|
2
|
+
# SRT - Subrip format
|
3
3
|
#
|
4
4
|
# N
|
5
5
|
# 00:55:21,600 --> 00:55:27,197
|
@@ -31,4 +31,14 @@ module SubtitleIt
|
|
31
31
|
out.join("\n")
|
32
32
|
end
|
33
33
|
end
|
34
|
-
end
|
34
|
+
end
|
35
|
+
|
36
|
+
#looks like subrip accepts some styling:
|
37
|
+
# sdict.add(new StyledFormat(ITALIC, "i", true));
|
38
|
+
# sdict.add(new StyledFormat(ITALIC, "/i", false));
|
39
|
+
# sdict.add(new StyledFormat(BOLD, "b", true));
|
40
|
+
# sdict.add(new StyledFormat(BOLD, "/b", false));
|
41
|
+
# sdict.add(new StyledFormat(UNDERLINE, "u", true));
|
42
|
+
# sdict.add(new StyledFormat(UNDERLINE, "/u", false));
|
43
|
+
# sdict.add(new StyledFormat(STRIKETHROUGH, "s", true));
|
44
|
+
# sdict.add(new StyledFormat(STRIKETHROUGH, "/s", false));
|
@@ -1,15 +1,29 @@
|
|
1
1
|
# SubtitleIt
|
2
|
-
# MicroDVD
|
2
|
+
# MPSub, MicroDVD or VOBSub format
|
3
|
+
#TODO: tricky.. detect which format we got.
|
3
4
|
#
|
4
5
|
# {1025}{1115}You always say that.|The same thing every time.
|
5
6
|
# {1118}{1177}"l'm throug h, never again,|too dangerous."
|
6
7
|
#
|
8
|
+
# MicroDVD:
|
9
|
+
# {1}{1}25.000
|
10
|
+
# {2447}{2513}You should come to the Drama Club, too.
|
11
|
+
# {2513}{2594}Yeah. The Drama Club is worried|that you haven't been coming.
|
12
|
+
# {2603}{2675}I see. Sorry, I'll drop by next time.
|
13
|
+
#
|
7
14
|
# Where N is ms / framerate / 1000 (ms -> s)
|
8
15
|
#
|
9
16
|
# parts of the code from 'simplesubtitler' from Marcin (tiraeth) Chwedziak
|
10
17
|
#
|
11
18
|
module SubtitleIt
|
12
|
-
module Formats
|
19
|
+
module Formats
|
20
|
+
#between our formats, what changes can be reduced to a value
|
21
|
+
def ratio
|
22
|
+
1
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
|
13
27
|
def parse_sub
|
14
28
|
@raw.to_a.inject([]) do |i,l|
|
15
29
|
line_data = l.scan(/^\{([0-9]{1,})\}\{([0-9]{1,})\}(.+)$/)
|
@@ -22,8 +36,8 @@ module SubtitleIt
|
|
22
36
|
|
23
37
|
def to_sub
|
24
38
|
@lines.inject([]) do |i,l|
|
25
|
-
start = l.text_on.to_i / @fps
|
26
|
-
stop = l.text_off.to_i / @fps
|
39
|
+
start = l.text_on.to_i / 1000 * @fps * ratio
|
40
|
+
stop = l.text_off.to_i / 1000 * @fps * ratio
|
27
41
|
i << "{%d}{%d}%s" % [start, stop, l.text]
|
28
42
|
end.join("\r\n")
|
29
43
|
end
|
data/lib/subtitle_it/movie.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# downsub - github.com/johanlunds/downsub
|
2
|
-
require '
|
2
|
+
require 'subtitle_it/movie_hasher'
|
3
3
|
|
4
4
|
module SubtitleIt
|
5
5
|
class Movie
|
@@ -10,12 +10,12 @@ module SubtitleIt
|
|
10
10
|
|
11
11
|
def initialize(filename)
|
12
12
|
@filename = filename
|
13
|
-
@
|
13
|
+
@haxx = nil
|
14
14
|
@info = {}
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
18
|
-
@
|
17
|
+
def haxx
|
18
|
+
@haxx ||= MovieHasher::compute_haxx(@filename)
|
19
19
|
end
|
20
20
|
|
21
21
|
def size
|
@@ -4,27 +4,27 @@ module SubtitleIt
|
|
4
4
|
|
5
5
|
CHUNK_SIZE = 64 * 1024 # in bytes
|
6
6
|
|
7
|
-
def self.
|
7
|
+
def self.compute_haxx(filename)
|
8
8
|
filesize = File.size(filename)
|
9
|
-
|
9
|
+
haxx = filesize
|
10
10
|
|
11
11
|
# Read 64 kbytes, divide up into 64 bits and add each
|
12
12
|
# to hash. Do for beginning and end of file.
|
13
13
|
File.open(filename, 'rb') do |f|
|
14
14
|
# Q = unsigned long long = 64 bit
|
15
15
|
f.read(CHUNK_SIZE).unpack("Q*").each do |n|
|
16
|
-
|
16
|
+
haxx = haxx + n & 0xffffffffffffffff # to remain as 64 bit number
|
17
17
|
end
|
18
18
|
|
19
19
|
f.seek([0, filesize - CHUNK_SIZE].max, IO::SEEK_SET)
|
20
20
|
|
21
21
|
# And again for the end of the file
|
22
22
|
f.read(CHUNK_SIZE).unpack("Q*").each do |n|
|
23
|
-
|
23
|
+
haxx = haxx + n & 0xffffffffffffffff
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
sprintf("%016x",
|
27
|
+
sprintf("%016x", haxx)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
## downsub - github.com/johanlunds/downsub
|
2
|
+
require 'xmlrpc/client'
|
3
|
+
require 'zlib'
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
require 'subtitle_it/version'
|
7
|
+
require 'subtitle_it/subtitle'
|
8
|
+
|
9
|
+
module SubtitleIt
|
10
|
+
class Subdown
|
11
|
+
@@host = "http://www.opensubtitles.org/xml-rpc"
|
12
|
+
@@host_dev = "http://dev.opensubtitles.org/xml-rpc"
|
13
|
+
|
14
|
+
@@user_agent = "SubtitleIt #{SubtitleIt::VERSION}"
|
15
|
+
|
16
|
+
@@no_token = %w(ServerInfo LogIn)
|
17
|
+
|
18
|
+
def initialize(host = @@host)
|
19
|
+
@client = XMLRPC::Client.new2(host)
|
20
|
+
@token = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def log_in!
|
24
|
+
result = call('LogIn', '', '', '', @@user_agent)
|
25
|
+
@token = result['token'].to_s
|
26
|
+
end
|
27
|
+
|
28
|
+
def logged_in?
|
29
|
+
!@token.nil? && !@token.empty?
|
30
|
+
end
|
31
|
+
|
32
|
+
def log_out!
|
33
|
+
call('LogOut')
|
34
|
+
@token = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def server_info
|
38
|
+
call('ServerInfo')
|
39
|
+
end
|
40
|
+
|
41
|
+
def search_subtitles(movie)
|
42
|
+
args = {
|
43
|
+
'sublanguageid' => '',
|
44
|
+
'moviehash' => movie.haxx,
|
45
|
+
'moviebytesize' => movie.size
|
46
|
+
}
|
47
|
+
|
48
|
+
result = call('SearchSubtitles', [args])
|
49
|
+
return [] unless result['data'] # if no results result['data'] == false
|
50
|
+
result['data'].inject([]) do |subs, sub_info|
|
51
|
+
subs << Subtitle.new(nil,nil,sub_info)
|
52
|
+
subs
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def download_subtitle(sub)
|
57
|
+
result = call('DownloadSubtitles', [sub.id])
|
58
|
+
sub.data = self.class.decode_and_unzip(result['data'][0]['data'])
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
def upload_subtitle(movie, subs)
|
63
|
+
end
|
64
|
+
|
65
|
+
def imdb_info(movie)
|
66
|
+
result = call('CheckMovieHash', [movie.haxx])
|
67
|
+
movie.info = result['data'][movie.haxx] # TODO: Handle if no result for movie
|
68
|
+
end
|
69
|
+
|
70
|
+
def subtitle_languages
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def call(method, *args)
|
76
|
+
unless @@no_token.include? method
|
77
|
+
raise 'Need to be logged in for this.' unless logged_in?
|
78
|
+
args = [@token, *args]
|
79
|
+
end
|
80
|
+
|
81
|
+
result = @client.call(method, *args)
|
82
|
+
# $LOG.debug "Client#call #{method}, #{args.inspect}: #{result.inspect}"
|
83
|
+
|
84
|
+
if result['status'] && !((200...300) === result['status'].to_i)
|
85
|
+
raise 'Status not OK in result.'
|
86
|
+
end
|
87
|
+
|
88
|
+
result
|
89
|
+
end
|
90
|
+
|
91
|
+
def prevent_session_expiration
|
92
|
+
call('NoOperation')
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.decode_and_unzip(data)
|
96
|
+
Zlib::GzipReader.new(StringIO.new(XMLRPC::Base64.decode(data))).read
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
File without changes
|
data/lib/subtitle_it/subtime.rb
CHANGED
@@ -4,60 +4,38 @@ module SubtitleIt
|
|
4
4
|
class Subtime
|
5
5
|
attr_accessor :hrs, :min, :sec, :ms
|
6
6
|
|
7
|
-
def initialize(
|
8
|
-
|
9
|
-
|
7
|
+
def initialize(data)
|
8
|
+
raise if data == nil
|
9
|
+
parse_data(data)
|
10
10
|
end
|
11
11
|
|
12
|
-
# parses string like '00:00:00,000'
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
@
|
18
|
-
@min =
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
case v.size
|
29
|
-
when 1
|
30
|
-
@sec = v.first
|
31
|
-
when 2
|
32
|
-
@min, @sec = v
|
33
|
-
when 3
|
34
|
-
@hrs, @min, @sec = v
|
35
|
-
else
|
36
|
-
raise "Wrong time format"
|
37
|
-
end
|
12
|
+
# parses string like '00:00:00,000' or single number as ms.
|
13
|
+
def parse_data(data)
|
14
|
+
case data
|
15
|
+
when Numeric
|
16
|
+
@sec, @ms = data.divmod(1000)
|
17
|
+
@min, @sec = @sec.divmod(60)
|
18
|
+
@hrs, @min = @min.divmod(60)
|
19
|
+
when String
|
20
|
+
time, float = data.split(/\.|\,/)
|
21
|
+
time = time.split(/:/).map { |s| s.to_i }
|
22
|
+
@ms = (("0.%d" % float.to_i).to_f * 1000).to_i if float
|
23
|
+
@sec, @min, @hrs = time.reverse
|
24
|
+
else raise "Format unknown."
|
25
|
+
end
|
26
|
+
#FIXME: dunno what to do about this.. nil = problems with to_i
|
27
|
+
@hrs ||= 0; @min ||= 0; @sec ||= 0; @ms ||= 0
|
38
28
|
end
|
39
|
-
|
29
|
+
|
40
30
|
# to_s(separator) => to_s(",") => 00:00:00,000
|
41
|
-
def to_s(sep='.')
|
42
|
-
"%02d:%02d:%02d#{sep}%03d" % [@hrs, @min, @sec, @ms]
|
43
|
-
end
|
31
|
+
def to_s(sep='.'); "%02d:%02d:%02d#{sep}%03d" % [@hrs, @min, @sec, @ms]; end
|
44
32
|
|
45
33
|
# return time as a total in ms
|
46
|
-
def to_i
|
47
|
-
( @hrs * 3600 + @min * 60 + @sec ) * 1000 + @ms
|
48
|
-
end
|
49
|
-
|
50
|
-
def +(other)
|
51
|
-
Subtime.new(self.to_i + other.to_i)
|
52
|
-
end
|
53
|
-
|
54
|
-
def -(other)
|
55
|
-
Subtime.new(self.to_i - other.to_i)
|
56
|
-
end
|
34
|
+
def to_i; ( @hrs * 3600 + @min * 60 + @sec ) * 1000 + @ms; end
|
57
35
|
|
58
|
-
def
|
59
|
-
|
60
|
-
end
|
36
|
+
def +(other); Subtime.new(self.to_i + other.to_i); end
|
37
|
+
def -(other); Subtime.new(self.to_i - other.to_i); end
|
38
|
+
def <=>(other); self.to_i <=> other.to_i; end
|
61
39
|
include Comparable
|
62
40
|
end
|
63
41
|
end
|
data/lib/subtitle_it/subtitle.rb
CHANGED
@@ -3,28 +3,51 @@ require 'subtitle_it/formats/sub'
|
|
3
3
|
require 'subtitle_it/formats/yml'
|
4
4
|
require 'subtitle_it/formats/rsb'
|
5
5
|
require 'subtitle_it/formats/xml'
|
6
|
+
require 'subtitle_it/formats/mpl'
|
6
7
|
|
7
8
|
module SubtitleIt
|
8
9
|
include Formats
|
9
10
|
|
10
11
|
class Subtitle
|
11
|
-
attr_reader :raw, :format, :lines, :style
|
12
|
+
attr_reader :id, :raw, :format, :lines, :style, :info, :filename
|
13
|
+
|
12
14
|
EXTS = %w(srt sub smi txt ssa ass mpl xml yml rsb)
|
13
15
|
|
14
|
-
def initialize(dump,
|
15
|
-
|
16
|
+
def initialize(dump=nil,format=nil,info=nil)
|
17
|
+
@info = info
|
18
|
+
@id = info['IDSubtitleFile'].to_i if info
|
19
|
+
@filename = info['SubFileName'].to_s if info
|
20
|
+
@format = info['SubFormat'].to_s if info
|
21
|
+
@fps=23.976
|
22
|
+
parse_dump(dump,format) if dump
|
23
|
+
end
|
24
|
+
|
25
|
+
def parse_dump(dump,format)
|
26
|
+
raise unless format =~ /^srt$|sub|yml|txt|rsb|xml|ass|mpl/
|
16
27
|
@raw = dump.kind_of?(String) ? dump : dump.read
|
17
28
|
@format = format
|
18
|
-
@style = style
|
19
|
-
@fps = fps
|
20
29
|
parse!
|
21
30
|
end
|
31
|
+
|
32
|
+
def style=(s)
|
33
|
+
@style = s
|
34
|
+
end
|
35
|
+
|
36
|
+
def fps=(fps)
|
37
|
+
@fps = fps
|
38
|
+
end
|
39
|
+
|
40
|
+
def data=(data)
|
41
|
+
@raw = data
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
private
|
22
46
|
|
23
47
|
def parse!
|
24
48
|
self.lines = send :"parse_#{@format}"
|
25
49
|
end
|
26
50
|
|
27
|
-
private
|
28
51
|
def lines=(lines)
|
29
52
|
@lines = lines
|
30
53
|
end
|
data/lib/subtitle_it/version.rb
CHANGED
data/lib/subtitle_it.rb
CHANGED
@@ -0,0 +1,12 @@
|
|
1
|
+
[1025][1115]You always say that.|The same thing every time.
|
2
|
+
[1118][1177]"l'm through, never again,|too dangerous."
|
3
|
+
[1180][1270]I know that's what I always say.|I'm always right too.
|
4
|
+
[1274][1364]- You forget about it in a day or two.|- The days of me forgetting are over.
|
5
|
+
[1368][1428]The days of me remembering|have just begun.
|
6
|
+
[1430][1490]You know, when you go on like this,|what you sound like ?
|
7
|
+
[1493][1583]- I sound like a sensible fuckin' man.|- You sound like a duck.
|
8
|
+
[1587][1707]- Quack, quack, quack.|- Take heart, 'cause you're never
|
9
|
+
[1712][1802]Since I'm never gonna|do it again, you're never
|
10
|
+
[1806][1956]- After tonight ?|- Correct. I got all tonight to quack.
|
11
|
+
[1962][2022]- Can I get anyone more coffee ?|- Oh, yes !
|
12
|
+
[2087][2176]- Thank you.|- You're welcome.
|
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
describe Formats, ".mpl" do
|
4
|
+
include SubFixtures
|
5
|
+
describe "In" do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@mpl = Subtitle.new(mpl_fixture,'mpl')
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should parse the sub to an array" do
|
12
|
+
@mpl.lines.should be_instance_of(Array)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should have N lines" do
|
16
|
+
@mpl.should have(12).lines
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should parse time of" do
|
20
|
+
@mpl.lines[0].text_on.to_s.should eql("00:17:05.000")
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should parse time of" do
|
24
|
+
@mpl.lines[0].text_off.to_s.should eql("00:18:35.000")
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should parse text" do
|
28
|
+
@mpl.lines[0].text.should eql("You always say that.|The same thing every time.")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "Out!" do
|
33
|
+
|
34
|
+
before(:each) do
|
35
|
+
@sub = Subtitle.new(yml_fixture,'yml')
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should dump the object as a SRT" do
|
39
|
+
@sub.to_mpl.should eql("[3265][3285]worth killing for...
|
40
|
+
[3604][3634]worth dying for...
|
41
|
+
[4203][4233]worth going to the hell for...
|
42
|
+
[4203][4233]worth going a | line...")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -40,7 +40,10 @@ describe Formats, ".sub" do
|
|
40
40
|
end
|
41
41
|
|
42
42
|
it "should dump the object as a SUB" do
|
43
|
-
@sub.to_sub.should eql("{
|
43
|
+
@sub.to_sub.should eql("{7816}{7864}worth killing for...\r
|
44
|
+
{8631}{8703}worth dying for...\r
|
45
|
+
{10069}{10141}worth going to the hell for...\r
|
46
|
+
{10069}{10141}worth going a | line...")
|
44
47
|
end
|
45
48
|
end
|
46
49
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Movie do
|
4
|
+
before(:each) do
|
5
|
+
@movie = Movie.new('pulpfiction')
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
it "should get subtitle languages" do
|
12
|
+
# @down.subtitle_languages.should be_nil
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Subdown do
|
4
|
+
before(:each) do
|
5
|
+
@down = Subdown.new
|
6
|
+
@down.log_in!
|
7
|
+
@movie = mock(Movie, :haxx => '09a2c497663259cb')
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
it "should get imdb info" do
|
12
|
+
@movie.should_receive('info=').with({"MovieYear"=>"2004",
|
13
|
+
"MovieImdbID"=>"403358",
|
14
|
+
"MovieName"=>"Nochnoy dozor",
|
15
|
+
"MovieHash"=>"09a2c497663259cb"})
|
16
|
+
@down.imdb_info(@movie)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should search subs info" do
|
20
|
+
@movie.stub!(:size).and_return(733589504)
|
21
|
+
res = @down.search_subtitles(@movie)
|
22
|
+
res.should be_instance_of(Array)
|
23
|
+
res.each do |r|
|
24
|
+
r.should be_instance_of(Subtitle)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
it "should get subtitle languages" do
|
31
|
+
@down.subtitle_languages.should be_nil
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
#
|
41
|
+
# @client.log_in!
|
42
|
+
# @movie = DownSub::Movie.new('/Users/lundan/Movies/21[2008]DvDrip-aXXo/21[2008]DvDrip-aXXo.avi') # ask_open_file
|
43
|
+
# @client.imdb_info(@movie)
|
44
|
+
#
|
45
|
+
# puts @client.search_subtitles(@movie).inspect
|
46
|
+
#
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
@@ -34,6 +34,17 @@ describe Subtime do
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
+
describe "and the other way around" do
|
38
|
+
it "should print nicely" do
|
39
|
+
@subtime = Subtime.new(3723400)
|
40
|
+
@subtime.to_s.should eql('01:02:03.400')
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
|
37
48
|
describe Subtime,"22" do
|
38
49
|
it "should convert a big time" do
|
39
50
|
@subtime = Subtime.new('11:22:33.742')
|
@@ -51,20 +62,20 @@ end
|
|
51
62
|
|
52
63
|
describe Subtime, ".other formats" do
|
53
64
|
|
54
|
-
it "should parse
|
65
|
+
it "should parse min:sec.ms" do
|
55
66
|
@subtime = Subtime.new('01:03.4')
|
56
67
|
end
|
57
68
|
|
58
|
-
it "should parse
|
69
|
+
it "should parse min:sec,ms" do
|
59
70
|
@subtime = Subtime.new('01:03,3')
|
60
71
|
end
|
61
72
|
|
62
|
-
it "should
|
73
|
+
it "should single as seconds hour should be nil" do
|
63
74
|
@subtime = Subtime.new('3')
|
64
75
|
@subtime.hrs.should eql(0)
|
65
76
|
end
|
66
77
|
|
67
|
-
it "should parse
|
78
|
+
it "should parse min:sec" do
|
68
79
|
@subtime = Subtime.new('01:03')
|
69
80
|
@subtime.min.should eql(1)
|
70
81
|
end
|
data/subtitle_it.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = %q{subtitle_it}
|
3
|
-
s.version = "0.
|
3
|
+
s.version = "0.7.0"
|
4
4
|
|
5
5
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
6
6
|
s.authors = ["Marcos Piccinini", "Warlley Rezende"]
|
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.email = ["x@nofxx.com"]
|
11
11
|
s.executables = ["subtitle_it"]
|
12
12
|
s.extra_rdoc_files = ["History.txt", "License.txt", "Manifest.txt", "README.txt", "README.markdown"]
|
13
|
-
s.files = [".autotest", "History.txt", "License.txt", "Manifest.txt", "README.markdown", "README.txt", "Rakefile", "bin/subtitle_it", "config/hoe.rb", "config/requirements.rb", "lib/subtitle_it.rb", "lib/subtitle_it/formats/ass.rb", "lib/subtitle_it/formats/rsb.rb", "lib/subtitle_it/formats/srt.rb", "lib/subtitle_it/formats/sub.rb", "lib/subtitle_it/formats/xml.rb", "lib/subtitle_it/formats/yml.rb", "lib/subtitle_it/movie.rb", "lib/subtitle_it/movie_hasher.rb", "lib/subtitle_it/subline.rb", "lib/subtitle_it/subtime.rb", "lib/subtitle_it/subtitle.rb", "lib/subtitle_it/version.rb", "script/console", "script/destroy", "script/generate", "script/txt2html", "setup.rb", "spec/fixtures/godfather.srt", "spec/fixtures/huge.ass", "spec/fixtures/movie.xml", "spec/fixtures/movie.yml", "spec/fixtures/pseudo.rsb", "spec/fixtures/pulpfiction.sub", "spec/fixtures/sincity.yml", "spec/spec.opts", "spec/spec_helper.rb", "spec/subtitle_it/formats/ass_spec.rb", "spec/subtitle_it/formats/rsb_spec.rb", "spec/subtitle_it/formats/srt_spec.rb", "spec/subtitle_it/formats/sub_spec.rb", "spec/subtitle_it/formats/xml_spec.rb", "spec/subtitle_it/formats/yml_spec.rb", "spec/subtitle_it/subline_spec.rb", "spec/subtitle_it/subtime_spec.rb", "spec/subtitle_it/subtitle_spec.rb", "spec/subtitle_it_spec.rb", "subtitle_it.gemspec", "tasks/deployment.rake", "tasks/environment.rake", "tasks/rspec.rake"]
|
13
|
+
s.files = [".autotest", "History.txt", "License.txt", "Manifest.txt", "README.markdown", "README.txt", "Rakefile", "bin/subtitle_it", "config/hoe.rb", "config/requirements.rb", "lib/subtitle_it.rb", "lib/subtitle_it/formats/ass.rb", "lib/subtitle_it/formats/mpl.rb", "lib/subtitle_it/formats/rsb.rb", "lib/subtitle_it/formats/srt.rb", "lib/subtitle_it/formats/sub.rb", "lib/subtitle_it/formats/xml.rb", "lib/subtitle_it/formats/yml.rb", "lib/subtitle_it/movie.rb", "lib/subtitle_it/movie_hasher.rb", "lib/subtitle_it/subdown.rb", "lib/subtitle_it/subline.rb", "lib/subtitle_it/substyle.rb", "lib/subtitle_it/subtime.rb", "lib/subtitle_it/subtitle.rb", "lib/subtitle_it/version.rb", "script/console", "script/destroy", "script/generate", "script/txt2html", "setup.rb", "spec/fixtures/godfather.srt", "spec/fixtures/huge.ass", "spec/fixtures/movie.xml", "spec/fixtures/movie.yml", "spec/fixtures/pseudo.rsb", "spec/fixtures/pulpfiction.sub", "spec/fixtures/puplfiction.mpl", "spec/fixtures/sincity.yml", "spec/spec.opts", "spec/spec_helper.rb", "spec/subtitle_it/formats/ass_spec.rb", "spec/subtitle_it/formats/mpl_spec.rb", "spec/subtitle_it/formats/rsb_spec.rb", "spec/subtitle_it/formats/srt_spec.rb", "spec/subtitle_it/formats/sub_spec.rb", "spec/subtitle_it/formats/xml_spec.rb", "spec/subtitle_it/formats/yml_spec.rb", "spec/subtitle_it/movie_hasher_spec.rb", "spec/subtitle_it/movie_spec.rb", "spec/subtitle_it/subdown_spec.rb", "spec/subtitle_it/subline_spec.rb", "spec/subtitle_it/substyle_spec.rb", "spec/subtitle_it/subtime_spec.rb", "spec/subtitle_it/subtitle_spec.rb", "spec/subtitle_it_spec.rb", "subtitle_it.gemspec", "tasks/deployment.rake", "tasks/environment.rake", "tasks/rspec.rake"]
|
14
14
|
s.has_rdoc = true
|
15
15
|
s.homepage = %q{http://github.com/nofxx/subtitle_it}
|
16
16
|
s.post_install_message = %q{
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: warlley-subtitle_it
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marcos Piccinini
|
@@ -57,6 +57,7 @@ files:
|
|
57
57
|
- config/requirements.rb
|
58
58
|
- lib/subtitle_it.rb
|
59
59
|
- lib/subtitle_it/formats/ass.rb
|
60
|
+
- lib/subtitle_it/formats/mpl.rb
|
60
61
|
- lib/subtitle_it/formats/rsb.rb
|
61
62
|
- lib/subtitle_it/formats/srt.rb
|
62
63
|
- lib/subtitle_it/formats/sub.rb
|
@@ -64,7 +65,9 @@ files:
|
|
64
65
|
- lib/subtitle_it/formats/yml.rb
|
65
66
|
- lib/subtitle_it/movie.rb
|
66
67
|
- lib/subtitle_it/movie_hasher.rb
|
68
|
+
- lib/subtitle_it/subdown.rb
|
67
69
|
- lib/subtitle_it/subline.rb
|
70
|
+
- lib/subtitle_it/substyle.rb
|
68
71
|
- lib/subtitle_it/subtime.rb
|
69
72
|
- lib/subtitle_it/subtitle.rb
|
70
73
|
- lib/subtitle_it/version.rb
|
@@ -79,16 +82,22 @@ files:
|
|
79
82
|
- spec/fixtures/movie.yml
|
80
83
|
- spec/fixtures/pseudo.rsb
|
81
84
|
- spec/fixtures/pulpfiction.sub
|
85
|
+
- spec/fixtures/puplfiction.mpl
|
82
86
|
- spec/fixtures/sincity.yml
|
83
87
|
- spec/spec.opts
|
84
88
|
- spec/spec_helper.rb
|
85
89
|
- spec/subtitle_it/formats/ass_spec.rb
|
90
|
+
- spec/subtitle_it/formats/mpl_spec.rb
|
86
91
|
- spec/subtitle_it/formats/rsb_spec.rb
|
87
92
|
- spec/subtitle_it/formats/srt_spec.rb
|
88
93
|
- spec/subtitle_it/formats/sub_spec.rb
|
89
94
|
- spec/subtitle_it/formats/xml_spec.rb
|
90
95
|
- spec/subtitle_it/formats/yml_spec.rb
|
96
|
+
- spec/subtitle_it/movie_hasher_spec.rb
|
97
|
+
- spec/subtitle_it/movie_spec.rb
|
98
|
+
- spec/subtitle_it/subdown_spec.rb
|
91
99
|
- spec/subtitle_it/subline_spec.rb
|
100
|
+
- spec/subtitle_it/substyle_spec.rb
|
92
101
|
- spec/subtitle_it/subtime_spec.rb
|
93
102
|
- spec/subtitle_it/subtitle_spec.rb
|
94
103
|
- spec/subtitle_it_spec.rb
|