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.
@@ -1,4 +1,5 @@
1
- # Relative imports
1
+ # frozen_string_literal: true
2
+
2
3
  require_relative 'ass_style_params'
3
4
  require_relative 'validator'
4
5
  require 'redgreenblue'
@@ -6,43 +7,46 @@ require 'redgreenblue'
6
7
  ##
7
8
  # This class defines an ASS style that can be applied on a subtitle line.
8
9
  class ASSStyle
9
- attr_reader :style_name
10
+ attr_reader :style_name
10
11
 
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
12
+ ##
13
+ # This method creates and instance of an ASSStyle.
14
+ #
15
+ # * Requires +style_name+, a string name for the style as input.
16
+ # * Requires +params+, a string of VTT styling as input.
17
+ # * Requires a video +width+ as input.
18
+ # * Requires a video +height+ as input.
19
+ def initialize(style_name, params, font_family, font_size, font_color, is_bold, is_italic, offset, width, height)
20
+ @width = width
21
+ @height = height
22
+ @font_family = font_family
23
+ @font_size = font_size
24
+ @font_color = font_color
25
+ @style_name = style_name
26
+ @s_params = ASSStyleParams.new(params, width, height)
27
+ @s_params.vertical_margin = 50 if style_name.eql? 'MainTop'
28
+ @s_params.vertical_margin -= offset[:line] if style_name.include?('Subtitle') || style_name.eql?('Main')
29
+ @s_params.vertical_margin += offset[:caption] if style_name.include?('Caption') || style_name.eql?('MainTop')
30
+ @is_italic = is_italic
31
+ @is_bold = is_bold
32
+ end
35
33
 
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
34
+ ##
35
+ # This method assigns the object values to an ASS style line and outputs it.
36
+ def to_s
37
+ # Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour,
38
+ # Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment,
39
+ # MarginL, MarginR, MarginV, Encoding
40
+ "Style: #{@style_name},#{@font_family},#{@font_size},#{@font_color},&H000000FF,&H00020713,&H00000000,"\
41
+ "#{@is_bold ? '-1' : '0'},#{@is_italic ? '-1' : '0'},0,0,100,100,0,0,1,2.0,2.0,#{@s_params.alignment},"\
42
+ "#{@s_params.horizontal_margin},0,#{@s_params.vertical_margin},1"
43
+ end
42
44
 
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
45
+ ##
46
+ # This method returns a ASS formated color value based on hex or color name value
47
+ def self.convert_color(color_value)
48
+ color_value.gsub!('#', '')
49
+ color = Validator.hex?(color_value) ? RGB.hex(color_value) : RGB.css(color_value)
50
+ format('&H00%<blue>02x%<green>02x%<red>02x', blue: color.b, green: color.g, red: color.r).upcase
51
+ end
52
+ end
@@ -1,87 +1,109 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ##
2
4
  # This class defines the ASS style parameters from VTT cue settings.
3
5
  class ASSStyleParams
4
- attr_accessor :horizontal_margin, :vertical_margin, :alignment, :align
6
+ attr_accessor :horizontal_margin, :vertical_margin, :alignment, :align
5
7
 
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
- create_alignment()
23
- create_horizontal_margin(width)
24
- create_vertical_margin(height)
8
+ ##
9
+ # Creates an instance of ASSStyleParams
10
+ # It takes VTT style arguments and assign them to their respectful instance variable.
11
+ # It calls methods to create ASS values from the VTT cue settings.
12
+ def initialize(params, width, height)
13
+ @align = nil
14
+ split_params(params)
15
+ create_alignment
16
+ create_horizontal_margin(width)
17
+ create_vertical_margin(height)
18
+ end
19
+
20
+ def split_params(params)
21
+ (params.split.map { |p| p.split(':') }).each do |p|
22
+ case p[0]
23
+ when 'position'
24
+ @position = p[1].gsub(/%/, '').to_i
25
+ when 'line'
26
+ @line = p[1].gsub(/%/, '').to_i
27
+ @line = @line == -1 ? 100 : @line
28
+ when 'align'
29
+ @align = p[1].chomp
30
+ end
25
31
  end
32
+ end
26
33
 
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 create_alignment()
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
34
+ ##
35
+ # This method decides the alignement value in a 9 position grid based of the
36
+ # values in cue settings "align" and "line".
37
+ def create_alignment
38
+ @alignment =
39
+ if defined?(@line) && !defined?(@position)
40
+ find_alignment(@align)
41
+ elsif defined?(@line) && defined?(@position)
42
+ 1 # bottom left
43
+ else
44
+ find_default_alignment(@align)
45
+ end
46
+ end
47
+
48
+ ##
49
+ # This method returns alignment when "line" value is specified but not "position"
50
+ def find_alignment(align)
51
+ if align.nil?
52
+ # If position is higher than 50% align to bottom center, else align to top center
53
+ @line >= 50 ? 2 : 8
54
+ else
55
+ case align
56
+ when 'left', 'start'
57
+ @line >= 50 ? 1 : 7
58
+ when 'right', 'end'
59
+ @line >= 50 ? 3 : 9
60
+ when 'center', 'middle'
61
+ @line >= 50 ? 2 : 8
62
+ end
58
63
  end
64
+ end
59
65
 
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 create_horizontal_margin(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
66
+ ##
67
+ # This method returns alignment when "line" and "position" values are not specified
68
+ def find_default_alignment(align)
69
+ case align
70
+ when 'left', 'start'
71
+ 1
72
+ when 'right', 'end'
73
+ 3
74
+ # when 'center', 'middle'
75
+ else
76
+ 2
70
77
  end
78
+ end
71
79
 
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 create_vertical_margin(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
80
+ ##
81
+ # This method calculates the horizontal margin in px between the alignement position and
82
+ # and the content displayed by using the "position" cue setting.
83
+ def create_horizontal_margin(width)
84
+ steps = (width / 100).to_i
85
+ @horizontal_margin =
86
+ if defined?(@position)
87
+ @position * steps
88
+ else
89
+ 0
90
+ end
91
+ end
92
+
93
+ ##
94
+ # This method calculates the vertical margin in px between the alignement position and
95
+ # and the content displayed by using the "line" cue setting.
96
+ def create_vertical_margin(height)
97
+ steps = (height / 100).to_i
98
+ @vertical_margin =
99
+ if defined?(@line)
100
+ if @alignment == 1
101
+ (100 - @line) * steps
83
102
  else
84
- @vertical_margin = 50
103
+ @line >= 50 ? (100 - @line) * steps : @line * steps
85
104
  end
86
- end
87
- end
105
+ else
106
+ 50
107
+ end
108
+ end
109
+ end
@@ -1,36 +1,38 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'css_parser'
2
4
  require_relative 'css_rule'
3
5
 
6
+ ##
7
+ # This class defines a CSS file for subtitles.
4
8
  class CSSFile
5
- attr_reader :rules
6
- include CssParser
9
+ attr_reader :rules
7
10
 
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
11
+ include CssParser
20
12
 
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
13
+ def initialize(file_path)
14
+ @file_path = file_path
15
+ parser = CssParser::Parser.new
16
+ parser.load_file!(file_path)
17
+ @rules = []
18
+ parser.each_selector do |selector, declarations, _specificity|
19
+ css_obj = CSSRule.new(selector, declarations)
20
+ @rules.push(css_obj) unless css_obj.name.empty?
30
21
  end
22
+ end
31
23
 
32
- def to_s
33
- return @file_path
24
+ def find_rule(value)
25
+ return_rule = nil
26
+ @rules.each do |rule|
27
+ if rule.name == value
28
+ return_rule = rule
29
+ break
30
+ end
34
31
  end
32
+ return_rule
33
+ end
35
34
 
36
- end
35
+ def to_s
36
+ @file_path
37
+ end
38
+ end
@@ -1,22 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # This class defines a CSS rule that is included in the CSS file.
1
5
  class CSSRule
2
- attr_reader :name, :properties
6
+ attr_reader :name, :properties
3
7
 
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
8
+ def initialize(selector, declarations)
9
+ @name = reduce_selector(selector)
10
+ @properties = []
11
+ declarations.split(/;\s?/).each do |dec|
12
+ temp = dec.split(/:\s?/)
13
+ @properties.push(
14
+ { key: temp.first, value: temp.last }
15
+ )
13
16
  end
17
+ end
14
18
 
15
- def to_s
16
- return "#{@name} #{@properties}"
17
- end
19
+ def to_s
20
+ "#{@name} #{@properties}"
21
+ end
18
22
 
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
23
+ ##
24
+ # This method removes the generic selector from a block.
25
+ def reduce_selector(selector)
26
+ selector.to_s.gsub(
27
+ /\.rmp-container>\.rmp-content>\.rmp-cc-area>\.rmp-cc-container>\.rmp-cc-display>\.rmp-cc-cue\s?\.?/, ''
28
+ )
29
+ end
30
+ end
@@ -1,10 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # This class defines validation tools for data.
1
5
  class Validator
2
- def self.hex?(value)
3
- hex = true
4
- value.gsub!('#', '')
5
- value.chars.each do |digit|
6
- hex = false unless digit.match(/\h/)
7
- end
8
- return hex
6
+ def self.hex?(value)
7
+ hex = true
8
+ value.gsub!('#', '')
9
+ value.chars.each do |digit|
10
+ hex = false unless digit.match(/\h/)
9
11
  end
10
- end
12
+ hex
13
+ end
14
+ end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ##
2
4
  # Vtt2ass module to provide the version number
3
5
  module Vtt2ass
4
6
  ##
5
7
  # This is the version of the application.
6
8
  # This needs to be changed for each gem release.
7
- VERSION = "0.3.4"
9
+ VERSION = '0.3.6'
8
10
  end
@@ -1,58 +1,58 @@
1
- # Relative imports
1
+ # frozen_string_literal: true
2
+
2
3
  require_relative 'vtt_line'
3
4
 
4
5
  ##
5
6
  # This class defines a VTT subtile file.
6
7
  class VTTFile
7
- attr_accessor :lines
8
+ attr_accessor :lines
8
9
 
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
10
+ ##
11
+ # Creates a new VTTFile instance and assigns the default values of instance variables.
12
+ def initialize(file_path, width, height)
13
+ @title = File.basename(file_path).gsub('.vtt', '')
14
+ @lines = []
15
+ separator = determine_line_ending(file_path) ? "\n\n" : "\r\n\r\n"
16
+ count = 0
17
+ style_count = 1
18
+ File.foreach(file_path, separator) do |paragraph|
19
+ paragraph = paragraph.rstrip.gsub(/[\r\n]/, "\n")
20
+ unless paragraph.eql? ''
21
+ vtt_line = VTTLine.new(paragraph, width, height)
22
+ if vtt_line.style.eql?('Main') &&
23
+ !vtt_line.params.to_s.empty? &&
24
+ (!vtt_line.params.to_s.eql?('align:middle') &&
25
+ !vtt_line.params.to_s.eql?('align:center'))
26
+ vtt_line.style = "Style#{style_count}"
27
+ style_count += 1
31
28
  end
32
- @lines.shift
29
+ @lines.push(vtt_line)
30
+ count += 1
31
+ end
33
32
  end
33
+ @lines.shift
34
+ end
34
35
 
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 write_to_file(file_path)
46
- File.open(file_path, 'w') do |line|
47
- line.print "\ufeff"
48
- line.puts self.to_s
49
- end
36
+ ##
37
+ # This method determines the line ending character to use as a separator.
38
+ def determine_line_ending(file_path)
39
+ File.open(file_path, 'r') do |file|
40
+ return file.readline[/\r?\n$/] == "\n"
50
41
  end
42
+ end
51
43
 
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
44
+ ##
45
+ # This method writes the content of the VTTFile object into a file path that is provided.
46
+ def write_to_file(file_path)
47
+ File.open(file_path, 'w') do |line|
48
+ line.print "\ufeff"
49
+ line.puts to_s
56
50
  end
51
+ end
57
52
 
58
- end
53
+ ##
54
+ # This method concatenates the object data in the right order for a string output.
55
+ def to_s
56
+ "WEBVTT\n\n\n#{@lines}"
57
+ end
58
+ end
@@ -1,44 +1,44 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ##
2
4
  # This class defines a VTT subtile line.
3
5
  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
6
+ attr_accessor :style
7
+ attr_reader :time_start, :time_end, :params, :text
17
8
 
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
9
+ ##
10
+ # This method creates an instance of an VTTLine.
11
+ #
12
+ # * Requires +paragraph+, a VTT formatted string as input.
13
+ def initialize(paragraph, width, height)
14
+ lines = paragraph.split("\n")
15
+ rx = /^([\d:.]*) --> ([\d:.]*)\s?(.*?)\s*$/
16
+ @style = 'Main'
17
+ @text, @time_start, @time_end, @params = ''
18
+ count = 0
35
19
 
36
- @text = @text.lstrip
20
+ lines.each do |line|
21
+ m = line.match(rx)
22
+ if !m && count.zero?
23
+ @style = line
24
+ elsif m
25
+ @time_start = m[1]
26
+ @time_end = m[2]
27
+ @params = m[3]
28
+ ass_style = ASSStyleParams.new(@params, width, height)
29
+ @style = 'MainTop' if @style.eql?('Main') && ass_style.alignment == 8
30
+ else
31
+ @text += "#{line}\n"
32
+ end
33
+ count += 1
37
34
  end
38
35
 
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
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
+ "#{@style} \n#{@time_start} --> #{@time_end} #{@params}\n#{@text}"
43
+ end
44
+ end