class SCC

Library to handle SCC Files

Uses the translator available to do the necessary language operations as defined by the AllFather

Constants

SUPPORTED_TRANSFORMATIONS

Public Class Methods

new(cc_file) click to toggle source
# File lib/scc.rb, line 19
def initialize(cc_file)
  @cc_file = cc_file
  raise "Invalid SCC file provided" unless is_valid?
end

Public Instance Methods

infer_languages() click to toggle source
# File lib/scc.rb, line 37
def infer_languages
  lang = nil
  begin
    sample_text = get_text(@cc_file, 100)
    lang = @translator.infer_language(sample_text)
  rescue StandardError => e
    puts "Error while detecting the language due to #{e.message}"
  end
  [lang]
end
is_valid?() click to toggle source
# File lib/scc.rb, line 24
def is_valid?
  # Do any SCC specific validations here
  if @cc_file =~ /^.*\.(scc)$/
    return true
  end
  return false
end
set_translator(translator) click to toggle source
Calls superclass method AllFather#set_translator
# File lib/scc.rb, line 32
def set_translator(translator)
  super(translator)
  @translator = translator
end
supported_transformations() click to toggle source
# File lib/scc.rb, line 52
def supported_transformations
  return SUPPORTED_TRANSFORMATIONS
end
transform_to(types, src_lang, target_lang, output_dir) click to toggle source
Calls superclass method AllFather#transform_to
# File lib/scc.rb, line 56
def transform_to(types, src_lang, target_lang, output_dir)
  # Let's start off with some validations
  super(types, src_lang, target_lang, output_dir)

  # Suffix output dir with File seperator
  output_dir = "#{output_dir}#{File::Separator}" unless output_dir.end_with?(File::Separator)
  
  # Prepare the output files for each type
  file_map = {}
  types.each do |type|
    output_file = File.basename(@cc_file, File.extname(@cc_file)) + extension_from_type(type)
    out_file = "#{output_dir}#{output_file}"
    if create_file(TYPE_SCC, type, out_file, target_lang)
      file_map[type] = out_file
    else
      raise StandardError.new("Failed to create output file for type #{type}")
    end
  end

  # Read the file and prepare the cue model
  prev_cue_info = cur_cue_info = nil
  ccfile = File.open(@cc_file, 'r:UTF-8', &:read)
  cue_index = 1
  ccfile.each_line do | line |
    time_point = line.scan(/(^\d\d:\d\d:\d\d:\d\d\s)(.*)/)
    unless time_point.empty?
      scc_text_code = time_point[0][1].strip
      message = decode(scc_text_code)
      # Replace \u0000 with empty as this causes the ttml / dfxp outputs
      # to treat them as end and terminates the xml the moment this is encountered
      # https://github.com/sparklemotion/nokogiri/issues/1535
      message = message.gsub(/\u0000/, '')
      if prev_cue_info.nil?
        prev_cue_info = CueInfo.new(TYPE_SCC)
        prev_cue_info.index = cue_index
        prev_cue_info.message = message
        prev_cue_info.start = time_point[0][0].strip
      else
        cur_cue_info = CueInfo.new(TYPE_SCC)
        cur_cue_info.index = cue_index
        cur_cue_info.message = message
        cur_cue_info.start = time_point[0][0].strip
        # Set the previous cue info's end time to current cue's start time
        # TODO: Need to see if we need to reduce alteast 1 fps or 1s
        prev_cue_info.end = cur_cue_info.start
        prev_cue_info.start_time_units = time_details(prev_cue_info.start, TYPE_SCC)
        prev_cue_info.end_time_units = time_details(prev_cue_info.end, TYPE_SCC)
        write_cue(prev_cue_info, file_map)
        prev_cue_info = cur_cue_info
      end
      cue_index += 1
    end
  end
  # we need to set some end time, but don't know the same !!
  # for now setting the start time itself
  cur_cue_info.end = cur_cue_info.start 
  cur_cue_info.start_time_units = time_details(cur_cue_info.start, TYPE_SCC)
  cur_cue_info.end_time_units = time_details(cur_cue_info.end, TYPE_SCC)
  write_cue(cur_cue_info, file_map, true)
end
translate(src_lang, dest_lang, out_file) click to toggle source
# File lib/scc.rb, line 48
def translate(src_lang, dest_lang, out_file)
  raise "Not Implemented. Class #{self.class.name} doesn't implement translate yet !!"
end

Private Instance Methods

decode(scc_code_text) click to toggle source
# File lib/scc.rb, line 134
def decode(scc_code_text)
  hex_codes = scc_code_text.gsub(/\s/,'').scan(/.{2}/)
  decoded_text = ""
  skip_next = false
  skip_count = 0
  hex_codes.each do | code |
    if ["94", "91", "92", "97", "15", "16", "10", "13"].include?(code)
      skip_next = true
      skip_count = skip_count + 1
      next
    end
    if skip_count == 1 && skip_next
      skip_next = false
      skip_count = 0
      next
    end
    dec_val = code.to_i(16) & 0x7F
    decoded_text << dec_val.chr
  end
  decoded_text
end
get_text(srt_file, num_chars) click to toggle source
# File lib/scc.rb, line 119
def get_text(srt_file, num_chars)
  ccfile = File.open(srt_file, 'r:UTF-8', &:read)
  text_sample = ""
  ccfile.each_line do | line |
    if line =~ /^\d\d:\d\d:\d\d:\d\d\s/
      scc_text_code = line.gsub(/^\d\d:\d\d:\d\d:\d\d\s/, '')
      text_sample << decode(scc_text_code)
      if text_sample.length > (num_chars + 1)
        break
      end
    end
  end
  return text_sample[0, num_chars]
end