The Alternative to Hacking
Contents
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)
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.
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.
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.
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.
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...
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.
Movies
Check out MetaX. Pretty easy to use and grabs data from the Internet.
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.
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.
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
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
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
TCMPLEX
Install tcmplex-panteltje and make sure the command is in your PATH.
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.
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/fritzplatte/AppleTV # 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`; 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.
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.
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.