agilecreativity/mp4_renamer

View on GitHub
lib/mp4_renamer/renamer.rb

Summary

Maintainability
A
1 hr
Test Coverage
module Mp4Renamer
  module Errors
    InvalidInputFileError = Class.new(StandardError)
    MetadataNotAvailableError = Class.new(StandardError)
  end

  class Renamer
    attr_reader :commit

    # Initialization code
    #
    # @param [Boolean] commit the flag to indicate if the operation is to be executed
    def initialize(commit = false)
      @commit = commit
    end

    # Rename the input mp4 file and append the track time to the end
    #
    # @param [String] filename the input file
    # @param [String] sep_string the separator string to use default to '_' underscore
    # @raise [Errors::InvalidInputFileError] if the file is not valid or not readable
    # @example
    #   If the running time for the `sample.mp4` is '06:10' minutes
    #
    #   rename("/path/to/sample.mp4")         #=> will rename the file to '/path/to/sample_06.10.mp4'
    #   rename("/path/to/bad-input-file.mp4") #=> will raise error
    def rename(filename, sep_string = '_')
      raise Errors::InvalidInputFileError unless File.exist?(filename) && File.readable?(filename)
      puts "FYI: input file : #{filename}"
      info = MP4Info.open(filename)

      # e.g. Other useful information that may be used if applicable
      # * SECS - Total seconds, rounded to nearest second
      # * MM   - Minutes
      # * SS   - Leftover seconds
      # * MS   - Leftover milliseconds, rounded to nearest millisecond
      # * TIME - Time in MM:SS, rounded to nearest second
      # Note: info.TIME always available? if not we need to ignore the operation
      # Or just skip the file?
      raise Errors::MetadataNotAvailableError unless info.TIME

      running_time = info.TIME.gsub(":", sep_string)

      base_name = File.basename(filename, '.*') # 'sample01'
      ext_name  = File.extname(filename)        # '.mp4'
      dir_name  = File.dirname(filename)        # '/path/to/this/sample'

      new_name = "#{base_name}#{sep_string}#{running_time}#{ext_name}"
      output_file = [ dir_name, new_name ].join(File::SEPARATOR)

      if rename_once?(output_file) || File.exist?(output_file)
        puts "FYI: output file: #{filename} already exist, no action required!"
      else
        FileUtils.mv filename, output_file if commit
        puts "FYI: output file: #{output_file}"
      end
      output_file
    end

    # Return true if the file has already been renamed
    # @param [String] filename the input file name
    # @example
    #   rename_once?("some_file.mp4")             == false
    #   rename_once?("some_file_12_34.mp4")       == false
    #   rename_once?("some_file_12_34_12_34.mp4") == true
    def rename_once?(filename)
      basename = File.basename(filename, File.extname(filename))
      basename.match(/^(.*)_(\d+)_(\d+)_\2_\3$/)
    end
  end
end