vtt2ass 0.2.4 → 0.2.10
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/Gemfile +1 -0
- data/README.md +2 -1
- data/doc/ASSFile.html +546 -29
- data/doc/ASSLine.html +940 -0
- data/doc/ASSStyle.html +23 -147
- data/doc/ASSStyleParams.html +819 -0
- data/doc/Application.html +58 -149
- data/doc/VTTFile.html +454 -0
- data/doc/VTTLine.html +700 -0
- data/doc/Vtt2ass.html +61 -29
- data/doc/_index.html +12 -17
- data/doc/class_list.html +1 -1
- data/doc/file.README.html +35 -8
- data/doc/index.html +35 -8
- data/doc/method_list.html +177 -49
- data/doc/top-level-namespace.html +3 -3
- data/lib/vtt2ass.rb +11 -8
- data/lib/vtt2ass/ASSFile.rb +41 -11
- data/lib/vtt2ass/{ASSSubtitle.rb → ASSLine.rb} +9 -7
- data/lib/vtt2ass/ASSStyle.rb +4 -64
- data/lib/vtt2ass/ASSStyleParams.rb +87 -0
- data/lib/vtt2ass/Application.rb +19 -53
- data/lib/vtt2ass/VTTFile.rb +42 -0
- data/lib/vtt2ass/{VTTSubtitle.rb → VTTLine.rb} +2 -2
- data/lib/vtt2ass/version.rb +6 -1
- data/vtt2ass.gemspec +7 -0
- metadata +81 -5
@@ -86,7 +86,7 @@
|
|
86
86
|
|
87
87
|
|
88
88
|
|
89
|
-
<strong class="classes">Classes:</strong> <span class='object_link'><a href="ASSFile.html" title="ASSFile (class)">ASSFile</a></span>, <span class='object_link'><a href="ASSStyle.html" title="ASSStyle (class)">ASSStyle</a></span>, <span class='object_link'><a href="
|
89
|
+
<strong class="classes">Classes:</strong> <span class='object_link'><a href="ASSFile.html" title="ASSFile (class)">ASSFile</a></span>, <span class='object_link'><a href="ASSLine.html" title="ASSLine (class)">ASSLine</a></span>, <span class='object_link'><a href="ASSStyle.html" title="ASSStyle (class)">ASSStyle</a></span>, <span class='object_link'><a href="ASSStyleParams.html" title="ASSStyleParams (class)">ASSStyleParams</a></span>, <span class='object_link'><a href="Application.html" title="Application (class)">Application</a></span>, <span class='object_link'><a href="VTTFile.html" title="VTTFile (class)">VTTFile</a></span>, <span class='object_link'><a href="VTTLine.html" title="VTTLine (class)">VTTLine</a></span>
|
90
90
|
|
91
91
|
|
92
92
|
</p>
|
@@ -102,9 +102,9 @@
|
|
102
102
|
</div>
|
103
103
|
|
104
104
|
<div id="footer">
|
105
|
-
Generated on
|
105
|
+
Generated on Tue Mar 23 21:07:02 2021 by
|
106
106
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
107
|
-
0.9.26 (ruby-
|
107
|
+
0.9.26 (ruby-3.0.0).
|
108
108
|
</div>
|
109
109
|
|
110
110
|
</div>
|
data/lib/vtt2ass.rb
CHANGED
@@ -17,17 +17,20 @@ module Vtt2ass
|
|
17
17
|
opts.banner = "Usage: vtt2ass [options]"
|
18
18
|
opts.separator ""
|
19
19
|
opts.separator "Specific options:"
|
20
|
-
opts.on("-i", "--input PATH", "Specify a custom input file or directory (default: './')") do |
|
21
|
-
options[:input] =
|
20
|
+
opts.on("-i", "--input PATH", "Specify a custom input file or directory (default: './')") do |file_path|
|
21
|
+
options[:input] = file_path
|
22
22
|
end
|
23
|
-
opts.on("-o", "--output PATH", "Specify a custom output directory (default: './')") do |
|
24
|
-
options[:output] =
|
23
|
+
opts.on("-o", "--output PATH", "Specify a custom output directory (default: './')") do |file_path|
|
24
|
+
options[:output] = file_path
|
25
25
|
end
|
26
|
-
opts.on("-f", "--font-family
|
27
|
-
options[:font_family] =
|
26
|
+
opts.on("-f", "--font-family FONT", String, "Specify a font family for the subtitles (default: 'Open Sans Semibold')") do |font_family|
|
27
|
+
options[:font_family] = font_family
|
28
28
|
end
|
29
|
-
opts.on("-s", "--font-size SIZE", Integer, "Specify a font size for the subtitles (default: 52)") do |
|
30
|
-
options[:font_size] =
|
29
|
+
opts.on("-s", "--font-size SIZE", Integer, "Specify a font size for the subtitles (default: 52)") do |font_size|
|
30
|
+
options[:font_size] = font_size
|
31
|
+
end
|
32
|
+
opts.on("-t", "--title TITLE", String, "Specify a title for you file. If the input is a directory, all files will share the same title.") do |title|
|
33
|
+
options[:title] = title
|
31
34
|
end
|
32
35
|
opts.on("-v", "--version", "Show version") do
|
33
36
|
puts Vtt2ass::VERSION
|
data/lib/vtt2ass/ASSFile.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
|
+
# Relative imports
|
2
|
+
require_relative 'ASSLine'
|
3
|
+
require_relative 'ASSStyle'
|
4
|
+
|
1
5
|
##
|
2
|
-
# This class defines
|
6
|
+
# This class defines an ASS subtitle file.
|
3
7
|
class ASSFile
|
8
|
+
attr_reader :title, :width, :height
|
9
|
+
attr_accessor :ass_styles, :ass_lines
|
4
10
|
|
5
11
|
##
|
6
|
-
#
|
7
|
-
|
8
|
-
# * Requires +ass_styles+, a list of ASSStyle as input.
|
9
|
-
# * Requires +ass_subs+, a list of ASSSubtitles as input.
|
10
|
-
# * Requires a video +width+ as input.
|
11
|
-
# * Requires a video +height+ as input.
|
12
|
-
def initialize(title, ass_styles, ass_subs, width, height)
|
12
|
+
# Creates a new ASSFile instance and assigns the default values of instance variables.
|
13
|
+
def initialize(title, width, height)
|
13
14
|
@width = width
|
14
15
|
@height = height
|
15
16
|
@header = [
|
@@ -26,18 +27,47 @@ class ASSFile
|
|
26
27
|
'[V4+ Styles]',
|
27
28
|
'Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding'
|
28
29
|
]
|
29
|
-
@ass_styles = ass_styles
|
30
30
|
@events = [
|
31
31
|
'',
|
32
32
|
'[Events]',
|
33
33
|
'Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text'
|
34
34
|
]
|
35
|
-
@
|
35
|
+
@ass_styles = []
|
36
|
+
@ass_lines = []
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# This method receives a VTTFile object and font arguments creates new ASSLine with the params of
|
41
|
+
# each VTTLine. All those ASSLine are stored in an array. It also creates an array of ASSStyle that
|
42
|
+
# will be used in the ASS style list.
|
43
|
+
def convertVTTtoASS(vtt_file, font_family, font_size)
|
44
|
+
vtt_file.lines.each do |line|
|
45
|
+
@ass_lines.push(ASSLine.new(line.style, line.time_start, line.time_end, line.text))
|
46
|
+
style_exists = false
|
47
|
+
@ass_styles.each do |style|
|
48
|
+
if (style.style_name == line.style) then
|
49
|
+
style_exists = true
|
50
|
+
break
|
51
|
+
end
|
52
|
+
end
|
53
|
+
if not style_exists then
|
54
|
+
@ass_styles.push(ASSStyle.new(line.style, line.params, font_family, font_size, @width, @height))
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# This method writes the content of the ASSFile object into a file path that is provided.
|
61
|
+
def writeToFile(file_path)
|
62
|
+
File.open(file_path, 'w') do |line|
|
63
|
+
line.print "\ufeff"
|
64
|
+
line.puts self.to_s
|
65
|
+
end
|
36
66
|
end
|
37
67
|
|
38
68
|
##
|
39
69
|
# This method concatenates the object data in the right order for a string output.
|
40
70
|
def to_s
|
41
|
-
return @header + @ass_styles + @events + @
|
71
|
+
return @header + @ass_styles + @events + @ass_lines
|
42
72
|
end
|
43
73
|
end
|
@@ -1,20 +1,21 @@
|
|
1
|
+
require 'htmlentities'
|
2
|
+
|
1
3
|
##
|
2
4
|
# This class defines an ASS subtile line.
|
3
|
-
class
|
4
|
-
attr_reader :style, :time_start, :time_end, :
|
5
|
+
class ASSLine
|
6
|
+
attr_reader :style, :time_start, :time_end, :text
|
5
7
|
|
6
8
|
##
|
7
|
-
# This method creates an instance of an
|
9
|
+
# This method creates an instance of an ASSLine.
|
8
10
|
#
|
9
11
|
# * Requires a +style+ name as input.
|
10
12
|
# * Requires +time_start+, a VTT formatted timestamp as input.
|
11
13
|
# * Requires +time_start+, a VTT formatted timestamp as input.
|
12
14
|
# * Requires +text+, a VTT formatted string as input.
|
13
|
-
def initialize(style, time_start, time_end,
|
15
|
+
def initialize(style, time_start, time_end, text)
|
14
16
|
@style = style
|
15
17
|
@time_start = convertTime(time_start)
|
16
18
|
@time_end = convertTime(time_end)
|
17
|
-
@params = params
|
18
19
|
@text = convertToAssText(text)
|
19
20
|
end
|
20
21
|
|
@@ -29,6 +30,7 @@ class ASSSubtitle
|
|
29
30
|
#
|
30
31
|
# * Requires +text+, a string of VTT formated text as input.
|
31
32
|
def convertToAssText(text)
|
33
|
+
decoder = HTMLEntities.new()
|
32
34
|
text = text
|
33
35
|
.gsub(/\r/, '')
|
34
36
|
.gsub(/\n/, '\\N')
|
@@ -43,7 +45,7 @@ class ASSSubtitle
|
|
43
45
|
.gsub(/<[^>]>/, '')
|
44
46
|
.gsub(/\\N$/, '')
|
45
47
|
.gsub(/ +$/, '')
|
46
|
-
return text
|
48
|
+
return decoder.decode(text)
|
47
49
|
end
|
48
50
|
|
49
51
|
##
|
@@ -81,7 +83,7 @@ class ASSSubtitle
|
|
81
83
|
end
|
82
84
|
|
83
85
|
##
|
84
|
-
#
|
86
|
+
# This method pads text so that time numbers are a fixed number of digit.
|
85
87
|
#
|
86
88
|
# * Requires +sep+, a string separator.
|
87
89
|
# * Requires +input+, an integer.
|
data/lib/vtt2ass/ASSStyle.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
# Relative imports
|
2
|
+
require_relative 'ASSStyleParams'
|
3
|
+
|
1
4
|
##
|
2
5
|
# This class defines an ASS style that can be applied on a subtitle line.
|
3
6
|
class ASSStyle
|
@@ -16,72 +19,9 @@ class ASSStyle
|
|
16
19
|
@font_family = font_family
|
17
20
|
@font_size = font_size
|
18
21
|
@style_name = style_name
|
19
|
-
@s_params =
|
22
|
+
@s_params = ASSStyleParams.new(params, width, height)
|
20
23
|
end
|
21
24
|
|
22
|
-
class StyleParams
|
23
|
-
attr_reader :horizontal_margin, :vertical_margin, :alignment
|
24
|
-
def initialize(params, width, height)
|
25
|
-
(params.split(' ').map { |p| p.split(':') }).each do |p|
|
26
|
-
case p[0]
|
27
|
-
when 'position'
|
28
|
-
@position = p[1].gsub(/%/, '').to_i
|
29
|
-
when 'line'
|
30
|
-
@line = p[1].gsub(/%/, '').to_i
|
31
|
-
@line = @line == -1 ? 100 : @line;
|
32
|
-
when 'alignment'
|
33
|
-
@align = p[1]
|
34
|
-
end
|
35
|
-
end
|
36
|
-
createAlignment
|
37
|
-
createHorizontalMargin(width)
|
38
|
-
createVerticalMargin(height)
|
39
|
-
end
|
40
|
-
def createAlignment
|
41
|
-
if (defined?(@line) and not defined?(@position)) then
|
42
|
-
if (defined?(@align)) then
|
43
|
-
case @align
|
44
|
-
when 'left'
|
45
|
-
when 'start'
|
46
|
-
@alignment = @line >= 50 ? 1 : 7
|
47
|
-
when 'right'
|
48
|
-
when 'end'
|
49
|
-
@alignment = @line >= 50 ? 3 : 9
|
50
|
-
when 'center'
|
51
|
-
when 'middle'
|
52
|
-
@alignment = @line >= 50 ? 2 : 8
|
53
|
-
end
|
54
|
-
else
|
55
|
-
@alignment = @line >= 50 ? 2 : 8 # If position is higher than 50% align to bottom center, else align to top center
|
56
|
-
end
|
57
|
-
elsif (defined?(@line) and defined?(@position)) then
|
58
|
-
@alignment = 1
|
59
|
-
else
|
60
|
-
@alignment = 2
|
61
|
-
end
|
62
|
-
end
|
63
|
-
def createHorizontalMargin(width)
|
64
|
-
steps = (width / 100).to_i
|
65
|
-
if defined?(@position) then
|
66
|
-
@horizontal_margin = @position * steps
|
67
|
-
else
|
68
|
-
@horizontal_margin = 0
|
69
|
-
end
|
70
|
-
end
|
71
|
-
def createVerticalMargin(height)
|
72
|
-
steps = (height / 100).to_i
|
73
|
-
if defined?(@line) then
|
74
|
-
if (@alignment == 1) then
|
75
|
-
@vertical_margin = (100 - @line) * steps
|
76
|
-
else
|
77
|
-
@vertical_margin = @line >= 50 ? (100 - @line) * steps : @line * steps
|
78
|
-
end
|
79
|
-
else
|
80
|
-
@vertical_margin = 50
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
25
|
##
|
86
26
|
# This method assigns the object values to an ASS style line and outputs it.
|
87
27
|
def to_s
|
@@ -0,0 +1,87 @@
|
|
1
|
+
##
|
2
|
+
# This class defines the ASS style parameters from VTT cue settings.
|
3
|
+
class ASSStyleParams
|
4
|
+
attr_reader :horizontal_margin, :vertical_margin, :alignment, :align
|
5
|
+
|
6
|
+
##
|
7
|
+
# Creates an instance of ASSStyleParams
|
8
|
+
# It takes VTT style arguments and assign them to their respectful instance variable.
|
9
|
+
# It calls methods to create ASS values from the VTT cue settings.
|
10
|
+
def initialize(params, width, height)
|
11
|
+
(params.split(' ').map { |p| p.split(':') }).each do |p|
|
12
|
+
case p[0]
|
13
|
+
when 'position'
|
14
|
+
@position = p[1].gsub(/%/, '').to_i
|
15
|
+
when 'line'
|
16
|
+
@line = p[1].gsub(/%/, '').to_i
|
17
|
+
@line = @line == -1 ? 100 : @line;
|
18
|
+
when 'align'
|
19
|
+
@align = p[1].chomp
|
20
|
+
end
|
21
|
+
end
|
22
|
+
createAlignment()
|
23
|
+
createHorizontalMargin(width)
|
24
|
+
createVerticalMargin(height)
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# This method decides the alignement value in a 9 position grid based of the
|
29
|
+
# values in cue settings "align" and "line".
|
30
|
+
def createAlignment()
|
31
|
+
if (defined?(@line) and not defined?(@position)) then
|
32
|
+
if (defined?(@align)) then
|
33
|
+
case @align
|
34
|
+
when 'left', 'start'
|
35
|
+
@alignment = @line >= 50 ? 1 : 7
|
36
|
+
when 'right', 'end'
|
37
|
+
@alignment = @line >= 50 ? 3 : 9
|
38
|
+
when 'center', 'middle'
|
39
|
+
@alignment = @line >= 50 ? 2 : 8
|
40
|
+
end
|
41
|
+
else
|
42
|
+
@alignment = @line >= 50 ? 2 : 8 # If position is higher than 50% align to bottom center, else align to top center
|
43
|
+
end
|
44
|
+
elsif (defined?(@line) and defined?(@position)) then
|
45
|
+
@alignment = 1
|
46
|
+
else
|
47
|
+
case @align
|
48
|
+
when 'left', 'start'
|
49
|
+
@alignment = 1
|
50
|
+
when 'right', 'end'
|
51
|
+
@alignment = 3
|
52
|
+
when 'center', 'middle'
|
53
|
+
@alignment = 2
|
54
|
+
else
|
55
|
+
@alignment = 2
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# This method calculates the horizontal margin in px between the alignement position and
|
62
|
+
# and the content displayed by using the "position" cue setting.
|
63
|
+
def createHorizontalMargin(width)
|
64
|
+
steps = (width / 100).to_i
|
65
|
+
if defined?(@position) then
|
66
|
+
@horizontal_margin = @position * steps
|
67
|
+
else
|
68
|
+
@horizontal_margin = 0
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# This method calculates the vertical margin in px between the alignement position and
|
74
|
+
# and the content displayed by using the "line" cue setting.
|
75
|
+
def createVerticalMargin(height)
|
76
|
+
steps = (height / 100).to_i
|
77
|
+
if defined?(@line) then
|
78
|
+
if (@alignment == 1) then
|
79
|
+
@vertical_margin = (100 - @line) * steps
|
80
|
+
else
|
81
|
+
@vertical_margin = @line >= 50 ? (100 - @line) * steps : @line * steps
|
82
|
+
end
|
83
|
+
else
|
84
|
+
@vertical_margin = 50
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/lib/vtt2ass/Application.rb
CHANGED
@@ -2,9 +2,7 @@
|
|
2
2
|
require 'os'
|
3
3
|
|
4
4
|
# Relative imports
|
5
|
-
require_relative '
|
6
|
-
require_relative 'ASSSubtitle'
|
7
|
-
require_relative 'ASSStyle'
|
5
|
+
require_relative 'VTTFile'
|
8
6
|
require_relative 'ASSFile'
|
9
7
|
|
10
8
|
##
|
@@ -15,12 +13,15 @@ class Application
|
|
15
13
|
# Creates a new Application instance.
|
16
14
|
# It receives +options+ that can define the input and output directories.
|
17
15
|
def initialize(options)
|
18
|
-
@input = options[:input] ? options[:input].gsub('\\', '/') : "
|
19
|
-
@output = options[:output] ? options[:output].gsub('\\', '/') : "
|
16
|
+
@input = options[:input] ? options[:input].gsub('\\', '/').delete_suffix('/') : "."
|
17
|
+
@output = options[:output] ? options[:output].gsub('\\', '/').delete_suffix('/') : "."
|
20
18
|
@width = 1920
|
21
19
|
@height = 1080
|
22
20
|
@font_family = options[:font_family] ? options[:font_family] : 'Open Sans Semibold'
|
23
21
|
@font_size = options[:font_size] ? options[:font_size] : 52
|
22
|
+
if options[:title] then
|
23
|
+
@title = options[:title]
|
24
|
+
end
|
24
25
|
end
|
25
26
|
|
26
27
|
##
|
@@ -30,62 +31,27 @@ class Application
|
|
30
31
|
def start
|
31
32
|
if File.directory?(@input) then
|
32
33
|
Dir["#{@input}/*.vtt"].each do |file_path|
|
33
|
-
|
34
|
+
vtt_to_ass(file_path).writeToFile(@output + '/' + File.basename(file_path).gsub('.vtt', '.ass'))
|
34
35
|
end
|
35
36
|
elsif File.file?(@input) then
|
36
|
-
|
37
|
+
vtt_to_ass(@input).writeToFile(@output + '/' + File.basename(@input).gsub('.vtt', '.ass'))
|
37
38
|
else
|
38
39
|
puts 'Error: input file or directory does not exist.'
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
42
|
-
def writeFile(file_path)
|
43
|
-
file_name = File.basename(file_path).gsub('.vtt', '.ass')
|
44
|
-
File.open("#{@output}/" + file_name, 'w') do |line|
|
45
|
-
line.print "\ufeff"
|
46
|
-
line.puts convertFileToASS(file_path)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
43
|
##
|
51
|
-
# This method
|
52
|
-
#
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
end
|
63
|
-
list_parapraph.shift
|
64
|
-
return list_parapraph
|
44
|
+
# This method creates a new VTTFile object from the file path provided and convert its content
|
45
|
+
# inside a new ASSFile object.
|
46
|
+
def vtt_to_ass(file_path)
|
47
|
+
vtt_file = VTTFile.new(file_path)
|
48
|
+
ass_file = ASSFile.new(
|
49
|
+
(defined?(@title) ? @title : File.basename(file_path).gsub('.vtt', '')),
|
50
|
+
@width,
|
51
|
+
@height
|
52
|
+
)
|
53
|
+
ass_file.convertVTTtoASS(vtt_file, @font_family, @font_size)
|
54
|
+
return ass_file
|
65
55
|
end
|
66
56
|
|
67
|
-
##
|
68
|
-
# This method gets the list of paragraphs from the VTT file and creates lists of ASSSubtitle and ASSStyles objects from them.
|
69
|
-
# Those lists are given a new ASSFile object to generate the file content.
|
70
|
-
# It requires a +file_path+ as input.
|
71
|
-
# It outputs an ASSFile object.
|
72
|
-
def convertFileToASS(file_path)
|
73
|
-
vtt_subs = readVTTFile(file_path)
|
74
|
-
ass_subs = []
|
75
|
-
ass_styles = []
|
76
|
-
vtt_subs.each do |sub|
|
77
|
-
ass_subs.push(ASSSubtitle.new(sub.style, sub.time_start, sub.time_end, sub.params, sub.text))
|
78
|
-
style_exists = false
|
79
|
-
ass_styles.each do |style|
|
80
|
-
if (style.style_name == sub.style) then
|
81
|
-
style_exists = true
|
82
|
-
break
|
83
|
-
end
|
84
|
-
end
|
85
|
-
if not style_exists then
|
86
|
-
ass_styles.push(ASSStyle.new(sub.style, sub.params, @font_family, @font_size, @width, @height))
|
87
|
-
end
|
88
|
-
end
|
89
|
-
return ASSFile.new(File.basename(file_path).gsub('.vtt', ''), ass_styles, ass_subs, @width, @height).to_s
|
90
|
-
end
|
91
57
|
end
|