subconv 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ require 'coveralls'
2
+ Coveralls.wear!
3
+
4
+ require 'subconv'
5
+ require 'test_helpers'
@@ -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 + '&lt;i&rt;&amp;Test&lt;/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
@@ -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