class Subconv::CaptionFilter

Apply post-processing to captions Supported operations:

Public Class Methods

new(options) click to toggle source
# File lib/subconv/caption_filter.rb, line 13
def initialize(options)
  @options = options
  @options[:filter_node_types] ||= []
  @options[:filter_node_types].push ColorNode if @options[:remove_color]
  @options[:filter_node_types].push FlashNode if @options[:remove_flash]
end

Public Instance Methods

process!(captions) click to toggle source
# File lib/subconv/caption_filter.rb, line 20
def process!(captions)
  last_timespan = nil
  open_captions = {}
  last_top_position = nil

  captions.map! do |caption|
    is_same_timespan = last_timespan == caption.timespan

    unless is_same_timespan
      # Time changed -> do not compare with previous top position
      last_top_position = nil
      open_captions = {}
    end

    if @options[:xy_position_to_top_or_bottom]
      caption.position = if caption.position.y < 0.5
                           last_top_position = caption.position.y
                           :top
                         elsif !last_top_position.nil? && (caption.position.y - last_top_position) < 0.08
                           # Do not move lines to the bottom when they are continuing directly
                           # from a caption displayed at the top to avoid continuous captions
                           # being thorn in half
                           last_top_position = caption.position.y
                           :top
                         else
                           :bottom
                         end

      # x position is removed altogether and the caption is now center-aligned
      caption.align = :middle
    end

    # Captions are expected to be ordered by increasing timespan and y position (this is
    # guaranteed for the SCC reader)
    if @options[:merge_by_position] && is_same_timespan && open_captions.key?(caption.position)
      target_caption = open_captions[caption.position]
      target_caption.content.children.push TextNode.new("\n")
      target_caption.content.children.concat caption.content.children
      # Remove this caption since it has been merged
      next
    end

    last_timespan = caption.timespan

    open_captions[caption.position] = caption
    caption
  end
  # Remove nils resulting from removed captions
  captions.compact!
  # Do per-caption processing after merging etc.
  captions.each(&method(:process_caption!))
end
process_caption!(caption) click to toggle source
# File lib/subconv/caption_filter.rb, line 73
def process_caption!(caption)
  filter_nodes! caption.content
  merge_text_nodes! caption.content
end

Private Instance Methods

filter_nodes!(node) click to toggle source

Remove specified nodes in an array, i.e. replace them with their children Only container nodes can be filtered

# File lib/subconv/caption_filter.rb, line 111
def filter_nodes!(node)
  return node unless node.is_a? ContainerNode

  node.children.map! do |child|
    # Filter recursively
    filter_nodes! child
    if @options[:filter_node_types].include?(child.class)
      # Replace child with contents
      child.children
    else
      child
    end
  end
  # Flatten away arrays that might have been introduced
  # by removing nodes
  node.children.flatten!

  node
end
merge_text_nodes!(node) click to toggle source

Merge continuous text nodes Example: [TextNode(“a”), TextNode(“b”)] -> [TextNode(“ab”)]

# File lib/subconv/caption_filter.rb, line 82
def merge_text_nodes!(node)
  return node unless node.is_a? ContainerNode

  current_text_node = nil
  node.children.map! do |child|
    if child.is_a? TextNode
      if current_text_node.nil?
        current_text_node = child
      else
        # Add text to previous node, copying the text if necessary (literals are frozen by default)
        current_text_node.text = current_text_node.text.dup if current_text_node.text.frozen?

        current_text_node.text << child.text
        # Remove this node
        next
      end
    else
      current_text_node = nil
      merge_text_nodes! child
    end
    child
  end

  # Remove nils from removed text nodes
  node.children.compact!
end