vtt2ass 0.3.2 → 0.3.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +19 -0
- data/Gemfile +2 -0
- data/README.md +70 -10
- data/Rakefile +8 -6
- data/bin/vtt2ass +2 -1
- data/exe/vtt2ass +2 -1
- data/lib/vtt2ass/application.rb +78 -0
- data/lib/vtt2ass/ass_file.rb +106 -0
- data/lib/vtt2ass/ass_line.rb +97 -0
- data/lib/vtt2ass/ass_style.rb +51 -0
- data/lib/vtt2ass/ass_style_params.rb +108 -0
- data/lib/vtt2ass/css_file.rb +38 -0
- data/lib/vtt2ass/css_rule.rb +30 -0
- data/lib/vtt2ass/validator.rb +14 -0
- data/lib/vtt2ass/version.rb +3 -1
- data/lib/vtt2ass/vtt_file.rb +58 -0
- data/lib/vtt2ass/vtt_line.rb +44 -0
- data/lib/vtt2ass.rb +52 -22
- data/vtt2ass.gemspec +19 -16
- metadata +32 -30
- data/lib/vtt2ass/ASSFile.rb +0 -110
- data/lib/vtt2ass/ASSLine.rb +0 -94
- data/lib/vtt2ass/ASSStyle.rb +0 -48
- data/lib/vtt2ass/ASSStyleParams.rb +0 -87
- data/lib/vtt2ass/Application.rb +0 -68
- data/lib/vtt2ass/CSSFile.rb +0 -36
- data/lib/vtt2ass/CSSRule.rb +0 -22
- data/lib/vtt2ass/VTTFile.rb +0 -58
- data/lib/vtt2ass/VTTLine.rb +0 -44
- data/lib/vtt2ass/Validator.rb +0 -10
data/lib/vtt2ass/ASSStyle.rb
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
# Relative imports
|
2
|
-
require_relative 'ASSStyleParams'
|
3
|
-
require_relative 'Validator'
|
4
|
-
require 'redgreenblue'
|
5
|
-
|
6
|
-
##
|
7
|
-
# This class defines an ASS style that can be applied on a subtitle line.
|
8
|
-
class ASSStyle
|
9
|
-
attr_reader :style_name
|
10
|
-
|
11
|
-
##
|
12
|
-
# This method creates and instance of an ASSStyle.
|
13
|
-
#
|
14
|
-
# * Requires +style_name+, a string name for the style as input.
|
15
|
-
# * Requires +params+, a string of VTT styling as input.
|
16
|
-
# * Requires a video +width+ as input.
|
17
|
-
# * Requires a video +height+ as input.
|
18
|
-
def initialize(style_name, params, font_family, font_size, font_color, is_bold, is_italic, line_offset, width, height)
|
19
|
-
@width = width
|
20
|
-
@height = height
|
21
|
-
@font_family = font_family
|
22
|
-
@font_size = font_size
|
23
|
-
@font_color = font_color
|
24
|
-
@style_name = style_name
|
25
|
-
@s_params = ASSStyleParams.new(params, width, height)
|
26
|
-
if style_name.eql? 'MainTop' then
|
27
|
-
@s_params.vertical_margin = 50
|
28
|
-
end
|
29
|
-
if style_name.include? 'Subtitle' then
|
30
|
-
@s_params.vertical_margin -= line_offset
|
31
|
-
end
|
32
|
-
@is_italic = is_italic
|
33
|
-
@is_bold = is_bold
|
34
|
-
end
|
35
|
-
|
36
|
-
##
|
37
|
-
# This method assigns the object values to an ASS style line and outputs it.
|
38
|
-
def to_s
|
39
|
-
# Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
|
40
|
-
return "Style: #{@style_name},#{@font_family},#{@font_size},#{@font_color},&H000000FF,&H00020713,&H00000000,#{@is_bold ? '-1' : '0'},#{@is_italic ? '-1' : '0'},0,0,100,100,0,0,1,2.0,2.0,#{@s_params.alignment},#{@s_params.horizontal_margin},0,#{@s_params.vertical_margin},1"
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.convert_color(color_value)
|
44
|
-
color_value.gsub!('#', '')
|
45
|
-
color = Validator.hex?(color_value) ? RGB.hex(color_value) : RGB.css(color_value)
|
46
|
-
return ("&H00%02x%02x%02x" % [color.b, color.g, color.r]).upcase
|
47
|
-
end
|
48
|
-
end
|
@@ -1,87 +0,0 @@
|
|
1
|
-
##
|
2
|
-
# This class defines the ASS style parameters from VTT cue settings.
|
3
|
-
class ASSStyleParams
|
4
|
-
attr_accessor :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
DELETED
@@ -1,68 +0,0 @@
|
|
1
|
-
# Relative imports
|
2
|
-
require_relative 'VTTFile'
|
3
|
-
require_relative 'ASSFile'
|
4
|
-
|
5
|
-
##
|
6
|
-
# Main application class that manages all the operations.
|
7
|
-
class Application
|
8
|
-
|
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
|
-
@input = input ? input.gsub('\\', '/').delete_suffix('/') : "."
|
14
|
-
@output = options[:output] ? options[:output].gsub('\\', '/').delete_suffix('/') : nil
|
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('\\', '/')
|
25
|
-
end
|
26
|
-
@line_offset = options[:line_offset]
|
27
|
-
end
|
28
|
-
|
29
|
-
##
|
30
|
-
# This method starts the application process.
|
31
|
-
# It sends the file_paths of VTT files in the input directory to convertFileToASS method
|
32
|
-
# and outputs the resulting ASS format to a new file.
|
33
|
-
def start
|
34
|
-
if File.directory?(@input) then
|
35
|
-
Dir["#{@input}/*.vtt"].each do |file_path|
|
36
|
-
convert(file_path)
|
37
|
-
end
|
38
|
-
elsif File.file?(@input) then
|
39
|
-
convert(@input)
|
40
|
-
else
|
41
|
-
puts 'Error: input file or directory does not exist.'
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def convert(input_path)
|
46
|
-
ass_file = vtt_to_ass(input_path)
|
47
|
-
if (not @output.nil?) then
|
48
|
-
ass_file.writeToFile(@output + '/' + File.basename(input_path).gsub('.vtt', '.ass'))
|
49
|
-
end
|
50
|
-
puts ass_file.to_s unless @quiet
|
51
|
-
end
|
52
|
-
|
53
|
-
##
|
54
|
-
# This method creates a new VTTFile object from the file path provided and convert its content
|
55
|
-
# inside a new ASSFile object.
|
56
|
-
def vtt_to_ass(file_path)
|
57
|
-
vtt_file = VTTFile.new(file_path, @width, @height)
|
58
|
-
ass_file = ASSFile.new(
|
59
|
-
(defined?(@title) ? @title : File.basename(file_path).gsub('.vtt', '')),
|
60
|
-
@width,
|
61
|
-
@height,
|
62
|
-
defined?(@css) ? @css : nil
|
63
|
-
)
|
64
|
-
ass_file.convertVTTtoASS(vtt_file, @font_family, @font_size, @line_offset)
|
65
|
-
return ass_file
|
66
|
-
end
|
67
|
-
|
68
|
-
end
|
data/lib/vtt2ass/CSSFile.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'css_parser'
|
2
|
-
require_relative 'CSSRule'
|
3
|
-
|
4
|
-
class CSSFile
|
5
|
-
attr_reader :rules
|
6
|
-
include CssParser
|
7
|
-
|
8
|
-
def initialize(file_path)
|
9
|
-
@file_path = file_path
|
10
|
-
parser = CssParser::Parser.new
|
11
|
-
parser.load_file!(file_path)
|
12
|
-
@rules = []
|
13
|
-
parser.each_selector do |selector, declarations, specificity|
|
14
|
-
css_obj = CSSRule.new(selector, declarations)
|
15
|
-
if not css_obj.name.empty? then
|
16
|
-
@rules.push(css_obj)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def find_rule(value)
|
22
|
-
return_rule = nil
|
23
|
-
@rules.each do |rule|
|
24
|
-
if rule.name == value then
|
25
|
-
return_rule = rule
|
26
|
-
break
|
27
|
-
end
|
28
|
-
end
|
29
|
-
return return_rule
|
30
|
-
end
|
31
|
-
|
32
|
-
def to_s
|
33
|
-
return @file_path
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|
data/lib/vtt2ass/CSSRule.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
class CSSRule
|
2
|
-
attr_reader :name, :properties
|
3
|
-
|
4
|
-
def initialize(selector, declarations)
|
5
|
-
@name = reduce_selector(selector)
|
6
|
-
@properties = []
|
7
|
-
declarations.split(/;\s?/).each do |dec|
|
8
|
-
temp = dec.split(/:\s?/)
|
9
|
-
@properties.push(
|
10
|
-
{ key: temp.first, value: temp.last}
|
11
|
-
)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def to_s
|
16
|
-
return "#{@name} #{@properties}"
|
17
|
-
end
|
18
|
-
|
19
|
-
def reduce_selector(selector)
|
20
|
-
return selector.to_s.gsub(/\.rmp-container>\.rmp-content>\.rmp-cc-area>\.rmp-cc-container>\.rmp-cc-display>\.rmp-cc-cue\s?\.?/, '')
|
21
|
-
end
|
22
|
-
end
|
data/lib/vtt2ass/VTTFile.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
# Relative imports
|
2
|
-
require_relative 'VTTLine'
|
3
|
-
|
4
|
-
##
|
5
|
-
# This class defines a VTT subtile file.
|
6
|
-
class VTTFile
|
7
|
-
attr_accessor :lines
|
8
|
-
|
9
|
-
##
|
10
|
-
# Creates a new VTTFile instance and assigns the default values of instance variables.
|
11
|
-
def initialize(file_path, width, height)
|
12
|
-
@title = File.basename(file_path).gsub('.vtt', '')
|
13
|
-
@lines = []
|
14
|
-
separator = determine_line_ending(file_path) ? "\n\n" : "\r\n\r\n"
|
15
|
-
count = 0
|
16
|
-
style_count = 1
|
17
|
-
File.foreach(file_path, separator) do |paragraph|
|
18
|
-
paragraph = paragraph.rstrip.gsub(/[\r\n]/, "\n")
|
19
|
-
if not paragraph.eql? "" then
|
20
|
-
vtt_line = VTTLine.new(paragraph, width, height)
|
21
|
-
if vtt_line.style.eql? 'Main' and
|
22
|
-
not vtt_line.params.to_s.empty? and
|
23
|
-
(not vtt_line.params.to_s.eql? 'align:middle' and
|
24
|
-
not vtt_line.params.to_s.eql? 'align:center') then
|
25
|
-
vtt_line.style = "Style#{style_count}"
|
26
|
-
style_count += 1
|
27
|
-
end
|
28
|
-
@lines.push(vtt_line)
|
29
|
-
count += 1
|
30
|
-
end
|
31
|
-
end
|
32
|
-
@lines.shift
|
33
|
-
end
|
34
|
-
|
35
|
-
##
|
36
|
-
# This method determines the line ending character to use as a separator.
|
37
|
-
def determine_line_ending(file_path)
|
38
|
-
File.open(file_path, 'r') do |file|
|
39
|
-
return file.readline[/\r?\n$/] == "\n"
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
##
|
44
|
-
# This method writes the content of the VTTFile object into a file path that is provided.
|
45
|
-
def writeToFile(file_path)
|
46
|
-
File.open(file_path, 'w') do |line|
|
47
|
-
line.print "\ufeff"
|
48
|
-
line.puts self.to_s
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
##
|
53
|
-
# This method concatenates the object data in the right order for a string output.
|
54
|
-
def to_s
|
55
|
-
return "WEBVTT\n\n\n" + @lines
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
data/lib/vtt2ass/VTTLine.rb
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
##
|
2
|
-
# This class defines a VTT subtile line.
|
3
|
-
class VTTLine
|
4
|
-
attr_accessor :style
|
5
|
-
attr_reader :time_start, :time_end, :params, :text
|
6
|
-
|
7
|
-
##
|
8
|
-
# This method creates an instance of an VTTLine.
|
9
|
-
#
|
10
|
-
# * Requires +paragraph+, a VTT formatted string as input.
|
11
|
-
def initialize(paragraph, width, height)
|
12
|
-
lines = paragraph.split("\n")
|
13
|
-
rx = /^([\d:.]*) --> ([\d:.]*)\s?(.*?)\s*$/
|
14
|
-
@style = "Main"
|
15
|
-
@text, @time_start, @time_end, @params = ""
|
16
|
-
count = 0
|
17
|
-
|
18
|
-
lines.each do |line|
|
19
|
-
m = line.match(rx)
|
20
|
-
if not m and count == 0 then
|
21
|
-
@style = line
|
22
|
-
elsif m then
|
23
|
-
@time_start = m[1]
|
24
|
-
@time_end = m[2]
|
25
|
-
@params = m[3]
|
26
|
-
ass_style = ASSStyleParams.new(@params, width, height)
|
27
|
-
if @style.eql? 'Main' and ass_style.alignment == 8 then
|
28
|
-
@style = 'MainTop'
|
29
|
-
end
|
30
|
-
else
|
31
|
-
@text += line + "\n"
|
32
|
-
end
|
33
|
-
count += 1;
|
34
|
-
end
|
35
|
-
|
36
|
-
@text = @text.lstrip
|
37
|
-
end
|
38
|
-
|
39
|
-
##
|
40
|
-
# This method assigns the object values and outputs a VTT dialogue line.
|
41
|
-
def to_s
|
42
|
-
return "#{@style} \n#{@time_start} --> #{@time_end} #{@params}\n#{@text}"
|
43
|
-
end
|
44
|
-
end
|