Normalise video file names

Updated: 2013-03-04 – Fixed bug that prevented names containing 720p/1080p from being parsed properly.

This is a perl script to normalize video file names for TV series, it will run under windows or linux.

Note: I have tested this and do use it however I may have missed something or there may be a bug I have not encountered, I would advise backing up the files to be renamed before running the script and then verify that it has worked as expected. If so delete the backups if not please leave a comment detailing what has happened and I’ll try to fix it asap.

Disclaimer: I am not responsible if this causes WWIII or nukes your computer, use at your own risk.

Supported naming schemes

Name

  • Single
  • Double.1
  • Double 2
  • Double-3
  • Double_4

Season-Episode

  • 101
  • 0102
  • 1×03
  • 1×4
  • 01×05
  • S1E06-e7
  • s1e8-9
  • S1e10-11
  • S01.E12
  • S01 E13
  • S01E14-E15

Supported file extensions

  • .avi
  • .mkv
  • .mpg
  • .mpeg
  • .mp4

Example “Double.1.1×1.XXX.XXX.XXX.mkv” would get normalized to “Double 1 S01E01.mkv”
and
Example “Double.1.1×1.720p.XXX.XXX.XXX.mkv” would get normalized to “Double 1 S01E01.mkv”

Requirements

All users need perl, windows users can get it (free) from http://www.activestate.com/Products/activeperl/

Usage

perl rname.pl – Will parse the directory given as an argument

perl rname.pl – Will ask the user to specify the directory to parse on the commandline

Files

Changelog

Code

rname.pl
#!/bin/perl -w
#!/usr/bin/perl -w
use warnings;
use strict;

my($verison) = "0.20";
print"\nrname.pl Version $verison...\n";
print"Copyright 2007 Ryan McLean\n\n";

use File::Copy;

my($input) = "";
if ($ARGV[0]) {
    $input = $ARGV[0];
} else {
    print "Enter directory to parse: ";
    $input = ; # Get Dir to parse
    chomp($input); # remove /r/n from input
}
my($dir) = "$input";

# Create log file
open (LOG, ">>$dir/rname.log");

printf LOG "\nParsing Files...\n\n";
print "\nParsing Files...\n\n";

opendir(THISDIR, "$dir") or die ("Error: $!");
 
my(@allfiles);

@allfiles = readdir THISDIR; 
closedir THISDIR; 

foreach my $fname (@allfiles) { # List contents of directory
    if (! -d "$dir/$fname" && ! -l "$dir/$fname") { # If not a dir & not a symlink to dir
         my($tmpName) = "";
	     my($tmpSE) = "";
	     my($addEp) = "";
	     my($ext) = "";
	     my(@chararr);
	     my($p1) = "";
	     my($p2) = "";
	
	     if ( ($fname =~ m/^.*\.(avi$|ogg$|mpg$|mpeg$|mkv$|mp4$)/) && (! -d $fname) ) { # Only get files with .avi, .ogg, .mpg, .mpeg, .mkv, .mp4 extension
	         $fname =~ m/^(.+?)[-\s_\.](S[0-9]+[\.\s]?E[0-9]+|[0-9]+x[0-9]+|[0-9]{3,4})(-[0-9]+|-E[0-9]+)?(\.[0-9]{3,4}[i|p])?.*\.(avi$|ogg$|mpg$|mpeg$|mkv$|mp4$)/i; # Match S01 E01 & S01E01 & 1x01 & 101 & 1001
	         $tmpName = $1;
	         $tmpSE = $2;
	         $addEp = $3;
	         $ext = $5;
	         
	         # Subsitute seperators with a single space, for files with multipart names
	         $tmpName =~ s/[-\s_\.]/ /i;
	         
	         if (!$tmpSE) { $tmpSE = ""; } # if $tmpSE is not set set it
	         if (!$tmpName) { $tmpName = ""; } # if $tmpName is not set set it
	         if (!$addEp) { $addEp = "" } # If there are no additional episodes then set it to null.
	         
	         if ($tmpSE =~ m/^[0-9]{3,3}$/i) {
	             @chararr = split(//, $tmpSE);
	             $tmpSE = "\L$chararr[0]x$chararr[1]$chararr[2]";
	         } elsif ($tmpSE =~ m/^[0-9]{4,4}$/i) {
	             @chararr = split(//, $tmpSE);
	             $tmpSE = "\L$chararr[0]$chararr[1]x$chararr[2]$chararr[3]";
	         } elsif ($tmpSE =~ m/^(.+)([xe][0-9]$)/i) {
	             # Catch S01E1 or 01x1 types and fix them to be E01 or x01
	             $tmpSE =~ m/^(.+)([xe][0-9]$)/i;
	             $p1 = $1;
	             $p2 = $2;
	             @chararr = split(//, $p2);
	             $tmpSE = "\L${p1}${chararr[0]}0${chararr[1]}";	          
	         } elsif ($tmpSE =~ m/^(S[0-9]+)[\.\s](E[0-9]+)$/i) {
	             $tmpSE = "\L${1}${2}";
	         }
	         if ($addEp =~ m/^-E?([0-9])$/i) {
	             $addEp = "-0${1}";
	         } elsif ($addEp =~ m/^-E([0-9]+)$/i) {
	             $addEp = "-${1}";
	         }
	         my($name) = "\u$tmpName \L$tmpSE$addEp.$ext";
	         if ($name =~ m/^[a-z0-9]+.*\.(avi$|ogg$|mpg$|mpeg$|mkv$|mp4$)/i) {
	            move("$dir/$fname", "$dir/$name"); # rename the files
	            print "Moved \"$dir/$fname\" -> \"$dir/$name\"\n";
	            printf LOG "Moved \"$dir/$fname\" -> \"$dir/$name\"\n";
	        }
         }
    }
}

 printf LOG "Filenames shortened...\n";
 print "Filenames shortened...\n";
 printf LOG "Using same naming convention for all files..\n";
 print "Using same naming convention for all files..\n";

 opendir(THISDIR, "$dir") or die ("Error: $!"); 

 @allfiles = readdir THISDIR; 
 closedir THISDIR; 
 
 foreach my $fname (@allfiles) { # List contents of directory
   if (! -d "$dir/$fname" && ! -l "$dir/$fname") { # If not a dir & not a symlink to dir
     my($tmpName) = "";
     my($tmpSE) = "";
     my($ext) = "";
     my(@chararr);
     my($SE) = "";

     $fname =~ s!^.*(/.*)$!$1!; # remove file path from file name
     $fname =~ s!^/(.*)$!$1!; # remove leading / from file name
     $fname =~ m/^(.+)\s(S[0-9]+E[0-9]+|[0-9]+x[0-9]+)\.(avi$|ogg$|mpg$|mpeg$|mkv$|mp4$)/i;
     $tmpName = $1;
     $tmpSE = $2;
     $ext = $3;
     if (!$tmpSE) { $tmpSE = ""; } # if $tmpSE is not set set it
     if (!$tmpName) { $tmpName = ""; } # if $tmpName is not set set it
     
     # Determine naming convention and rename
     if ($tmpSE =~ m/^[0-9]+x[0-9]+$/i) {
         @chararr = split(//, $tmpSE);
         if ($chararr[1] eq "x") {
             $SE = "\LS0$chararr[0]E$chararr[2]$chararr[3]";
         } elsif ($chararr[2] eq "x") {
             $SE = "\LS$chararr[0]$chararr[1]E$chararr[3]$chararr[4]";
         } else {
             die;
         }
     } elsif ($tmpSE =~ m/^S[0-9]E[0-9]+$/i) {
         @chararr = split(//, $tmpSE);
         $SE = "\LS0$chararr[1]E$chararr[3]$chararr[4]";
     } else {
         $SE = " ";
     }
     # Rename the files
     if ($SE =~ m/^[^\s]/i) {
        my($nname) = "$tmpName $SE.$ext";
        move("$dir/$fname", "$dir/$nname"); # rename the files
        printf LOG "Moved \"$dir/$fname\" -> \"$dir/$nname\"\n";
        print "Moved \"$dir/$fname\" -> \"$dir/$nname\"\n";
     }
   }
 }

 printf LOG "\nFinished..\n";
 close LOG;
 print "\nFinished..\n"; 
 

rnameTest.pl

# Test Suite for rname.pl
# version 1.4

$dir = "test 1";
$dir2 = "test 3";
$subdir = "test 2";

if ( ($ARGV[0]) && ($ARGV[0] = "-d" ) ) {
	opendir(THISDIR, "$dir") or die ("Error: $!");
	@files = readdir THISDIR;
	closedir THISDIR;
	open (LOG, ">>$dir/rnameTest.log");
	foreach my $fname (@files) { # List contents of directory
		if (! -d "$dir/$fname" && ! -l "$dir/$fname") { # If not a dir & not a symlink to dir
			if ($fname =~ m/^[a-z]+(\s[0-9])?\ss[0-9]+e[0-9]+(-\d+)?\.(avi$|ogg$|mpg$|mpeg$|mkv$)/i) {
				printf LOG "$fname\n";
				unlink("$dir/$fname");
			}
		}
	}
	close LOG;
} else {
	# File Name arrys
	@name = ("Single", "Double.1", "double 2", "Double-3", "Double_4");
	@SE = ("101", "0102", "1x03", "1x4", "01x05", "S1E06-e7", "s1e8-9", "S01e10-11", "S01.E12", "S01 E13", "S01E14-E15");
	@ext = (".avi", ".ogg", ".mpg", ".mpeg", ".mkv");
	$crap = "zzzz.ssss";

	# Make Directory
	mkdir "$dir";
	mkdir "$dir2";
	mkdir "$dir/$subdir";

	# Create files

	foreach $fname (@name) {
	 foreach $fse (@SE) {
	  foreach $fext (@ext) {
	    $nfname = "${fname}.${fse}-${crap}${fext}";
	    open F, ">$dir/$nfname";
	    close F;
	  }
	 }
	}

	foreach $fname (@name) {
	foreach $fse (@SE) {
	  foreach $fext (@ext) {
	    $nfname = "${fname}.${fse}-${crap}${fext}";
	    open F, ">$dir2/$nfname";
	    close F;
	  }
	 }
	}

	# File noise (to ensure just the $ext files are processed)
	open F, ">$dir/test.log";
	close F;
	open F, ">$dir/test.av";
	close F;
	open F, ">$dir/test.htm";
	close F;
	open F, ">$dir2/test.log";
	close F;
	open F, ">$dir2/test.av";
	close F;
	open F, ">$dir2/test.htm";
	close F;
}

test2.bat

@echo off
rem C:\rname\test.pl "dir1" "dir2" "dir3" "dir4" "dir5" "dir6" "dir7"
perl C:\rname\rnameTest.pl
perl C:\rname\rname.pl "test 1" "test 3"
perl C:\rname\rnameTest.pl "-d"
pause

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This blog is kept spam free by WP-SpamFree.