vtt2ass 0.3.4 → 0.3.6

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: 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