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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5e94988be1922e26d861f105404e3eff863a2df470aa3aa7fc5f35cdf26c3c71
4
- data.tar.gz: 055641cfd88eef119e3c623adbae16b9eb70a7091c26b13410d8b94c2c8e55ec
3
+ metadata.gz: 3047227acbd6bf731e5dc95113a7d70081bed94392e3b00078b760ebbc4440a4
4
+ data.tar.gz: e9bc514e5b41028d872d9e983cc4dbd4442fc648ab1065e2c3e5a2aca3c9b8fd
5
5
  SHA512:
6
- metadata.gz: 785df255fc71e0479a8b124222e25033e2aca337765cdd17bf46c6ef0e11adae7fb854b01fa23959946f8d9ebd8bbfefcaf6cafc10b9a7089a52b11806f5e82a
7
- data.tar.gz: 9cd4940b1d5667136aa51d9bff670a2d98e4a966ee898110230c15d710c87898aaf596afd6a6c7173f0ef06cf26eb57e7f2b3acd1c670f95209d97be9c5d5480
6
+ metadata.gz: 388af342ebe22e69e52e92e4dadf5a04ea48cb6e491398e864ed1e9d5ae3a602601cddc070ae20f7e8edef0b652a87aa3e8a66f8b8128626315dbac0dd421873
7
+ data.tar.gz: fa2f3b0fa33c3ee1ade343b14837e8f09d2b5145f41e60f68e1cc7236e17e23c67cb7a811f5abf145df7e7121fd651364870073b6ff74679f6c9ddfe375a2ddc
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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in vtt2ass.gemspec
data/README.md CHANGED
@@ -2,35 +2,54 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/vtt2ass.svg)](https://badge.fury.io/rb/vtt2ass)
4
4
 
5
- This is a simple application to convert VTT files to ASS subtitles.
5
+ ## Description
6
+
7
+ This is a simple CLI (Command Line Interface) application to convert VTT files to ASS subtitles.
8
+
9
+ This application is originally based on the `vttconvert` module of [anidl/hidive-downloader-nx](https://github.com/anidl/hidive-downloader-nx) repository. The [maxwbot/maxwhidive](https://github.com/maxwbot/maxwhidive) repository was also used as inspiration for handling the positionning of subs.
10
+
11
+ Those two tools were missing features and didn't work well on a lot of more complex subtitles files. For that reason, I wrote a new tool that can handle everything.
12
+
13
+ ### Features
14
+
15
+ - Convert simple VTT files
16
+ - Convert complex VTT files with positioning
17
+ - Convert Hidive VTT files with CSS styling
18
+ - Convert subtitles in batches by specifying the input directory
19
+ - Handles subtitles made for lower resolution video
20
+ - Can add offset to subtitle lines
21
+ - Can output result to the CLI
22
+ - Can output to the specifed directory
23
+ - Can change the base font size
24
+ - Can specify a custom font family for non-styled lines
25
+ - Can add a title to the converted files
6
26
 
7
27
  ## Requirements
28
+
8
29
  - ruby 2.7.2 or newer
9
30
 
10
- It might work with older versions of ruby, but it hasn't been tested
31
+ Development is currently done on ruby 3.0+, but the Gitlab runner for builds works with ruby version 2.7.2. Older versions of ruby may be compatible, but they won't be tested.
11
32
 
12
33
  ## Installation
13
34
 
14
35
  To install:
15
36
  ```bash
16
- gem install vtt2ass
17
- ```
18
-
19
- # Build
20
-
21
- ```bash
22
- gem build vtt2ass.gemspec
37
+ $ gem install vtt2ass
23
38
  ```
24
39
 
25
40
  ## Usage
26
41
 
42
+ - Empty arguments lists the available commands
27
43
  ```bash
28
44
  $ vtt2ass
29
45
  Commands:
30
46
  vtt2ass convert INPUT # Run the VTT to ASS conversion for the specified file(s)
31
47
  vtt2ass help [COMMAND] # Describe available commands or one specific command
32
48
  vtt2ass version # Show version
49
+ ```
33
50
 
51
+ - Help command shows available options of the specified command
52
+ ```bash
34
53
  $ vtt2ass help convert
35
54
  Usage:
36
55
  vtt2ass convert INPUT
@@ -45,12 +64,53 @@ Options:
45
64
  -c, [--css=CSS] # Specify a CSS file path for Hidive subs
46
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)
47
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
48
71
  -q, [--quiet], [--no-quiet] # Don't output to the console
49
72
 
50
73
  Run the VTT to ASS conversion for the specified file(s)
51
74
  ```
52
75
 
53
- # Donate
76
+ - Convert command
77
+ ```bash
78
+ $ vtt2ass convert ./path/to/input/ -o ./path/to/output/ -l 50 -q
79
+ ```
80
+
81
+ - Version command shows the application version
82
+ ```bash
83
+ $ vtt2ass version
84
+ 0.3.3
85
+ ```
86
+
87
+ ## Contributing
88
+
89
+ Contributions are welcome. Create an *Issue* on Gitlab and link it with a *Pull Request* of the changes made. The changes needs to pass the ruby tests.
90
+
91
+ ```
92
+ $ rake test
93
+ ```
94
+
95
+ ## Build
96
+
97
+ To build a gem file for local installation:
98
+ ```bash
99
+ $ git clone https://gitlab.com/dkb-weeblets/vtt2ass.git
100
+ $ cd vtt2ass/
101
+ $ gem build vtt2ass.gemspec
102
+ ```
103
+
104
+ To install the gem file:
105
+ ```bash
106
+ $ gem install ./vtt2ass-0.3.5.gem
107
+ ```
108
+
109
+ ## License
110
+
111
+ Licensed under the **MIT** Licence. For more information read the `LICENSE.txt` file.
112
+
113
+ ## Donate
54
114
 
55
115
  If you want to support me, consider buying me a coffee.
56
116
 
data/Rakefile CHANGED
@@ -1,10 +1,12 @@
1
- require "bundler/gem_tasks"
2
- require "rake/testtask"
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 << "test"
6
- t.libs << "lib"
7
- t.test_files = FileList["test/**/*_test.rb"]
7
+ t.libs << 'test'
8
+ t.libs << 'lib'
9
+ t.test_files = FileList['test/**/*_test.rb']
8
10
  end
9
11
 
10
- task :default => :test
12
+ task default: :test
data/bin/vtt2ass CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require_relative '../lib/vtt2ass'
4
- MainCommand.start
5
+ MainCommand.start
data/exe/vtt2ass CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'vtt2ass'
4
- MainCommand.start
5
+ MainCommand.start
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'vtt_file'
4
+ require_relative 'ass_file'
5
+
6
+ ##
7
+ # Main application class that manages all the operations.
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
16
+
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
23
+
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.'
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
+ end
43
+
44
+ ##
45
+ # This method launches the conversion process on the specified input file.
46
+ def convert(input_path)
47
+ output = sanitize_path(@options[:output])
48
+ raise StandardError, 'ERROR: Output directory does not exist.' unless File.directory?(output)
49
+
50
+ ass_file = vtt_to_ass(input_path)
51
+ ass_file.write_to_file("#{output}/#{File.basename(input_path).gsub('.vtt', '.ass')}") unless output.nil?
52
+ puts ass_file.to_s unless @options[:quiet]
53
+ end
54
+
55
+ ##
56
+ # This method creates a new VTTFile object from the file path provided and convert its content
57
+ # inside a new ASSFile object.
58
+ def vtt_to_ass(file_path)
59
+ base_file_name = File.basename(file_path).gsub('.vtt', '')
60
+ css_file =
61
+ if !@options[:css].nil? && File.directory?(@options[:css])
62
+ "#{sanitize_path(@options[:css])}/#{base_file_name}.css"
63
+ elsif File.file?("#{file_path.gsub('.vtt', '')}.css")
64
+ "#{file_path.gsub('.vtt', '')}.css"
65
+ else
66
+ @options[:css]
67
+ end
68
+ vtt_file = VTTFile.new(file_path, @options[:width], @options[:height])
69
+ ass_file = ASSFile.new(
70
+ (@options[:title].nil? ? base_file_name : @options[:title]),
71
+ @options[:width],
72
+ @options[:height],
73
+ css_file
74
+ )
75
+ ass_file.convert_vtt_to_ass(vtt_file, @options[:font_family], @options[:font_size], @options[:line_offset])
76
+ ass_file
77
+ end
78
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'ass_line'
4
+ require_relative 'ass_style'
5
+ require_relative 'css_file'
6
+ require_relative 'css_rule'
7
+
8
+ ##
9
+ # This class defines an ASS subtitle file.
10
+ class ASSFile
11
+ attr_reader :title, :width, :height
12
+ attr_accessor :ass_styles, :ass_lines
13
+
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 = CSSFile.new(css_file_path) unless css_file_path.nil?
20
+ @header = <<~HEADER
21
+ [Script Info]
22
+ Title: #{title}
23
+ ScriptType: v4.00+
24
+ Collisions: Normal
25
+ PlayDepth: 0
26
+ PlayResX: #{@width}
27
+ PlayResY: #{@height}
28
+ WrapStyle: 0
29
+ ScaledBorderAndShadow: yes
30
+
31
+ [V4+ Styles]
32
+ Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
33
+ HEADER
34
+ @events = <<~EVENTS
35
+
36
+ [Events]
37
+ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
38
+ EVENTS
39
+ @ass_styles = []
40
+ @ass_lines = []
41
+ end
42
+
43
+ ##
44
+ # This method receives a VTTFile object and font arguments creates new ASSLine with the params of
45
+ # each VTTLine. All those ASSLine are stored in an array. It also creates an array of ASSStyle that
46
+ # will be used in the ASS style list.
47
+ def convert_vtt_to_ass(vtt_file, font_family, font_size, line_offset = 0) # rubocop:disable Metrics/MethodLength
48
+ fs = font_size
49
+ vtt_file.lines.each do |line| # rubocop:disable Metrics/BlockLength
50
+ font_color = '&H00FFFFFF'
51
+ is_italic = false
52
+ is_bold = false
53
+ @ass_lines.push(ASSLine.new(line.style, line.time_start, line.time_end, line.text))
54
+ style_exists = false
55
+ @ass_styles.each do |style|
56
+ if style.style_name.eql? line.style
57
+ style_exists = true
58
+ break
59
+ end
60
+ end
61
+ next if style_exists
62
+
63
+ unless @css_file.nil?
64
+ css_rule = @css_file.find_rule(line.style)
65
+ css_rule&.properties&.each do |property|
66
+ case property[:key]
67
+ when 'font-family'
68
+ font_family = property[:value].gsub('"', '').split(' ,').last
69
+ when 'font-size'
70
+ em_size = 1
71
+ em_size = "0#{property[:value]}".gsub('em', '').to_f if property[:value][0].eql? '.'
72
+ font_size = (fs * em_size).to_i
73
+ when 'color'
74
+ font_color = ASSStyle.convert_color(property[:value])
75
+ when 'font-weight'
76
+ is_bold = true if property[:value].eql? 'bold'
77
+ when 'font-style'
78
+ is_italic = true if property[:value].eql? 'italic'
79
+ end
80
+ end
81
+ end
82
+ @ass_styles.push(
83
+ ASSStyle.new(
84
+ line.style, line.params,
85
+ font_family, font_size, font_color, is_bold, is_italic,
86
+ line_offset, @width, @height
87
+ )
88
+ )
89
+ end
90
+ end
91
+
92
+ ##
93
+ # This method writes the content of the ASSFile object into a file path that is provided.
94
+ def write_to_file(file_path)
95
+ File.open(file_path, 'w') do |line|
96
+ line.print "\ufeff"
97
+ line.puts to_s
98
+ end
99
+ end
100
+
101
+ ##
102
+ # This method concatenates the object data in the right order for a string output.
103
+ def to_s
104
+ "#{@header}#{@ass_styles.join("\n")}#{@events}#{@ass_lines.join("\n")}"
105
+ end
106
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'htmlentities'
4
+
5
+ ##
6
+ # This class defines an ASS subtile line.
7
+ class ASSLine
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
80
+
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))
84
+
85
+ n.join
86
+ end
87
+
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
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'ass_style_params'
4
+ require_relative 'validator'
5
+ require 'redgreenblue'
6
+
7
+ ##
8
+ # This class defines an ASS style that can be applied on a subtitle line.
9
+ class ASSStyle
10
+ attr_reader :style_name
11
+
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, line_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 -= line_offset if style_name.include? 'Subtitle'
29
+ @is_italic = is_italic
30
+ @is_bold = is_bold
31
+ end
32
+
33
+ ##
34
+ # This method assigns the object values to an ASS style line and outputs it.
35
+ def to_s
36
+ # Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour,
37
+ # Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment,
38
+ # MarginL, MarginR, MarginV, Encoding
39
+ "Style: #{@style_name},#{@font_family},#{@font_size},#{@font_color},&H000000FF,&H00020713,&H00000000,"\
40
+ "#{@is_bold ? '-1' : '0'},#{@is_italic ? '-1' : '0'},0,0,100,100,0,0,1,2.0,2.0,#{@s_params.alignment},"\
41
+ "#{@s_params.horizontal_margin},0,#{@s_params.vertical_margin},1"
42
+ end
43
+
44
+ ##
45
+ # This method returns a ASS formated color value based on hex or color name value
46
+ def self.convert_color(color_value)
47
+ color_value.gsub!('#', '')
48
+ color = Validator.hex?(color_value) ? RGB.hex(color_value) : RGB.css(color_value)
49
+ format('&H00%<blue>02x%<green>02x%<red>02x', blue: color.b, green: color.g, red: color.r).upcase
50
+ end
51
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # This class defines the ASS style parameters from VTT cue settings.
5
+ class ASSStyleParams
6
+ attr_accessor :horizontal_margin, :vertical_margin, :alignment, :align
7
+
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
+ split_params(params)
14
+ create_alignment
15
+ create_horizontal_margin(width)
16
+ create_vertical_margin(height)
17
+ end
18
+
19
+ def split_params(params)
20
+ (params.split.map { |p| p.split(':') }).each do |p|
21
+ case p[0]
22
+ when 'position'
23
+ @position = p[1].gsub(/%/, '').to_i
24
+ when 'line'
25
+ @line = p[1].gsub(/%/, '').to_i
26
+ @line = @line == -1 ? 100 : @line
27
+ when 'align'
28
+ @align = p[1].chomp
29
+ end
30
+ end
31
+ end
32
+
33
+ ##
34
+ # This method decides the alignement value in a 9 position grid based of the
35
+ # values in cue settings "align" and "line".
36
+ def create_alignment
37
+ @alignment =
38
+ if defined?(@line) && !defined?(@position)
39
+ find_alignment(@align)
40
+ elsif defined?(@line) && defined?(@position)
41
+ 1 # bottom left
42
+ else
43
+ find_default_alignment(@align)
44
+ end
45
+ end
46
+
47
+ ##
48
+ # This method returns alignment when "line" value is specified but not "position"
49
+ def find_alignment(align)
50
+ if align.nil?
51
+ # If position is higher than 50% align to bottom center, else align to top center
52
+ @line >= 50 ? 2 : 8
53
+ else
54
+ case align
55
+ when 'left', 'start'
56
+ @line >= 50 ? 1 : 7
57
+ when 'right', 'end'
58
+ @line >= 50 ? 3 : 9
59
+ when 'center', 'middle'
60
+ @line >= 50 ? 2 : 8
61
+ end
62
+ end
63
+ end
64
+
65
+ ##
66
+ # This method returns alignment when "line" and "position" values are not specified
67
+ def find_default_alignment(align)
68
+ case align
69
+ when 'left', 'start'
70
+ 1
71
+ when 'right', 'end'
72
+ 3
73
+ # when 'center', 'middle'
74
+ else
75
+ 2
76
+ end
77
+ end
78
+
79
+ ##
80
+ # This method calculates the horizontal margin in px between the alignement position and
81
+ # and the content displayed by using the "position" cue setting.
82
+ def create_horizontal_margin(width)
83
+ steps = (width / 100).to_i
84
+ @horizontal_margin =
85
+ if defined?(@position)
86
+ @position * steps
87
+ else
88
+ 0
89
+ end
90
+ end
91
+
92
+ ##
93
+ # This method calculates the vertical margin in px between the alignement position and
94
+ # and the content displayed by using the "line" cue setting.
95
+ def create_vertical_margin(height)
96
+ steps = (height / 100).to_i
97
+ @vertical_margin =
98
+ if defined?(@line)
99
+ if @alignment == 1
100
+ (100 - @line) * steps
101
+ else
102
+ @line >= 50 ? (100 - @line) * steps : @line * steps
103
+ end
104
+ else
105
+ 50
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'css_parser'
4
+ require_relative 'css_rule'
5
+
6
+ ##
7
+ # This class defines a CSS file for subtitles.
8
+ class CSSFile
9
+ attr_reader :rules
10
+
11
+ include CssParser
12
+
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?
21
+ end
22
+ end
23
+
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
31
+ end
32
+ return_rule
33
+ end
34
+
35
+ def to_s
36
+ @file_path
37
+ end
38
+ end