Last active
June 14, 2017 11:53
-
-
Save whitequark/5d9e2c164c5022984395733231f36548 to your computer and use it in GitHub Desktop.
Automated subtitle file renamer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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