4

This is my first post on StackOverflow. Be gentle. :)

I have a linux server that I download television shows to and manually move the files to their respective folders for my Plex server to utilize. I would like to automate this process. I have gotten as far as below.

File naming convention Show.Name.SeasonNumberEpisodeNumber.HDTV.X264.etc...

Example: Almost.Human.S01E01.720p.HDTV.X264.mkv

NOTE: The Show name can be different lengths with a . between each word in the name.

I am able to extract the show folder name from the filename.

#!/bin/bash
readonly FILEPATH=~/downloads
readonly SAVEPATH=~/shows

for file in $FILEPATH/*.mkv
do
#Get foldername from filename (everything before .S0 is foldername
        foldername=$(basename "${file%.S0*}" | tr '.' ' ')
#Need to convert extracted season info into folder name ex. S01 = Season 1
#       seasonfolder=$(basename "${file}" | sed -e 's/^[^S0]*//;')

#Copy the file to the path we built.
#Auto-create folder if it doesn't exist?

#       cp $file  "$SAVEPATH/$foldername/#seasonfolder"

done

Issues:

  • I would like to also extract the season information from the filename and use it to build the rest of the folder path. Each file has a SxxExx portion that I can use to get the Season info. I would convert, for example, S01 into Season 1 to be part of the folder path.

Resulting Copy command would look something like this (using above filename)

cp Almost.Human.S01E01.720p.HDTV.X264.mkv shows/Almost Human/Season 1

I am not savvy enough with sed or regex to get the syntax right and after lots of searching, no one is quite doing this in any example I can "borrow" from.

Thanks in advance!

UPDATE

Much thanks to Janos! Not only did he provide an excellent solution, but helped me absorb a little more about using regex.

I made a few changes to the final product. After some research about Plex's naming convention requirements, I adjusted the regex to acommodate and also built in a "file exists" check to avoid unnecessary transfers.

Here's the final result that I will be adding to CRON later tonight.

#!/bin/bash
readonly FILEPATH=~/downloads
readonly SAVEPATH=~/shows

for file in $FILEPATH/*.mkv
do
        dfile="$SAVEPATH/$(basename "$file" | sed -e 's/\./ /g' -e 's?\(.*\) [Ss]\([0-9][0-9]\)[Ee]\([0-9][0-9]\) .*?\1/Season \2/\1 - S\2E\3.mkv?')"

        if [ ! -f "$dfile" ]

        then
                cp -v "$file" "$dfile"
                mkdir -p "$(dirname "$dfile")"
        else
                echo "file exists "$dfile""
        fi

done
JonShado
  • 43
  • 5
  • Welcome to SO! Try to limit a post to just one question. Regarding the folder, you may be interested in http://stackoverflow.com/questions/4906579/how-to-use-bash-to-create-a-folder-if-it-doesnt-already-exist – Jeff Jan 07 '14 at 16:06
  • Although you struggled to explain the input and output conventions, it would be more useful to give real examples of input and 'what you want to get' output. – Mihai Jan 07 '14 at 16:08
  • Thanks! Updated with examples and removed second question. (Thanks Jeff, I'll use that post and work it out for the file name) – JonShado Jan 07 '14 at 16:16
  • 1
    +1 for good question and ability to accept advice ; -) Good luck to all. – shellter Jan 07 '14 at 16:23
  • Your naming convention is awkward. Is there any way you could use a different separator than dot as a replacement for spaces in the show's name? Underscore seems to be a popular choice, or simple URL%20encoding. – tripleee Jan 07 '14 at 16:36
  • Possibly. I would have to script the name change though. The naming convention is that way when I download the files. – JonShado Jan 07 '14 at 16:39
  • I know that this has been there for a long time, but I developed a [library](https://github.com/divijbindlish/parse-torrent-name) in python that can do this for you. – Divij Bindlish Sep 01 '15 at 21:55

1 Answers1

2

You could do something like this:

for file in $FILEPATH/*.mkv; do
    # get the destination filename
    dfile="$SAVEPATH/$(basename "$file" | sed -e 's/\./ /g' -e 's?\(.*\) S0\([0-9]\)E\([0-9][0-9]\) .*?\1/Season \2/Episode \3.mkv?')"

    # create the destination directory
    mkdir -p "$(dirname "$dfile")"

    cp "$file" "$dfile"
done

This will create filenames like:

Almost Human/Season 1/Episode 01.mkv

To make filenames like this:

Almost Human/Season 1/Almost Human Episode 01.mkv

then change the sed like this:

sed -e 's/\./ /g' -e 's?\(.*\) S0\([0-9]\)E\([0-9][0-9]\) .*?\1/Season \2/\1 Episode \3.mkv?

The key in this solution is capturing the relevant parts of the name within \(...\), and then making references to these captured matches using \1 for the first \(...\), \2 for the second, and so on.

janos
  • 120,954
  • 29
  • 226
  • 236
  • I love it! Thanks for your answer! I think the only change i'd make (i'm working on figuring it out myself at the moment) is to add the show title into the Episode name to keep all file names unique. Otherwise I'd have an Episode 1 for each show name. I'm pretty sure Plex would like it more as Almost Human Episode 7.mkv. (Or with connectors like Almost_Human_Episode7.mkv) – JonShado Jan 07 '14 at 17:08