captions 1.3.0 → 1.3.2

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
- SHA1:
3
- metadata.gz: aabb7f8d8e05f0bdd97f11c7d3d6ad2272daa4a8
4
- data.tar.gz: 2487803e670a82b5280cbe710d8b1f53aeb7ad7d
2
+ SHA256:
3
+ metadata.gz: f28c0fae37de5bc2c02bc8e47e088a595ae63c5a6579f2f7592ddd52f5f7a3b6
4
+ data.tar.gz: 0d9be70a499a0664aa1d1102bcc6a66aa91d963b38a8c9bdd1fbac2f5f44bf7e
5
5
  SHA512:
6
- metadata.gz: 247cbaedb31a2c5afc6d987b9521a62ef11e7c40460d1a5831093e00f1308ef682e86ee68832695110f85452dd3365fbdf3ea1d76219147b18838b0dd8812d22
7
- data.tar.gz: ad8c0e97e9fb83e97facabfd17058427368672aa5ac2aa79f9f3b5908b5cf2c9e1e23c9a84c5e2ac8e3369e4e527144c6ab557e82126f15eb5cca828657cbe59
6
+ metadata.gz: 85a5e3b4adbd7fd0ae4bda2a42e53d1a44ec72143911017759f5e4220aeee9c9b8bbfd5d54bd64751935440796b552f6ab111f680bd8eba8f4520a9e7a1a5609
7
+ data.tar.gz: ea86bfa471ef771f0b714f162e807adb9c0364e708512f3feca04c601053ad0b3cd2a3c25b85be5ef1d35baba82ce75571a5f10b0490a943535343ea4d295d9c
data/.travis.yml CHANGED
@@ -2,7 +2,7 @@ language: ruby
2
2
  cache: bundler
3
3
 
4
4
  rvm:
5
- - 2.0.0-p247
5
+ - ruby-2.3.8
6
6
 
7
7
  script: 'bundle exec rspec'
8
8
 
data/bin/console CHANGED
@@ -1,14 +1,14 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "bundler/setup"
4
- require "captions"
5
-
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "captions"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/captions.gemspec CHANGED
@@ -1,27 +1,27 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'captions/version'
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "captions"
8
- spec.version = Captions::VERSION
9
- spec.authors = ["navin"]
10
- spec.email = ["navin@amagi.com"]
11
-
12
- spec.summary = %q{Subtitle Editor and Converter written in Ruby}
13
- spec.description = %q{Subtitle Editor and Converter written in Ruby. Captions can read/modify/export subtitles from one format to another }
14
- spec.homepage = "https://github.com/navinre/captions"
15
- spec.license = "MIT"
16
-
17
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
- f.match(%r{^(test|spec|features)/})
19
- end
20
- spec.bindir = "exe"
21
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
- spec.require_paths = ["lib"]
23
-
24
- spec.add_development_dependency "rspec"
25
- spec.add_development_dependency "bundler", "~> 1.13"
26
- spec.add_development_dependency "rake", "~> 10.0"
27
- end
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'captions/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "captions"
8
+ spec.version = Captions::VERSION
9
+ spec.authors = ["navin"]
10
+ spec.email = ["navin@amagi.com"]
11
+
12
+ spec.summary = %q{Subtitle Editor and Converter written in Ruby}
13
+ spec.description = %q{Subtitle Editor and Converter written in Ruby. Captions can read/modify/export subtitles from one format to another }
14
+ spec.homepage = "https://github.com/navinre/captions"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_development_dependency "rspec"
25
+ spec.add_development_dependency "bundler"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+ end
data/lib/captions/cue.rb CHANGED
@@ -1,93 +1,93 @@
1
- module Captions
2
- class Cue
3
- include Util
4
-
5
- # Text Properties supported
6
- ALIGNMENT = "alignment"
7
- COLOR = "color"
8
- POSITION = "position"
9
-
10
- # List of Text Properties
11
- TEXT_PROPERTIES = [ALIGNMENT, COLOR, POSITION]
12
-
13
- attr_accessor :number, :start_time, :end_time, :duration, :text, :properties
14
-
15
- # Creates a new Cue class
16
- # Each cue denotes a subtitle.
17
- def initialize
18
- self.text = nil
19
- self.start_time = nil
20
- self.end_time = nil
21
- self.duration = nil
22
- self.number = nil
23
- self.properties = {}
24
- end
25
-
26
- # Sets the time for the cue. Both start-time and
27
- # end-time can be passed together. This just assigns
28
- # the value passed.
29
- def set_time(start_time, end_time, duration = nil)
30
- self.start_time = start_time
31
- self.end_time = end_time
32
- self.duration = duration
33
- end
34
-
35
- # Getter and Setter methods for Text Properties
36
- # These are pre-defined properties. This is just to assign
37
- # or access the properties of that text.
38
- TEXT_PROPERTIES.each do |setting|
39
- define_method :"#{setting}" do
40
- if self.properties[setting].present?
41
- return self.properties[setting]
42
- end
43
- return nil
44
- end
45
-
46
- define_method :"#{setting}=" do |value|
47
- self.properties[setting] = value
48
- end
49
- end
50
-
51
- # Serializes the values set for the cue.
52
- # Converts start-time, end-time and duration to milliseconds
53
- # If duration is not found, it will be calculated based on
54
- # start-time and end-time.
55
- def serialize(fps)
56
- raise InvalidSubtitle, "Subtitle should have start time" if self.start_time.nil?
57
- raise InvalidSubtitle, "Subtitle shold have end time" if self.end_time.nil?
58
-
59
- begin
60
- ms_per_frame = (1000.0 / fps)
61
- self.start_time = convert_to_msec(self.start_time, ms_per_frame)
62
- self.end_time = convert_to_msec(self.end_time, ms_per_frame)
63
- if duration.nil?
64
- self.duration = self.end_time - self.start_time
65
- else
66
- self.duration = convert_to_msec(self.duration, ms_per_frame)
67
- end
68
- rescue
69
- raise InvalidSubtitle, "Cannot calculate start-time or end-time"
70
- end
71
- end
72
-
73
- # Changes start-time, end-time and duration based on new frame-rate
74
- def change_frame_rate(old_rate, new_rate)
75
- self.start_time = convert_frame_rate(self.start_time, old_rate, new_rate)
76
- self.end_time = convert_frame_rate(self.end_time, old_rate, new_rate)
77
- self.duration = convert_frame_rate(self.duration, old_rate, new_rate)
78
- end
79
-
80
- # Adds text. If text is already found, new-line is appended.
81
- def add_text(text)
82
- if self.text.nil?
83
- self.text = text
84
- else
85
- self.text += "\n" + text
86
- end
87
- end
88
-
89
- def <=>(other_cue)
90
- self.start_time <=> other_cue.start_time
91
- end
92
- end
93
- end
1
+ module Captions
2
+ class Cue
3
+ include Util
4
+
5
+ # Text Properties supported
6
+ ALIGNMENT = "alignment"
7
+ COLOR = "color"
8
+ POSITION = "position"
9
+
10
+ # List of Text Properties
11
+ TEXT_PROPERTIES = [ALIGNMENT, COLOR, POSITION]
12
+
13
+ attr_accessor :number, :start_time, :end_time, :duration, :text, :properties
14
+
15
+ # Creates a new Cue class
16
+ # Each cue denotes a subtitle.
17
+ def initialize(cue_number = nil)
18
+ self.text = nil
19
+ self.start_time = nil
20
+ self.end_time = nil
21
+ self.duration = nil
22
+ self.number = cue_number
23
+ self.properties = {}
24
+ end
25
+
26
+ # Sets the time for the cue. Both start-time and
27
+ # end-time can be passed together. This just assigns
28
+ # the value passed.
29
+ def set_time(start_time, end_time, duration = nil)
30
+ self.start_time = start_time
31
+ self.end_time = end_time
32
+ self.duration = duration
33
+ end
34
+
35
+ # Getter and Setter methods for Text Properties
36
+ # These are pre-defined properties. This is just to assign
37
+ # or access the properties of that text.
38
+ TEXT_PROPERTIES.each do |setting|
39
+ define_method :"#{setting}" do
40
+ if self.properties[setting].present?
41
+ return self.properties[setting]
42
+ end
43
+ return nil
44
+ end
45
+
46
+ define_method :"#{setting}=" do |value|
47
+ self.properties[setting] = value
48
+ end
49
+ end
50
+
51
+ # Serializes the values set for the cue.
52
+ # Converts start-time, end-time and duration to milliseconds
53
+ # If duration is not found, it will be calculated based on
54
+ # start-time and end-time.
55
+ def serialize(fps)
56
+ raise InvalidSubtitle, "Subtitle should have start time" if self.start_time.nil?
57
+ raise InvalidSubtitle, "Subtitle shold have end time" if self.end_time.nil?
58
+
59
+ begin
60
+ ms_per_frame = (1000.0 / fps)
61
+ self.start_time = convert_to_msec(self.start_time, ms_per_frame)
62
+ self.end_time = convert_to_msec(self.end_time, ms_per_frame)
63
+ if duration.nil?
64
+ self.duration = self.end_time - self.start_time
65
+ else
66
+ self.duration = convert_to_msec(self.duration, ms_per_frame)
67
+ end
68
+ rescue
69
+ raise InvalidSubtitle, "Cannot calculate start-time or end-time"
70
+ end
71
+ end
72
+
73
+ # Changes start-time, end-time and duration based on new frame-rate
74
+ def change_frame_rate(old_rate, new_rate)
75
+ self.start_time = convert_frame_rate(self.start_time, old_rate, new_rate)
76
+ self.end_time = convert_frame_rate(self.end_time, old_rate, new_rate)
77
+ self.duration = convert_frame_rate(self.duration, old_rate, new_rate)
78
+ end
79
+
80
+ # Adds text. If text is already found, new-line is appended.
81
+ def add_text(text)
82
+ if self.text.nil?
83
+ self.text = text
84
+ else
85
+ self.text += "\n" + text
86
+ end
87
+ end
88
+
89
+ def <=>(other_cue)
90
+ self.start_time <=> other_cue.start_time
91
+ end
92
+ end
93
+ end
@@ -3,34 +3,43 @@ module Captions
3
3
 
4
4
  def parse
5
5
  base_parser do
6
- count = 1
7
- cue = Cue.new
8
- number = nil
9
- lines = []
10
- while(line = @file.gets) do
11
- line = line.strip
12
- if line.empty?
13
- @cue_list.append(cue) if cue and cue.start_time
14
- cue = Cue.new
15
- # This is done to handle white spaces at the beginning
16
- # and end of the file
17
- if(number = @file.gets)
18
- # Reads the number immediately followed by white-space
19
- cue.number = number.to_i
20
- else
6
+ count = 0
7
+ state = :new_cue
8
+ cue = nil
9
+ loop do
10
+ count += 1
11
+ line = @file.gets
12
+ break if line.nil? ## End of file
13
+ line.chomp!
14
+ case state
15
+ when :new_cue
16
+ line.strip!
17
+ next if line.empty? ## just another blank line, remain in new_cue state
18
+ begin
19
+ cue = Cue.new(Integer(line))
20
+ rescue ArgumentError
21
+ raise InvalidSubtitle, "Invalid Cue Number at line #{count}"
22
+ end
23
+ state = :time
24
+ when :time
25
+ line.strip!
26
+ raise InvalidSubtitle, "Invalid Time Format at line #{count}" unless is_time?(line)
27
+ start_time, end_time = get_time(line)
28
+ cue.set_time(start_time, end_time)
29
+ state = :text
30
+ when :text
31
+ if line.empty?
32
+ ## end of previous cue
33
+ @cue_list.append(cue) if cue && cue.start_time
21
34
  cue = nil
35
+ state = :new_cue
36
+ else
37
+ line.strip!
38
+ cue.add_text(line)
22
39
  end
23
- elsif is_time?(line)
24
- s , e = get_time(line)
25
- cue.set_time(s, e)
26
- elsif is_text?(line)
27
- cue.add_text(line)
28
- elsif !line.empty?
29
- raise MalformedString, "Invalid format at line #{count}"
30
40
  end
31
- count += 1
32
41
  end
33
- @cue_list.append(cue) if cue
42
+ @cue_list.append(cue) if cue && cue.start_time
34
43
  end
35
44
  end
36
45
 
@@ -1,121 +1,122 @@
1
- module Captions
2
- class VTT < Base
3
-
4
- # Header used for all VTT files
5
- VTT_HEADER = "WEBVTT"
6
-
7
- # VTT file comments/style section
8
- VTT_METADATA = /^NOTE|^STYLE/
9
-
10
- # Auto Keyword used in Alignment
11
- AUTO_KEYWORD = "auto"
12
-
13
- # Alignment Data
14
- ALIGNMENT_VALUES = {
15
- "middle" => "middle",
16
- "left" => "left",
17
- "right" => "right",
18
- "start" => "start",
19
- "end" => "end",
20
- }
21
-
22
- # Parse VTT file and update CueList
23
- def parse
24
- base_parser do
25
- count = 1
26
- cue_count = 0
27
- meta_data_section = false
28
- cue = nil
29
- raise InvalidSubtitle, "Invalid VTT Signature" unless validate_header(@file.gets)
30
- while(line = @file.gets) do
31
- line = line.strip
32
- if line.empty?
33
- meta_data_section = false
34
- elsif is_meta_data?(line)
35
- meta_data_section = true
36
- elsif is_time?(line)
37
- @cue_list.append(cue) if cue
38
- cue_count += 1
39
- cue = Cue.new
40
- cue.number = cue_count
41
- line = line.split
42
- cue.set_time(line[0], line[2])
43
- set_properties(cue, line[3..-1])
44
- elsif !meta_data_section and is_text?(line)
45
- cue.add_text(line)
46
- end
47
- end
48
- @cue_list.append(cue) if cue
49
- end
50
- end
51
-
52
- # Export CueList to VTT file
53
- def dump(file)
54
- base_dump(file) do |file|
55
- file.write(VTT_HEADER)
56
- @cue_list.each do |cue|
57
- file.write("\n\n")
58
- file.write(msec_to_timecode(cue.start_time))
59
- file.write(" --> ")
60
- file.write(msec_to_timecode(cue.end_time))
61
- file.write("\n")
62
- file.write(cue.text)
63
- end
64
- end
65
- end
66
-
67
- # Check whether its a VTT_HEADER or not
68
- def validate_header(line)
69
- !!line.strip.match(/^#{VTT_HEADER}/)
70
- end
71
-
72
- # Check whether its a meta-data or not
73
- def is_meta_data?(text)
74
- !!text.match(VTT_METADATA)
75
- end
76
-
77
- # Timecode format used in VTT file
78
- def is_time?(text)
79
- !!text.match(/^(\d{2}:)?\d{2}:\d{2}.\d{3}.*(\d{2}:)?\d{2}:\d{2}.\d{3}/)
80
- end
81
-
82
- # Check whether if its subtilte text or not
83
- def is_text?(text)
84
- !text.empty? and text.is_a?(String) and text != VTT_HEADER
85
- end
86
-
87
- def set_properties(cue, properties)
88
- properties.each do |prop|
89
- prop, value = prop.split(":")
90
- value.gsub!("%","")
91
- case prop
92
- when "align"
93
- cue.alignment = get_alignment(value)
94
- when "line"
95
- value = value.split(",")[0]
96
- cue.position = get_line(value)
97
- end
98
- end
99
- end
100
-
101
- def get_alignment(value)
102
- raise InvalidSubtitle, "Invalid VTT Alignment Property" unless ALIGNMENT_VALUES[value]
103
- return ALIGNMENT_VALUES[value]
104
- end
105
-
106
- def get_line(value)
107
- raise InvalidSubtitle, "VTT Line property should be a valid number" if !is_integer?(value) and value != AUTO_KEYWORD
108
- return value.to_i
109
- end
110
-
111
- def get_position(value)
112
- raise InvalidSubtitle, "VTT Position should be a valid number" if !is_integer?(value)
113
- raise InvalidSubtitle, "VTT Position should be a number between 0 to 100" if (value.to_i < 0) or (value.to_i > 100)
114
- return value.to_i
115
- end
116
-
117
- def is_integer?(val)
118
- val.to_i.to_s == val
119
- end
120
- end
121
- end
1
+ module Captions
2
+ class VTT < Base
3
+
4
+ # Header used for all VTT files
5
+ VTT_HEADER = "WEBVTT"
6
+
7
+ # VTT file comments/style section
8
+ VTT_METADATA = /^NOTE|^STYLE/
9
+
10
+ # Auto Keyword used in Alignment
11
+ AUTO_KEYWORD = "auto"
12
+
13
+ # Alignment Data
14
+ ALIGNMENT_VALUES = {
15
+ "middle" => "middle",
16
+ "center" => "middle",
17
+ "left" => "left",
18
+ "right" => "right",
19
+ "start" => "start",
20
+ "end" => "end",
21
+ }
22
+
23
+ # Parse VTT file and update CueList
24
+ def parse
25
+ base_parser do
26
+ count = 1
27
+ cue_count = 0
28
+ meta_data_section = false
29
+ cue = nil
30
+ raise InvalidSubtitle, "Invalid VTT Signature" unless validate_header(@file.gets)
31
+ while(line = @file.gets) do
32
+ line = line.strip
33
+ if line.empty?
34
+ meta_data_section = false
35
+ elsif is_meta_data?(line)
36
+ meta_data_section = true
37
+ elsif is_time?(line)
38
+ @cue_list.append(cue) if cue
39
+ cue_count += 1
40
+ cue = Cue.new
41
+ cue.number = cue_count
42
+ line = line.split
43
+ cue.set_time(line[0], line[2])
44
+ set_properties(cue, line[3..-1])
45
+ elsif !meta_data_section and is_text?(line)
46
+ cue.add_text(line)
47
+ end
48
+ end
49
+ @cue_list.append(cue) if cue
50
+ end
51
+ end
52
+
53
+ # Export CueList to VTT file
54
+ def dump(file)
55
+ base_dump(file) do |file|
56
+ file.write(VTT_HEADER)
57
+ @cue_list.each do |cue|
58
+ file.write("\n\n")
59
+ file.write(msec_to_timecode(cue.start_time))
60
+ file.write(" --> ")
61
+ file.write(msec_to_timecode(cue.end_time))
62
+ file.write("\n")
63
+ file.write(cue.text)
64
+ end
65
+ end
66
+ end
67
+
68
+ # Check whether its a VTT_HEADER or not
69
+ def validate_header(line)
70
+ !!line.strip.match(/^#{VTT_HEADER}/)
71
+ end
72
+
73
+ # Check whether its a meta-data or not
74
+ def is_meta_data?(text)
75
+ !!text.match(VTT_METADATA)
76
+ end
77
+
78
+ # Timecode format used in VTT file
79
+ def is_time?(text)
80
+ !!text.match(/^(\d{2}:)?\d{2}:\d{2}.\d{3}.*(\d{2}:)?\d{2}:\d{2}.\d{3}/)
81
+ end
82
+
83
+ # Check whether if its subtilte text or not
84
+ def is_text?(text)
85
+ !text.empty? and text.is_a?(String) and text != VTT_HEADER
86
+ end
87
+
88
+ def set_properties(cue, properties)
89
+ properties.each do |prop|
90
+ prop, value = prop.split(":")
91
+ value.gsub!("%","")
92
+ case prop
93
+ when "align"
94
+ cue.alignment = get_alignment(value)
95
+ when "line"
96
+ value = value.split(",")[0]
97
+ cue.position = get_line(value)
98
+ end
99
+ end
100
+ end
101
+
102
+ def get_alignment(value)
103
+ raise InvalidSubtitle, "Invalid VTT Alignment Property" unless ALIGNMENT_VALUES[value]
104
+ return ALIGNMENT_VALUES[value]
105
+ end
106
+
107
+ def get_line(value)
108
+ raise InvalidSubtitle, "VTT Line property should be a valid number" if !is_integer?(value) and value != AUTO_KEYWORD
109
+ return value.to_i
110
+ end
111
+
112
+ def get_position(value)
113
+ raise InvalidSubtitle, "VTT Position should be a valid number" if !is_integer?(value)
114
+ raise InvalidSubtitle, "VTT Position should be a number between 0 to 100" if (value.to_i < 0) or (value.to_i > 100)
115
+ return value.to_i
116
+ end
117
+
118
+ def is_integer?(val)
119
+ val.to_i.to_s == val
120
+ end
121
+ end
122
+ end
@@ -1,3 +1,3 @@
1
1
  module Captions
2
- VERSION = "1.3.0"
2
+ VERSION = "1.3.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: captions
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - navin
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-10-11 00:00:00.000000000 Z
11
+ date: 2023-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '1.13'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '1.13'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -84,7 +84,7 @@ homepage: https://github.com/navinre/captions
84
84
  licenses:
85
85
  - MIT
86
86
  metadata: {}
87
- post_install_message:
87
+ post_install_message:
88
88
  rdoc_options: []
89
89
  require_paths:
90
90
  - lib
@@ -99,9 +99,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
99
  - !ruby/object:Gem::Version
100
100
  version: '0'
101
101
  requirements: []
102
- rubyforge_project:
103
- rubygems_version: 2.4.8
104
- signing_key:
102
+ rubygems_version: 3.1.2
103
+ signing_key:
105
104
  specification_version: 4
106
105
  summary: Subtitle Editor and Converter written in Ruby
107
106
  test_files: []