Created
May 28, 2010 20:36
-
-
Save henrik/417708 to your computer and use it in GitHub Desktop.
Ruby script/command to rename TV series episodes by pattern, e.g. for Plex.
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 -r ftools | |
# "vname" by Henrik Nyh <http://henrik.nyh.se> on 2010-05-28 under the MIT license. | |
# | |
# Usage: | |
# | |
# vname PATTERN | |
# | |
# Prompts to rename files in the working directory matching the PATTERN into this pattern: | |
# | |
# X-Files - S01E03 - Pilot.avi | |
# | |
# Useful for e.g. renaming TV series episodes for Plex. | |
# | |
# The pattern is a combination of whichever of these you like: | |
# | |
# :s - season number (defaults to 1) | |
# :e - episode number (also handles intervals like 01-02, defaults to 1) | |
# :p - programme/show name | |
# :t - episode title | |
# ... - any uninteresting sequence of characters | |
# | |
# The pattern doesn't have to match the full filename, only part. Don't mention the extension. | |
# | |
# You can use e.g. ":s:e" for "203.avi" to get "S02E03". In that case it assumes the season is a single digit. | |
# | |
# You may also specify programme and season explicitly as second and third command-line arguments, to get around | |
# tricky names. E.g. "tpz-deadwood301.avi" makes it difficult to separate programme and season, so you could do | |
# | |
# vname tpz-deadwood3:e Deadwood 3 | |
# | |
# Example session: | |
# | |
# $ touch "X-Files [1x01] Pilot- DVDRip.avi" | |
# $ touch "X-Files [1x02] Ett kul avsnitt- DVDRip.avi" | |
# $ ls X-Files* | |
# X-Files [1x01] Pilot- DVDRip.avi X-Files [1x02] Ett kul avsnitt- DVDRip.avi | |
# $ vname ":p [:sx:e] :t-" | |
# | |
# From: X-Files [1x01] Pilot- DVDRip.avi | |
# To: X-Files - S01E01 - Pilot.avi | |
# | |
# From: X-Files [1x02] Ett kul avsnitt- DVDRip.avi | |
# To: X-Files - S01E02 - Ett kul avsnitt.avi | |
# | |
# Rename 2 files (y/n - default: n)? y | |
# | |
# Renamed: X-Files [1x01] Pilot- DVDRip.avi ==> X-Files - S01E01 - Pilot.avi | |
# Renamed: X-Files [1x02] Ett kul avsnitt- DVDRip.avi ==> X-Files - S01E02 - Ett kul avsnitt.avi | |
# | |
# Done. | |
# $ ls X-Files* | |
# X-Files - S01E01 - Pilot.avi X-Files - S01E02 - Ett kul avsnitt.avi | |
# Usage instructions. | |
if ARGV.empty? | |
puts File.readlines(__FILE__).grep(/^# /) | |
exit | |
end | |
pattern = ARGV[0] | |
global_programme = ARGV[1] | |
global_season = ARGV[2] | |
patterns = pattern.split(/(:[pest]|\.\.\.)/u) | |
parts = patterns.map { |part| | |
case part | |
when ':p': /(.+)/ | |
when ':e': /(\d+(?:-\d+)?)/ | |
when ':s': /(\d+?)/ | |
when ':t': /(.+)/ | |
when '...': /.*/ | |
else Regexp.escape(part) | |
end | |
} | |
parts << /.*(\.\w+)$/ # Extension. | |
re = parts.join | |
capture_groups = patterns.select { |part| part.match(/:[pest]/) } | |
renamings = [] | |
filenames = Dir["*"] | |
filenames.each do |old_filename| | |
next unless (match = old_filename.match(re)) | |
captures = match.captures | |
extension = captures.pop | |
mapping = captures.to_enum.with_index.inject({}) {|hash, (value, index)| hash.merge( capture_groups[index] => value ) } | |
programme, episode, season, title = mapping.values_at(*%w[:p :e :s :t]) | |
programme = global_programme || programme | |
season = global_season || season | |
new_filename_parts = [] | |
new_filename_parts << programme | |
new_filename_parts << format("S%02dE%02d", (season ? season.to_i : 1), (episode ? episode.to_i : 1)) | |
new_filename_parts << title | |
new_filename = new_filename_parts.compact.join(' - ') + extension | |
renamings << [old_filename, new_filename] | |
puts | |
puts "From: #{old_filename}" | |
puts "To: #{new_filename}" | |
end | |
if renamings.empty? | |
puts "Nothing matches that pattern." | |
else | |
puts | |
print "Rename #{renamings.length} file#{'s' if renamings.length > 1} (y/n - default: n)? " | |
answer = STDIN.gets | |
exit unless answer.match(/y/i) | |
puts | |
renamings.each do |old_filename, new_filename| | |
File.mv(old_filename, new_filename) | |
puts "Renamed: #{old_filename} ==> #{new_filename}" | |
end | |
puts | |
puts "Done." | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment