Sunday, June 16, 2013

Script for changing name and/or numbering of anime files

I have an HTPC running XBMC, and I like anime, which tends to lead to a problem (very much a luxury problem, but still).

Anime series often have files that use absolute numbering, ie just an episode number, they are not divided into seasons. The problem is that the scrapers used by XBMC are not able to handle this, since their sources do use the "normal" season & episode format.

Now if a show is just 10 or 20 episodes, this is a minor inconvenience, just rename the files and it's done. If the show has 40 or 50 episodes, it's a bit more of an inconvenience. But if the show has a large number of episodes, it's a real pain. I remember renaming the show "Bleach" (which is a quite popular anime) in this way, it has 366 episodes (not counting the specials), and let me tell you, it was not particularly entertaining.

So in order to avoid this in future, I decided to make a bash script capable of handling this. Yes, I know, I could have done it as a full on program, with a GUI, but I felt like learning more about bash scripting and regular expressions.

Anyway, here it is. If you want to use it, just copy-paste it to a textfile (I named it chNamNum), then make the file executable using "chmod u+x chNamNum" in terminal. To execute the script, open terminal, go to the folder you saved the script in, and enter "./chNamNum <path to the folder the files are in>". The script will then ask questions about what you want to change in the filename:
  • Do you want to change the name of the show? (y/n)
    • Please enter the new name of the show
  • Do you want to keep the name part after the episode#? (y/n)
  • Do you want to change the numbering from absolute to seasons&episodes? (y/n)
    • Please enter the number of seasons
    • How many episodes are there in season <x>
The last one is repeated for each of the number of seasons specified.

Now, I can't really cover all eventualities of how the filename is formatted beforehand, so there are some limitations to the script. It assumes that the filename is something along the lines of "name01description.mkv". It can handle quite a few variations, but the important thing for it to work is that the first numbers in the filename is the episode number. So if the name of the show you want to use it on contains a number, I'm afraid you are out of luck (though you could adapt the script specifically for that pattern).


 #!/bin/bash  
 #Function for changing absolute numbers into Se/Ep-string  
 absToSeEp ()  
 { #args: Number of seasons; array with number of episodes in each season; absolute episode number  
  i=0  
  totalEps=0  
  mySeason=0  
  arr1=( $(echo "$2") )  
  myEp=$3  
  while [ "$i" -le "$1" -a "$myEp" -gt "$totalEps" ]  
  do  
   arrVal=${arr1[$i]}  
   totalEps=$(($totalEps+$arrVal))  
   if [ "$myEp" -le "$totalEps" ]; then  
    mySeason=$(($i+1))  
   fi  
   i=$(($i+1))  
  done  
  myEpisode=0  
  myEpisode=$(($myEp-$totalEps+${arr1[$(($mySeason-1))]}))  
  if [ $myEpisode -lt 10 ]; then  
   myEpisode="0$myEpisode"  
  fi  
  if [ $mySeason -lt 10 ]; then  
   mySeason="0$mySeason"  
  fi  
  echo """S"$mySeason"E"$myEpisode""  
 }  
 # Name change  
 read -p "Do you want to change the name of the show? (y/n): " nameChange  
 if [ "$nameChange" == "y" ]; then  
  read -p "Please enter the new name of the show: " newName  
 fi  
 # Kepp end of name  
 read -p "Do you want to keep the name part after the episode#? (y/n): " keepEnd  
 # Change absolute numbers to se/ep  
 read -p "Do you want to change the numbering from absolute to seasons&episodes? (y/n): " epChange  
 if [ "$epChange" == "y" ]; then  
  read -p "Please enter the number of seasons: " numSeasons  
  for (( i = 1; i <= "$numSeasons" ; i++ ))  
  do  
    read -p "How many episodes are there in season "$i": " epsInSe["$i"]  
  done  
 fi  
 if [ "$nameChange" == "y" -o "$epChange" == "y" ]; then  
  myDir="$1"  
  myFiles=""$1"/*"  
  newFile=""  
  ls -f "$1" | while read fil;  
  #for f in $myFiles  
  do  
   if [[ "$fil" =~ ^\. ]]; then  
    echo "NOPT"  
   else  
    if [ "$nameChange" == "y" ]; then  
     if [ "$epChange" == "y" ]; then  
      absNum=`echo "$fil" | sed -r 's/^[^0-9]*([0-9]+).*$/\1/'`  
      seEp=$(absToSeEp $numSeasons "$(echo ${epsInSe[@]})" $absNum)  
       if [ "$keepEnd" == "y" ]; then  
       myFileEnd=`echo "$fil" | sed -r 's/^[^0-9]*[0-9]+(.*)$/\1/'`  
        if [[ "$myFileEnd" == .* ]] || [[ "$myFileEnd" == _* ]] || [[ "$myFileEnd" == -* ]]; then  
         fileEnd="${myFileEnd:1:${#myFileEnd}}"  
        else  
          fileEnd=$myFileEnd  
        fi  
       else  
        fileEnd=`echo "$fil" | sed -r 's/^[^0-9]*[0-9]+.*\.([a-z]+)$/\1/'`  
      fi  
      newFile="$myDir/$newName.$seEp.$fileEnd"  
     else  
      orgRem=`echo "$fil" | sed -r 's/^[^0-9]*([0-9]+.*)$/\1/'`  
      newFile="$myDir/$newName.$orgRem"  
     fi     
    else  
     if [ "$epChange" == "y" ]; then  
      absNum=`echo "$fil" | sed -r 's/^[^0-9]*([0-9]+).*$/\1/'`  
      seEp=$(absToSeEp $numSeasons "$(echo ${epsInSe[@]})" $absNum)  
      if [ "$keepEnd" == "y" ]; then  
       myFileEnd=`echo "$fil" | sed -r 's/^[^0-9]*[0-9]+(.*)$/\1/'`  
        if [[ "$myFileEnd" == .* ]] || [[ "$myFileEnd" == _* ]] || [[ "$myFileEnd" == -* ]]; then  
         fileEnd="${myFileEnd:1:${#myFileEnd}}"  
        else  
         fileEnd=$myFileEnd  
        fi  
       else  
        fileEnd=`echo "$fil" | sed -r 's/^[^0-9]*[0-9]+.*\.([a-z]+)$/\1/'`  
      fi  
       orgName=`echo "$fil" | sed -r 's/(^[^0-9]*)[0-9]+.*$/\1/'`  
       if [[ "$orgName" == *. ]] || [[ "$orgName" == *_ ]] || [[ "$orgName" == *- ]]; then  
        finalName="${orgName:0:${#orgName}-1}"  
       else  
         finalName=$orgName  
       fi  
      newFile="$myDir/$finalName.$seEp.$fileEnd"  
     else  
      echo "Nothing to do!"  
     fi  
    fi  
    myFileName=$fil  
    myNewFileName=$newFile  
    echo "org. name: $myDir/$myFileName"  
    echo "new name: $myNewFileName"  
    mv "$myDir/$fil" "$myNewFileName"  
   fi  
  done  
 fi  

No comments:

Post a Comment