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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a864637934d7b15e7f459c532cd5f521e21e3445e0408cea0a0a7b3c966f550
4
- data.tar.gz: 5a58b036d877c8529accd0ccc21fe5568d0bdbd686d994ba119ebc894c906e3b
3
+ metadata.gz: bacdcc421becff18a39326c953658fb28c07eb06bd5a4dacc951098e661a9601
4
+ data.tar.gz: ef37756d00cdfa88d23a778fd2ad0718e1129e74e412aa77a5ceebfd0daeb5f7
5
5
  SHA512:
6
- metadata.gz: e46d22748e6e8b64ec2d0486ce42cce993bcdb00b88be35db80c234bbcdf0ddad0b869e35f2b880a30a451b0a81ce99f48dfb5d671cfa40ad284b4eece17f1d3
7
- data.tar.gz: 3bbe4b767f309e820d4c44bf8c351090cbe0810219069970c4ac131e50453eeb7b593e9f4793987a69dc9596ab8d6f35815d2d9bbc6785afe755551bcec7c49d
6
+ metadata.gz: 74ffa9400ecd804d00fe2a5649cb9a7e5b0ebb14b2cb7fd1fe4744517b047c4af4e05edf5e0f9ad1b8d34e47ece1d4c8f8e74c749b78f88a193258853fffceb9
7
+ data.tar.gz: e861fe563ab6ef59085062bd1e2269ca56f20eb939df05eaead50ff78fb754c8339fdb4291c3cf9f357fdd5712df7a2fcbacdf8d4bce2a2773e11c51694d37ce
data/.gitignore CHANGED
@@ -1,3 +1,6 @@
1
+ # RubyMine
2
+ .idea/
3
+
1
4
  # Lock file
2
5
  Gemfile.lock
3
6
 
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
@@ -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.3.gem
106
+ $ gem install ./vtt2ass-0.3.5.gem
103
107
  ```
104
108
 
105
109
  ## License
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
@@ -1,77 +1,81 @@
1
- # Relative imports
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
- # 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('\\', '/').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
- # 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
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
- def convert(input_path)
46
- ass_file = vtt_to_ass(input_path)
47
- if (not @output.nil?) then
48
- ass_file.write_to_file(@output + '/' + File.basename(input_path).gsub('.vtt', '.ass'))
49
- end
50
- puts ass_file.to_s unless @quiet
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
- # 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
- 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
- end
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
@@ -1,4 +1,5 @@
1
- # Relative imports
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
- attr_reader :title, :width, :height
11
- attr_accessor :ass_styles, :ass_lines
11
+ attr_reader :title, :width, :height
12
+ attr_accessor :ass_styles, :ass_lines
12
13
 
13
- ##
14
- # Creates a new ASSFile instance and assigns the default values of instance variables.
15
- def initialize(title, width, height, css_file_path = nil)
16
- @width = width
17
- @height = height
18
- if not css_file_path.nil? then
19
- @css_file = CSSFile.new(css_file_path)
20
- end
21
- @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
- ]
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
- # 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, line_offset = 0)
49
- fs = font_size
50
- vtt_file.lines.each do |line|
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) then
58
- style_exists = true
59
- break
60
- end
61
- end
62
- if not style_exists then
63
- if defined?(@css_file) then
64
- css_rule = @css_file.find_rule(line.style)
65
- if not css_rule.nil? then
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 = 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
- end
61
+ end
62
+ next if style_exists
95
63
 
96
- ##
97
- # This method writes the content of the ASSFile object into a file path that is provided.
98
- def write_to_file(file_path)
99
- File.open(file_path, 'w') do |line|
100
- line.print "\ufeff"
101
- line.puts self.to_s
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
- # This method concatenates the object data in the right order for a string output.
107
- def to_s
108
- return @header + @ass_styles + @events + @ass_lines
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
@@ -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
- attr_reader :style, :time_start, :time_end, :text
7
-
8
- ##
9
- # This method creates an instance of an ASSLine.
10
- #
11
- # * Requires a +style+ name as input.
12
- # * Requires +time_start+, a VTT formatted timestamp as input.
13
- # * Requires +time_start+, a VTT formatted timestamp as input.
14
- # * Requires +text+, a VTT formatted string as input.
15
- def initialize(style, time_start, time_end, text)
16
- @style = style
17
- @time_start = convert_time(time_start)
18
- @time_end = convert_time(time_end)
19
- @text = convert_to_ass_text(text)
20
- end
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
- # This method assigns the object values and outputs an ASS dialogue line.
24
- def to_s
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
- # This method replaces characters and tags to ASS compatible characters and tags.
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
- # This method validates the time format and sends the matching time to be converted
53
- #
54
- # * Requires +str+, a VTT formatted time string.
55
- def convert_time(time)
56
- mTime = time.match(/([\d:]*)\.?(\d*)/)
57
- return to_subs_time(mTime[0])
58
- end
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