lørdag 14. november 2009

rTorrent + XBMC TV Library

In my never ending quest of creating the best home theater solution, i have written a bash script that converts downloaded media into a tv-series library structure. Read the description field of the script for more detailed information.

So in short, this script will turn the following folder structure:
/series/
       tv-show.s09.e10.xxxxx
       tv-show-0609.xxxxx
       tv-show_09x10.xxxxx

into the following:

/series/tv-show/season 06/
                         tv-show-0609.xxxxx
/series/tv-show/season 09/
                         tv-show.s09.e10.xxxxx
                         tv-show_09x10.xxxxx

And here is the script that does all the dirty work.

#!/bin/bash
# Filename:  mv-series
# Author:  Kim Eik
# License:  GPLv3
# Description:  This file is used in conjunction with rtorrent, it takes a
# a single input argument ex. "mythbusters.s01.e09.avi" and
# an optional prefix argument ex "/home/user". With this data
# the script creates the directory:
# "/home/user/Mythbusters/Season 01"
# And also creates the files: 
# "/home/user/Mythbusters/tvshow.nfo"
# and
# "/home/user/Mythbusters/Season 01/mythbusters.s01.e09.nfo"
# which XBMC can read to lookup tv-show information through
# scrapers. In addition the script prints out 
# "/home/user/Mythbuster/Season 01" without new line feed
# at the end. This output is for use with rtorrent, to set the
# new download directory (d.set_directory)

shopt -s nocasematch
filename=$1
seriesRegex=(
                "(.{3,})s([0-9]+).{0,1}?e([0-9]+{0,1}){0,1}"
                "(.{3,})([0-9]+)x([0-9]+)"
  "(.{3,})([0-9]{2})([0-9]{2})"
  "(.{3,})([0-9]{1})([0-9]{2})"
            )

trim()
{
    trimmed=$1
    trimmed=${trimmed%% }
    trimmed=${trimmed## }
    echo $trimmed
}

caseChange() {
 output=''
 for arg in $*
 do
  firstChar=${arg:0:1}
  rest=${arg:1}
  output="${output} `echo "${firstChar}" | tr '[a-z]' '[A-Z]'``echo "${rest}" | tr '[A-Z]' '[a-z]'`"
 done
 echo $output;
}

setSeriesTitle () {
        seriesTitle=$(trim "`echo $1 | tr '[_. ]' ' '`")
 seriesTitle=$(caseChange $seriesTitle)
}

setSeriesSeason() {
        seriesSeason=$1
}

setSeriesEpisode() {
 seriesEpisode=$1
}

createSeriesNFO() {
 file="${1}tvshow.nfo"
 if [[ ! -f $file ]]; then
 echo "
  <tvshow>
   <title>${2}</title>
  </tvshow>
      " > "${file}"
 fi
}

createEpisodeNFO() {
 file="${1}.nfo"
 if [[ ! -f $file ]]; then
 echo "
  <episodedetails>
    <season>${2}</season>
    <episode>${3}</episode>
  </episodedetails>
      " > "${file}"
 fi
}

if [[ $# -gt 2 ]]; then
        echo "Usage: ${0} \"filename\" [\"prefix\"]"
        exit 1
fi

for (( x=0; x<${#seriesRegex[@]}; x++ ))
do
        regex=${seriesRegex[$x]}
        if [[ $filename =~ $regex ]]; then
                case $x in
                        * )
                        setSeriesTitle "${BASH_REMATCH[1]}"
                        setSeriesSeason "${BASH_REMATCH[2]}"
   setSeriesEpisode "${BASH_REMATCH[3]}"
                        ;;
                esac
  if [ $# -eq 2 ]; then
   if [ "${2:$((${#2}-${#filename}))}" = "$filename" ]; then
    directory="${2:0:$((${#2}-${#filename}))}"
   else
    directory="$2/"
   fi
  fi
  seriesDir="${directory}${seriesTitle}/"
                seriesSeasonDir="${seriesDir}Season ${seriesSeason}/"
  mkdir -p "$seriesSeasonDir"
  
  #create nfo files
  #createSeriesNFO "$seriesDir" "$seriesTitle"
  
  if [[ "$filename" =~ (.*)\..{3} ]]; then
   filename=${BASH_REMATCH[1]}
   #createEpisodeNFO "${seriesSeasonDir}${filename}" "$seriesSeason" "$seriesEpisode"
   output="${seriesSeasonDir}"
  else
   #createEpisodeNFO "${seriesSeasonDir}${filename}" "$seriesSeason" "$seriesEpisode"
   output="${seriesSeasonDir}${filename}"
  fi

  #Output for rtorrent
  echo -n "${output}"
                exit 0
        fi
done

exit 1


in .rtorrent.rc:
schedule = watch_directory_1,5,5,"load_start=~/watch/series/*.torrent,d.set_directory=~/series/,d.set_custom3=series"
system.method.set_key = event.download.inserted_new,move_series,"branch=d.get_custom3=,\"d.set_directory=\\\"$execute_capture=/usr/local/bin/mv-series,$d.get_name=,$d.get_directory=\\\"\""

for all torrents in the watch folder "series" i set the custom3 variable to series, and in the case where custom3 variable is not empty rtorrent will execute the mv-series script which will return the new download directory.

And thats about it, according to the xbmc documentation, my htpc should now be showing my tv series in library mode.

A note about the nfo creation. It seems that xbmc omits looking up series information from scrapers when a nfo is present, where i originally thought it used nfo files as a supplement to the scrapers. Because of this, i have commented out the lines that actually creates the nfo files.

If you put this script too use, and you make any changes to it, please share your changes with the masses, so other can benefit from it.

Reference:
http://xbmc.org/wiki/?title=TV_Shows_%28Video_Library%29
http://xbmc.org/wiki/?title=Import_-_Export_Library#Video_nfo_Files

7 kommentarer:

  1. the script wont run for me, rtorrent moves it to /home/myuser/series/ but it doesnt sort it, so there seems to be something wrong. Im on Ubuntu Server 9.04.

    Also, where do I set the path for it to move the episodes to? I want them to be moved to /media/TV/ and not /series/

    SvarSlett
  2. Well, first of all, it only creates the correct directory structure, if and only if the input filename (the first argument of mv-series) matches any of the specified regex sentences in the script. Secondly, the reason its moved to /series/ is probably because you defined the schedule command (in .rtorrent.rc) to set d.set_directory to /series/. read the rTorrent documentation and customize the code according to your needs.

    SvarSlett
  3. Ah, so you need to add the name of the series you want to be sorted, I see. but where? under the filename=$1?

    SvarSlett
  4. no, thats not what i said at all. you only need to customize your .rtorrent.rc config. the schedule = ... line.
    you should change the value of d.set_directory.
    now it says d.set_directory=/series/ you should change it to /media/TV

    SvarSlett
  5. Well, yeah, I got that, that's not a issue anymore. The problem now is the script it self, it just moves the episode to the /media/TV-folder, it doesnt make a folder structure or move into a existing structure in the destination folder, when I start a torrent rtorrent prints me the error:
    "(19:14:48) Download event action failed: Bad return code."


    This is what i have in my .rtorrent.rc
    http://pastie.org/704554

    SvarSlett
  6. Ok, your making headway. In that case im very interested in knowing what your torrent names are. Try testing all the regex defined in $seriesRegex with this tool http://myregexp.com, that should show you if your tv torrents matches any of the regex sentences. and if not you probably have to define your own. as an example, the regex should match names as set in the example in this blogpost.

    SvarSlett
  7. I made a perl version of your shell script, which addresses some issues yours has with special characters and such in torrent names.

    Thanks for the inspiration!

    Script at: http://pastebin.com/GS8g4PMs

    BTW, for the Season Packs to work, the .rtorrent.rc-lines should be changed to:

    schedule = watch_directory_1,5,5,"load_start=/home/adam/MyLibrary/Watch/series/*.torrent,d.set_custom4=/home/adam/MyLibrary/TV-Shows/,d.set_custom3=series"
    system.method.set_key = event.download.inserted_new,move_series,"branch=d.get_custom3=,\"d.set_directory=\\\"$execute_capture=/home/adam/bin/mv-shows.pl,$d.get_name=,$d.get_custom4=\\\"\""


    That will give you a season-pack folder under Shows/Show Title/Season 01/Season_Pack_S01_Group/

    Redundant, I know, but it allows you to seed and watch in XBMC at the same time :)

    SvarSlett