captive 1.0.2 → 1.1.2

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: 030c1968b45eac6bb952f8bfd45b569820747ec338c6c6b155c6c7ba22f61a77
4
- data.tar.gz: 8f9819a585d7633b3dab6741d0a650e555171bdbdf578fcb8cad34016c415593
3
+ metadata.gz: 0efb1ac420047333556fffa1f812da51c934d04ec1c4663abdd16dff37119bae
4
+ data.tar.gz: a82f64acf3da2b74cf5d72714939ee0559121b8ec43fbc2f92a5597c1f179a78
5
5
  SHA512:
6
- metadata.gz: 5d4cd22b2a652db4198de20628d68465fe84d0727e0e4db8586635b4fadcc5860e3767998a4fbd9364c3cdaf8f8a62a53d85b2faf8983c54f9ef87c754e36bfe
7
- data.tar.gz: 3823a40e5354abff877951bd636a6e2482d38af42b281ba95ec8cd5be3fe7ba71188dea4242c790b05b7526f04c7df5d9e947403c110357e183520f625ba8887
6
+ metadata.gz: a8a2c9496fcfe350776c912599e03495d3df9f907cfb4dbe85b9a531740c2a1b843e84fbf5eba9e1c27a0717b23a6b438a8e833ac0c6c45d653c67841b50f5ba
7
+ data.tar.gz: 8a369222333aaefdcb4cf5798536a2174baf344a46aab0f7e59bb687235865e9c5f29c7bd7322383b28c61736f3d2074f135cbcbb8d642dc8bc569fd2c558539
@@ -14,6 +14,15 @@ module Captive
14
14
  def from_blob(blob:)
15
15
  new(cue_list: parse(blob: blob))
16
16
  end
17
+
18
+ def from_json(json:, mapping: {})
19
+ json = JSON.parse(json) if json.is_a?(String)
20
+ cues = json['cues'] || json[:cues]
21
+ raise InvalidJsonInput unless cues.is_a?(Array)
22
+
23
+ cues.map! { |cue_json| Cue.from_json(json: cue_json, mapping: mapping) }
24
+ new(cue_list: cues)
25
+ end
17
26
  end
18
27
 
19
28
  def self.included(base)
@@ -12,18 +12,35 @@ module Captive
12
12
  # List of Text Properties
13
13
  TEXT_PROPERTIES = [ALIGNMENT, COLOR, POSITION].freeze
14
14
 
15
- attr_accessor :number, :text, :properties
15
+ attr_accessor :text, :properties
16
16
  attr_reader :start_time, :end_time
17
17
 
18
18
  # Creates a new Cue class denoting a subtitle.
19
- def initialize(text: nil, start_time: nil, end_time: nil, cue_number: nil, properties: {})
19
+ def initialize(text: nil, start_time: nil, end_time: nil, properties: {})
20
20
  self.text = text
21
21
  self.start_time = start_time
22
22
  self.end_time = end_time
23
- self.number = cue_number
24
23
  self.properties = properties || {}
25
24
  end
26
25
 
26
+ def self.from_json(json:, mapping: {})
27
+ schema = {}
28
+ %i[text! start_time! end_time! properties].each do |field|
29
+ field_name = field.to_s.delete('!')
30
+ schema[field] = mapping[field_name] || mapping[field_name.to_sym] || field_name.to_sym
31
+ end
32
+ data = {}
33
+ schema.each do |mask, mapper|
34
+ key = mask[-1] == '!' ? mask.to_s[0...-1].to_sym : mask
35
+ if key.to_s != mask.to_s && !(json.key?(mapper.to_s) || json.key?(mapper.to_sym))
36
+ raise InvalidJsonInput, "Cue missing field: #{mapper}"
37
+ end
38
+
39
+ data[key] = json[mapper.to_s] || json[mapper.to_sym]
40
+ end
41
+ new(**data)
42
+ end
43
+
27
44
  def start_time=(time)
28
45
  set_time(:start_time, time)
29
46
  end
@@ -68,11 +85,16 @@ module Captive
68
85
  end
69
86
 
70
87
  def as_json(**args)
71
- if respond_to?(:instance_values) && instance_values.respond_to?(:as_json)
72
- instance_values.as_json(**args)
73
- else
74
- instance_variables.each_with_object({}) { |key, hash| hash[key[1..-1]] = instance_variable_get(key) }
75
- end
88
+ options = args.delete(:options) || {}
89
+ format = options['format'] || options[:format] || {}
90
+ mapping = (options['mapping'] || options[:mapping] || {}).map { |k, v| [k.to_s, v.to_s] }.to_h
91
+ obj = {
92
+ mapping['start_time'] || 'start_time' => format[:time] == :timecode ? milliseconds_to_timecode(start_time) : start_time,
93
+ mapping['end_time'] || 'end_time' => format[:time] == :timecode ? milliseconds_to_timecode(end_time) : end_time,
94
+ mapping['text'] || 'text' => text,
95
+ mapping['properties'] || 'properties' => properties,
96
+ }
97
+ obj.respond_to?(:as_json) ? obj.as_json(**args) : obj
76
98
  end
77
99
 
78
100
  private
@@ -16,4 +16,7 @@ module Captive
16
16
  # Error denoting incorrect input to a method.
17
17
  class InvalidInput < CaptiveError
18
18
  end
19
+
20
+ class InvalidJsonInput < CaptiveError
21
+ end
19
22
  end
@@ -19,13 +19,12 @@ module Captive
19
19
 
20
20
  raise InvalidSubtitle, "Invalid Cue Number at line #{count}" if /^\d+$/.match(line).nil?
21
21
 
22
- cue = Cue.new(cue_number: line.to_i)
23
22
  state = :time
24
23
  when :time
25
24
  raise InvalidSubtitle, "Invalid Time Format at line #{count}" unless timecode?(line)
26
25
 
27
26
  start_time, end_time = line.split('-->').map(&:strip)
28
- cue.set_times(
27
+ cue = Cue.new(
29
28
  start_time: format_time(start_time),
30
29
  end_time: format_time(end_time)
31
30
  )
@@ -51,8 +50,8 @@ module Captive
51
50
 
52
51
  def to_s
53
52
  string = String.new
54
- @cue_list.each do |cue|
55
- string << cue.number.to_s
53
+ cues.each_with_index do |cue, index|
54
+ string << (index + 1).to_s
56
55
  string << "\n"
57
56
  string << milliseconds_to_timecode(cue.start_time).gsub!('.', ',')
58
57
  string << ' --> '
@@ -14,7 +14,6 @@ module Captive
14
14
  def self.parse(blob:)
15
15
  cue_list = []
16
16
  lines = blob.split("\n")
17
- cue_count = 1
18
17
  state = :new_cue
19
18
  cue = nil
20
19
  raise InvalidSubtitle, 'Invalid VTT Signature' unless validate_header(lines.shift)
@@ -42,8 +41,7 @@ module Captive
42
41
  elements = line.split
43
42
  start_time = elements[0]
44
43
  end_time = elements[2]
45
- cue = Cue.new(cue_number: cue_count, start_time: start_time, end_time: end_time)
46
- cue_count += 1
44
+ cue = Cue.new(start_time: start_time, end_time: end_time)
47
45
  state = :text
48
46
  when :text
49
47
  if line.empty?
@@ -73,7 +71,7 @@ module Captive
73
71
  def to_s
74
72
  string = VTT_HEADER.dup
75
73
  string << "\n\n"
76
- @cue_list.each do |cue|
74
+ cues.each do |cue|
77
75
  string << milliseconds_to_timecode(cue.start_time)
78
76
  string << ' --> '
79
77
  string << milliseconds_to_timecode(cue.end_time)
@@ -86,7 +84,8 @@ module Captive
86
84
 
87
85
  # VTT Header tag matcher
88
86
  def self.validate_header(line)
89
- !!line.strip.match(/^#{VTT_HEADER}/)
87
+ # Make sure BOM does not interfere with header detection
88
+ !!line.force_encoding('UTF-8').delete("\xEF\xBB\xBF").strip.match(/^#{VTT_HEADER}/)
90
89
  end
91
90
 
92
91
  # VTT Metadata tag matcher
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Captive
4
- VERSION = '1.0.2'
4
+ VERSION = '1.1.2'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: captive
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - mserran2
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-14 00:00:00.000000000 Z
11
+ date: 2020-07-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -109,7 +109,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
109
109
  requirements:
110
110
  - - ">="
111
111
  - !ruby/object:Gem::Version
112
- version: '0'
112
+ version: 1.9.2
113
113
  required_rubygems_version: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - ">="