vtt2ass 0.3.4 → 0.3.6
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 +4 -4
- data/.gitignore +3 -0
- data/.rubocop.yml +19 -0
- data/Gemfile +2 -0
- data/README.md +5 -1
- data/Rakefile +8 -6
- data/bin/vtt2ass +2 -1
- data/exe/vtt2ass +2 -1
- data/lib/vtt2ass/application.rb +69 -65
- data/lib/vtt2ass/ass_file.rb +91 -94
- data/lib/vtt2ass/ass_line.rb +89 -86
- data/lib/vtt2ass/ass_style.rb +42 -38
- data/lib/vtt2ass/ass_style_params.rb +97 -75
- data/lib/vtt2ass/css_file.rb +28 -26
- data/lib/vtt2ass/css_rule.rb +25 -17
- data/lib/vtt2ass/validator.rb +12 -8
- data/lib/vtt2ass/version.rb +3 -1
- data/lib/vtt2ass/vtt_file.rb +45 -45
- data/lib/vtt2ass/vtt_line.rb +37 -37
- data/lib/vtt2ass.rb +66 -21
- data/vtt2ass.gemspec +20 -16
- metadata +31 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bacdcc421becff18a39326c953658fb28c07eb06bd5a4dacc951098e661a9601
|
4
|
+
data.tar.gz: ef37756d00cdfa88d23a778fd2ad0718e1129e74e412aa77a5ceebfd0daeb5f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74ffa9400ecd804d00fe2a5649cb9a7e5b0ebb14b2cb7fd1fe4744517b047c4af4e05edf5e0f9ad1b8d34e47ece1d4c8f8e74c749b78f88a193258853fffceb9
|
7
|
+
data.tar.gz: e861fe563ab6ef59085062bd1e2269ca56f20eb939df05eaead50ff78fb754c8339fdb4291c3cf9f357fdd5712df7a2fcbacdf8d4bce2a2773e11c51694d37ce
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
---
|
2
|
+
AllCops:
|
3
|
+
TargetRubyVersion: 2.7.2
|
4
|
+
NewCops: enable
|
5
|
+
# Set method line number to 25
|
6
|
+
Metrics/MethodLength:
|
7
|
+
Max: 25
|
8
|
+
# Set parameter number to 10
|
9
|
+
Metrics/ParameterLists:
|
10
|
+
Max: 10
|
11
|
+
# Disable checking of ABC metrics (assignment, branch, condition)
|
12
|
+
Metrics/AbcSize:
|
13
|
+
Enabled: false
|
14
|
+
# Disable method perceived complexity (how it is hard to read a method)
|
15
|
+
Metrics/PerceivedComplexity:
|
16
|
+
Enabled: false
|
17
|
+
# Disable cyclomatic complexity which is a number of paths through a method
|
18
|
+
Metrics/CyclomaticComplexity:
|
19
|
+
Enabled: false
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -64,6 +64,10 @@ Options:
|
|
64
64
|
-c, [--css=CSS] # Specify a CSS file path for Hidive subs
|
65
65
|
-l, [--line-offset=N] # Specify a line offset for the main dialog (e.g. 50 lowers the text line by 50px of the total height)
|
66
66
|
# Default: 0
|
67
|
+
-w, [--width=N] # Specify the video width
|
68
|
+
# Default: 1920
|
69
|
+
-h, [--height=N] # Specify the video height
|
70
|
+
# Default: 1080
|
67
71
|
-q, [--quiet], [--no-quiet] # Don't output to the console
|
68
72
|
|
69
73
|
Run the VTT to ASS conversion for the specified file(s)
|
@@ -99,7 +103,7 @@ $ gem build vtt2ass.gemspec
|
|
99
103
|
|
100
104
|
To install the gem file:
|
101
105
|
```bash
|
102
|
-
$ gem install ./vtt2ass-0.3.
|
106
|
+
$ gem install ./vtt2ass-0.3.5.gem
|
103
107
|
```
|
104
108
|
|
105
109
|
## License
|
data/Rakefile
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rake/testtask'
|
3
5
|
|
4
6
|
Rake::TestTask.new(:test) do |t|
|
5
|
-
t.libs <<
|
6
|
-
t.libs <<
|
7
|
-
t.test_files = FileList[
|
7
|
+
t.libs << 'test'
|
8
|
+
t.libs << 'lib'
|
9
|
+
t.test_files = FileList['test/**/*_test.rb']
|
8
10
|
end
|
9
11
|
|
10
|
-
task :
|
12
|
+
task default: :test
|
data/bin/vtt2ass
CHANGED
data/exe/vtt2ass
CHANGED
data/lib/vtt2ass/application.rb
CHANGED
@@ -1,77 +1,81 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require_relative 'vtt_file'
|
3
4
|
require_relative 'ass_file'
|
4
5
|
|
5
6
|
##
|
6
7
|
# Main application class that manages all the operations.
|
7
8
|
class Application
|
9
|
+
##
|
10
|
+
# Creates a new Application instance.
|
11
|
+
# It receives +options+ that can define the input and output directories.
|
12
|
+
def initialize(input, options)
|
13
|
+
@options = options
|
14
|
+
@input = sanitize_path(input)
|
15
|
+
end
|
8
16
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
@width = 1920
|
16
|
-
@height = 1080
|
17
|
-
@font_family = options[:font_family] ? options[:font_family] : 'Open Sans Semibold'
|
18
|
-
@font_size = options[:font_size] ? options[:font_size] : 52
|
19
|
-
if options[:title] then
|
20
|
-
@title = options[:title]
|
21
|
-
end
|
22
|
-
@quiet = options[:quiet]
|
23
|
-
if options[:css] then
|
24
|
-
@css = options[:css].gsub('\\', '/').delete_suffix('/')
|
25
|
-
end
|
26
|
-
@line_offset = options[:line_offset]
|
27
|
-
end
|
17
|
+
##
|
18
|
+
# Replace backslashes from Windows paths to normal slashes.
|
19
|
+
# Deletes the trailing slash if there is one.
|
20
|
+
def sanitize_path(path)
|
21
|
+
path&.gsub('\\', '/')&.delete_suffix('/')
|
22
|
+
end
|
28
23
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
end
|
24
|
+
##
|
25
|
+
# This method starts the application process.
|
26
|
+
# It sends the file_paths of VTT files in the input directory to convertFileToASS method
|
27
|
+
# and outputs the resulting ASS format to a new file.
|
28
|
+
def start
|
29
|
+
if File.directory?(@input)
|
30
|
+
Dir["#{@input}/*.vtt"].each do |file_path|
|
31
|
+
convert(file_path)
|
32
|
+
end
|
33
|
+
elsif File.file?(@input)
|
34
|
+
convert(@input)
|
35
|
+
else
|
36
|
+
raise StandardError, 'ERROR: Input file or directory does not exist.'
|
43
37
|
end
|
38
|
+
rescue SystemExit, Interrupt
|
39
|
+
puts 'ERROR: The application stopped unexpectedly. The conversion may not have been completed.'
|
40
|
+
rescue StandardError => e
|
41
|
+
puts e.message
|
42
|
+
puts e.backtrace
|
43
|
+
end
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
end
|
45
|
+
##
|
46
|
+
# This method launches the conversion process on the specified input file.
|
47
|
+
def convert(input_path)
|
48
|
+
output = sanitize_path(@options[:output])
|
49
|
+
output = '.' if output.nil?
|
50
|
+
raise StandardError, 'ERROR: Output directory does not exist.' unless File.directory?(output)
|
52
51
|
|
53
|
-
|
54
|
-
#
|
55
|
-
|
56
|
-
|
57
|
-
base_file_name = File.basename(file_path).gsub('.vtt', '')
|
58
|
-
css_file = nil
|
59
|
-
if defined?(@css) and File.directory?(@css) then
|
60
|
-
css_file = "#{@css}/#{base_file_name}.css"
|
61
|
-
elsif File.file?("#{file_path.gsub('.vtt', '')}.css") then
|
62
|
-
css_file = "#{file_path.gsub('.vtt', '')}.css"
|
63
|
-
else
|
64
|
-
css_file = @css
|
65
|
-
end
|
66
|
-
vtt_file = VTTFile.new(file_path, @width, @height)
|
67
|
-
ass_file = ASSFile.new(
|
68
|
-
(defined?(@title) ? @title : base_file_name),
|
69
|
-
@width,
|
70
|
-
@height,
|
71
|
-
css_file
|
72
|
-
)
|
73
|
-
ass_file.convert_vtt_to_ass(vtt_file, @font_family, @font_size, @line_offset)
|
74
|
-
return ass_file
|
75
|
-
end
|
52
|
+
ass_file = vtt_to_ass(input_path)
|
53
|
+
ass_file.write_to_file("#{output}/#{File.basename(input_path).gsub('.vtt', '.ass')}") unless output.nil?
|
54
|
+
puts ass_file.to_s unless @options[:quiet]
|
55
|
+
end
|
76
56
|
|
77
|
-
|
57
|
+
##
|
58
|
+
# This method creates a new VTTFile object from the file path provided and convert its content
|
59
|
+
# inside a new ASSFile object.
|
60
|
+
def vtt_to_ass(file_path)
|
61
|
+
base_file_name = File.basename(file_path).gsub('.vtt', '')
|
62
|
+
css_file =
|
63
|
+
if !@options[:css].nil? && File.directory?(@options[:css])
|
64
|
+
"#{sanitize_path(@options[:css])}/#{base_file_name}.css"
|
65
|
+
elsif File.file?("#{file_path.gsub('.vtt', '')}.css")
|
66
|
+
"#{file_path.gsub('.vtt', '')}.css"
|
67
|
+
else
|
68
|
+
@options[:css]
|
69
|
+
end
|
70
|
+
vtt_file = VTTFile.new(file_path, @options[:width], @options[:height])
|
71
|
+
ass_file = ASSFile.new(
|
72
|
+
(@options[:title].nil? ? base_file_name : @options[:title]),
|
73
|
+
@options[:width],
|
74
|
+
@options[:height],
|
75
|
+
css_file
|
76
|
+
)
|
77
|
+
ass_file.convert_vtt_to_ass(vtt_file, @options[:font_family], @options[:font_size],
|
78
|
+
{ line: @options[:line_offset], caption: @options[:caption_offset] })
|
79
|
+
ass_file
|
80
|
+
end
|
81
|
+
end
|
data/lib/vtt2ass/ass_file.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require_relative 'ass_line'
|
3
4
|
require_relative 'ass_style'
|
4
5
|
require_relative 'css_file'
|
@@ -7,104 +8,100 @@ require_relative 'css_rule'
|
|
7
8
|
##
|
8
9
|
# This class defines an ASS subtitle file.
|
9
10
|
class ASSFile
|
10
|
-
|
11
|
-
|
11
|
+
attr_reader :title, :width, :height
|
12
|
+
attr_accessor :ass_styles, :ass_lines
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
@events = [
|
36
|
-
'',
|
37
|
-
'[Events]',
|
38
|
-
'Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text'
|
39
|
-
]
|
40
|
-
@ass_styles = []
|
41
|
-
@ass_lines = []
|
42
|
-
end
|
14
|
+
##
|
15
|
+
# Creates a new ASSFile instance and assigns the default values of instance variables.
|
16
|
+
def initialize(title, width, height, css_file_path = nil)
|
17
|
+
@width = width
|
18
|
+
@height = height
|
19
|
+
@css_file = nil
|
20
|
+
@css_file = CSSFile.new(css_file_path) unless css_file_path.nil?
|
21
|
+
@header = <<~HEADER
|
22
|
+
[Script Info]
|
23
|
+
Title: #{title}
|
24
|
+
ScriptType: v4.00+
|
25
|
+
Collisions: Normal
|
26
|
+
PlayDepth: 0
|
27
|
+
PlayResX: #{@width}
|
28
|
+
PlayResY: #{@height}
|
29
|
+
WrapStyle: 0
|
30
|
+
ScaledBorderAndShadow: yes
|
31
|
+
|
32
|
+
[V4+ Styles]
|
33
|
+
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
|
34
|
+
HEADER
|
35
|
+
@events = <<~EVENTS
|
43
36
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
case property[:key]
|
68
|
-
when 'font-family'
|
69
|
-
font_family = property[:value].gsub('"', '').split(' ,').last
|
70
|
-
when 'font-size'
|
71
|
-
em_size = 1
|
72
|
-
#em_size = property[:value][0].eql? '.' ? "0#{property[:value]}" : property[:value]
|
73
|
-
if property[:value][0].eql? '.' then
|
74
|
-
em_size = "0#{property[:value]}".gsub('em', '').to_f
|
75
|
-
end
|
76
|
-
font_size = (fs * em_size).to_i
|
77
|
-
when 'color'
|
78
|
-
font_color = ASSStyle.convert_color(property[:value])
|
79
|
-
when 'font-weight'
|
80
|
-
if property[:value].eql? 'bold' then
|
81
|
-
is_bold = true
|
82
|
-
end
|
83
|
-
when 'font-style'
|
84
|
-
if property[:value].eql? 'italic' then
|
85
|
-
is_italic = true
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
@ass_styles.push(ASSStyle.new(line.style, line.params, font_family, font_size, font_color, is_bold, is_italic, line_offset, @width, @height))
|
92
|
-
end
|
37
|
+
[Events]
|
38
|
+
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
|
39
|
+
EVENTS
|
40
|
+
@ass_styles = []
|
41
|
+
@ass_lines = []
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# This method receives a VTTFile object and font arguments creates new ASSLine with the params of
|
46
|
+
# each VTTLine. All those ASSLine are stored in an array. It also creates an array of ASSStyle that
|
47
|
+
# will be used in the ASS style list.
|
48
|
+
def convert_vtt_to_ass(vtt_file, font_family, font_size, offset = { line: 0, caption: 0 }) # rubocop:disable Metrics/MethodLength
|
49
|
+
fs = font_size
|
50
|
+
vtt_file.lines.each do |line| # rubocop:disable Metrics/BlockLength
|
51
|
+
font_color = '&H00FFFFFF'
|
52
|
+
is_italic = false
|
53
|
+
is_bold = false
|
54
|
+
@ass_lines.push(ASSLine.new(line.style, line.time_start, line.time_end, line.text))
|
55
|
+
style_exists = false
|
56
|
+
@ass_styles.each do |style|
|
57
|
+
if style.style_name.eql? line.style
|
58
|
+
style_exists = true
|
59
|
+
break
|
93
60
|
end
|
94
|
-
|
61
|
+
end
|
62
|
+
next if style_exists
|
95
63
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
64
|
+
unless @css_file.nil?
|
65
|
+
css_rule = @css_file.find_rule(line.style)
|
66
|
+
css_rule&.properties&.each do |property|
|
67
|
+
case property[:key]
|
68
|
+
when 'font-family'
|
69
|
+
font_family = property[:value].gsub('"', '').split(' ,').last
|
70
|
+
when 'font-size'
|
71
|
+
em_size = 1
|
72
|
+
em_size = "0#{property[:value]}".gsub('em', '').to_f if property[:value][0].eql? '.'
|
73
|
+
font_size = (fs * em_size).to_i
|
74
|
+
when 'color'
|
75
|
+
font_color = ASSStyle.convert_color(property[:value])
|
76
|
+
when 'font-weight'
|
77
|
+
is_bold = true if property[:value].eql? 'bold'
|
78
|
+
when 'font-style'
|
79
|
+
is_italic = true if property[:value].eql? 'italic'
|
80
|
+
end
|
102
81
|
end
|
82
|
+
end
|
83
|
+
@ass_styles.push(
|
84
|
+
ASSStyle.new(
|
85
|
+
line.style, line.params,
|
86
|
+
font_family, font_size, font_color, is_bold, is_italic,
|
87
|
+
offset, @width, @height
|
88
|
+
)
|
89
|
+
)
|
103
90
|
end
|
91
|
+
end
|
104
92
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
93
|
+
##
|
94
|
+
# This method writes the content of the ASSFile object into a file path that is provided.
|
95
|
+
def write_to_file(file_path)
|
96
|
+
File.open(file_path, 'w') do |line|
|
97
|
+
line.print "\ufeff"
|
98
|
+
line.puts to_s
|
109
99
|
end
|
110
|
-
end
|
100
|
+
end
|
101
|
+
|
102
|
+
##
|
103
|
+
# This method concatenates the object data in the right order for a string output.
|
104
|
+
def to_s
|
105
|
+
"#{@header}#{@ass_styles.join("\n")}#{@events}#{@ass_lines.join("\n")}"
|
106
|
+
end
|
107
|
+
end
|
data/lib/vtt2ass/ass_line.rb
CHANGED
@@ -1,94 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'htmlentities'
|
2
4
|
|
3
5
|
##
|
4
6
|
# This class defines an ASS subtile line.
|
5
7
|
class ASSLine
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
8
|
+
attr_reader :style, :time_start, :time_end, :text
|
9
|
+
|
10
|
+
##
|
11
|
+
# This method creates an instance of an ASSLine.
|
12
|
+
#
|
13
|
+
# * Requires a +style+ name as input.
|
14
|
+
# * Requires +time_start+, a VTT formatted timestamp as input.
|
15
|
+
# * Requires +time_start+, a VTT formatted timestamp as input.
|
16
|
+
# * Requires +text+, a VTT formatted string as input.
|
17
|
+
def initialize(style, time_start, time_end, text)
|
18
|
+
@style = style
|
19
|
+
@time_start = convert_time(time_start)
|
20
|
+
@time_end = convert_time(time_end)
|
21
|
+
@text = convert_to_ass_text(text)
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# This method assigns the object values and outputs an ASS dialogue line.
|
26
|
+
def to_s
|
27
|
+
"Dialogue: 0,#{@time_start},#{@time_end},#{@style},,0,0,0,,#{@text}"
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# This method replaces characters and tags to ASS compatible characters and tags.
|
32
|
+
#
|
33
|
+
# * Requires +text+, a string of VTT formated text as input.
|
34
|
+
def convert_to_ass_text(text)
|
35
|
+
decoder = HTMLEntities.new
|
36
|
+
text =
|
37
|
+
text
|
38
|
+
.gsub(/\r/, '')
|
39
|
+
.gsub(/\n/, '\\N')
|
40
|
+
.gsub(/\\n/, '\\N')
|
41
|
+
.gsub(/\\N +/, '\\N')
|
42
|
+
.gsub(/ +\\N/, '\\N')
|
43
|
+
.gsub(/(\\N)+/, '\\N')
|
44
|
+
.gsub(%r{<b[^>]*>([^<]*)</b>}) { |_s| "{\\b1}#{Regexp.last_match(1)}{\\b0}" }
|
45
|
+
.gsub(%r{<i[^>]*>([^<]*)</i>}) { |_s| "{\\i1}#{Regexp.last_match(1)}{\\i0}" }
|
46
|
+
.gsub(%r{<u[^>]*>([^<]*)</u>}) { |_s| "{\\u1}#{Regexp.last_match(1)}{\\u0}" }
|
47
|
+
.gsub(%r{<c[^>]*>([^<]*)</c>}) { |_s| Regexp.last_match(1) }
|
48
|
+
.gsub(/<[^>]>/, '')
|
49
|
+
.gsub(/\\N$/, '')
|
50
|
+
.gsub(/ +$/, '')
|
51
|
+
decoder.decode(text)
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# This method validates the time format and sends the matching time to be converted
|
56
|
+
#
|
57
|
+
# * Requires +str+, a VTT formatted time string.
|
58
|
+
def convert_time(time)
|
59
|
+
matched_time = time.match(/([\d:]*)\.?(\d*)/)
|
60
|
+
to_subs_time(matched_time[0])
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# This method converts time from VTT format to the ASS format.
|
65
|
+
#
|
66
|
+
# * Requires +str+, a VTT formatted time string.
|
67
|
+
def to_subs_time(str)
|
68
|
+
n = []
|
69
|
+
x = str.split(/[:.]/).map(&:to_i)
|
70
|
+
|
71
|
+
ms_len = 2
|
72
|
+
h_len = 1
|
73
|
+
|
74
|
+
x[3] = "0.#{x[3].to_s.rjust(3, '0')}"
|
75
|
+
sx = (x[0] * 60 * 60) + (x[1] * 60) + x[2] + x[3].to_f
|
76
|
+
sx = format('%.2f', sx).split('.')
|
77
|
+
|
78
|
+
n.unshift(pad_time_num('.', sx[1], ms_len))
|
79
|
+
sx = sx[0].to_f
|
21
80
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
return "Dialogue: 0,#{@time_start},#{@time_end},#{@style},,0,0,0,,#{@text}"
|
26
|
-
end
|
81
|
+
n.unshift(pad_time_num(':', (sx % 60).to_i, 2))
|
82
|
+
n.unshift(pad_time_num(':', (sx / 60).floor % 60, 2))
|
83
|
+
n.unshift(pad_time_num('', (sx / 3600).floor % 60, h_len))
|
27
84
|
|
28
|
-
|
29
|
-
|
30
|
-
#
|
31
|
-
# * Requires +text+, a string of VTT formated text as input.
|
32
|
-
def convert_to_ass_text(text)
|
33
|
-
decoder = HTMLEntities.new()
|
34
|
-
text = text
|
35
|
-
.gsub(/\r/, '')
|
36
|
-
.gsub(/\n/, '\\N')
|
37
|
-
.gsub(/\\n/, '\\N')
|
38
|
-
.gsub(/\\N +/, '\\N')
|
39
|
-
.gsub(/ +\\N/, '\\N')
|
40
|
-
.gsub(/(\\N)+/, '\\N')
|
41
|
-
.gsub(/<b[^>]*>([^<]*)<\/b>/) { |s| "{\\b1}#{$1}{\\b0}" }
|
42
|
-
.gsub(/<i[^>]*>([^<]*)<\/i>/) { |s| "{\\i1}#{$1}{\\i0}" }
|
43
|
-
.gsub(/<u[^>]*>([^<]*)<\/u>/) { |s| "{\\u1}#{$1}{\\u0}" }
|
44
|
-
.gsub(/<c[^>]*>([^<]*)<\/c>/) { |s| $1 }
|
45
|
-
.gsub(/<[^>]>/, '')
|
46
|
-
.gsub(/\\N$/, '')
|
47
|
-
.gsub(/ +$/, '')
|
48
|
-
return decoder.decode(text)
|
49
|
-
end
|
85
|
+
n.join
|
86
|
+
end
|
50
87
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
# This method converts time from VTT format to the ASS format.
|
62
|
-
#
|
63
|
-
# * Requires +str+, a VTT formatted time string.
|
64
|
-
def to_subs_time(str)
|
65
|
-
n = []
|
66
|
-
x = str.split(/[:.]/).map { |x| x.to_i }
|
67
|
-
|
68
|
-
msLen = 2
|
69
|
-
hLen = 1
|
70
|
-
|
71
|
-
x[3] = '0.' + (x[3].to_s).rjust(3, '0')
|
72
|
-
sx = x[0]*60*60 + x[1]*60 + x[2] + x[3].to_f
|
73
|
-
sx = ("%.2f" % sx).split('.')
|
74
|
-
|
75
|
-
n.unshift(pad_time_num('.', sx[1], msLen))
|
76
|
-
sx = sx[0].to_f
|
77
|
-
|
78
|
-
n.unshift(pad_time_num(':', (sx % 60).to_i, 2))
|
79
|
-
n.unshift(pad_time_num(':', (sx / 60).floor % 60, 2))
|
80
|
-
n.unshift(pad_time_num('', (sx / 3600).floor % 60, hLen))
|
81
|
-
|
82
|
-
return n.join('')
|
83
|
-
end
|
84
|
-
|
85
|
-
##
|
86
|
-
# This method pads text so that time numbers are a fixed number of digit.
|
87
|
-
#
|
88
|
-
# * Requires +sep+, a string separator.
|
89
|
-
# * Requires +input+, an integer.
|
90
|
-
# * Requires +pad+, an integer for the number of digits to be padded.
|
91
|
-
def pad_time_num(sep, input, pad)
|
92
|
-
return sep + (input.to_s).rjust(pad, '0')
|
93
|
-
end
|
94
|
-
end
|
88
|
+
##
|
89
|
+
# This method pads text so that time numbers are a fixed number of digit.
|
90
|
+
#
|
91
|
+
# * Requires +sep+, a string separator.
|
92
|
+
# * Requires +input+, an integer.
|
93
|
+
# * Requires +pad+, an integer for the number of digits to be padded.
|
94
|
+
def pad_time_num(sep, input, pad)
|
95
|
+
sep + input.to_s.rjust(pad, '0')
|
96
|
+
end
|
97
|
+
end
|