Archive

Media

I made some changes to make my handleMedia.sh script more generic, removing some duplicate code, etc. Here is the final result. I’m still trying to think of a good way to pare it down even more, I don’t like how ugly all the matching is to figure out if the files are located in the Downloads folder or one or two folders deep.

#!/bin/bash

#/usr/local/bin/handleMedia.sh
#
# Jay Holler 09-24-2011
# Find files in the Downloads directory and move them to
# the appropriate folder on the NFS share or put them in the Dropbox directory for syncing to iTunes.

# Set up some reusable variables
notify=$(/usr/local/bin/prowl.pl -apikey=”/dev/null” -application=”`basename $0`” -event=”Done” -notification=”`cat /tmp/emailmessage.txt`”)
umask 0022

#Function for matching TV shows, assumes SxxExx format and “.” separators
function MOVE_TV_SHOWS() {

storageDir=/home/jholler/TV
cd /home/jholler/Downloads

for myFile in *.$ext; do

shopt -s nocasematch
if [[ "$myFile" =~ ([A-Za-z0-9\.]*)\.(S..E..).*.$ext ]] ; then
File=${BASH_REMATCH[2]}.$ext
PreShowName=${BASH_REMATCH[1]}
ShowName=$(echo $PreShowName | sed ‘s/\./ /g’)
echo “[*] A new episode of $ShowName is ready for your enjoyment: $File” > /tmp/emailmessage.txt && sleep 2
[ -d "$storageDir/$ShowName" ] || mkdir -v “$storageDir/$ShowName”
mv -v $myFile “$storageDir/$ShowName/$ShowName.$File”
$notify
else
echo “[+] $myFile does not appear to be a TV show, pushing it to /home/jholler/Movies on lunchbox” > /tmp/emailmessage.txt
mv -v “$myFile” “/home/jholler/Movies/$myFile”
$notify
fi
done

}

#Function for matching mp3s, typically stored in a folder for the album.
function MOVE_MP3() {

storageDir=/home/jholler/Music/new
cd /home/jholler/Downloads

myFile=$(ls */*.mp3 | head -1)

shopt -s nocasematch
if [[ "$myFile" =~ ([A-Za-z0-9].*)\/([A-Za-z0-9].*).mp3 ]] ; then
AlbumName=${BASH_REMATCH[1]}
[ -d "$storageDir/$AlbumName" ] || mkdir -v “$storageDir/$AlbumName”
mv -v “$AlbumName” “$storageDir/”
echo “[*] The album $AlbumName is now ready for your enjoyment” > /tmp/emailmessage.txt && sleep 2
$notify
else
echo “[+] $myFile does not appear to consist of mp3 files, please investigate” > /tmp/emailmessage.txt
$notify
fi

shopt -u nocasematch

}

###############################################
## Start the avi matching portion of the script
## If for some reason the file is located in a folder or several folders deep, find it and put it in the Downloads directory for further manipulation.
###############################################
cd /home/jholler/Downloads
ls *.avi 2> /dev/null | wc -l && ext=avi; MOVE_TV_SHOWS
ls */*.avi 2> /dev/null | wc -l && mv */*.avi /home/jholler/Downloads; ext=avi; MOVE_TV_SHOWS
ls Movies/*/*.avi 2> /dev/null | wc -l && mv Movies/*/*.avi /home/jholler/Downloads; ext=avi; MOVE_TV_SHOWS
ls TV/*.avi 2> /dev/null | wc -l && mv TV/*.avi /home/jholler/Downloads; ext=avi; MOVE_TV_SHOWS
ls TV/*/*.avi 2> /dev/null | wc -l && mv TV/*/*.avi /home/jholler/Downloads; ext=avi; MOVE_TV_SHOWS
#########################################
## End avi matching portion of the script
#########################################
###############################################
## Start the mkv matching portion of the script
## If for some reason the file is located in a folder or several folders deep, find it and put it in the Downloads directory for further manipulation.
###############################################
ls *.mkv i 2> /dev/null | wc -l && ext=mkv; MOVE_TV_SHOWS
ls */*.mkv 2> /dev/null | wc -l && mv */*.mkv /home/jholler/Downloads; ext=mkv; MOVE_TV_SHOWS
ls */*/*.mkv 2> /dev/null | wc -l && mv */*/*.mkv /home/jholler/Downloads; ext=mkv; MOVE_TV_SHOWS
ls Movies/*/*.mkv 2> /dev/null | wc -l && mv Movies/*/*.mkv /home/jholler/Downloads; ext=mkv; MOVE_TV_SHOWS
ls TV/*.mkv 2> /dev/null | wc -l && mv TV/*.mkv /home/jholler/Downloads; ext=mkv; MOVE_TV_SHOWS
ls TV/*/*.mkv 2> /dev/null | wc -l && mv TV/*/*.mkv /home/jholler/Downloads; ext=mkv; MOVE_TV_SHOWS
#########################################
## End mkv matching portion of the script
#########################################
###########################################
## Begin mp3 matching portion of the script
###########################################
MOVE_MP3
#########################################
## End mp3 matching portion of the script
#########################################
exit 0

I have decided to take my nice new core quad PC and turn it into a Linux based DVR using Mythbuntu. I ordered a HVR-1600 card to record both HD and SD independently. Anna is looking forward to it greatly, as when we had an old PC serving this duty in the past it was the ultimate TV machine to her. Mostly this is because she sometimes ends up late to see a show while it is in, so now she won’t miss stuff or have to wait for it to download the next day. I am excited to have a great new project to tackle. Looking forward to seeing how much better MythTV is in the last three years.

For years I have been trying to find a way to easily and elegantly stream video to multiple small devices in our home. We only have one TV, and not everyone wants to watch the same thing at the same time. This really isn’t the worst problem in the world, obviously, but something I have tried to solve using all manner of different software and hardware combinations. A few weeks ago I discovered an iPhone application that required a server application running on either WIndows or Mac OS X. I tried to install the Windows version on my Ubuntu box running under Wine, but the application would crash as soon as the iPhone app tried to read a file from the hard drive. As they say, Wine Is Not an Emulator, and in this capacity it wasn’t going to cut it. I also checked the forums for the iPhone app developers who provide the PC app, and they had no intention of making a Linux version available anytime soon. So, I did what any self respecting geek would do presented with a solution which could potentially work, made it more complicated.
I first went through the process of building a new virtual machine in VirtualBox to host the Windows XP machine. That was quick and easy, and I happened to have an old XP disc lying around which isn’t in use on any computer anymore, since I haven’t used Windows at home since about 2004. The most challenging part was getting the Windows XP Guest OS to join the same network as the rest of the machines on my internal LAN, because virtual machines create a software interface and the actual packets are actually coming in through the same physical NIC card on the Linux machine. Fortunately, not too much googling later provided me with exactly the solution I was looking for. After installing these two utilities and running the script, provided at this blog, I was able to make the WIndows XP Guest OS join the 192.168.1.0 network! Perfect.
Now, all I had to do was install Bonjour from Apple, the Air Video Server application provided at inmethod.com and start it up.

I had to share the local Linux directory that stores all of our media, and set that up through VirtualBox, but that was relatively painless, requiring only that I get the VirtualBoxGuestAdditions.iso and use that on the Windows XP Guest OS so that it would recognize the shared folders and I could mount them permanently.

Once it was all good to go, I just added the /storage directory (which I mounted under Windows as Z:/ using the command “net use z: \\vboxsvr\storage”) to the shared directories in the Air Video Server app.

Here’s a screenshot of what this all looked like on the Windows XP Guest OS:

Air Video running in a Windows XP Guest OS

Air Video running in a Windows XP Guest OS

Now it was time to fire up the iPhone application and test all this juicy new streaming goodness!

I had been messing with this most of the night so the app had already detected the Windows instance of Air Video Server using Bonjour, which is why I had to install it on the Windows XP Guest OS:

AirVideo app Servers

AirVideo app Servers

Once you tap on the servername, the next screen shows you available shares:

AirVideo app available shares

AirVideo app available shares

Tapping on the Z:/ drive I made available shows me the directories and files located there, including a count of folders and files next to the folder names:

AirVideo app directories list

AirVideo app directories list

Drilling down into the TV directory shows me the same thing, folders and the number of files/folders in each directory:

AirVideo showing the TV directory

AirVideo showing the TV directory

Here I have selected the Bored to Death directory, and you can see that the app grabs screenshots as well as displaying some pertinent file information for each file found, very nice:

AirVideo app Bored to Death

AirVideo app Bored to Death

After selecting a particular file, I am presented with a few different options. Since this file is an xvid encoded avi, the app won’t be able to play the file natively. Air Video Server will take care of transcoding the file on the fly so that the iPhone app can play it:

AirVideo app avi file options

AirVideo app avi file options

Now comes the good stuff, after selecting “Play with Live Conversion”, I am presented with the option to play from the previously played position, the beginning, or seek to a new position, very slick indeed:

AirVideo app Live Conversion options

AirVideo app Live Conversion options

After making my choice: “The Beginning”, the app begins the process of buffering the video to the iPhone app:

AirVideo app Preparing Video

AirVideo app Preparing Video

Now, I suspect that because I’m running Air Video Server inside Windows XP running as a guest OS inside VirtualBox on a Linux host on a older desktop machine, the app complains that it doesn’t have the power to actually play the file, but all is not lost:

AirVideo app lies to me

AirVideo app lies to me

I just tell the app to continue anyway, and I was able to play the entire show without interruption:

AirVideo app buffering video

AirVideo app buffering video

And boom, about 5-10 seconds later, my TV show begins playing in perfect stutter-free fashion:

AirVideo app playing Bored to Death S01E01.avi

AirVideo app playing Bored to Death S01E01.avi

Tapping on the screen while the video is streaming brings up controls, in this case a little different than playing an x264 encoded file because the Air Video Server app is transcoding on the fly:

AirVideo app streaming converted file controls

AirVideo app streaming converted file controls

If I wanted to seek to a different position, the app handles that too, which is pretty nice to have, although honestly I usually just watch a show straight through:

AirVideo app live conversion seek menu

AirVideo app live conversion seek menu

All in all this app kicks total ass! I can now stream to any and all of the three iPhones in our house running from a single instance on a Windows XP Guest OS on my Linux box! The app works so well and I couldn’t be more pleased to be able to have this ability, which means I can now watch stuff while lying in bed without using a laptop, which is very nice indeed.

I’m always looking for ways to improve my current media setup, I can never be satisfied. After speaking with a co-worker I discovered I could change the format of one of my scripts and I wound up cutting the number of lines from 533 to 234! Here is the new and improved script:

#!/bin/bash
#
#/usr/local/bin/moveAVIs.sh
#
# Jay Holler 10-29-2008
# A script to find *.AVI files in the Downloads directory and move them to
# the appropriate folder on the NFS share at lunchbox (192.168.1.128)

storageDir=/storage/TV

MOVE_FILE() {
echo “[*] A new episode of $ShowName is ready for your enjoyment: $File” > /tmp/emailmessage.txt && sleep 2
[ -d "$storageDir/$ShowName" ] || mkdir -v “$storageDir/$ShowName”
mv -v $myFile “$storageDir/$ShowName/$File”
S=$(echo $File | sed -e ‘s/S0\(.\).*.AVI/\1/’)
E=$(echo $File | sed -e ‘s/S..E\(..\).*.AVI/\1/’)
if [ $E -lt 10 ]; then
episode=$(echo $E | sed -e ‘s/0\(.\)/\1/’)
/usr/local/bin/tvxml.sh “$ShowName” $S $episode TV $EpisodeID
else
/usr/local/bin/tvxml.sh “$ShowName” $S $E TV $EpisodeID
fi
wget http://localhost:49153/web/ushare.cgi?action=refresh -o /dev/null -P /dev/null
/usr/local/bin/email.sh
exit 0
}

## Look for AVI files and mv -v them over to the NFS Share on lunchbox
## Look for the shows we watch, and move files to the right place.
cd /home/jayholler/Downloads
for i in *.[A,a][V,v][I,i]
do
myFile=`echo $i | tr [:lower:] [:upper:]`
mv -v $i $myFile

case $myFile in

LOST*)
File=$(echo $myFile | sed ‘s/\(.*OST\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Lost’
MOVE_FILE
;;
ROBOT*)
File=$(echo $myFile | sed ‘s/\(.*KEN\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Robot Chicken’
MOVE_FILE
;;
BIG*)
File=$(echo $myFile | sed ‘s/\(.*OVE\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Big Love’
MOVE_FILE
;;
MAD*)
File=$(echo $myFile | sed ‘s/\(.*MEN\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Mad Men’
MOVE_FILE
;;
GLEE*)
GleeFile=$(echo $myFile | sed ‘s/\(.*LEE\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Glee’
MOVE_FILE
;;
REAL.HOUSEWIVES*)
File=$(echo $myFile | sed ‘s/\(.*SEY\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Real Housewives’
MOVE_FILE
;;
WIZARDS.OF.WAVERLY*)
File=$(echo $myFile | sed ‘s/\(.*ACE\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Wizards of Waverly Place’
MOVE_FILE
;;
ICARLY*)
File=$(echo $myFile | sed ‘s/\(.*RLY\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’iCarly’
MOVE_FILE
;;
DAISY.OF.LOVE*)
File=$(echo $myFile | sed ‘s/\(.*OVE\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Daisy of Love’
MOVE_FILE
;;
WEEDS*)
File=$(echo $myFile | sed ‘s/\(.*EEDS\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Weeds’
MOVE_FILE
;;
NURSE.JACKIE*)
File=$(echo $myFile | sed ‘s/\(.*KIE\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Nurse Jackie’
MOVE_FILE
;;
FAMILY.GUY*)
File=$(echo $myFile | sed ‘s/\(.*GUY\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Family Guy’
MOVE_FILE
;;
PUSHI*)
File=$(echo $myFile | sed ‘s/\(.*IES\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Pushing Daisies’
MOVE_FILE
;;
TRUE*)
File=$(echo $myFile | sed ‘s/\(.*LOOD\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’True Blood’
MOVE_FILE
;;
SUMMER*)
File=$(echo $myFile | sed ‘s/\(.*IGH\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Summer Heights High’
MOVE_FILE
;;
THE.TUDOR*)
File=$(echo $myFile | sed ‘s/\(.*ORS\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’The Tudors’
MOVE_FILE
;;
TIM.AND*)
File=$(echo $1 | sed ‘s/\(.*HOW\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Tim and Eric Awesome Show Good Job’
EpisodeID=’79905′
MOVE_FILE
;;
DOLLHOUSE*)
File=$(echo $myFile | sed ‘s/\(.*OUSE\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Dollhouse’
MOVE_FILE
;;
FLIGHT*)
File=$(echo $myFile | sed ‘s/\(.*ORDS\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Flight of the Conchords’
MOVE_FILE
;;
HEROES*)
File=$(echo $myFile | sed ‘s/\(.*EROES\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Heroes’
MOVE_FILE
;;
GOSSIP*)
File=$(echo $myFile | sed ‘s/\(.*IRL\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Gossip Girl’
MOVE_FILE
;;
THE.SECRET*)
File=$(echo $myFile | sed ‘s/\(.*AGER\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’The Secret Life of the American Teenager’
MOVE_FILE
;;
AMERICAN.IDOL)
File=$(echo $myFile | sed ‘s/\(.*DOL\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’American Idol’
MOVE_FILE
;;
AMERICAS.NEXT*)
File=$(echo $myFile | sed ‘s/\(.*ODEL\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Americas Next Top Model’
MOVE_FILE
;;
DEXTER*)
File=$(echo $myFile | sed ‘s/\(.*XTER\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Dexter’
MOVE_FILE
;;
90210*)
File=$(echo $myFile | sed ‘s/\(.*0210\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’90210′
MOVE_FILE
;;
THE.OFFICE*)
File=$(echo $myFile | sed ‘s/\(.*FFICE.US\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’The Office’
EpisodeID=’73244′
MOVE_FILE
;;
CALIFORNICATION*)
File=$(echo $myFile | sed ‘s/\(.*ION\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Californication’
MOVE_FILE
;;
ITS.ALWAYS*)
File=$(echo $myFile | sed ‘s/\(.*PHIA\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Its Always Sunny in Philadelphia’
MOVE_FILE
;;
DESPERATE*)
File=$(echo $myFile | sed ‘s/\(.*IVES\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Desperate Housewives’
MOVE_FILE
;;
PARIS*)
File=$(echo $myFile | sed ‘s/\(.*EVER\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Paris Hilton is my BFF’
MOVE_FILE
;;
THE.IT*)
File=$(echo $myFile | sed ‘s/\(.*ROWD\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’The IT Crowd’
MOVE_FILE
;;
HANNAH*)
File=$(echo $myFile | sed ‘s/\(.*TANA\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Hannah Montana’
MOVE_FILE
;;
ROCK*)
File=$(echo $myFile | sed ‘s/\(.*OVE\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’Rock of Love’
EpisodeID=’80610′
MOVE_FILE
;;
24.*)
File=$(echo $myFile | sed ‘s/\(.*4\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.AVI/’)
ShowName=’24′
MOVE_FILE
;;
*)
echo “[+] $myFile does not match our TV shows, pushing it to /storage/Movies on lunchbox” > /tmp/emailmessage.txt
mv -v “$myFile” /storage/Movies/$myFile
/usr/local/bin/email.sh
;;
esac
done
exit 0

I have recently discovered that the program I use on my AppleTV to browse our media share, ATVFiles, has the facility to parse XML about the file and display that in a very nice way. So I whipped up a script to pull down data from thetvdb.com, parse out the data I need into a new XML file that ATVFiles understands, and clean up after itself. In addition, since I name all my files SXXEXX.avi I grab the official screen shots of the show so now all the metadata is really nice, clean, and accurate. Plus, it is way easier to see whether I have seen a show or not already. Here’s the script, please ignore the underscores in the section where it actually writes the XML file, blogger gave me a hard time, and I’m too lazy to look into it that much.:


#!/bin/bash

# Setup the storage directories
HD=/storage/HDTV
TV=/storage/TV

# Tell us what we’ve provided
echo -e “\n[ $(date +%T) ] Show is: $1″
sleep 1
echo -e “\n[ $(date +%T) ] Season is: $2″
sleep 1
echo -e “\n[ $(date +%T) ] Episode is: $3″
sleep 1
echo -e “\n[ $(date +%T) ] TV type is: $4\n”

show=”$1″

#Get the series ID, so we can dig deeper
wget -O /tmp/”$show”.xml “http://www.thetvdb.com/api/GetSeries.php?seriesname=$show”

if [ -z $5 ]; then
series=$(grep seriesid /tmp/”$show”.xml | head -1 | sed -e ‘s/\(\)\([0-9]*\)\(\)/\2/’)
else
series=$5
fi

echo -e “/n[ $(date +%T) ] Series number is: $series\n”

# Take the series ID and get the episode ID, so we can dig ever more deeply
wget -O /tmp/S0$2E$3.xml http://www.thetvdb.com/api/30A6C059BE4318B9/series/$series/default/$2/$3/en.xml
episodeid=$(grep id /tmp/S0$2E$3.xml | head -1 | sed -e ‘s:\([0-9]*\):\1:’ | awk -F ” ” ‘{print $1}’)

# Set some variables we’ll need for writing the XML file
description=$(grep \ /tmp/S0$2E$3.xml | sed -e ‘s:\(\)\(.*\)\(\):\2:’ | sed ‘s/^ *//’)
title=$(grep \ /tmp/S0$2E$3.xml | sed -e ‘s:\(\)\(.*\)\(\):\2:’ | sed ‘s/^ *//’)

# Write the XML data to a file
cat > /tmp/file.xml << EOF

$title
$description
$show
$3
$2

EOF

# Move the XML data to the appropriate location
if [ $4 = HDTV ]; then
if [ $3 -lt 10 ]; then
mv -v /tmp/file.xml $HD/”$show”/S0$2E0$3.xml
wget -O $HD/”$show”/S0$2E0$3.jpg http://www.thetvdb.com/banners/episodes/$series-$episodeid.jpg
else
mv -v /tmp/file.xml $HD/”$show”/S0$2E$3.xml
wget -O $HD/”$show”/S0$2E$3.jpg http://www.thetvdb.com/banners/episodes/$series-$episodeid.jpg
fi
else
if [ $3 -lt 10 ]; then
mv -v /tmp/file.xml $TV/”$show”/S0$2E0$3.xml
wget -O $TV/”$show”/S0$2E0$3.jpg http://www.thetvdb.com/banners/episodes/$series-$episodeid.jpg
else
mv -v /tmp/file.xml $TV/”$show”/S0$2E$3.xml
wget -O $TV/”$show”/S0$2E$3.jpg http://www.thetvdb.com/banners/episodes/$series-$episodeid.jpg
fi
fi

# Cleanup unecessary files
rm /tmp/”$show”.xml
rm /tmp/S0$2E$3.xml

echo -e “\n[ $(date +%T) ] Done!”
exit 0

There are a few things to note here. First of all, you run it like this:

tvxml.sh Lost 5 1 HDTV

This tells the script that you want Lost, Season 5, Episode 1, and it’s in the HDTV folder, TV is the other option. If the show name has more than one word, you’ll have to put the name in quotes, like this:

tvxml.sh “Battlestar Galactica” 4 15 HDTV

In addition, Battlestar pulled up three different versions of the show, so I had to go find out the show id that www.thetvdb.com uses, and manually include it like this:

tvxml.sh “Battlestar Galactica” 4 15 HDTV 73545

Also, if you want to grab an entire directory of shows at once, it’s pretty simple with a little for loop:

for i in $(ls | sed -e ‘s/S04E\(..\).mp4/\1/’); do /usr/local/bin/tvxml.sh “Battlestar Galactica” 4 $i HDTV 73545; done

This loop just says, for every episode number in the /storage/HDTV/Battlestar\ Galactica/
directory run the script with the approriate episode number. Easy Peasy. This was run right IN the /storage/HDTV/Battlestar\ Galactica directory so I didn’t need to explicity specify that in the for loop.

In the future I will make this interactive by pulling out all the names and show id’s out of the first xml file grabbed, and let the user decide which one they’re looking for. This happens so rarely for me that it’s a version 2 feature of this script.

I thought today I’d share my method of taking avi files I’ve got stored on my NFS share and creating DVDs which will play in North American region DVD players, complete with menus and animated thumbnail previews. I do this on the same Linux box used below for transcoding and storing mp4s. This server is running Ubuntu 8.10, and I use the tovid suite of tools to accomplish the creation of the DVD menus, and transcode the files for maximum compatibility, and then genisoimage and growisofs to make the VIDEO_TS folder and burn it to DVD. With the following script it is possible to get it all done in one shot:

todisc \
-menu-title “Lost: Season\ 1″ \
-menu-fade \
-menu-font Arial \
-menu-fontsize 20 \
-title-color ‘#ffffff’ \
-stroke-color lightgray \
-files \
/storage/TV/Lost/Season\ 1/S01E13.avi \
/storage/TV/Lost/Season\ 1/S01E14.avi \
/storage/TV/Lost/Season\ 1/S01E15.avi \
/storage/TV/Lost/Season\ 1/S01E16.avi \
/storage/TV/Lost/Season\ 1/S01E17.avi \
/storage/TV/Lost/Season\ 1/S01E18.avi \
-thumb-font Arial \
-thumb-fontsize 20 \
-thumb-text-color ‘#ffffff’ \
-titles \
“Episode 13″ \
“Episode 14″ \
“Episode 15″ \
“Episode 16″ \
“Episode 17″ \
“Episode 18″ \
-showcase \
-showcase-titles-align west \
-text-mist \
-text-mist-color gray85 \
-text-mist-opacity 70 \
-out LostS01Eps13-18
-no-ask
-noask

genisoimage -dvd-video -input-charset=ISO-8859-1 -J -R -o LostS01Eps13-18.iso LostS01Eps13-18

growisofs -dvd-compat -Z /dev/dvdrw1=LostS01Eps13-18.iso

So there you have it. Fairly simple, but so cool to be able to make DVDs for your less tech-savvy friends to enjoy.

So after successfully automating my perfect TV setup with minimal human interaction, I decided to take the next logical step and prepare for more HD content, seeing as how Lost is back, and I’m on the late shift so I always have to watch it after it has aired on cable. I cobbled together a script from a number of different scripts I had for dealing with various media files, and I also wrote a little while loop to prevent my server from having too many instances of ffmpeg running at once. Here is the script, below:

### Transcode 720p H264 mkv files for the Apple TV

if [ -z $1 ]; then
echo “Usage: `basename $0` filename”
exit 0
fi

# Wait while any other ffmpeg processes are running
while [ -n "$(ps -ef | grep ffmpeg | grep -v grep)" ];
do
echo -e “\n[$(date +%b\ %d\ %Y:\ %H:%M:%S)]\nffmpeg is currently working…”
sleep 300
done

# Get the beginning time from the date cmd.
START=$(date +%D\ %T)

# Email us that the next process has begun
echo -e “About to start transcoding $1 at $START” > /tmp/emailmessage.txt
/usr/local/bin/email.sh

# ffmpeg cmd
ffmpeg -y -i $1 -threads 2 -s 1280×720 -aspect 1280:720 -r ntsc-film -vcodec libx264 -g 150 -qmin 8 -b 4500k -level 31 -loop 1 -sc_threshold 40 -partp4x4 1 -rc_eq ‘blurCplx^(1-qComp)’ -refs 2 -qmax 51 -maxrate 4500k -bf 1 -keyint_min 40 -async 1 -acodec libfaac -ar 48000 -ac 2 -ab 384k $1.mp4

# Get the ending time of the transcode process from the date cmd.
END=$(date +%D\ %T)

# Inform us with an email
echo “Transcoding of $1 was started on $START and completed on $END.” > /tmp/emailmessage.txt
/usr/local/bin/email.sh
mv -v $1 /mkvs

HDstorageDir=/storage/HDTV

## Look for HD files and mv -v them over to the NFS Share on lunchbox
## Look for the shows we watch, and move files to the right place.

TranscodedFile=$1.mp4

if [[ "$TranscodedFile" =~ lost* ]] || [[ "$TranscodedFile" =~ Lost* ]]; then
LostFile=$(echo $TranscodedFile | sed ‘s/\(.*ost\).\([Ss][0-9]*[Ee][0-9]*\).mkv.*/\2./’)
echo “[*] A new episode of Lost (in HD!) is ready for your enjoyment: $LostFile” > /tmp/emailmessage.txt && sleep 2
mv -v “$TranscodedFile” $HDstorageDir/Lost/$LostFile
/usr/local/bin/email.sh
exit 0
elif [[ "$TranscodedFile" =~ Heroes* ]] || [[ "$TranscodedFile" =~ heroes* ]]; then
HeroesFile=$(echo $TranscodedFile | sed ‘s/\(.*oes\).\([Ss][0-9]*[Ee][0-9]*\).mkv./\2./’)
echo “[*] A new Episode of Heroes (in HD!) is ready for your enjoyment: $HeroesFile” > /tmp/emailmessage.txt && sleep 2
mv -v “$TranscodedFile” $HDstorageDir/Heroes/$HeroesFile
/usr/local/bin/email.sh
exit 0
elif [[ "$TranscodedFile" =~ Battlestar* ]] || [[ "$TranscodedFile" =~ battlestar* ]]; then
BattleFile=$(echo $TranscodedFile | sed ‘s/\(.*tica\).\([Ss][0-9]*[Ee][0-9]*\).mkv./\2./’)
echo “[*] A new Episode of Battlestar Galactica (in HD!) is ready for your enjoyment: $BattleFile” > /tmp/emailmessage.txt && sleep 2
mv -v “$TranscodedFile” $HDstorageDir/Battlestar\ Galactica/$BattleFile
/usr/local/bin/email.sh
exit 0
elif [[ "$TranscodedFile" =~ The.Office* ]] || [[ "$TranscodedFile" =~ the.office* ]]; then
OfficeFile=$(echo $TranscodedFile | sed ‘s/\(.*ffice\).\([Ss][0-9]*[Ee][0-9]*\).mkv./\2./’)
echo “[*] A new Episode of The Office (in HD!) is ready for your enjoyment: $OfficeFile” > /tmp/emailmessage.txt && sleep 2
mv -v “$TranscodedFile” $HDstorageDir/iThe\ Office/$OfficeFile
/usr/local/bin/email.sh
exit 0
elif [[ "$TranscodedFile" =~ 24* ]]; then
TwentyFourFile=$(echo $TranscodedFile | sed ‘s/\(.*4\).\([Ss][0-9]*[Ee][0-9]*\).mkv./\2./’)
echo “[*] A new Episode of 24 (in HD!) is ready for your enjoyment: $TwentyFourFile” > /tmp/emailmessage.txt && sleep 2
mv -v “$TranscodedFile” $HDstorageDir/24/$TwentyFourFile
/usr/local/bin/email.sh
exit 0
else
echo “[+] $1 does not match our TV shows, pushing it to /storage/HD Movies on lunchbox” > /tmp/emailmessage.txt
mv -v “$TranscodedFile” “/storage/HD\ Movies/$(echo $i | sed -e ‘s/\(.*\).720.*\(.mkv\)\(.mp4\)/\1\3/’)”
/usr/local/bin/email.sh
fi

exit 0

Hopefully someone finds this useful for their own media management purposes. Basically the script just waits until ffmpeg isn’t running, emails me that it is starting, transcodes the HD file for playback on the AppleTV, emails me when transcoding is done, and then uses sed (string editor) to chop of the bits of the filename I don’t want showing up, and places it in the correct directory depending on the name of the show. Also, if the filename doesn’t match any show, it goes to the HD Movies directory. In addition, when it’s all over, it emails me to let me know I’ve got some new media to enjoy!

I have been working for a while at getting things just right with our TV setup, and I thought I would put it up so others could benefit from my work. Overall we are using 4 separate systems to run our entertainment center: A 32″ Westinghouse HDTV, an Apple TV, a Linux box which stores files on an NFS share, and another Linux box which does all the downloading, transcoding, and shifting around of files.

To start, I set up a giganews account, and an account at nzbsrus.com to download only the specific files which I desire. Then, I wrote a few scripts and got a few Linux utilities to handle everything for me, below is the process a file takes from start to end.

To start, I browse nzbsrus.com on my laptop for a certain show or movie, and have firefox configured to download the nzb file to my laptop. A cron job runs on my laptop that copies any nzb files over to LinuxBox1:

#!/bin/bash

for i in ~/Downloads/*.nzb; do scp ${i} jayholler@lunchbox:/home/jayholler/Downloads/; rm ${i}; done;
exit 0

LinuxBox1 is running a utility called fsniper, which hooks into filesystem events and executes actions you can configure manually. This is my fsniper config file:

watch {
~/Downloads {
*.avi {
handler = /usr/local/bin/moveAVIs.sh %%
}
*.nzb {
handler = mv %% /home/jayholler/.hellanzb/nzb/daemon.queue/
}
}

}

So when fsniper sees a new nzb file it drops it into a directory that another utility watches, called hellanzb. Hellanzb is a python program that automatically downloads, checks, and unrars files, and it can optionally be configured to run a script when it is done. So I have another little script which moves files back out from hellanzb’s directory to the directory fsniper is watching.

#!/bin/bash

for i in /home/jayholler/.hellanzb/done/*/*.avi; do mv “$i” /home/jayholler/Downloads/; done;
exit 0

Once fsniper sees the completed file, a final script is used to check which directory it should be moved to on the NFS share set up on LinuxBox2:

#!/bin/bash
#
#/usr/local/bin/moveAVIs.sh

AVI_DIR=/home/jayholler/Downloads

cd $AVI_DIR

function HEROES {

HeroesFile=`ls [Hh]er*.avi | sed ‘s/\(.*[s]\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.avi/’`
mv `ls [Hh]er*.avi` $HeroesFile
echo “[*] scp’ing $HeroesFile to basementbox” && sleep 2
scp $HeroesFile basementbox:/storage/TV/Heroes/
rm $HeroesFile
}

function FRINGE {

FringeFile=`ls [Ff]ri*.avi | sed ‘s/\(.*[e]\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.avi/’`
mv `ls [Ff]ri*.avi` $FringeFile
echo “[*] scp’ing $FringeFile to basementbox” && sleep 2
scp $FringeFile basementbox:/storage/TV/Fringe/
rm $FringeFile
}

function GOSSIP_GIRL {

GossipFile=`ls [Gg]os*.avi | sed ‘s/\(.*[l]\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.avi/’`
mv `ls [Gg]os*.avi` $GossipFile
echo “[*] scp’ing $GossipFile to basementbox” && sleep 2
scp $GossipFile ‘basementbox:/storage/TV/Gossip\ Girl/’
rm $GossipFile
}

function NEXT_TOP_MODEL {

ModelFile=`ls [Aa]me*.avi | sed ‘s/\(.*[l]\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.avi/’`
mv `ls [Aa]me*.avi` $ModelFile
echo “[*] scp’ing $ModelFile to basementbox” && sleep 2
scp $ModelFile ‘basementbox:/storage/TV/Americas\ Next\ Top\ Model/’
rm $ModelFile
}

function DEXTER {

DexterFile=`ls [Dd]ex*.avi | sed ‘s/\(.*[r]\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.avi/’`
mv `ls [Dd]ex*.avi` $DexterFile
echo “[*] scp’ing $DexterFile to basementbox” && sleep 2
scp $DexterFile basementbox:/storage/TV/Dexter/
rm $DexterFile
}

function Nine0210 {

mv `ls [9]02*.avi` $Nine0210File
echo “[*] scp’ing $Nine0210File to basementbox” && sleep 2
scp $Nine0210File basementbox:/storage/TV/90210/
rm $Nine0210File
}

function THE_OFFICE {

OfficeFile=`ls [Tt]he*[Oo]ffice*.avi | sed ‘s/\(.*[e]\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.avi/’`
mv `ls [Tt]he*[Oo]ffice*.avi` $OfficeFile
echo “[*] scp’ing $OfficeFile to basementbox” && sleep 2
scp $OfficeFile ‘basementbox:/storage/TV/The\ Office/’
rm $OfficeFile
}

function CALIFORNICATION {

CaliFile=`ls [Cc]ali*.avi | sed ‘s/\(.*[n]\).\([Ss][0-9]*[Ee][0-9]*\).*/\2.avi/’`
mv `ls [Cc]ali*.avi` $CaliFile
echo “[*] scp’ing $CaliFile to basementbox” && sleep 2
scp $CaliFile ‘basementbox:/storage/TV/Californication/’
rm $CaliFile
}

## Look for avi files and scp them over to the NFS Share on basementbox
## Call each function, look for the shows we watch, and move files to the right place.

if [[ "$1" =~ heroes* ]]; then
HEROES
exit 0
elif [[ "$1" =~ Heroes* ]]; then
HEROES
exit 0
elif [[ "$1" =~ fringe* ]]; then
FRINGE
exit 0
elif [[ "$1" =~ Fringe* ]]; then
FRINGE
exit 0
elif [[ "$1" =~ gossip* ]]; then
GOSSIP_GIRL
exit 0
elif [[ "$1" =~ Gossip* ]]; then
GOSSIP_GIRL
exit 0
elif [[ "$1" =~ america* ]]; then
NEXT_TOP_MODEL
exit 0
elif [[ "$1" =~ America* ]]; then
NEXT_TOP_MODEL
exit 0
elif [[ "$1" =~ dexter* ]]; then
DEXTER
exit 0
elif [[ "$1" =~ Dexter* ]]; then
DEXTER
exit 0
elif [[ "$1" =~ 90210* ]]; then
Nine0210
exit 0
elif [[ "$1" =~ office* ]]; then
THE_OFFICE
exit 0
elif [[ "$1" =~ Office* ]]; then
THE_OFFICE
exit 0
elif [[ "$1" =~ californication* ]]; then
CALIFORNICATION
exit 0
elif [[ "$1" =~ Californication* ]]; then
CALIFORNICATION
exit 0
elif [[ "$1" =~ *.mkv ]]; then
echo “Looks like we have an mkv file, sending this to appletv.sh…”
/usr/local/bin/appletv.sh “$1″
exit 0
else
echo “$1 does not match our TV shows, sending it to /storage/Movies/”
scp “$1″ ‘basementbox:/storage/Movies/’
fi
exit 0

Finally, the Apple TV is hacked to mount the NFS share on LinuxBox2, expanding the amount of material we can view using the Apple TV greatly.

I hope someday someone finds this useful for their own similar setup.

Follow

Get every new post delivered to your Inbox.

Join 133 other followers