Class: VideoChapter

Inherits:
ApplicationRecord show all
Defined in:
app/models/video_chapter.rb

Overview

A single YouTube-style chapter marker for a Video. Persisted locally so we
can edit and re-push to the YouTube description without re-running AI
generation.

Constant Summary

Constants included from Schedulable

Schedulable::SIMPLE_FORM_OPTIONS

Instance Attribute Summary collapse

Belongs to collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from ApplicationRecord

ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation

Methods included from Schedulable

config

Methods included from Models::AfterCommittable

#after_commit

Methods included from Models::EventPublishable

#publish_event

Instance Attribute Details

#start_msObject (readonly)



14
# File 'app/models/video_chapter.rb', line 14

validates :start_ms, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 }

#titleObject (readonly)



13
# File 'app/models/video_chapter.rb', line 13

validates :title, presence: true, length: { maximum: 100 }

Class Method Details

.format_ms_to_hms(ms) ⇒ String?

Format a millisecond offset for display. Drops the hour part when zero.

Parameters:

  • ms (Integer, nil)

Returns:

  • (String, nil)


53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'app/models/video_chapter.rb', line 53

def self.format_ms_to_hms(ms)
  return nil if ms.nil?

  total_seconds = ms.to_i / 1000
  hours = total_seconds / 3600
  minutes = (total_seconds % 3600) / 60
  seconds = total_seconds % 60
  if hours.positive?
    format('%<h>d:%<m>02d:%<s>02d', h: hours, m: minutes, s: seconds)
  else
    format('%<m>d:%<s>02d', m: minutes, s: seconds)
  end
end

.parse_timestamp_to_ms(value) ⇒ Integer?

Parse a user-entered timestamp into milliseconds.

Parameters:

  • value (String, Integer, nil)

Returns:

  • (Integer, nil)

    milliseconds, or nil when the input is blank or unparseable.



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'app/models/video_chapter.rb', line 33

def self.parse_timestamp_to_ms(value)
  return nil if value.nil?

  s = value.to_s.strip
  return nil if s.empty?

  parts = s.split(':')
  return nil unless parts.all? { |p| p.match?(/\A\d+\z/) }

  nums = parts.map(&:to_i)
  case nums.length
  when 1 then nums[0] * 1000
  when 2 then ((nums[0] * 60) + nums[1]) * 1000
  when 3 then ((nums[0] * 3600) + (nums[1] * 60) + nums[2]) * 1000
  end
end

Instance Method Details

#timestamp_hmsString?

Hours-minutes-seconds string (zero-padded MM/SS), used by the CRM form.

Returns:

  • (String, nil)

    e.g. "1:02:03" or "0:42"; nil when start_ms is blank.



18
19
20
# File 'app/models/video_chapter.rb', line 18

def timestamp_hms
  self.class.format_ms_to_hms(start_ms)
end

#timestamp_hms=(value) ⇒ Integer?

Setter paired with #timestamp_hms for accepts_nested_attributes_for forms.
Accepts "H:MM:SS", "M:SS", or a bare integer seconds string. Blank clears.

Parameters:

  • value (String, Integer, nil)

Returns:

  • (Integer, nil)

    the milliseconds value just assigned to start_ms.



26
27
28
# File 'app/models/video_chapter.rb', line 26

def timestamp_hms=(value)
  self.start_ms = self.class.parse_timestamp_to_ms(value)
end

#videoVideo

Returns:

See Also:



9
# File 'app/models/video_chapter.rb', line 9

belongs_to :video, foreign_key: :digital_asset_id, class_name: 'Video', inverse_of: :video_chapters