The Alternative to Hacking
From AwkwardTV
Contents |
[edit] Hack Me Not
For all cool things that you can do with your Apple TV without resorting to all that SSH malarkey or touching a screwdriver, read on. If you want to contact me, please do so though this site. --Simplicity 13:57, 4 June 2008 (CEST)
[edit] Stream and Sync Simplified
One of the very best reasons to hack your Apple TV was to get more storage. With 2.0 and iTunes 7.6.1 onwards you get much better sync / stream options. The ATV used to distinguish between "Shared" iTunes libaries, from which you could stream content and that which was synced. Now, you can select what to sync and what to stream from a library and as long as the iTunes Mac/PC is on, all the content is available seamlessly - whether local to the ATV or not.
Better still, you can choose what TV Shows to sync (Last 1,3,5+ or unwatched episodes only) of selected shows, so if the iTunes Mac/PC is off, you can still watch the latest episodes.
With this seamless sync / stream linking to your iTunes library, even a 40Gb ATV becomes totally usable.
[edit] More Content
Everything you can put on a hacked ATV, you can put on a normal ATV running 2.x. And, you won't have to pray that a new firmware release won't break everything. Only a one-time conversion of existing files is needed. Compared to the time you need to maintain a hacked ATV, it's really, genuinely, properly, not much hassle.
[edit] DVD Rips
Use the free Handbrake for all your DVD ripping needs. It has presets for the Apple TV, which will deliver near DVD quality rips that will stream easily to your ATV.
[edit] DivX / AVI
Previously, you could convert any AVI movies you had kicking around using the freely available iSquint or its shareware big brother VisualHub from Techspansion. Sadly though, both these brilliant programs were discontinued in late September, 2008.
Fortunately, the team behind HandBrake is picking up where Techspansion left off.
[edit] Easy Metadata
Whatever you have ripped or downloaded can be converted using the above and then copied to iTunes, but it will appear without any TV Show / Movie data like episide name, number, etc. To fix...
[edit] TV
Make Video Tags is first choice as it has a basic but effective interface. With iTunes 8, this seems to be working more reliably than before. Alternatively, try the more hands on Set Video Kind of Selected. Both from Doug's AppleScripts for iTunes.
TVTaggr also looks like a promising project, with future versions possibly scraping the internet to auto-populate key fields.
[edit] Movies
Check out MetaX. Pretty easy to use and grabs data from the Internet.
[edit] Rentals / Podcasts / iTunes Store
Come here, there's more. Running 2.x, you get get movie rentals, buy TV shows and browse podcasts straight from your Apple TV. A lot of items in the store are now available in HD, too.
Not in the US and missing rentals and TV Shows? You can get a US Account by following the instructions posted here and buying US iTunes Gift Vouchers from Internet Tat Bazaar eBay.
[edit] VDR
If you have a Linux computer running the excellent video recording software VDR, you can extend VDR to be able to produce Apple TV compatible video files including metadata based on the information sent with the DVB EPG (albeit the type (movie or show) will be guessed). Here is a short HOWTO for setting it up. It is based on an Ubuntu Jaunty install using Hanno's e-tobi Debian VDR builds but should be adaptable to all other VDR installs as well. The following directions are for the computer running VDR, nothing has to be done on the Apple TV. The script will produce an Apple TV compatible, H.264 encoded MP4 file with AAC audio and put it in a defined directory. This can then be shared via Samba or NFS to be able to access it from Mac OS or Windows. Then, the only thing you have to do is drag and drop the generated MP4 files to iTunes and review the metadata.
But: It doesn't support cutlists. So, you have to cut the recording first and transcode the cut one.
[edit] Prerequisites
- VDR up and running
- working FFMPEG with libx264 and libfaac support (For Ubuntu, consult this link on how to compile it the right way)
- At least Java Runtime Environment 1.5 in your PATH, i.e., the user running VDR can launch the "java" command without explicitly specifying a path
- The user running VDR must have a valid shell (i.e. not /bin/false, but /bin/bash or /bin/sh)
- The command "at" working and accessible by the user VDR runs as
[edit] The FFMPEG preset
For H264 encoding, the FFMPEG authors recommend using presets. The following one produces quite good results at reasonable encoding speeds. Copy it to the folder containing the global (system-wide) presets (e.g. /usr/share/ffmpeg) as libx264-appletv_normal.ffpreset
coder=1 flags=+loop cmp=+chroma partitions=+parti8x8+parti4x4+partp8x8+partb8x8 me_method=hex subq=6 me_range=16 g=250 keyint_min=25 sc_threshold=40 i_qfactor=0.71 b_strategy=1 qcomp=0.6 qmin=10 qmax=51 qdiff=4 bf=3 refs=2 directpred=3 trellis=0 flags2=+wpred-dct8x8+fastpskip
[edit] ProjectX
Install Java (at least JRE 1.5) and get ProjectX 0.90.4 or higher. Place the ProjectX.jar file along with the whole lib folder in a directory the user running VDR has access to. Then, rename the ProjectX.jar to pX.jar or create a symlink.
Create a file named pX.ini in the same directory where you copied (or symlinked) the above ProjectX files and put the following content into it:
# Application Application.Agreement=1 Application.Language=en # ExternPanel #ExternPanel.renameAudio=1 ExternPanel.renameVideo=1 # WindowPosition WindowPosition.Main.Height=652 WindowPosition.Main.Width=906 WindowPosition.Main.X=50 WindowPosition.Main.Y=50
[edit] TCMPLEX
Install tcmplex-panteltje and make sure the command is in your PATH.
[edit] Atomic Parsley
To embed the metadata, Atomic Parsley is used. Either install it from your distribution's repository or from the link. Make sure it is invoked with AtomicParsley and resides somewhere in your PATH.
[edit] The script itself
Put the following script somewhere where the user running VDR has access to. Call it vdr2atv.sh and make it executable for the user running VDR.
#/!bin/bash
# VDR2ATV version 0.2
# This script is provided as-is, without any warranty. It is licensed under the GNU GPL v3.
# Please review the following variables and adjust the paths according to your configuration
# This directory indicates where to put the encoding queue.
# It has to be writable by the user VDR runs as
SPOOLDIR=/var/spool/vdr2atv
# Here the temporary audio and video files as well as the logs will go.
# The temporary files will be deleted after finishing a transcoding process
# but the logs will be kept.
# The user VDR runs as needs to have write permissions for this dir.
# This must be on a partition with enough free space on it. 10GB will do.
TEMPDIR=/var/lib/video.00/atvtmp
# This is the directory where the completed files will go.
OUTDIR=/media/AppleTVExport
# This is the path to your ProjectX dir.
# In this dir, the pX.jar, pX.ini and the libs for pX will be expected.
PX=/etc/vdr/vdr2atv/pX
# The path to the SVDRPSEND command to send progress messages to the VDR OSD.
SVDRPSEND=/usr/lib/vdr/svdrpsend.pl
# The video dir (default for manual VDR installs is /video)
VPREFIX=/var/lib/video.00
# If this word exists in the title or subtitle of the recording,
# a movie is assumed. Else, the script tries to guess the video type.
MOVIETRIGGER=movie
case "$1" in
l)
if [ -f $SPOOLDIR/queue ]; then
for n in `cat $SPOOLDIR/queue`; do
dest=${n#$VPREFIX}
cutnum=`echo $dest |grep -o "/" |wc -l`
cutnum=`expr 1 + $cutnum`
suff=`echo $dest |cut -d/ -f$cutnum`;suff=`echo /$suff`
dest=${dest%$suff}
i=`expr index $dest \/`
if [ $i -eq 1 ]; then
dest=${dest#\/}
fi
cutnum=`echo $dest |grep -o "/" |wc -l`
cutnum=`expr 1 + $cutnum`
file=`echo $dest |cut -d/ -f$cutnum`
suff=`echo /$file`
if [ `echo $file |grep -E ^%+.* |wc -l` -ge 1 ]; then
file=`echo $file |sed 's/%//'`
fi
destdir=${dest%$suff}
echo $file \(`du -m $n |sort -n |tail -n1 |awk '{print $1}'`MiB\)
done
if [ `wc -l $SPOOLDIR/queue |awk '{print $1}'` -eq 0 ]; then
echo Queue is empty!
fi
else
echo Queue is empty!
fi
;;
d)
if [ -f $SPOOLDIR/queue ]; then
touch $SPOOLDIR/temp
for n in `cat $SPOOLDIR/queue`; do
if [ $n != $2 ]; then
echo $n >>$SPOOLDIR/temp
fi
done
cp $SPOOLDIR/temp $SPOOLDIR/queue
rm $SPOOLDIR/temp
$0 l
else
echo Queue is empty!
fi
;;
x)
rm $SPOOLDIR/queue
touch $SPOOLDIR/queue
echo Queue is now empty.
;;
a)
found=`grep $2 $SPOOLDIR/queue |wc -l`
if [ $found -lt 1 ]; then
echo $2 >>$SPOOLDIR/queue
fi
$0 l
;;
t)
if [ -f $SPOOLDIR/queue ]; then
if [ -f $SPOOLDIR/worker ]; then
echo There is already another job running!
$SVDRPSEND MESG There is already a job running!
else
$SVDRPSEND MESG Starting transcode job
mv $SPOOLDIR/queue $SPOOLDIR/worker
for n in `cat $SPOOLDIR/worker`; do
$SVDRPSEND MESG Demultiplexing $n
mkdir -pv $TEMPDIR
dir=`mktemp -d -p $TEMPDIR`
echo + $n
echo + $dir
mkdir -pv $dir
dest=${n#$VPREFIX}
cutnum=`echo $dest |grep -o "/" |wc -l`
cutnum=`expr 1 + $cutnum`
suff=`echo $dest |cut -d/ -f$cutnum`;suff=`echo /$suff`
dest=${dest%$suff}
i=`expr index $dest \/`
if [ $i -eq 1 ]; then
dest=${dest#\/}
fi
cutnum=`echo $dest |grep -o "/" |wc -l`
cutnum=`expr 1 + $cutnum`
file=`echo $dest |cut -d/ -f$cutnum`
suff=`echo /$file`
if [ `echo $file |grep -E ^%+.* |wc -l` -ge 1 ]; then
file=`echo $file |sed 's/%//'`
fi
destdir=${dest%$suff}
$SVDRPSEND MESG Demultiplexing $file with ProjectX
for m in `find "$n" -name ???.vdr |sort`; do
echo \"$m\"
done |xargs java -Djava.awt.headless=true -jar $PX/pX.jar -ini $PX/pX.ini -out $dir
$SVDRPSEND MESG Remultiplexing with only the first audio track
CURDIR=`pwd`
cd $dir
tcmplex-panteltje -i 001.mpv -0 `ls ???.* |grep -v mpv |sort -n |head -n 1` -m s -o temp.mpg
cd $CURDIR
rm -rf $TEMPDIR/complete
mkdir -pv $TEMPDIR/complete/$destdir
$SVDRPSEND MESG Transcoding to H264/AAC
ffmpeg -y -i $dir/temp.mpg -threads 8 -deinterlace -vcodec libx264 -vpre appletv_normal -b 1500k -bf 16 -acodec libfaac -ar 48000 -ab 128k $TEMPDIR/complete/$destdir/$file.mp4
$SVDRPSEND MESG Embedding metadata
for m in `find $TEMPDIR/complete -name *.mp4 `; do
info=`find $n -name info.vdr |head -n 1`
echo +++ $info
echo +++ $m
descr=`grep ^D $info |sed 's/D //'`
tit=`grep ^T $info |sed 's/T //'`
sub=`grep ^S $info |sed 's/S //'`
chan=`grep ^C $info |sed 's/C [SCT][-0123456789]* //'`
contains_film=`echo $tit $sub |grep -i $MOVIETRIGGER |wc -l`
has_subtitle=`grep ^S $info |wc -l`
isshow=0
if [ $contains_film -eq 0 ]; then
if [ $has_subtitle -gt 0 ]; then
isshow=1
echo +++ is show
fi
fi
echo +++ $isshow $contains_film $has_subtitle
epnum=-1
numeps=0
if [ $isshow -eq 1 ]; then
if [ `echo $tit |grep -e / |wc -l` -gt 0 ]; then
epnum=`echo $tit |cut -d/ -f1 |sed 's/[^0123456789]//g'`
numeps=`echo $tit |cut -d/ -f2 |cut -d\ -f1 |sed 's/[^0123456789]//g'`
tit=`echo $tit |sed 's/[^\/]*\/[^\/ ]*\ //'`
elif [ `echo $sub |grep -e / |wc -l` -gt 0 ]; then
epnum=`echo $sub |cut -d/ -f1 |sed 's/[^0123456789]//g'`
numeps=`echo $sub |cut -d/ -f2 |cut -d\ -f1 |sed 's/[^0123456789]//g'`
sub=`echo $sub |sed 's/[^\/]*\/[^\/ ]*\ //'`
fi
if [ $epnum -ge 0 ]; then
echo +++ AtomicParsley $m --stik "TV Show" --title "$sub" --tracknum "$epnum/$numeps" --TVEpisodeNum "$epnum" --TVShowName "$tit" --description "$descr" --TVNetwork "$chan"
AtomicParsley $m --stik "TV Show" --title "$sub" --tracknum "$epnum/$numeps" --TVEpisodeNum "$epnum" --TVShowName "$tit" --description "$descr" --TVNetwork "$chan"
else
echo +++ AtomicParsley $m --stik "TV Show" --title "$sub" --TVShowName "$tit" --description "$descr" --TVNetwork "$chan"
AtomicParsley $m --stik "TV Show" --title "$sub" --TVShowName "$tit" --description "$descr" --TVNetwork "$chan"
fi
else
if [ $has_subtitle -gt 0 ]; then
echo +++ AtomicParsley $m --stik "Movie" --description "$descr" --TVNetwork "$chan" --title "$tit - $sub"
AtomicParsley $m --stik "Movie" --description "$descr" --TVNetwork "$chan" --title "$tit - $sub"
else
echo +++ AtomicParsley $m --stik "Movie" --description "$descr" --TVNetwork "$chan" --title "$tit"
AtomicParsley $m --stik "Movie" --description "$descr" --TVNetwork "$chan" --title "$tit"
fi
fi
done
temp1=`find $TEMPDIR/complete -name *-temp*.mp4 |head -n1`
temp2=`find $TEMPDIR/complete -name *.mp4 |sort |head -n1`
cp -v $temp1 $temp2
rm -v $temp1
$SVDRPSEND MESG Copying files to outdir
mkdir -pv $OUTDIR
cp -Rvf $TEMPDIR/complete/* $OUTDIR/
chmod -Rvf 777 $OUTDIR
$SVDRPSEND MESG Deleting temporary files
rm -Rvf $dir
rm -Rvf $TEMPDIR/complete
done
rm $SPOOLDIR/worker
fi
else
echo Queue is empty!
fi
;;
start)
if [ `wc -l $SPOOLDIR/queue |awk '{print $1}'` -lt 1 ]; then
echo Queue is empty!
else
LOGFILE=$TEMPDIR/atv-`date +%Y%m%d%H%M%S`.log
echo $0 t \>$LOGFILE 2\>\&1 |at now
fi
;;
*)
echo This script has to be called from within VDR.
;;
esac
Create the directory the variable SPOOLDIR points to and make it writable for the user VDR runs as. Then make the script executable.
[edit] reccmds.conf
Put the following into your reccmds.conf or if using a VDR distro which builds this file automatically on each start, put it into the custom reccmds file:
Apple TV : true - Transcode this : /etc/vdr/vdr2atv/vdr2atv.sh a - Don't transcode this : /etc/vdr/vdr2atv/vdr2atv.sh d - Clear queue : /etc/vdr/vdr2atv/vdr2atv.sh x - Show queue : /etc/vdr/vdr2atv/vdr2atv.sh l - Start transcoding : /etc/vdr/vdr2atv/vdr2atv.sh start
Replace /etc/vdr/vdr2atv/vdr2atv.sh with the real path to where you put it.
[edit] Results
Now, when selecting a recording and pressing "Red" in the VDR menu, a new entry named "Apple TV" will show up. Selecting it will open up a submenu where you can queue and un-queue the selected item, convert everything on the queue or clear/show it.
Log files will be created as atv-<current date>.log in the temporary folder, if anything goes wrong.
The script is not much more than a "quick and dirty hack" and has plenty of optimization potential.
