Skip to content

Instantly share code, notes, and snippets.

@whitequark whitequark/subrenamer.rb
Last active Jun 14, 2017

Embed
What would you like to do?
Automated subtitle file renamer
#!/usr/bin/env ruby
# License: BSD-0-clause
VIDEO_EXTS = %w(.mkv .avi .mp4)
SUBTITLE_EXTS = %w(.ssa .ass .srt)
if ARGV.empty?
puts "Automatic subtitle file renamer by whitequark@whitequark.org"
puts "Usage: #{$0} *.ssa *.mkv"
puts " or: DRY_RUN=1 #{$0} *.ssa *.mkv"
puts "Known extensions: #{VIDEO_EXTS.join ' '} #{SUBTITLE_EXTS.join ' '}"
exit 0
end
videos = ARGV.select { |f| VIDEO_EXTS.include? File.extname(f) }
subtitles = ARGV.select { |f| SUBTITLE_EXTS.include? File.extname(f) }
if videos.size + subtitles.size != ARGV.size
puts "Unsupported files: #{ARGV - videos - subtitles}"
exit 1
end
def common_prefix(strings)
prefix = strings.first
old_prefix = prefix
strings.each do |string|
until string.start_with? prefix
prefix = prefix.chop
if prefix.empty?
puts "No shared prefix between #{old_prefix.inspect} and #{string.inspect}"
exit 1
end
old_prefix = prefix
end
end
prefix.sub(/\d+$/, '')
end
video_prefix = common_prefix(videos)
subtitle_prefix = common_prefix(subtitles)
puts "Video prefix: #{video_prefix.inspect}"
puts "Subtitle prefix: #{subtitle_prefix.inspect}"
def split(prefix, string)
if string =~ /^(^#{Regexp.escape prefix})(\d+)(.+)$/
[$1, $2, $3]
else
puts "Cannot extract episode number from #{string.inspect}"
exit 1
end
end
subtitles_by_episode = {}
subtitles.each do |subtitle|
prefix, episode, suffix = split(subtitle_prefix, subtitle)
if subtitles_by_episode.include? episode
puts "Duplicate subtitle for episode #{episode}"
exit 1
end
subtitles_by_episode[episode] = [prefix, suffix]
end
subtitle_map = {}
videos.each do |video|
video_prefix, episode, video_suffix = split(video_prefix, File.basename(video, ".*"))
unless subtitles_by_episode.include? episode
puts "Episode #{episode} does not have a subtitle track"
exit 1
end
subtitle_prefix, subtitle_suffix = subtitles_by_episode[episode]
subtitle_map["#{subtitle_prefix}#{episode}#{subtitle_suffix}"] =
"#{video_prefix}#{episode}#{video_suffix}#{File.extname subtitle_suffix}"
end
non_unique_subtitles = (subtitle_map.values - subtitle_map.values.uniq).uniq
if non_unique_subtitles.any?
puts "Renamed subtitles are non-unique: #{non_unique_subtitles.inspect}"
exit 1
end
subtitle_map.each do |from, to|
puts "#{from.inspect} => #{to.inspect}"
if File.exists? to
puts "Renamed subtitle file already exists: #{to.inspect}"
exit 1
end
end
unless ENV.include? 'DRY_RUN'
subtitle_map.each do |from, to|
File.rename from, to
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.