captions 1.2.2 → 1.3.0

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
  SHA1:
3
- metadata.gz: bc2fd7159d9f46c3251b271226828af0370c6c72
4
- data.tar.gz: b87491508efc86cc0b403d76ce98aebaf91aaa2f
3
+ metadata.gz: aabb7f8d8e05f0bdd97f11c7d3d6ad2272daa4a8
4
+ data.tar.gz: 2487803e670a82b5280cbe710d8b1f53aeb7ad7d
5
5
  SHA512:
6
- metadata.gz: 6cd1fa878ad14fa718323d7191da8cb82f44b99feb15aa67987fdb55a8d25136fe2d4bf1a316109011bfec7b4260ce28906e1c2129f667d7e3ff8f5eb093325f
7
- data.tar.gz: e4e09a6c34efcfe00892c956decd8c803b786f7afde0f0764c23976d01826871b47d82fe540cfee44181ebb93cacb66cb5bdca91aa8fa83adb8e949ee708986c
6
+ metadata.gz: 247cbaedb31a2c5afc6d987b9521a62ef11e7c40460d1a5831093e00f1308ef682e86ee68832695110f85452dd3365fbdf3ea1d76219147b18838b0dd8812d22
7
+ data.tar.gz: ad8c0e97e9fb83e97facabfd17058427368672aa5ac2aa79f9f3b5908b5cf2c9e1e23c9a84c5e2ac8e3369e4e527144c6ab557e82126f15eb5cca828657cbe59
@@ -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
@@ -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", "~> 1.13"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+ end
@@ -170,9 +170,9 @@ module Captions
170
170
  # block is passed, it returns the entire cuelist.
171
171
  def fetch_result(&block)
172
172
  if block_given?
173
- @cue_list.select(&block)
173
+ return @cue_list.select(&block)
174
174
  else
175
- @cue_list
175
+ return @cue_list
176
176
  end
177
177
  end
178
178
  end
@@ -1,66 +1,93 @@
1
- module Captions
2
- class Cue
3
- include Util
4
-
5
- attr_accessor :number, :start_time, :end_time, :duration, :text, :property
6
-
7
- # Creates a new Cue class
8
- # Each cue denotes a subtitle.
9
- def initialize
10
- self.text = nil
11
- self.start_time = nil
12
- self.end_time = nil
13
- self.duration = nil
14
- self.number = nil
15
- self.property = {}
16
- end
17
-
18
- # Sets the time for the cue. Both start-time and
19
- # end-time can be passed together. This just assigns
20
- # the value passed.
21
- def set_time(start_time, end_time, duration = nil)
22
- self.start_time = start_time
23
- self.end_time = end_time
24
- self.duration = duration
25
- end
26
-
27
- # Serializes the values set for the cue.
28
- # Converts start-time, end-time and duration to milliseconds
29
- # If duration is not found, it will be calculated based on
30
- # start-time and end-time.
31
- def serialize(fps)
32
- raise InvalidSubtitle, "Subtitle should have start time" if self.start_time.nil?
33
- raise InvalidSubtitle, "Subtitle shold have end time" if self.end_time.nil?
34
-
35
- begin
36
- ms_per_frame = (1000.0 / fps)
37
- self.start_time = convert_to_msec(self.start_time, ms_per_frame)
38
- self.end_time = convert_to_msec(self.end_time, ms_per_frame)
39
- if duration.nil?
40
- self.duration = self.end_time - self.start_time
41
- else
42
- self.duration = convert_to_msec(self.duration, ms_per_frame)
43
- end
44
- rescue
45
- raise InvalidSubtitle, "Cannot calculate start-time or end-time"
46
- end
47
- end
48
-
49
- # Changes start-time, end-time and duration based on new frame-rate
50
- def change_frame_rate(old_rate, new_rate)
51
- self.start_time = convert_frame_rate(self.start_time, old_rate, new_rate)
52
- self.end_time = convert_frame_rate(self.end_time, old_rate, new_rate)
53
- self.duration = convert_frame_rate(self.duration, old_rate, new_rate)
54
- end
55
-
56
- # Adds text. If text is already found, new-line is appended.
57
- def add_text(text)
58
- if self.text.nil?
59
- self.text = text
60
- else
61
- self.text += "\n" + text
62
- end
63
- end
64
-
65
- end
66
- 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
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,75 +1,121 @@
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
- # Parse VTT file and update CueList
11
- def parse
12
- base_parser do
13
- count = 1
14
- cue_count = 0
15
- meta_data_section = false
16
- cue = nil
17
- raise InvalidSubtitle, "Invalid VTT Signature" unless validate_header(@file.gets)
18
- while(line = @file.gets) do
19
- line = line.strip
20
- if line.empty?
21
- meta_data_section = false
22
- elsif is_meta_data?(line)
23
- meta_data_section = true
24
- elsif is_time?(line)
25
- @cue_list.append(cue) if cue
26
- cue_count += 1
27
- cue = Cue.new
28
- cue.number = cue_count
29
- line = line.split
30
- cue.set_time(line[0], line[2])
31
- elsif !meta_data_section and is_text?(line)
32
- cue.add_text(line)
33
- end
34
- end
35
- @cue_list.append(cue) if cue
36
- end
37
- end
38
-
39
- # Export CueList to VTT file
40
- def dump(file)
41
- base_dump(file) do |file|
42
- file.write(VTT_HEADER)
43
- @cue_list.each do |cue|
44
- file.write("\n\n")
45
- file.write(msec_to_timecode(cue.start_time))
46
- file.write(" --> ")
47
- file.write(msec_to_timecode(cue.end_time))
48
- file.write("\n")
49
- file.write(cue.text)
50
- end
51
- end
52
- end
53
-
54
- # Check whether its a VTT_HEADER or not
55
- def validate_header(line)
56
- !!line.strip.match(/^#{VTT_HEADER}/)
57
- end
58
-
59
- # Check whether its a meta-data or not
60
- def is_meta_data?(text)
61
- !!text.match(VTT_METADATA)
62
- end
63
-
64
- # Timecode format used in VTT file
65
- def is_time?(text)
66
- !!text.match(/^(\d{2}:)?\d{2}:\d{2}.\d{3}.*(\d{2}:)?\d{2}:\d{2}.\d{3}/)
67
- end
68
-
69
- # Check whether if its subtilte text or not
70
- def is_text?(text)
71
- !text.empty? and text.is_a?(String) and text != VTT_HEADER
72
- end
73
-
74
- end
75
- 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
+ "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
@@ -13,6 +13,11 @@ module Captions
13
13
  @fps
14
14
  end
15
15
 
16
+ # Returns the parsed subtitles
17
+ def entries
18
+ @list
19
+ end
20
+
16
21
  # Hide all cues when inspecting CueList
17
22
  # Show only necessary info rather than printing everything
18
23
  def inspect
@@ -36,7 +41,13 @@ module Captions
36
41
 
37
42
  # Iterate through CueList
38
43
  def each
44
+ return to_enum(:each) unless block_given?
39
45
  @list.each { |c| yield(c) }
40
46
  end
47
+
48
+ # Array based enumerables for cuelist
49
+ def [](index)
50
+ @list[index]
51
+ end
41
52
  end
42
53
  end
@@ -1,3 +1,3 @@
1
1
  module Captions
2
- VERSION = "1.2.2"
2
+ VERSION = "1.3.0"
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.2.2
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - navin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-05-21 00:00:00.000000000 Z
11
+ date: 2017-10-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec