subconv 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +39 -0
- data/.rubocop.yml +74 -0
- data/.travis.yml +4 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +59 -0
- data/Rakefile +10 -0
- data/bin/subconv +58 -0
- data/dist/eia608.css +106 -0
- data/lib/subconv.rb +5 -0
- data/lib/subconv/caption.rb +106 -0
- data/lib/subconv/caption_filter.rb +129 -0
- data/lib/subconv/scc/reader.rb +470 -0
- data/lib/subconv/scc/transformer.rb +259 -0
- data/lib/subconv/utility.rb +42 -0
- data/lib/subconv/version.rb +3 -0
- data/lib/subconv/webvtt/writer.rb +131 -0
- data/spec/caption_filter_spec.rb +154 -0
- data/spec/scc/reader_spec.rb +311 -0
- data/spec/scc/transformer_spec.rb +167 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/test_helpers.rb +73 -0
- data/spec/webvtt/writer_spec.rb +106 -0
- data/subconv.gemspec +34 -0
- metadata +188 -0
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
module Subconv
|
2
|
+
module TestHelpers
|
3
|
+
def default_fps
|
4
|
+
25
|
5
|
+
end
|
6
|
+
|
7
|
+
def t1
|
8
|
+
Timecode.new(10, default_fps)
|
9
|
+
end
|
10
|
+
|
11
|
+
def t2
|
12
|
+
Timecode.new(20, default_fps)
|
13
|
+
end
|
14
|
+
|
15
|
+
def t3
|
16
|
+
Timecode.new(30, default_fps)
|
17
|
+
end
|
18
|
+
|
19
|
+
def t1_2
|
20
|
+
Utility::Timespan.new(t1, t2)
|
21
|
+
end
|
22
|
+
|
23
|
+
def t2_3
|
24
|
+
Utility::Timespan.new(t2, t3)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_grid
|
28
|
+
Scc::Grid.new.insert_text(0, 0, 'Test')
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_content
|
32
|
+
RootNode.new([TextNode.new('Test')])
|
33
|
+
end
|
34
|
+
|
35
|
+
def left_top
|
36
|
+
Position.new(0.2, 0.1)
|
37
|
+
end
|
38
|
+
|
39
|
+
def single_scc_caption_with_grid(grid)
|
40
|
+
[Scc::Caption.new(timecode: t1, grid: grid), Scc::Caption.new(timecode: t2)]
|
41
|
+
end
|
42
|
+
|
43
|
+
def single_caption_with_content(content)
|
44
|
+
# Auto-promote the content to a TextNode if necessary
|
45
|
+
content = TextNode.new(content) if content.instance_of?(String)
|
46
|
+
# Auto-promote the content to an array if necessary
|
47
|
+
content = [content] unless content.instance_of?(Array)
|
48
|
+
[Caption.new(timespan: t1_2, position: left_top, content: RootNode.new(content), align: :start)]
|
49
|
+
end
|
50
|
+
|
51
|
+
def root_with_text(text)
|
52
|
+
RootNode.new([TextNode.new(text)])
|
53
|
+
end
|
54
|
+
|
55
|
+
def caption_all_node_types
|
56
|
+
single_caption_with_content(
|
57
|
+
[
|
58
|
+
ColorNode.new(:blue, [TextNode.new('1')]),
|
59
|
+
FlashNode.new([TextNode.new('2')]),
|
60
|
+
ItalicsNode.new([TextNode.new('3')]),
|
61
|
+
UnderlineNode.new([TextNode.new('4')])
|
62
|
+
]
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
def caption_filter_process(options)
|
67
|
+
original = yield
|
68
|
+
processed = yield
|
69
|
+
CaptionFilter.new(options).process!(processed)
|
70
|
+
[original, processed]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Subconv
|
4
|
+
describe WebVtt::Writer do
|
5
|
+
include TestHelpers
|
6
|
+
include Subconv
|
7
|
+
|
8
|
+
let(:header) { "WEBVTT\n\n" }
|
9
|
+
# Header including one cue from t1 to t2 at top left
|
10
|
+
let(:cue_header) { header + "00:00:00.400 --> 00:00:00.800 align:start line:10.000% position:20.000%\n" }
|
11
|
+
|
12
|
+
before(:each) do
|
13
|
+
@writer = WebVtt::Writer.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def write(captions)
|
17
|
+
stringio = StringIO.new
|
18
|
+
@writer.write(stringio, captions)
|
19
|
+
# Strip whitespace from the end of the string since it doesn't particularly matter
|
20
|
+
stringio.string.rstrip
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should write out a single caption' do
|
24
|
+
expect(write(single_caption_with_content('Test'))).to eq(cue_header + 'Test')
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should write out multiple captions' do
|
28
|
+
captions = [
|
29
|
+
Caption.new(timespan: t1_2, position: left_top, content: root_with_text('Test 1'), align: :start),
|
30
|
+
Caption.new(timespan: t1_2, position: Position.new(0.2, 0.3), content: root_with_text('Test 2'), align: :start),
|
31
|
+
Caption.new(timespan: Utility::Timespan.new(Timecode.new(25, default_fps), Timecode.new(35, default_fps)), position: left_top, content: root_with_text('Test 3'), align: :start)
|
32
|
+
]
|
33
|
+
|
34
|
+
expected = header + <<"END".rstrip
|
35
|
+
00:00:00.400 --> 00:00:00.800 align:start line:10.000% position:20.000%
|
36
|
+
Test 1
|
37
|
+
|
38
|
+
00:00:00.400 --> 00:00:00.800 align:start line:30.000% position:20.000%
|
39
|
+
Test 2
|
40
|
+
|
41
|
+
00:00:01.000 --> 00:00:01.400 align:start line:10.000% position:20.000%
|
42
|
+
Test 3
|
43
|
+
END
|
44
|
+
expect(write(captions)).to eq(expected)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'support simple positioning and alignment' do
|
48
|
+
captions = [
|
49
|
+
Caption.new(timespan: t1_2, position: :top, content: root_with_text('Test 1'), align: :start),
|
50
|
+
# align:middle should not be output as it is the default
|
51
|
+
Caption.new(timespan: t2_3, position: :bottom, content: root_with_text('Test 2'), align: :middle)
|
52
|
+
]
|
53
|
+
|
54
|
+
expected = header + <<"END".rstrip
|
55
|
+
00:00:00.400 --> 00:00:00.800 align:start line:5%
|
56
|
+
Test 1
|
57
|
+
|
58
|
+
00:00:00.800 --> 00:00:01.200 line:-1,end
|
59
|
+
Test 2
|
60
|
+
END
|
61
|
+
expect(write(captions)).to eq(expected)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should support italics' do
|
65
|
+
expect(write(single_caption_with_content(ItalicsNode.new([TextNode.new('Test')])))).to eq(cue_header + '<i>Test</i>')
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should support underline' do
|
69
|
+
expect(write(single_caption_with_content(UnderlineNode.new([TextNode.new('Test')])))).to eq(cue_header + '<u>Test</u>')
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should support flash' do
|
73
|
+
expect(write(single_caption_with_content(FlashNode.new([TextNode.new('Test')])))).to eq(cue_header + '<c.blink>Test</c>')
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should support colors' do
|
77
|
+
expect(write(single_caption_with_content(ColorNode.new(:magenta, [TextNode.new('Test')])))).to eq(cue_header + '<c.magenta>Test</c>')
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should escape special characters' do
|
81
|
+
expect(write(single_caption_with_content('<i>&Test</i>'))).to eq(cue_header + '<i&rt;&Test</i&rt;')
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should support complicated combinations of styles' do
|
85
|
+
nodes = [
|
86
|
+
TextNode.new('a'),
|
87
|
+
ItalicsNode.new([
|
88
|
+
ColorNode.new(:blue, [
|
89
|
+
FlashNode.new([
|
90
|
+
TextNode.new('b'),
|
91
|
+
UnderlineNode.new([
|
92
|
+
TextNode.new('cde')
|
93
|
+
])
|
94
|
+
])
|
95
|
+
]),
|
96
|
+
ColorNode.new(:cyan, [
|
97
|
+
UnderlineNode.new([
|
98
|
+
TextNode.new('f')
|
99
|
+
])
|
100
|
+
])
|
101
|
+
])
|
102
|
+
]
|
103
|
+
expect(write(single_caption_with_content(nodes))).to eq(cue_header + 'a<i><c.blue><c.blink>b<u>cde</u></c></c><c.cyan><u>f</u></c></i>')
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
data/subconv.gemspec
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'subconv/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = 'subconv'
|
8
|
+
s.version = Subconv::VERSION
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
|
11
|
+
s.required_ruby_version = '>= 2.0'
|
12
|
+
s.authors = ['Philipp Kerling']
|
13
|
+
s.email = ['pkerling@casix.org']
|
14
|
+
s.homepage = 'https://github.com/pkerling/subconv'
|
15
|
+
s.files = `git ls-files -z`.split("\x0").reject { |elem| elem =~ %r{^scc-data/} }
|
16
|
+
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
18
|
+
s.require_paths = ['lib']
|
19
|
+
s.license = 'MIT'
|
20
|
+
|
21
|
+
s.rdoc_options = ['--charset=UTF-8']
|
22
|
+
s.require_paths = ['lib']
|
23
|
+
|
24
|
+
s.rubygems_version = '1.3.7'
|
25
|
+
s.summary = 'Subtitle conversion (SCC to WebVTT)'
|
26
|
+
s.add_dependency 'solid-struct'
|
27
|
+
s.add_dependency 'timecode'
|
28
|
+
s.add_development_dependency 'bundler', '~> 1.7'
|
29
|
+
s.add_development_dependency 'rspec', '~> 3.4.0'
|
30
|
+
s.add_development_dependency 'rake'
|
31
|
+
s.add_development_dependency 'rubocop'
|
32
|
+
s.add_development_dependency 'json'
|
33
|
+
s.add_development_dependency 'coveralls'
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: subconv
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Philipp Kerling
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-02-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: solid-struct
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: timecode
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.7'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.7'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 3.4.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 3.4.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: json
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: coveralls
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description:
|
126
|
+
email:
|
127
|
+
- pkerling@casix.org
|
128
|
+
executables:
|
129
|
+
- subconv
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- ".gitignore"
|
134
|
+
- ".rubocop.yml"
|
135
|
+
- ".travis.yml"
|
136
|
+
- Gemfile
|
137
|
+
- LICENSE
|
138
|
+
- README.md
|
139
|
+
- Rakefile
|
140
|
+
- bin/subconv
|
141
|
+
- dist/eia608.css
|
142
|
+
- lib/subconv.rb
|
143
|
+
- lib/subconv/caption.rb
|
144
|
+
- lib/subconv/caption_filter.rb
|
145
|
+
- lib/subconv/scc/reader.rb
|
146
|
+
- lib/subconv/scc/transformer.rb
|
147
|
+
- lib/subconv/utility.rb
|
148
|
+
- lib/subconv/version.rb
|
149
|
+
- lib/subconv/webvtt/writer.rb
|
150
|
+
- spec/caption_filter_spec.rb
|
151
|
+
- spec/scc/reader_spec.rb
|
152
|
+
- spec/scc/transformer_spec.rb
|
153
|
+
- spec/spec_helper.rb
|
154
|
+
- spec/test_helpers.rb
|
155
|
+
- spec/webvtt/writer_spec.rb
|
156
|
+
- subconv.gemspec
|
157
|
+
homepage: https://github.com/pkerling/subconv
|
158
|
+
licenses:
|
159
|
+
- MIT
|
160
|
+
metadata: {}
|
161
|
+
post_install_message:
|
162
|
+
rdoc_options:
|
163
|
+
- "--charset=UTF-8"
|
164
|
+
require_paths:
|
165
|
+
- lib
|
166
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
167
|
+
requirements:
|
168
|
+
- - ">="
|
169
|
+
- !ruby/object:Gem::Version
|
170
|
+
version: '2.0'
|
171
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
172
|
+
requirements:
|
173
|
+
- - ">="
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
version: '0'
|
176
|
+
requirements: []
|
177
|
+
rubyforge_project:
|
178
|
+
rubygems_version: 2.4.8
|
179
|
+
signing_key:
|
180
|
+
specification_version: 4
|
181
|
+
summary: Subtitle conversion (SCC to WebVTT)
|
182
|
+
test_files:
|
183
|
+
- spec/caption_filter_spec.rb
|
184
|
+
- spec/scc/reader_spec.rb
|
185
|
+
- spec/scc/transformer_spec.rb
|
186
|
+
- spec/spec_helper.rb
|
187
|
+
- spec/test_helpers.rb
|
188
|
+
- spec/webvtt/writer_spec.rb
|