class Subconv::WebVtt::Writer

WebVTT caption writer

Public Class Methods

new(options = {}) click to toggle source
# File lib/subconv/webvtt/writer.rb, line 15
def initialize(options = {})
  @options = options
end

Public Instance Methods

write(io, captions) click to toggle source

Write captions to an IO stream captions must be an array of Caption instances

# File lib/subconv/webvtt/writer.rb, line 21
def write(io, captions)
  io.write(FILE_MAGIC + "\n\n")

  captions.each do |caption|
    write_caption(io, caption)
  end
end
write_caption(io, caption) click to toggle source

Write a single Scc::Caption to an IO stream

# File lib/subconv/webvtt/writer.rb, line 30
def write_caption(io, caption)
  settings = settings_to_string(caption_settings(caption))

  io.write(format(CUE_FORMAT, start_time: timecode_to_webvtt(caption.timespan.start_time), end_time: timecode_to_webvtt(caption.timespan.end_time), settings: settings) + "\n")
  text = node_to_webvtt_markup caption.content
  if @options[:trim_line_whitespace]
    # Trim leading and trailing whitespace from each line
    text = text.split("\n").each(&:strip!).join("\n")
  end
  io.write "#{text}\n\n"
end

Private Instance Methods

caption_settings(caption) click to toggle source

Convert WebVTT cue settings from a caption

# File lib/subconv/webvtt/writer.rb, line 63
def caption_settings(caption)
  settings = {
    'align' => caption.align.to_s
  }
  if caption.position.is_a?(Position)
    settings['line'] = webvtt_percentage(caption.position.y)
    settings['position'] = webvtt_percentage(caption.position.x)
  else
    settings['line'] = webvtt_simple_position(caption.position)
  end

  # Remove align if it is the default value anyway
  settings.delete('align') if settings['align'] == 'middle'

  settings
end
escape_text(text) click to toggle source

Replace WebVTT special characters in the text

# File lib/subconv/webvtt/writer.rb, line 100
def escape_text(text)
  text = text.dup
  text.gsub!('&', '&')
  text.gsub!('<', '&lt;')
  text.gsub!('>', '&rt;')
  text
end
node_to_webvtt_markup(node) click to toggle source

Convert one node to its corresponding WebVTT markup Conversion is very straightforward. Container nodes are converted recursively by calling nodes_to_webvtt_markup from within this function. Recursion depth should not be a problem since their are not that many different properties.

# File lib/subconv/webvtt/writer.rb, line 117
def node_to_webvtt_markup(node)
  # Text nodes just need to have their text converted
  return escape_text(node.text) if node.instance_of?(TextNode)

  # If it is not a text node, it must have children
  children = nodes_to_webvtt_markup(node.children)

  # Use an array because the === operator of Class does not work as expected (Array === Array is false)
  case [node.class]
  when [RootNode]
    children
  when [ItalicsNode]
    '<i>' + children + '</i>'
  when [UnderlineNode]
    '<u>' + children + '</u>'
  when [FlashNode]
    '<c.blink>' + children + '</c>'
  when [ColorNode]
    '<c.' + node.color.to_s + '>' + children + '</c>'
  else
    fail "Unknown node class #{node.class}"
  end
end
nodes_to_webvtt_markup(nodes) click to toggle source

Convert an array of nodes to their corresponding WebVT markup

# File lib/subconv/webvtt/writer.rb, line 109
def nodes_to_webvtt_markup(nodes)
  nodes.map { |node| node_to_webvtt_markup(node) }.join
end
settings_to_string(settings) click to toggle source

Convert a setting hash to the WebVTT settings string

# File lib/subconv/webvtt/writer.rb, line 81
def settings_to_string(settings)
  settings.map { |setting|
    setting.join(':')
  }.join(' ')
end
timecode_to_webvtt(time) click to toggle source

Convert a timecode to the h/m/s format required by WebVTT

# File lib/subconv/webvtt/writer.rb, line 88
def timecode_to_webvtt(time)
  value = time.to_seconds

  milliseconds = ((value * 1000) % 1000).to_i
  seconds      =  value.to_i % 60
  minutes      = (value.to_i / 60) % 60
  hours        =  value.to_i / 60 / 60

  format(TIMECODE_FORMAT, hours, minutes, seconds, milliseconds)
end
webvtt_percentage(value) click to toggle source

Format a value between 0 and 1 as percentage with 3 digits behind the decimal point

# File lib/subconv/webvtt/writer.rb, line 45
def webvtt_percentage(value)
  format('%.3f%%', (value * 100.0))
end
webvtt_simple_position(position) click to toggle source

Convert simple top/bottom positions to their corresponding WebVTT setting

# File lib/subconv/webvtt/writer.rb, line 50
def webvtt_simple_position(position)
  case position
  when :top
    # '0' would be better here, but Chrome does not support that yet
    '5%'
  when :bottom
    '-1,end'
  else
    fail ArgumentError, "Unknown position #{caption.position}"
  end
end