Skip to content

Instantly share code, notes, and snippets.

@whitequark
Last active June 14, 2017 11:53
Show Gist options
  • Save whitequark/5d9e2c164c5022984395733231f36548 to your computer and use it in GitHub Desktop.
Save whitequark/5d9e2c164c5022984395733231f36548 to your computer and use it in GitHub Desktop.
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 [email protected]"
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