From c3589abad837334030b962217d470780571060ce Mon Sep 17 00:00:00 2001
From: James Meyer <james.meyer@operamail.com>
Date: Sun, 31 Jan 2010 14:48:35 -0600
Subject: mythtv-stable: added new menu called LiveTV. This restores the Watch
 TV button to the top of the list. .22 requires menutheme_fallback.patch but
 hopefully .23 will not, as a patch was submitted to mythtv for inclusion.
 closes FS#608

Signed-off-by: James Meyer <james.meyer@operamail.com>
---
 .../mythtv/stable-0.22/mythtv/PKGBUILD             | 18 ++++--
 .../stable-0.22/mythtv/menu-xml/mainmenu.tv.patch  | 68 ++++++++++++++++++++++
 .../stable-0.22/mythtv/menu-xml/themeinfo.xml-tv   | 48 +++++++++++++++
 .../stable-0.22/mythtv/menutheme_fallback.patch    | 18 ++++++
 4 files changed, 148 insertions(+), 4 deletions(-)
 create mode 100644 abs/core-testing/mythtv/stable-0.22/mythtv/menu-xml/mainmenu.tv.patch
 create mode 100644 abs/core-testing/mythtv/stable-0.22/mythtv/menu-xml/themeinfo.xml-tv
 create mode 100644 abs/core-testing/mythtv/stable-0.22/mythtv/menutheme_fallback.patch

diff --git a/abs/core-testing/mythtv/stable-0.22/mythtv/PKGBUILD b/abs/core-testing/mythtv/stable-0.22/mythtv/PKGBUILD
index b671f8e..47cdedd 100755
--- a/abs/core-testing/mythtv/stable-0.22/mythtv/PKGBUILD
+++ b/abs/core-testing/mythtv/stable-0.22/mythtv/PKGBUILD
@@ -1,6 +1,6 @@
 pkgname=mythtv
 pkgver=0.22
-pkgrel=22005
+pkgrel=23247
 pkgdesc="A personal video recorder for Linux"
 url="http://www.mythtv.org"
 license="GPL"
@@ -16,7 +16,7 @@ groups=('pvr')
 #MAKEFLAGS="-j6"
 install='mythtv.install'
 
-patchs=()
+patchs=('menutheme_fallback.patch')
 #patchs=('smolt_jump.patch')
 source=('mythbackend' 'myth.sh' `echo ${patchs[@]:0}` 'mythbackend.lr' 'mythfrontend.lr' 'pretty')
 arch=('i686' 'x86_64')
@@ -50,7 +50,7 @@ build() {
 	[ "$CARCH" = "x86_64" ] && ARCH="x86-64"
 
 	# clean up from last build
-	make distclean
+#	make distclean
 
 	# configure
 	./configure --prefix=/usr --arch=${ARCH} \
@@ -63,7 +63,6 @@ build() {
 	. /etc/profile
 	make || return 1
 	make INSTALL_ROOT=$startdir/pkg install || return 1
-    
 	# install db schema, scripts and docs
 	install -m0644 database/mc.sql $startdir/pkg/usr/share/mythtv/ || return 1
 	install -D -m0755 ../mythbackend $startdir/pkg/etc/rc.d/mythbackend || return 1
@@ -81,6 +80,17 @@ build() {
 	patch -p0 < $startdir/menu-xml/library.xml.patch || return 1
 	patch -p0 < $startdir/menu-xml/util_menu.xml.patch || return 1
 
+	#create new for those that still want live-tv on top
+	mkdir -p $startdir/pkg/usr/share/mythtv/themes/LiveTV
+	cp $startdir/menu-xml/themeinfo.xml-tv $startdir/pkg/usr/share/mythtv/themes/LiveTV/themeinfo.xml
+	cp  $startdir/pkg/usr/share/mythtv/themes/defaultmenu/mainmenu.xml  $startdir/pkg/usr/share/mythtv/themes/LiveTV/
+	cd  $startdir/pkg/usr/share/mythtv/themes/LiveTV/
+	patch -p5 < $startdir/menu-xml/mainmenu.tv.patch || return 1
+	
+
+
+
+
 	# make log dir
 	mkdir -p $startdir/pkg/var/log/mythtv
 	chown 1000.1000 $startdir/pkg/var/log/mythtv
diff --git a/abs/core-testing/mythtv/stable-0.22/mythtv/menu-xml/mainmenu.tv.patch b/abs/core-testing/mythtv/stable-0.22/mythtv/menu-xml/mainmenu.tv.patch
new file mode 100644
index 0000000..930fc5b
--- /dev/null
+++ b/abs/core-testing/mythtv/stable-0.22/mythtv/menu-xml/mainmenu.tv.patch
@@ -0,0 +1,68 @@
+--- usr/share/mythtv/themes/defaultmenu/mainmenu.xml.orig	2010-01-07 04:56:58.000000000 +0000
++++ usr/share/mythtv/themes/defaultmenu/mainmenu.xml	2010-01-07 04:57:35.000000000 +0000
+@@ -2,6 +2,32 @@
+ <mythmenu name="MAIN">
+ 
+     <button>
++        <type>TV_WATCH_TV</type>
++        <text>Watch TV</text>
++        <text lang="IT">Guarda la TV</text>
++        <text lang="ES">Ver la TV</text>
++        <text lang="NL">TV Kijken</text>
++        <text lang="DE">Fernsehen</text>
++        <text lang="DA">Se TV</text>
++        <text lang="IS">Horfa á sjónvarp</text>
++        <text lang="PT">Ver Televisão</text>
++        <text lang="SV">Se på TV</text>
++        <text lang="JA">TV放送</text>
++        <text lang="FI">Katso Televisiota</text>
++        <text lang="ZH_TW">觀看電視</text>
++        <text lang="SL">Glej TV</text>
++        <text lang="ET">Vaata telerit</text>
++        <text lang="RU">Смотреть ТВ</text>
++        <text lang="AR">شاهد التلفاز</text>
++        <text lang="PL">Oglądanie TV</text>
++        <text lang="HE">צפיה בטלויזיה</text>
++        <text lang="HU">TV nézés</text>
++        <description>Watch live television</description>
++        <description lang="DE">Jetzt Fernsehen schauen</description>
++        <action>TV_WATCH_LIVE</action>
++    </button>
++
++    <button>
+         <type>MENU_MEDIA_LIBRARY</type>
+         <text>Media Library</text>
+         <text lang="IT">Multimedia</text>
+@@ -130,32 +156,6 @@
+     </button>
+ 
+     <button>
+-        <type>TV_WATCH_TV</type>
+-        <text>Watch TV</text>
+-        <text lang="IT">Guarda la TV</text>
+-        <text lang="ES">Ver la TV</text>
+-        <text lang="NL">TV Kijken</text>
+-        <text lang="DE">Fernsehen</text>
+-        <text lang="DA">Se TV</text>
+-        <text lang="IS">Horfa á sjónvarp</text>
+-        <text lang="PT">Ver Televisão</text>
+-        <text lang="SV">Se på TV</text>
+-        <text lang="JA">TV放送</text>
+-        <text lang="FI">Katso Televisiota</text>
+-        <text lang="ZH_TW">觀看電視</text>
+-        <text lang="SL">Glej TV</text>
+-        <text lang="ET">Vaata telerit</text>
+-        <text lang="RU">Смотреть ТВ</text>
+-        <text lang="AR">شاهد التلفاز</text>
+-        <text lang="PL">Oglądanie TV</text>
+-        <text lang="HE">צפיה בטלויזיה</text>
+-        <text lang="HU">TV nézés</text>
+-        <description>Watch live television</description>
+-        <description lang="DE">Jetzt Fernsehen schauen</description>
+-        <action>TV_WATCH_LIVE</action>
+-    </button>
+-
+-    <button>
+         <type>MENU_UTILITIES_SETUP</type>
+         <text>Service Menu</text>
+         <description>LinHES Service Menu</description>
diff --git a/abs/core-testing/mythtv/stable-0.22/mythtv/menu-xml/themeinfo.xml-tv b/abs/core-testing/mythtv/stable-0.22/mythtv/menu-xml/themeinfo.xml-tv
new file mode 100644
index 0000000..64a3207
--- /dev/null
+++ b/abs/core-testing/mythtv/stable-0.22/mythtv/menu-xml/themeinfo.xml-tv
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<themeinfo>
+    <!-- The Theme Name (Required) -->
+    <name>LiveTV</name>
+   
+    <!-- The Theme Types (Required) -->
+    <types>
+        <!-- Type. Legal Values are one or more of: UI, OSD and Menu -->
+        <type>Menu</type>
+    </types>
+   
+    <!-- Theme Author Details (Optional)-->
+    <author>
+        <!-- Your name -->
+        <name></name>
+       
+        <!-- Your Email Address -->
+        <email></email>
+    </author>
+   
+    <!-- The Versioning Info (Required) -->
+    <version>
+        <!-- Major version changes mean the theme is no longer
+             compatible with earlier versions of mythtv -->
+        <major>1</major>
+       
+        <!-- Minor version changes are backwards compatible -->
+        <minor>1</minor>
+    </version>
+   
+    <!-- Theme Details (Required) -->
+    <detail>
+        <!-- At least one thumbnail image named "preview" must be included
+             with the theme.
+             There is no limit to the number of thumbnails.
+             Each thumbnail must be given a different name -->
+        <thumbnail name="preview"></thumbnail>
+       
+        <!-- A description of the theme, including general colours and
+             style. The description should include any details that
+             may help to locate your theme in a search. -->
+        <description></description>
+       
+        <!-- Errata. A list of known faults, missing elements or unfinished
+             areas. e.g. "mythgallery not themed" -->
+        <errata>N/A</errata>
+    </detail>
+</themeinfo>
diff --git a/abs/core-testing/mythtv/stable-0.22/mythtv/menutheme_fallback.patch b/abs/core-testing/mythtv/stable-0.22/mythtv/menutheme_fallback.patch
new file mode 100644
index 0000000..aa633ff
--- /dev/null
+++ b/abs/core-testing/mythtv/stable-0.22/mythtv/menutheme_fallback.patch
@@ -0,0 +1,18 @@
+Index: libs/libmythui/myththemedmenu.cpp
+===================================================================
+--- libs/libmythui/myththemedmenu.cpp	(revision 23401)
++++ libs/libmythui/myththemedmenu.cpp	(working copy)
+@@ -778,6 +778,13 @@
+     else
+         VERBOSE(VB_FILE+VB_EXTRA, "No menu file " + testdir);
+ 
++    testdir = GetShareDir() + "themes/defaultmenu/" + menuname;
++    file.setFileName(testdir);
++    if (file.exists())
++        return testdir;
++    else
++        VERBOSE(VB_FILE+VB_EXTRA, "No menu file " + testdir);
++
+     return QString();
+ }
+ 
-- 
cgit v0.12


From f1a341f44d57589e1d8352f7c4ecc63f6dd15eda Mon Sep 17 00:00:00 2001
From: James Meyer <james.meyer@operamail.com>
Date: Sun, 31 Jan 2010 14:53:34 -0600
Subject: runit-scripts: fixed typo for setserial command. closes FS#550

---
 abs/core-testing/runit-scripts/PKGBUILD | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/abs/core-testing/runit-scripts/PKGBUILD b/abs/core-testing/runit-scripts/PKGBUILD
index 80f8054..c8c362f 100755
--- a/abs/core-testing/runit-scripts/PKGBUILD
+++ b/abs/core-testing/runit-scripts/PKGBUILD
@@ -1,6 +1,6 @@
 pkgname=runit-scripts
 pkgver=1.8.0
-pkgrel=104
+pkgrel=106
 pkgdesc="collection of startup scripts for runit"
 url="http://smarden.org/runit/"
 license="BSD"
-- 
cgit v0.12


From 32682bf8db7b684150558c30f6c01aca3fce922a Mon Sep 17 00:00:00 2001
From: James Meyer <james.meyer@operamail.com>
Date: Sun, 31 Jan 2010 14:55:35 -0600
Subject: mythvodka: dropped from repo.

---
 abs/extra/mythvodka/PKGBUILD          |   36 -
 abs/extra/mythvodka/hulu_grabber.sh   |   16 -
 abs/extra/mythvodka/mythvodka.diff    | 3933 ---------------------------------
 abs/extra/mythvodka/mythvodka.install |   47 -
 4 files changed, 4032 deletions(-)
 delete mode 100644 abs/extra/mythvodka/PKGBUILD
 delete mode 100755 abs/extra/mythvodka/hulu_grabber.sh
 delete mode 100644 abs/extra/mythvodka/mythvodka.diff
 delete mode 100644 abs/extra/mythvodka/mythvodka.install

diff --git a/abs/extra/mythvodka/PKGBUILD b/abs/extra/mythvodka/PKGBUILD
deleted file mode 100644
index 0832093..0000000
--- a/abs/extra/mythvodka/PKGBUILD
+++ /dev/null
@@ -1,36 +0,0 @@
-# $Id: PKGBUILD 5936 2008-07-21 20:24:16Z thomas $
-# Maintainer: Cecil Watson<knoppmyth@gmail.com>
-
-pkgname=mythvodka
-pkgver=0.7
-pkgrel=11
-pkgdesc="MythVodka (Video On Demand Killer App) is a plugin for MythTV allowing streaming of BBC iPlayer, Hulu, HTTP and NZB content."
-arch=('i686' 'x86_64')
-license=('GPL2')
-url="http://code.google.com/p/mythvodka/"
-depends=('rtmpdump' 'perl-xml-dom' 'beautiful-soup')
-install=mythvodka.install
-source=('http://mythvodka.googlecode.com/files/mythvodka.07.tar.gz' 'mythvodka.diff' 'hulu_grabber.sh' 'http://ftp.knoppmyth/R6/sources/huludata.tar.bz2')
-
-build() {
-	patch -p0 < mythvodka.diff
-	cd $startdir/src/mythvodka/mythvodka
-	rm -fr Makefile
-	qmake mythvodka.pro
-	make
-	mkdir -p $startdir/pkg/usr/lib/mythtv/plugins/
-	cp libmythvodka.so $startdir/pkg/usr/lib/mythtv/plugins/
-	strip --strip-unneeded $startdir/pkg/usr/lib/mythtv/plugins/libmythvodka.so
-	mkdir -p $startdir/pkg/usr/share/mythtv/themes/default/
-	cp streams-ui.xml $startdir/pkg/usr/share/mythtv/themes/default/
-	mkdir -p $startdir/pkg/usr/share/mythtv/themes/default-wide/
-	cp theme-wide/streams-ui.xml $startdir/pkg/usr/share/mythtv/themes/default-wide/
-	mkdir -p $startdir/pkg/usr/local/bin
-	chmod a+x ../scripts/*
-	cp -p ../scripts/* $startdir/pkg/usr/local/bin
-	mkdir -p $startdir/pkg/etc/cron.daily/
-	chmod 755 ../../hulu_grabber.sh
-	cp ../../hulu_grabber.sh $startdir/pkg/etc/cron.daily/
-	mkdir -p $startdir/pkg/var/tmp
-	cp $startdir/src/huludata.xml $startdir/pkg/var/tmp
-}
diff --git a/abs/extra/mythvodka/hulu_grabber.sh b/abs/extra/mythvodka/hulu_grabber.sh
deleted file mode 100755
index 4840dc0..0000000
--- a/abs/extra/mythvodka/hulu_grabber.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#! /bin/bash
-log=/var/log/mythtv/hulu_grabber.log
-out=/var/tmp/huludata.xml
-rm -f $log
-echo "Start on `date`" >>$log 2>&1
-/usr/local/bin/gethulu.pl $out.new >>$log 2>&1
-stat=$?
-if [ $stat -ne 0 ]; then
-  echo "Bad status $stat from gethulu.pl" >>$log 2>&1
-  exit 1
-fi
-rm -f $out.old
-mv $out $out.old
-mv $out.new $out
-echo "Done on `date`" >>$log 2>&1
-ls -lh $out >>$log 2>&1
diff --git a/abs/extra/mythvodka/mythvodka.diff b/abs/extra/mythvodka/mythvodka.diff
deleted file mode 100644
index 5735a42..0000000
--- a/abs/extra/mythvodka/mythvodka.diff
+++ /dev/null
@@ -1,3933 +0,0 @@
-diff -ruaN mythvodka.orig/mythvodka/streamsui.cpp mythvodka/mythvodka/streamsui.cpp
---- mythvodka.orig/mythvodka/streamsui.cpp	2009-01-06 00:18:35.000000000 +0000
-+++ mythvodka/mythvodka/streamsui.cpp	2009-02-12 07:28:31.000000000 +0000
-@@ -646,7 +646,7 @@
-     
-         MythProgressDialog *buffer_progress;
-         buffer_progress = new MythProgressDialog(
--            QObject::tr("If she kicks you in the balls, you have the ability and the right..."), bufferSize, true, this, SLOT(cancelPressed()));
-+            QObject::tr("Buffering... Just a moment please."), bufferSize, true, this, SLOT(cancelPressed()));
-     
-         QFile file(filename);
-     
-@@ -729,7 +729,7 @@
-     
-         MythProgressDialog *buffer_progress;
-         buffer_progress = new MythProgressDialog(
--            QObject::tr("Nascar Sucks / Hillary For President / Man Love Rules Ok"), bufferSize, true, this, SLOT(cancelPressed()));
-+            QObject::tr("Your video is being loaded..."), bufferSize, true, this, SLOT(cancelPressed()));
-     
-         QFile file(filename);
-     
-@@ -822,7 +822,7 @@
-     
-         MythProgressDialog *buffer_progress;
-         buffer_progress = new MythProgressDialog(
--            QObject::tr("RING RING... I FUCKED YOUR GRANDDAUGHTER"), bufferSizemov, true, this, SLOT(cancelPressed()));
-+            QObject::tr("We seem to have hit some sort of problem..."), bufferSizemov, true, this, SLOT(cancelPressed()));
-     
-         QFile filemov(filenamemov);
-     
-diff -ruaN mythvodka.orig/scripts/get_iplayer mythvodka/scripts/get_iplayer
---- mythvodka.orig/scripts/get_iplayer	2009-01-06 19:11:24.000000000 +0000
-+++ mythvodka/scripts/get_iplayer	2009-02-12 07:27:44.000000000 +0000
-@@ -3,16 +3,17 @@
- # get_iplayer
- #
- # Lists and downloads BBC iPlayer audio and video streams
--# 
-+# + Downloads ITVplayer Catch-Up video streams
-+#
- # Author: Phil Lewis
- # Email: iplayer (at sign) linuxcentre.net
- # Web: http://linuxcentre.net/iplayer
- # License: GPLv3 (see LICENSE.txt)
- #
- # Other credits:
--# RTMP additions: Andrej Stepanchuk
-+#  RTMP additions: Andrej Stepanchuk
- #
--my $version = 1.04;
-+my $version = 1.17;
- #
- # Help:
- #	./get_iplayer --help
-@@ -29,13 +30,16 @@
- # * Index/Download live radio streams w/schedule feeds to assist timing
- # * Podcasts for 'local' stations are missing (only a handful). They use a number of different station ids which will involve reading html to determine rss feed. 
- # * Remove all rtsp/mplayer/lame/tee dross when realaudio streams become obselete (not quite yet)
--# * Cope with radio via rtmp
- # * Stdout mode with rtmp
--#
-+# * Do subtitle downloading after programme download so that rtmp auth doesn't timeout
-+
- # Known Issues:
- # * In ActivePerl/windows downloaded iPhone video files do not get renamed (remain with .partial.mov)
- # * vlc does not quit after downloading an rtsp N95 video stream (ctrl-c is required) - need a --play-and-quit option if such a thing exists
--# * flv conversions from rtmp downloads aren't quite right yet. A/V sync issues?
-+# * rtmpdump (v1.2) of flashaudio fails at end of stream => non-zero exit code
-+# * if ffmpeg trys to convert flv to mp3 it succeeds but => non-zero exit code
-+# * Some rtmpdump downloads always give a non-zero exit code regardless of success (using a min-filesize workaround for now)
-+# * resuming a flashaudio download fails
- 
- use Env qw[@PATH];
- use Fcntl;
-@@ -62,10 +66,17 @@
- my %opt_cmdline = (); # a hash of which options came from the cmdline rather than the options files
- my %opt_file = (); # a hash of which options came from the options files rather than the cmdline
- 
--# Print to STDERR if not quiet unless verbose or debug
-+# Print to STDERR/STDOUT if not quiet unless verbose or debug
- sub logger(@) {
- 	# Make sure quiet can be overridden by verbose and debug options
--	print STDERR $_[0] if (! $opt{quiet}) || $opt{verbose} || $opt{debug};
-+	if ( $opt{verbose} || $opt{debug} || ! $opt{quiet} ) {
-+		# Only send messages to STDERR if pvr or stdout options are being used.
-+		if ( $opt{stdout} || $opt{pvr} || $opt{stderr} ) {
-+			print STDERR $_[0];
-+		} else {
-+			print STDOUT $_[0];
-+		}
-+	}
- }
- 
- sub usage {
-@@ -74,7 +85,7 @@
- Search Programmes:  get_iplayer [<search options>] [<regex|index|pid|pidurl> ...]
- Download files:     get_iplayer --get [<search options>] <regex|index|pid|pidurl> ...
-                     get_iplayer --pid <pid|pidurl> [<options>]
--Stream Downloads:   get_iplayer --stdout [<options>] <regex|index|pid|pidurl> | mplayer -cache 2048 -
-+Stream Downloads:   get_iplayer --stdout [<options>] <regex|index|pid|pidurl> | mplayer -cache 3072 -
- Update get_iplayer: get_iplayer --update
- 
- Search Options:
-@@ -83,9 +94,10 @@
-  --channel <regex>             Narrow search to matched channel(s)
-  --category <regex>            Narrow search to matched categories
-  --versions <regex>            Narrow search to matched programme version(s)
-+ --exclude <regex>             Narrow search to exclude matched programme names
-  --exclude-channel <regex>     Narrow search to exclude matched channel(s)
-  --exclude-category <regex>    Narrow search to exclude matched catogories
-- --type <radio|tv|podcast|all> Only search in these types of programmes (tv is default)
-+ --type <type>                 Only search in these types of programmes: radio, tv, podcast, all, itv (tv is default)
-  --since <hours>               Limit search to programmes added to the cache in the last N hours
-  
- Display Options:
-@@ -95,26 +107,25 @@
-  -i, --info                    Show full programme metadata (only if number of matches < 50)
-  --list <categories|channel>   Show a list of available categories/channels for the selected type and exit
-  --hide                        Hide previously downloaded programmes
-+ --streaminfo                  Returns all of the media stream urls of the programme(s)
- 
- Download Options:
-  -g, --get                     Download matching programmes
-  -x, --stdout                  Additionally stream to STDOUT (so you can pipe output to a player)
-  -p, --proxy <url>             Web proxy URL spec
-  --partial-proxy               Works around for some broken web proxies (try this extra option if your proxy fails)
-- --pid <pid|url>               Download an arbitrary pid that does not appear in the index
-+ --pid <pid|url>               Download an arbitrary pid that does not appear in the index (itv:<pid> for itv programmes)
-  --force-download              Ignore download history (unsets --hide option also)
-- --realaudio                   Use the RealAudio radio stream and not the MP3 stream
-- --mp3audio                    Use the MP3 radio stream for radio and dont fallback to the RealAudio stream
-+ --amode <mode>,<mode>,...     Audio Download mode(s): iphone,flashaudio,realaudio (default: iphone,flashaudio,realaudio)
-+ --vmode <mode>,<mode>,...     Video Download mode(s): iphone,rtmp,flashhigh,flashnormal,flashwii,n95_wifi (default: iphone,flashhigh,flashnormal)
-  --wav                         In radio realaudio mode output as wav and don't transcode to mp3
-- --raw                         In radio/realaudio or iPhone/video mode don't transcode or change the downloaded stream in any way
-- --n95                         In TV mode download/stream low quality Nokia N95 H.264 stream (alpha)
-- --rtmp                        In TV mode download/stream high quality flash stream (alpha)
-+ --raw                         Don't transcode or change the downloaded stream in any way (i.e. radio/realaudio, rtmp/flv, iphone/mov)
-  --bandwidth                   In radio realaudio mode specify the link bandwidth in bps for rtsp streaming (default 512000)
-  --subtitles                   In TV mode, download subtitles into srt/SubRip format if available
-  --suboffset <offset>          Offset the subtitle timestamps by the specified number of milliseconds
-  --version-list <versions>     Override the version of programme to download (e.g. '--version-list signed,default')
-  -t, --test                    Test only - no download (will show programme type)
-- 
-+
- PVR Options:
-  --pvr                         Runs the PVR download using all saved PVR searches (intended to be run every hour from cron etc)
-  --pvradd <search name>        Add the current search terms to the named PVR search
-@@ -139,18 +150,18 @@
-  -f, --flush, --refresh        Refresh cache
-  -e, --expiry <secs>           Cache expiry in seconds (default 4hrs)
-  --symlink <file>              Create symlink to <file> once we have the header of the download
-- --fxd <file>                  Create Freevo FXD XML in specified file
-- --mythtv <file>               Create Mythtv streams XML in specified file
-+ --fxd <file>                  Create Freevo FXD XML of matching programmes in specified file
-+ --mythtv <file>               Create Mythtv streams XML of matching programmes in specified file
-  --xml-channels                Create freevo/Mythtv menu of channels -> programme names -> episodes
-  --xml-names                   Create freevo/Mythtv menu of programme names -> episodes
-  --xml-alpha                   Create freevo/Mythtv menu sorted alphabetically by programme name
-- --html <file>                 Create basic HTML index of programmes in specified file
-+ --html <file>                 Create basic HTML index of matching programmes in specified file
-  --mplayer <path>              Location of mplayer binary
-+ --ffmpeg <path>               Location of ffmpeg binary
-  --lame <path>                 Location of lame binary
-  --id3v2 <path>                Location of id3v2 binary
-  --rtmpdump <path>             Location of rtmpdump binary
-- --vlc <path>                  Location of vlc binary
-- --streaminfo                  Returns all of the media stream urls of the programme(s)
-+ --vlc <path>                  Location of vlc or cvlc binary
-  -v, --verbose                 Verbose
-  -u, --update                  Update get_iplayer if a newer one exists
-  -h, --help                    Help
-@@ -192,14 +203,17 @@
- Getopt::Long::Configure ("bundling");
- # cmdline opts take precedence
- GetOptions(
-+	"amode=s"			=> \$opt_cmdline{amode},
- 	"bandwidth=n"			=> \$opt_cmdline{bandwidth},
- 	"category=s"			=> \$opt_cmdline{category},
- 	"channel=s"			=> \$opt_cmdline{channel},
- 	"c|command=s"			=> \$opt_cmdline{command},
- 	"debug"				=> \$opt_cmdline{debug},
-+	"exclude=s"			=> \$opt_cmdline{exclude},
- 	"exclude-category=s"		=> \$opt_cmdline{excludecategory},
- 	"exclude-channel=s"		=> \$opt_cmdline{excludechannel},
- 	"expiry|e=n"			=> \$opt_cmdline{expiry},
-+	"ffmpeg=s"			=> \$opt_cmdline{ffmpeg},
- 	"file-prefix|fileprefix=s"	=> \$opt_cmdline{fileprefix},
- 	"flush|refresh|f"		=> \$opt_cmdline{flush},
- 	"force-download"		=> \$opt_cmdline{forcedownload},
-@@ -238,7 +252,7 @@
- 	"rtmpdump=s"			=> \$opt_cmdline{rtmpdump},
- 	"save"				=> \$save,
- 	"since=n"			=> \$opt_cmdline{since},
--	"stdout|stream|x"		=> \$opt_cmdline{stdout},
-+	"stdout|x"			=> \$opt_cmdline{stdout},
- 	"streaminfo"			=> \$opt_cmdline{streaminfo},
- 	"subdirs|subdir|s"		=> \$opt_cmdline{subdir},
- 	"suboffset=n"			=> \$opt_cmdline{suboffset},
-@@ -253,6 +267,7 @@
- 	"versions=s"			=> \$opt_cmdline{versions},
- 	"verbose|v"			=> \$opt_cmdline{verbose},
- 	"vlc=s"				=> \$opt_cmdline{vlc},
-+	"vmode=s"			=> \$opt_cmdline{vmode},
- 	"wav"				=> \$opt_cmdline{wav},
- 	"whitespace|ws|w"		=> \$opt_cmdline{whitespace},
- 	"xml-channels|fxd-channels"	=> \$opt_cmdline{xmlchannels},
-@@ -269,7 +284,7 @@
- save_options_file( $optfile ) if $save;
- 
- 
--# Global vars
-+### Global vars ###
- 
- # Programme data structure
- # $prog{$pid} = {
-@@ -283,7 +298,7 @@
- #	'thumbnail'	=> <programme thumbnail url>
- #	'channel	=> <channel>
- #	'categories'	=> <Comma separated list of categories>
--# 	'type'		=> <Type: tv, radio or podcast>
-+# 	'type'		=> <Type: tv, radio, itv or podcast>
- #	'timeadded'	=> <timestamp when programme was added to cache>
- #	'longname'	=> <Long name (only parsed in stage 1 download)>,
- #	'version'	=> <selected version e.g default, signed, etc - only set before d/load>
-@@ -292,11 +307,35 @@
- #	'fileprefix'	=> <Filename Prefix of saved file - set only while downloading>
- #	'ext'		=> <Filename Extension of saved file - set only while downloading>
- #};
-+
-+# Define cache file format
-+my @cache_format = qw/index type name pid available episode versions duration desc channel categories thumbnail timeadded guidance/;
-+
-+# List of all types
-+my @all_prog_types = qw/ tv radio podcast itv /;
-+
-+# Ranges of numbers used in the indicies for each programme type
-+my %index_range;
-+$index_range{tv}{min} 		= 1;
-+$index_range{tv}{max} 		= 9999;
-+$index_range{radio}{min} 	= 10001;
-+$index_range{radio}{max} 	= 19999;
-+$index_range{podcast}{min} 	= 20001;
-+$index_range{podcast}{max} 	= 29999;
-+$index_range{itv}{min} 		= 100001;
-+$index_range{itv}{max} 		= 199999;
-+# Set maximun index number
-+my $max_index;
-+for (@all_prog_types) {
-+	$max_index = $index_range{$_}{max} if $index_range{$_}{max} > $max_index;
-+}
- my %prog;
-+my %type;
- my %pids_history;
- my %index_pid; # Hash to obtain pid given an index
- my $now;
- my $childpid;
-+my $min_download_size = 1000000;
- 
- # Static URLs
- my $channel_feed_url		= 'http://feeds.bbc.co.uk/iplayer'; # /$channel/list/limit/400
-@@ -396,6 +435,18 @@
- 	'bbc_radio_jersey'			=> 'radio|BBC Jersey',
- };
- 
-+$channels{itv} = {
-+	'crime'					=> 'itv|TV Classics Crime Drama',
-+	'perioddrama'				=> 'itv|TV Classics Period Drama',
-+	'familydrama'				=> 'itv|TV Classics Family Drama',
-+	'documentary'				=> 'itv|TV Classics Documentaries',
-+	'comedy'				=> 'itv|TV Classics Comedy',
-+	'kids'					=> 'itv|TV Classics Children\'s TV',
-+	'soaps'					=> 'itv|TV Classics Soaps',
-+	'/'					=> 'itv|TV Classics',
-+};
-+
-+
- # User Agents
- my %user_agent = (
-   	coremedia	=> 'Apple iPhone v1.1.1 CoreMedia v1.0.0.3A110a',
-@@ -410,6 +461,7 @@
- 
- # Other Non-option dependant vars
- my %cachefile = (
-+	'itv'		=> "${profile_dir}/itv.cache",
- 	'tv'		=> "${profile_dir}/tv.cache",
- 	'radio'		=> "${profile_dir}/radio.cache",
- 	'podcast'	=> "${profile_dir}/podcast.cache",
-@@ -430,6 +482,7 @@
- my $mplayer;
- #my $mencoder;
- my $ffmpeg;
-+my $ffmpeg_opts;
- my $rtmpdump;
- my $mplayer_opts;
- my $lame;
-@@ -480,7 +533,7 @@
- 	# Display default options
- 	display_default_options();
- 	# For each PVR search
--	for my $name ( sort {$a <=> $b} keys %pvrsearches ) {
-+	for my $name ( sort {lc $a cmp lc $b} keys %pvrsearches ) {
- 		# Ignore if this search is disabled
- 		if ( $pvrsearches{$name}{disable} ) {
- 			logger "\nSkipping disabled PVR Search '$name'\n" if $opt{verbose};
-@@ -519,27 +572,29 @@
- 	# Option dependant vars
- 	%download_dir	= (
- 		'tv'		=> $opt{outputtv} || $opt{output} || $ENV{IPLAYER_OUTDIR} || '.',
-+		'itv'		=> $opt{outputtv} || $opt{output} || $ENV{IPLAYER_OUTDIR} || '.',
- 		'radio'		=> $opt{outputradio} || $opt{output} || $ENV{IPLAYER_OUTDIR} || '.',
- 		'podcast'	=> $opt{outputpodcast} || $opt{output} || $ENV{IPLAYER_OUTDIR} || '.',
- 	);
--	# Default to type=tv
--	$opt{type} 		= 'tv' if ! $opt{type};
--	# Expand 'all' to various prog types
--	$opt{type} 		= 'tv,radio,podcast' if $opt{type} =~ /(all|any)/i;
-+
- 	# Ensure lowercase
--	$opt{type} = lc( $opt{type} );
-+	$opt{type}		= lc( $opt{type} );
-+	# Expand 'all' to comma separated list all prog types
-+	$opt{type} 		= join(',', @all_prog_types) if $opt{type} =~ /(all|any)/i;
-+	# Hash to store specified prog types
-+	%type = ();
-+	$type{$_} = 1 for split /,/, $opt{type};
-+	# Default to type=tv if no type option is set
-+	$type{tv}		= 1 if keys %type == 0;
- 	$cache_secs 		= $opt{expiry} || 14400;
- 	$mplayer		= $opt{mplayer} || 'mplayer';
- 	$mplayer_opts		= '-nolirc';
- 	$mplayer_opts		.= ' -really-quiet' if $opt{quiet};
--	# Assume mencoder/ffmpeg is in the same path as mplayer
--#	$mencoder		= $mplayer;
--#	$mencoder		=~ s|^(.*?)mplayer|$1mencoder|g;
--	$ffmpeg			= $mplayer;
--	$ffmpeg			=~ s|^(.*?)mplayer|$1ffmpeg|g;
-+	$ffmpeg			= $opt{ffmpeg} || 'ffmpeg';
-+	$ffmpeg_opts		= '';
- 	$lame			= $opt{lame} || 'lame';
--	$lame_opts		= '-f ';
--	$lame_opts		.= '--quiet ' if $opt{quiet};
-+	$lame_opts		= '-f';
-+	$lame_opts		.= ' --quiet ' if $opt{quiet};
- 	$vlc			= $opt{vlc} || 'cvlc';
- 	$vlc_opts		= '-vv';
- 	$id3v2			= $opt{id3v2} || 'id3v2';
-@@ -562,11 +617,11 @@
- 		exit 1;
- 	}
- 
--	# Disable rtmp mode if rtmpdump does not exist
--	if ( $opt{rtmp} && ! exists_in_path($rtmpdump)) {
--		logger "\nERROR: Required program $rtmpdump does not exist (see http://linuxcentre.net/getiplayer/installation and http://linuxcentre.net/getiplayer/download), falling back to iphone mode\n";
--		delete $opt{rtmp};
--	}
-+	# Backward compatability options - to be removed eventually
-+	$opt{vmode} = 'rtmp' if $opt{rtmp};
-+	$opt{vmode} = 'n95_wifi' if $opt{n95};
-+	$opt{amode} = 'realaudio' if $opt{realaudio};
-+	$opt{amode} = 'iphone' if $opt{mp3audio};
- 
- 	# Web proxy
- 	$proxy_url = $opt{proxy} || $ENV{HTTP_PROXY} || $ENV{http_proxy} || '';
-@@ -585,8 +640,21 @@
- 		}
- 	}
- 
--	# Get arbitrary pid
-+	# Get prog by arbitrary pid (then exit)
- 	if ( $opt{pid} ) {
-+
-+		# Temporary hack to get 'ITV Catch-up' downloads specified as --pid itv:<pid>
-+		$type{itv} = 1 if $opt{pid} =~ m{^itv:(.+?)$};
-+		if ( $type{itv} ) {
-+			exit 1 if ( ! $opt{streaminfo} ) && check_download_history( $opt{pid} );
-+			# Remove leading itv: tag (backwards compat)
-+			$opt{pid} =~ s/^itv:(.+?)$/$1/ig;
-+			# Force prog type to itv
-+			$prog{$opt{pid}}{type} = 'itv';
-+			download_programme( $opt{pid} );
-+			exit 0;
-+		}
-+
- 		# Remove any url parts from the pid
- 		$opt{pid} =~ s/^.*(b0[a-z,0-9]{6}).*$/$1/g;
- 		# Retry loop
-@@ -594,21 +662,29 @@
- 		my $retries = 3;
- 		my $retcode;
- 		exit 1 if ( ! $opt{streaminfo} ) && check_download_history( $opt{pid} );
--		while ( $count < $retries && ($retcode = download_programme( $opt{pid} )) eq 'retry' ) {
--			logger "WARNING: Retrying download for PID $opt{pid}\n";
--			$count++;
-+		for ($count = 1; $count <= $retries; $count++) {
-+			$retcode = download_programme( $opt{pid} );
-+			return 0 if $retcode eq 'skip';
-+			if ( $retcode eq 'retry' && $count < $retries ) {
-+				logger "WARNING: Retrying download for PID $opt{pid}\n";
-+			} else {
-+				$retcode = 1 if $retcode eq 'retry';
-+				last;
-+			}
- 		}
- 		# Add to history, tag and Run post download command if download was successful
- 		if ($retcode == 0) {
- 			add_to_download_history( $opt{pid} );
- 			tag_file( $opt{pid} );
- 			run_user_command( $opt{pid}, $opt{command} ) if $opt{command};
--		}	
-+		} elsif (! $opt{test}) {
-+			logger "ERROR: Failed to download PID $opt{pid}\n";
-+		}
- 		exit 0;
- 	}
- 
- 	# Get stream links from BBC iplayer site or from cache (also populates all hashes) specified in --type option
--	get_links( $_ ) for split /,/, $opt{type};
-+	get_links( $_ ) for keys %type;
- 
- 	# List elements (i.e. 'channel' 'categories') if required and exit
- 	if ( $opt{list} ) {
-@@ -616,18 +692,13 @@
- 		exit 0;
- 	}
- 
--	# Write HTML and XML files if required
--	create_html( sort {$a <=> $b} keys %index_pid ) if $opt{html};
--	create_xml( $opt{fxd}, sort {$a <=> $b} keys %index_pid ) if $opt{fxd};
--	create_xml( $opt{mythtv}, sort {$a <=> $b} keys %index_pid ) if $opt{mythtv};
--
- 	# Parse remaining args
- 	my @match_list;
- 	for ( @search_args ) {
- 		chomp();
--	
--		# If Numerical value < 30000
--		if ( /^[\d]+$/ && $_ < 30000) {
-+
-+		# If Numerical value < $max_index
-+		if ( /^[\d]+$/ && $_ <= $max_index) {
- 			push @match_list, $_;
- 	
- 		# If PID then find matching programmes with this PID
-@@ -649,24 +720,29 @@
- 	# Go get the cached data for other programme types if the index numbers require it
- 	my %require;
- 	for ( @match_list ) {
--		$require{tv} = 1 if $_ >= 1 && $_ < 10000 && ( ! $require{tv} ) && $opt{type} !~ /tv/;
--		$require{radio} = 1 if $_ >= 10000 && $_ < 20000 && ( ! $require{radio} ) && $opt{type} !~ /radio/;
--		$require{podcast} = 1 if $_ >= 20000 && $_ < 30000 && ( ! $require{podcast} ) && $opt{type} !~ /podcast/;
-+		for my $types ( @all_prog_types ) {
-+			$require{$types} = 1 if $_ >= $index_range{$types}{min} && $_ <= $index_range{$types}{max} && ( ! $require{$types} ) && ( ! $type{$types} );
-+		}
- 	}
-+
- 	# Get extra required programme caches
- 	logger "INFO: Additionally getting cached programme data for ".(join ', ', keys %require)."\n" if %require > 0;
- 	# Get stream links from BBC iplayer site or from cache (also populates all hashes)
- 	for (keys %require) {
- 		# Get $_ stream links
- 		get_links( $_ );
--		# Add new prog types to the type option
--		$opt{type} .= ",$_";
-+		# Add new prog types to the type list
-+		$type{$_} = 1;
- 	}
--
- 	# Display list for download
- 	logger "Matches:\n" if @match_list;
- 	@match_list = list_progs( @match_list );
- 
-+	# Write HTML and XML files if required (with search options applied)
-+	create_html( @match_list ) if $opt{html};
-+	create_xml( $opt{fxd}, @match_list ) if $opt{fxd};
-+	create_xml( $opt{mythtv}, @match_list ) if $opt{mythtv};
-+
- 	# Do the downloads based on list of index numbers if required
- 	if ( $opt{get} || $opt{stdout} ) {
- 		for (@match_list) {
-@@ -681,16 +757,27 @@
- 				logger "ERROR: No PID for index $_ (try using --type option ?)\n";
- 				next;
- 			}
--			while ( $count < $retries && $pid && ($retcode = download_programme( $pid )) eq 'retry' ) {
--				logger "WARNING: Retrying download for '$prog{$pid}{name} - $prog{$pid}{episode}'\n";
--				$count++;
-+			for ($count = 1; $count <= $retries; $count++) {
-+				$retcode = download_programme( $pid );
-+				last if $retcode eq 'skip';
-+				if ( $retcode eq 'retry' && $count < $retries ) {
-+					logger "WARNING: Retrying download for '$prog{$pid}{name} - $prog{$pid}{episode}'\n";
-+				} else {
-+					$retcode = 1 if $retcode eq 'retry';
-+					last;
-+				}
- 			}
- 			# Add to history, tag file, and run post download command if download was successful
--			if ($retcode eq '0') {
-+			if ($retcode == 0) {
- 				add_to_download_history( $pid );
- 				tag_file( $pid );
- 				run_user_command( $pid, $opt{command} ) if $opt{command};
- 				pvr_report( $pid ) if $opt{pvr};
-+			# Next match if 'skip' was returned
-+			} elsif ( $retcode eq 'skip' ) {
-+				last;
-+			} elsif (! $opt{test}) {
-+				logger "ERROR: Failed to download '$prog{$pid}{name} - $prog{$pid}{episode}'\n";
- 			}
- 		}
- 	}
-@@ -702,16 +789,11 @@
- 
- # Lists progs given an array of index numbers, also returns an array with non-existent entries removed
- sub list_progs {
--	my $ua;
-+	my $ua = create_ua('desktop');
- 	my @checked;
- 	my %names;
- 	# Setup user agent for a persistent connection to get programme metadata
- 	if ( $opt{info} ) {
--		$ua = LWP::UserAgent->new;
--		$ua->timeout([$lwp_request_timeout]);
--		$ua->proxy( ['http'] => $proxy_url );
--		$ua->agent( $user_agent{desktop} );
--		$ua->conn_cache(LWP::ConnCache->new());
- 		# Truncate array if were lisiting info and > $info_limit entries are requested - be nice to the beeb!
- 		if ( $#_ >= $info_limit ) {
- 			$#_ = $info_limit - 1;
-@@ -733,18 +815,7 @@
- 		push @checked, $_;
- 		if ( $opt{info} ) {
- 			my %metadata = get_pid_metadata( $ua, $pid );
--			logger "\nPid:\t\t$metadata{pid}\n";
--			logger "Index:\t\t$metadata{index}\n";
--			logger "Type:\t\t$metadata{type}\n";
--			logger "Duration:\t$metadata{duration}\n";
--			logger "Channel:\t$metadata{channel}\n";
--			logger "Available:\t$metadata{available}\n";
--			logger "Expires:\t$metadata{expiry}\n";
--			logger "Versions:\t$metadata{versions}\n";
--			logger "Guidance:\t$metadata{guidance}\n";
--			logger "Categories:\t$metadata{categories}\n";
--			logger "Description:\t$metadata{desc}\n";
--			logger "Player:\t\t$metadata{player}\n";
-+			display_metadata( \%metadata, qw/ pid index type duration channel available expiry versions guidance categories desc player / );
- 		}
- 	}
- 	logger "\n";
-@@ -758,8 +829,9 @@
- # Display a line containing programme info (using long, terse, and type options)
- sub list_prog_entry {
- 	my ( $pid, $prefix, $tree ) = ( @_ );
--	my $type = '';
--	$type = "$prog{$pid}{type}, " if $opt{type} !~ /^(tv|radio|podcast)$/i;
-+	my $prog_type = '';
-+	# Show the type field if >1 type has been specified
-+	$prog_type = "$prog{$pid}{type}, " if keys %type > 1;
- 	my $name;
- 	# If tree view
- 	if ( $opt{tree} ) {
-@@ -768,20 +840,21 @@
- 	} else {
- 		$name = "$prog{$pid}{name} - ";
- 	}
--	# Remove some info depending on type
-+	# Remove some info depending on prog_type
- 	my $optional;
- 	$optional = ", '$prog{$pid}{channel}', $prog{$pid}{categories}, $prog{$pid}{versions}" if $prog{$pid}{type} eq 'tv';
-+	$optional = ", '$prog{$pid}{channel}'" if $prog{$pid}{type} eq 'itv';
- 	$optional = ", '$prog{$pid}{channel}', $prog{$pid}{categories}" if $prog{$pid}{type} eq 'radio';
- 	$optional = ", '$prog{$pid}{available}', '$prog{$pid}{channel}', $prog{$pid}{categories}" if $prog{$pid}{type} eq 'podcast';
--	logger "\n${type}$prog{$pid}{name}\n" if $opt{tree} && ! $tree;
-+	logger "\n${prog_type}$prog{$pid}{name}\n" if $opt{tree} && ! $tree;
- 	# Display based on output options
- 	if ( $opt{long} ) {
- 		my @time = gmtime( time() - $prog{$pid}{timeadded} );
--		logger "${prefix}$prog{$pid}{index}:\t${type}${name}$prog{$pid}{episode}${optional}, $time[7] days $time[2] hours ago - $prog{$pid}{desc}\n";
-+		logger "${prefix}$prog{$pid}{index}:\t${prog_type}${name}$prog{$pid}{episode}${optional}, $time[7] days $time[2] hours ago - $prog{$pid}{desc}\n";
- 	} elsif ( $opt{terse} ) {
--		logger "${prefix}$prog{$pid}{index}:\t${type}${name}$prog{$pid}{episode}\n";
-+		logger "${prefix}$prog{$pid}{index}:\t${prog_type}${name}$prog{$pid}{episode}\n";
- 	} else {
--		logger "${prefix}$prog{$pid}{index}:\t${type}${name}$prog{$pid}{episode}${optional}\n";
-+		logger "${prefix}$prog{$pid}{index}:\t${prog_type}${name}$prog{$pid}{episode}${optional}\n";
- 	}
- 	return 0;
- }
-@@ -795,6 +868,7 @@
- 	my $channel_regex = $opt{channel} || '.*';
- 	my $category_regex = $opt{category} || '.*';
- 	my $versions_regex = $opt{versions} || '.*';
-+	my $exclude_regex = $opt{exclude} || '^ROGUE$';
- 	my $channel_exclude_regex = $opt{excludechannel} || '^ROGUE$';
- 	my $category_exclude_regex = $opt{excludecategory} || '^ROGUE$';
- 	my $since = $opt{since} || 99999;
-@@ -808,6 +882,7 @@
- 		  && $prog{$pid}{categories} =~ /$category_regex/i
- 		  && $prog{$pid}{versions} =~ /$versions_regex/i
- 		  && $prog{$pid}{channel} !~ /$channel_exclude_regex/i
-+		  && $prog{$pid}{name} !~ /$exclude_regex/i
- 		  && $prog{$pid}{categories} !~ /$category_exclude_regex/i
- 		  && $prog{$pid}{timeadded} >= $now - ($since * 3600)
- 		) {
-@@ -828,25 +903,22 @@
- 			);
- 		}
- 	}
-+
- 	return sort {$a <=> $b} keys %download_hash;
- }
- 
- 
--# get_links_atom (%channels)
--sub get_links_atom {
--	my $type = shift;
-+# get_links_bbciplayer (%channels)
-+sub get_links_bbciplayer {
-+	my $prog_type = shift;
- 	my %channels = %{$_[0]};
- 
- 	my $xml;
- 	my $feed_data;
- 	my $res;
--	logger "INFO: Getting $type Index Feeds\n";
-+	logger "INFO: Getting $prog_type Index Feeds\n";
- 	# Setup User agent
--	my $ua = LWP::UserAgent->new;
--	$ua->timeout([$lwp_request_timeout]);
--	$ua->proxy( ['http'] => $proxy_url );
--	$ua->agent( $user_agent{desktop} );
--	$ua->conn_cache(LWP::ConnCache->new());
-+	my $ua = create_ua('desktop');
- 
- 	# Download index feed
- 	# Sort feeds so that category based feeds are done last - this makes sure that the channels get defined correctly if there are dups
-@@ -909,7 +981,7 @@
- 		# Discard first element == header
- 		shift @entries;
- 
--		my ( $name, $episode, $desc, $pid, $available, $channel, $duration, $thumbnail, $type, $versions );
-+		my ( $name, $episode, $desc, $pid, $available, $channel, $duration, $thumbnail, $prog_type, $versions );
- 		foreach my $entry (@entries) {
- 
- 			my $entry_flat = $entry;
-@@ -939,7 +1011,7 @@
- 			}
- 
- 			# Extract channel and type
--			($type, $channel) = (split /\|/, $channels{$_})[0,1];
-+			($prog_type, $channel) = (split /\|/, $channels{$_})[0,1];
- 
- 			logger "DEBUG: '$pid, $name - $episode, $channel'\n" if $opt{debug};
- 
-@@ -980,7 +1052,7 @@
- 				'thumbnail'	=> "${thumbnail_prefix}/${pid}_150_84.jpg",
- 				'channel'	=> $channel,
- 				'categories'	=> join(',', @category),
--				'type'		=> $type,
-+				'type'		=> $prog_type,
- 			};
- 		}
- 	}
-@@ -996,13 +1068,8 @@
- 
- 	# Add index field based on alphabetical sorting by prog name
- 	my %index;
--	$index{tv} = 1;
--	
--	# Start index counter at 10001 for radio progs
--	$index{radio} = 10001;
--
--	# Start index counter at 20001 for podcast progs
--	$index{podcast} = 20001;
-+	# Start index counter at 'min' for each prog type
-+	$index{$_} = $index_range{$_}{min} for @all_prog_types;
- 
- 	my @prog_pid;
- 
-@@ -1013,10 +1080,10 @@
- 	for (sort @prog_pid) {
- 		# Extract pid
- 		my $pid = (split /\|/)[1];
--		my $type = $prog{$pid}{type};
--		$index_pid{ $index{$type} } = $pid;
--		$prog{$pid}{index} = $index{$type};
--		$index{$type}++;
-+		my $prog_type = $prog{$pid}{type};
-+		$index_pid{ $index{$prog_type} } = $pid;
-+		$prog{$pid}{index} = $index{$prog_type};
-+		$index{$prog_type}++;
- 	}
- 	return 0;
- }
-@@ -1024,18 +1091,14 @@
- 
- 
- # Uses: $podcast_index_feed_url
--# get_podcast_links ()
--sub get_podcast_links {
-+# get_links_bbcpodcast ()
-+sub get_links_bbcpodcast {
- 
- 	my $xml;
- 	my $res;
- 	logger "INFO: Getting podcast Index Feeds\n";
- 	# Setup User agent
--	my $ua = LWP::UserAgent->new;
--	$ua->timeout([$lwp_request_timeout]);
--	$ua->proxy( ['http'] => $proxy_url );
--	$ua->agent( $user_agent{get_iplayer} );
--	$ua->conn_cache(LWP::ConnCache->new());
-+	my $ua = create_ua('get_iplayer');
- 	
- 	# Method
- 	# $podcast_index_feed_url (gets list of rss feeds for each podcast prog) =>
-@@ -1224,6 +1287,302 @@
- 
- 
- 
-+# Uses:
-+# get_links_itv ()
-+sub get_links_itv {
-+	my %channels = %{$_[0]};
-+	my $xml;
-+	my $res;
-+	my %series_pid;
-+	my %episode_pid;
-+	logger "INFO: Getting itv Index Feeds\n";
-+	# Setup User agent
-+	my $ua = create_ua('desktop');
-+
-+	# Method
-+	# http://www.itv.com/_data/xml/CatchUpData/CatchUp360/CatchUpMenu.xml (gets list of urls for each prog series) =>
-+	#  =>
-+	
-+	# Download index feed
-+	my $itv_index_shows_url = 'http://www.itv.com/ClassicTVshows/'; # $channel/default.html
-+	my $itv_index_feed_url = 'http://www.itv.com/_data/xml/CatchUpData/CatchUp360/CatchUpMenu.xml';
-+
-+	# Sort feeds so that pages are done last - this makes sure that the channels get defined correctly if there are dups
-+	my @channel_list;
-+	push @channel_list, grep !/\//, keys %channels;
-+	push @channel_list, grep  /\//, keys %channels;
-+	# ITV ClassicShows parsing
-+	for my $channel ( @channel_list ) {
-+		# <li class="first-child"><a href="http://www.itv.com/ClassicTVshows/comedy/ABitofaDo/default.html">A Bit of a Do</a><br></li>
-+		# <li><a href="http://www.itv.com/ClassicTVshows/familydrama/achristmascarol/default.html">A Christmas Carol</a><br></li>
-+		# Get page, search for relevent lines which contain series links and loop through each matching line
-+		for my $s_line ( grep /(<li><a\s+href=".+?"><img\s+src=".+?"\s+alt=".+?"><\/a><h4>|<li.*?><a href=".+?">.+?<\/a><br><\/li>)/, ( split /\n/, request_url_retry($ua, $itv_index_shows_url.${channel}.'/default.html', 3, '.', "WARNING: Failed to get itv ${channel} index from site\n") ) ) {
-+			my ($url, $name);
-+			# Extract series url + series description
-+			($url, $name) = ($1, $2) if $s_line =~ m{<li><a\s+href="\s*(.+?)\s*"><img\s+src=".+?"\s+alt="\s*(.+?)\s*"><\/a><h4>};
-+			($url, $name) = ($1, $2) if $s_line =~ m{<li.*?><a href="\s*(.+?)\s*">\s*(.+?)\s*<\/a><br><\/li>};
-+			chomp($url);
-+			chomp($name);
-+			next if ! ($url && $name);
-+			logger "DEBUG: Channel: '$channel' Series: '$name' URL: '$url'\n" if $opt{verbose};
-+
-+			# Get list of episodes for this series
-+			# e.g. <li class="first-child"><a title="Play" href="?vodcrid=crid://itv.com/993&amp;DF=0">Episode one</a><br>The Sun in a Bottle</li>
-+			#      <li><a title="Play" href="?vodcrid=crid://itv.com/994&amp;DF=0">Episode two</a><br>Castle Saburac</li>
-+			#      <li class="first-child"><a class="nsat" title="This programme contains strong language and violence       " href="?vodcrid=crid://itv.com/588&amp;G=10&amp;DF=0">Episode one</a><br>The Dead of Jericho</li>
-+			#
-+			# e.g. <li><a class="playVideo" title="Play" href="?vodcrid=crid://itv.com/1232&amp;DF=0"><img src="img/60x45/Crossroads-Rosemary-shoots-David-efeef7cd-8d41-416c-9e30-26ce1b3d625c.jpg" alt="Crossroads: Rosemary shoots David"><span>Play</span></a><h4>
-+			#      vodcrid=crid://itv.com/971&amp;DF=0"><img src="img/60x45/9d20fd47-5d4b-44f5-9188-856505de0d0f.jpg" alt="Emmerdale  2002 Louise kills Ray"
-+			#
-+			# e.g. <a class="playVideo" title="Play" href="?vodcrid=crid://itv.com/1854&amp;DF=1"><img src="img/157x104/140c456c-d8bd-49d5-90f8-f7cc6d86f132.jpg" alt="Soldier Soldier "><span>Play</span></a><h2>Soldier Soldier</h2>
-+			#
-+			for my $e_line ( grep /vodcrid=crid/, ( split /\n/, request_url_retry($ua, $url, 3, '.', "WARNING: Failed to get ${name} index from site\n") ) ) {
-+				my ($guidance, $pid, $episode, $thumbnail);
-+				logger "DEBUG: Match Line: $e_line\n" if $opt{debug};
-+				# Extract episode data
-+				($guidance, $pid, $episode)  = ($2, $3, $4) if $e_line =~ m{<li.*?><a\s+(class="nsat"\s+)?title="\s*(.+?)\s*"\s+href="\?vodcrid=crid://itv.com/(\d+?)&.+?>\s*(.+?)\s*<};
-+				($pid, $thumbnail, $episode) = ($1, $2, $3) if $e_line =~ m{vodcrid=crid://itv.com/(\d+?)&.+?><img\s+src="(.+?)"\s+alt="\s*(.+?)\s*"};
-+				next if ! ($pid && $episode);
-+				# Remove 'Play'
-+				$guidance =~ s/^Play$//ig;
-+				# Strip non-printables
-+				$guidance =~ s/[\s\x00\xc2\xa0]+$//ig;
-+				#$guidance =~ s|[^\w\s\-\!"£\$\\/%\^&\*\(\)\+=,\.\?':;@~\[\]]+||gi;
-+				#$guidance =~ s/(\s\s)+//g;
-+				logger "DEBUG: PID: '$pid' Episode: '$episode' Guidance: '$guidance'\n" if $opt{debug};
-+
-+				# Skip if this pid is a duplicate
-+				if ( defined $prog{$pid} ) {
-+					logger "WARNING: '$pid, $prog{$pid}{name} - $prog{$pid}{episode}, $prog{$pid}{channel}' already exists (this channel = $channel)\n" if $opt{verbose};
-+					# Merge data (hack)
-+					#$prog{$pid}{episode} .= ','.$episode;
-+					my $oldname = $prog{$pid}{name};
-+					$prog{$pid}{episode} = $episode if (! $prog{$pid}{episode}) || $prog{$pid}{episode} =~ /$oldname/i;
-+					$prog{$pid}{thumbnail} = $thumbnail if ! $prog{$pid}{thumbnail};
-+					$prog{$pid}{guidance} = $guidance if ! $prog{$pid}{guidance};
-+					next;
-+				}
-+
-+				# build data structure
-+				$prog{$pid} = {
-+					'name'		=> $name,
-+					'versions'	=> 'default',
-+					'episode'	=> $episode,
-+					'channel'	=> (split /\|/, $channels{$channel})[1],
-+					'guidance'	=> $guidance,
-+					'categories'	=> (split /\|/, $channels{$channel})[1],
-+					'type'		=> 'itv',
-+				};
-+			}
-+		}
-+	}
-+
-+	my $xmlindex = request_url_retry($ua, $itv_index_feed_url, 3, '.', "WARNING: Failed to get itv index from site\n");
-+	$xmlindex =~ s/[\n\r]//g;
-+
-+	# This gives a list of programme series (sometimes episodes)
-+	#    <ITVCatchUpProgramme>
-+	#      <ProgrammeId>50</ProgrammeId>
-+	#      <ProgrammeTitle>A CHRISTMAS CAROL</ProgrammeTitle>
-+	#      <ProgrammeMediaId>615915</ProgrammeMediaId>
-+	#      <ProgrammeMediaUrl>
-+	#      http://www.itv.com//img/150x113/A-Christmas-Carol-2f16d25a-de1d-4a3a-90cb-d47489eee98e.jpg</ProgrammeMediaUrl>
-+	#      <LastUpdated>2009-01-06T12:24:22.7419643+00:00</LastUpdated>
-+	#      <Url>
-+	#      http://www.itv.com/CatchUp/Video/default.html?ViewType=5&amp;Filter=32910</Url>
-+	#      <EpisodeCount>1</EpisodeCount>
-+	#      <VideoID>32910</VideoID>
-+	#      <DentonID>-1</DentonID>
-+	#      <DentonRating></DentonRating>
-+	#      <AdditionalContentUrl />
-+	#      <AdditionalContentUrlText />
-+	#    </ITVCatchUpProgramme>
-+
-+	for my $feedxml ( split /<ITVCatchUpProgramme>/, $xmlindex ) {
-+		# Extract feed data
-+		my ($episodecount, $viewtype, $videoid, $url);
-+		my @entries;
-+
-+		logger "\n\nDEBUG: XML: $feedxml\n"  if $opt{debug}; 
-+
-+		# <EpisodeCount>1</EpisodeCount>
-+		$episodecount = $1 if $feedxml =~ m{<EpisodeCount>\s*(\d+)\s*<\/EpisodeCount>};
-+
-+		# <Url>http://www.itv.com/CatchUp/Video/default.html?ViewType=5&amp;Filter=32910</Url>
-+		($viewtype, $videoid) = ($1, $2) if $feedxml =~ m{<Url>\s*.+?ViewType=(\d+).+?Filter=(\d+)\s*<\/Url>}i;
-+
-+		## <VideoID>32910</VideoID>
-+		#$videoid = $1 if $feedxml =~ m{<VideoID>\s*(\d+)\s*<\/VideoID>};
-+
-+		# Skip if there is no feed data for channel
-+		next if ($viewtype =~ /^0*$/ || $videoid =~ /^0*$/ );
-+
-+		logger "DEBUG: Got ViewType=$viewtype VideoId=$videoid EpisodeCount=$episodecount\n" if $opt{debug};
-+
-+		my $url = "http://www.itv.com/_app/Dynamic/CatchUpData.ashx?ViewType=${viewtype}&Filter=${videoid}";
-+
-+		# Add response from episode metadata url to list to be parsed if this is an episode link
-+		if ( $viewtype == 5 ) {
-+			next if $episode_pid{$videoid};
-+			$episode_pid{$videoid} = 1;
-+			# Get metadata pages for episode
-+
-+			my ( $name, $guidance, $channel, $episode, $desc, $pid, $available, $duration, $thumbnail );
-+
-+			$pid = $videoid;
-+			$channel = 'ITV Catch-up';
-+
-+			# Skip if this pid is a duplicate
-+			if ( defined $prog{$pid} ) {
-+				logger "WARNING: '$pid, $prog{$pid}{name} - $prog{$pid}{episode}, $prog{$pid}{channel}' already exists (this channel = $channel)\n" if $opt{verbose};
-+				next;
-+			}
-+
-+			$name = $1 if $feedxml =~ m{<ProgrammeTitle>\s*(.+?)\s*<\/ProgrammeTitle>};
-+			$guidance = $1 if $feedxml =~ m{<DentonRating>\s*(.+?)\s*<\/DentonRating>};
-+			$thumbnail = $1 if $feedxml =~ m{<ProgrammeMediaUrl>\s*(.+?)\s*<\/ProgrammeMediaUrl>};
-+			$episode = $pid;
-+			# Strip non-printable chars
-+			$guidance =~ s/[\s\x00\xc2\xa0]+$//ig;
-+
-+			# build data structure
-+			$prog{$pid} = {
-+				'name'		=> $name,
-+				'versions'	=> 'default',
-+				'episode'	=> $episode,
-+				'guidance'	=> $guidance,
-+				'desc'		=> $desc,
-+				'available'	=> $available,
-+				'duration'	=> $duration,
-+				'thumbnail'	=> $thumbnail,
-+				'channel'	=> $channel,
-+				'categories'	=> 'TV',
-+				'type'		=> 'itv',
-+			};
-+
-+
-+
-+
-+
-+		# Get next episode list and parse
-+		#     <div class="listItem highlight contain">
-+		#      <div class="floatLeft"><a href="http://www.itv.com/CatchUp/Video/default.html?ViewType=5&amp;Filter=33383"><img src="http://www.itv.com//img/157x88/P7-67e0b86f-b335-4f6b-8db
-+		#      <div class="content">
-+		#        <h3><a href="http://www.itv.com/CatchUp/Video/default.html?ViewType=5&amp;Filter=33383">Emmerdale</a></h3>
-+		#        <p class="date">Mon 05 Jan 2009</p>
-+		#        <p class="progDesc">Donna is stunned to learn Marlon has pointed the finger at Ross. Aaron defaces Tom King's grave.</p>
-+		#        <ul class="progDetails">
-+		#          <li>
-+		#                          Duration: 30 min
-+		#          </li>
-+		#          <li class="days">
-+		#            Expires in
-+		#                        <strong>29</strong>
-+		#                                        days
-+		#                                </li>
-+		#        </ul>
-+		#      </div>
-+		#    </div>
-+		#    <div class="listItem contain">
-+		#      <div class="floatLeft"><a href="http://www.itv.com/CatchUp/Video/default.html?ViewType=5&amp;Filter=33245"><img src="http://www.itv.com//img/157x88/Marlon-Dingle-742c50b3-3b
-+		#      <div class="content">
-+		#        <h3><a href="http://www.itv.com/CatchUp/Video/default.html?ViewType=5&amp;Filter=33245">Emmerdale</a></h3>
-+		#        <p class="date">Fri 02 Jan 2009</p>
-+		#        <p class="progDesc">Marlon gets his revenge on Ross. The King brothers struggle to restart their business without Matthew. Scarlett is fed up with Victoria getting all Daz
-+		#        <ul class="progDetails">
-+		#          <li>
-+		#                          Duration: 30 min
-+		#          </li>
-+		#          <li class="days">
-+		#            Expires in
-+		#                        <strong>26</strong>
-+		#                                        days
-+		#                                </li>
-+		#        </ul>
-+		#      </div>
-+		#    </div>
-+		# 
-+		} elsif ( $viewtype == 1 ) {
-+			# Make sure we don't duplicate parsing a series
-+			next if $series_pid{$videoid};
-+			$series_pid{$videoid} = 1;
-+
-+			# Get metadata pages for each series
-+			logger "DEBUG: Getting series metadata $url\n" if $opt{debug};
-+			$xml = request_url_retry($ua, $url, 2, '.', "WARNING: Failed to get itv series data for ${videoid} from itv site\n") if $opt{verbose};
-+			$xml = request_url_retry($ua, $url, 2, '.', '') if ! $opt{verbose};
-+
-+			# skip if no data
-+			next if ! $xml;
-+
-+			decode_entities($xml);
-+			# Flatten entry
-+			$xml =~ s/[\n\r]//g;
-+
-+			# Extract Filter (pids) from this list
-+			# e.g. <h3><a href="http://www.itv.com/CatchUp/Video/default.html?ViewType=5&amp;Filter=32042">Emmerdale</a></h3>
-+			my @videoids = (split /<h3><a href=.+?Filter=/, $xml);
-+
-+			# Get episode data for each videoid
-+			$viewtype = 5;
-+
-+			my @episode_data = split/<h3><a href=.+?Filter=/, $xml;
-+			# Ignore first entry
-+			shift @episode_data;
-+			logger "INFO: Got ".($#episode_data+1)." programmes\n" if $opt{verbose};
-+
-+			for my $xml (@episode_data) {
-+				$videoid = $1 if $xml =~ m{^(\d+?)".+$}i;
-+
-+				# Make sure we don't duplicate parsing an episode
-+				next if $episode_pid{$videoid};
-+				$episode_pid{$videoid} = 1;
-+
-+				my ( $name, $guidance, $channel, $episode, $desc, $pid, $available, $duration, $thumbnail );
-+	
-+				$pid = $videoid;
-+				$channel = 'ITV Catch-up';
-+	
-+				# Skip if this pid is a duplicate
-+				if ( defined $prog{$pid} ) {
-+					logger "WARNING: '$pid, $prog{$pid}{name} - $prog{$pid}{episode}, $prog{$pid}{channel}' already exists (this channel = $channel)\n" if $opt{verbose};
-+					next;
-+				}
-+				$name = $1 if $feedxml =~ m{<ProgrammeTitle>\s*(.+?)\s*<\/ProgrammeTitle>};
-+				$available = $1 if $xml =~ m{<p\s+class="date">(.+?)<\/p>}i;
-+				$episode = $available;
-+				$duration = $1 if $xml =~ m{<li>Duration:\s*(.+?)\s*<\/li>}i;
-+				$desc = $1 if $xml =~ m{<p\s+class="progDesc">(.+?)\s*<\/p>};
-+				$guidance = $1 if $feedxml =~ m{<DentonRating>\s*(.+?)\s*<\/DentonRating>};
-+				$thumbnail = $1 if $feedxml =~ m{<ProgrammeMediaUrl>\s*(.+?)\s*<\/ProgrammeMediaUrl>};
-+				$guidance =~ s/[\s\x00\xc2\xa0]+$//ig;
-+
-+				logger "DEBUG: name='$name' episode='$episode' pid=$pid available='$available' \n" if $opt{debug};	
-+	
-+				# build data structure
-+				$prog{$pid} = {
-+					'name'		=> $name,
-+					'versions'	=> 'default',
-+					'episode'	=> $episode,
-+					'guidance'	=> $guidance,
-+					'desc'		=> $desc,
-+					'available'	=> $available,
-+					'duration'	=> $duration,
-+					'thumbnail'	=> $thumbnail,
-+					'channel'	=> $channel,
-+					'categories'	=> 'TV',
-+					'type'		=> 'itv',
-+				};
-+			}
-+		}	
-+
-+	}
-+	logger "\n";
-+	return 0;
-+}
-+
-+
-+
- # Feed info:
- #	# Also see http://derivadow.com/2008/07/18/interesting-bbc-data-to-hack-with/
- #	# All podcasts menu (iphone)
-@@ -1261,14 +1620,14 @@
- #	http://www.bbc.co.uk/cbbc/programmes/genres/childrens/player
- #	http://www.bbc.co.uk/programmes/genres/childrens/schedules/upcoming.ics
- #
--# get_links( <radio|tv|podcast> )
-+# get_links( <prog_type> )
- sub get_links {
- 	my @cache;
- 	my $now = time();
--	my $type = shift;
-+	my $prog_type = shift;
- 
- 	# Open cache file (need to verify we can even read this)
--	if ( open(CACHE, "< $cachefile{$type}") ) {
-+	if ( open(CACHE, "< $cachefile{$prog_type}") ) {
- 		# Get file contents less any comments
- 		@cache = grep !/^[\#\s]/, <CACHE>;
- 		close (CACHE);
-@@ -1281,47 +1640,40 @@
- 		for (@cache) {
- 			# Populate %prog from cache
- 			chomp();
--			my ($index, $type, $name, $pid, $available, $episode, $versions, $duration, $desc, $channel, $categories, $thumbnail, $timeadded) = split /\|/;
--			# Create data structure with prog data
--			$prog_old{$pid} = {
--				'index'		=> $index,
--				'name'		=> $name,
--				'episode'	=> $episode,
--				'desc'		=> $desc,
--				'available'	=> $available,
--				'duration'	=> $duration,
--				'versions'	=> $versions,
--				'channel'	=> $channel,
--				'categories'	=> $categories,
--				'thumbnail'	=> $thumbnail,
--				'type'		=> $type,
--				'timeadded'	=> $timeadded,
--			};
--			$index_pid_old{$index}	= $pid;
-+			# Get cache line
-+			my @record = split /\|/;
-+			my %record_entries;
-+			# Update fields in %prog hash for $pid
-+			$record_entries{$_} = shift @record for @cache_format;
-+			$prog_old{ $record_entries{pid} } = \%record_entries;
-+			$index_pid_old{ $record_entries{index} }  = $record_entries{pid};
- 		}
- 	}
- 
- 	# if a cache file doesn't exist/corrupted, flush option is specified or original file is older than $cache_sec then download new data
--	if ( (! @cache) || (! -f $cachefile{$type}) || $opt{flush} || ($now >= ( stat($cachefile{$type})->mtime + $cache_secs )) ) {
-+	if ( (! @cache) || (! -f $cachefile{$prog_type}) || $opt{flush} || ($now >= ( stat($cachefile{$prog_type})->mtime + $cache_secs )) ) {
- 
--		# Podcast only
--		get_podcast_links() if $type eq 'podcast';
-+		# BBC Podcast only
-+		get_links_bbcpodcast() if $prog_type eq 'podcast';
- 
--		# Radio and TV
--		get_links_atom( $type, \%{$channels{$type}} ) if $type =~ /(tv|radio)/;
-+		# ITV only
-+		get_links_itv( \%{$channels{$prog_type}} ) if $prog_type eq 'itv';
-+
-+		# BBC Radio and TV
-+		get_links_bbciplayer( $prog_type, \%{$channels{$prog_type}} ) if $prog_type =~ /^(tv|radio)$/;
- 
- 		# Sort indexes
- 		sort_indexes();
- 		
- 		# Open cache file for writing
--		unlink $cachefile{$type};
-+		unlink $cachefile{$prog_type};
- 		my $now = time();
--		if ( open(CACHE, "> $cachefile{$type}") ) {
--			print CACHE "#Index|Type|Name|Pid|Available|Episode|Versions|Duration|Desc|Channel|Categories|Thumbnail|TimeAdded\n";
-+		if ( open(CACHE, "> $cachefile{$prog_type}") ) {
-+			print CACHE "#".(join '|', @cache_format)."\n";
- 			for (sort {$a <=> $b} keys %index_pid) {
- 				my $pid = $index_pid{$_};
- 				# Only write entries for correct prog type
--				if ($prog{$pid}{type} eq $type) {
-+				if ($prog{$pid}{type} eq $prog_type) {
- 					# Merge old and new data to retain timestamps
- 					# if the entry was in old cache then retain timestamp from old entry
- 					if ( $prog_old{$pid}{timeadded} ) {
-@@ -1332,12 +1684,17 @@
- 						list_prog_entry( $pid, 'Added: ' );
- 					}
- 					# write to cache file
--					print CACHE "$_|$prog{$pid}{type}|$prog{$pid}{name}|$pid|$prog{$pid}{available}|$prog{$pid}{episode}|$prog{$pid}{versions}|$prog{$pid}{duration}|$prog{$pid}{desc}|$prog{$pid}{channel}|$prog{$pid}{categories}|$prog{$pid}{thumbnail}|$prog{$pid}{timeadded}\n";
-+					$prog{$pid}{pid} = $pid;
-+					# Write each field into cache line
-+					for my $field (@cache_format) {
-+						print CACHE $prog{$pid}{$field}.'|';
-+					}
-+					print CACHE "\n";
- 				}
- 			}
- 			close (CACHE);
- 		} else {
--			logger "WARNING: Couldn't open cache file '$cachefile{$type}' for writing\n";
-+			logger "WARNING: Couldn't open cache file '$cachefile{$prog_type}' for writing\n";
- 		}
- 
- 
-@@ -1354,172 +1711,434 @@
- # Usage: download_programme (<pid>)
- sub download_programme {
- 	my $pid = shift;
-+	my %streamdata;
-+	my %version_pids;
-+	my $return;
- 
- 	# Setup user-agent
--	# Switch off automatic redirects
--	my $ua = LWP::UserAgent->new( requests_redirectable => [] );
--	# Setup user agent
--	$ua->timeout([$lwp_request_timeout]);
--	$ua->proxy( ['http'] => $proxy_url );
--	$ua->cookie_jar( HTTP::Cookies->new( file => $cookiejar, autosave => 1, ignore_discard => 1 ) );
-+	my $ua = create_ua('desktop');
- 
--	my $dir = $download_dir{ $prog{$pid}{type} };
--	$prog{$pid}{ext} = 'mov';
-+	# download depending on the prog type
-+	logger "INFO: Attempting to Download $prog{$pid}{type}: $prog{$pid}{name} - $prog{$pid}{episode}\n";
- 
--	# If were a podcast...
-+	# ITV TV
-+	if ( $prog{$pid}{type} eq 'itv' ) {
-+		# stream data
-+		# Display media stream data if required
-+		if ( $opt{streaminfo} ) {
-+			display_stream_info( $pid, undef, 'all' );
-+			$opt{quiet} = 1;
-+			return 'skip';
-+		}
-+		return download_programme_itv( $ua, $pid );
-+	}
-+
-+	# BBC Podcasts
- 	if ( $prog{$pid}{type} eq 'podcast' ) {
--		# Determine the correct filename and extension for this download
--		my $filename_orig = $pid;
--		$prog{$pid}{ext} = $pid;
--		$filename_orig =~ s|^.+/(.+?)\.\w+$|$1|g;
--		$prog{$pid}{ext} =~ s|^.*\.(\w+)$|$1|g;
--		$prog{$pid}{fileprefix} = generate_download_filename_prefix($pid, $dir, $opt{fileprefix} || "<longname> - <episode> $filename_orig");
--		$prog{$pid}{dir} = $dir;
--		logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                  \n";
--		my $file_done = "${dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
--		my $file = "${dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
--		$prog{$pid}{filename} = $file_done;
--		if ( -f $file_done ) {
--			logger "WARNING: File $file_done already exists\n\n";
--			return 1;
-+		# stream data not available
-+		return 'skip' if $opt{streaminfo};
-+		return download_programme_podcast( $ua, $pid );
-+	}
-+
-+	# For BBC Radio/TV we might have a pid with no prog_type - determine here first
-+	( $prog{$pid}{type}, $prog{$pid}{longname}, %version_pids ) = get_version_pids( $ua, $pid );
-+
-+	# BBC TV
-+	if ( $prog{$pid}{type} eq 'tv' ) {
-+
-+		# Deal with BBC TV fallback modes
-+		# Valid modes are iphone,rtmp,flashhigh,flashnormal,flashwii,n95_wifi
-+		$opt{vmode} = 'flashhigh,flashnormal' if $opt{vmode} eq 'rtmp' || $opt{vmode} eq 'flash';
-+		# Defaults
-+		if ( $opt{vmode} eq 'auto' || ! $opt{vmode} ) {
-+			if ( ! exists_in_path($rtmpdump) ) {
-+				$opt{vmode} = 'iphone';	
-+			} else {
-+				$opt{vmode} = 'iphone,flashhigh,flashnormal';
-+			}
- 		}
-+		# Expand the modes into a loop
-+		logger "INFO: $opt{vmode} modes will be tried\n";
-+		for my $mode ( split /,/, $opt{vmode} ) {
-+			chomp( $mode );
-+			logger "INFO: Attempting to download using $mode mode\n";
-+			$return = download_programme_tv( $ua, $pid, $mode, \%version_pids );
-+			logger "DEBUG: Download using $mode mode return code: '$return'\n" if $opt{debug};
- 
--		# Skip from here if we are only testing downloads
--		return 1 if $opt{test};
-+			# Give up trying alternative download methods
-+			return 2 if $return eq 'abort';
- 
--		# Create symlink filename if required
--		my $file_symlink;
--		if ( $opt{symlink} ) {
--			# Substitute the fields for the pid
--			$file_symlink = substitute_fields( $pid, $opt{symlink} );
-+			# Return to retry loop if successful or retry requested 
-+			return 'retry' if $return eq 'retry';
-+
-+			# Return to retry loop and do nothing 
-+			return 'skip' if $return eq 'skip';
-+
-+			# Return 0 if successful 
-+			return 0 if ! $return;
-+
-+			# Return failed if there is no 'next'
-+			return 1 if $return ne 'next';
- 		}
--		
--		return download_podcast_stream( $ua, $pid, $file, $file_done, $file_symlink );
- 	}
- 
--	logger "INFO: Attempting to Download: $prog{$pid}{name} - $prog{$pid}{episode}\n";
-+	# BBC Radio
-+	if ( $prog{$pid}{type} eq 'radio' ) {
-+		# This will always be the pid version for radio
-+		$prog{$pid}{version} = 'default';
-+		# Display media stream data if required
-+		if ( $opt{streaminfo} ) {
-+			display_stream_info( $pid, $version_pids{default}, 'all' );
-+			$opt{quiet} = 1;
-+			return 'skip';
-+		}
-+
-+		# Deal with radio fallback modes
-+		# Valid modes are mp3|iphone,flash|rtmp,real|ra
-+		# Defaults
-+		$opt{amode} = 'iphone,flash,real' if $opt{amode} eq 'auto' || ! $opt{amode};
-+
-+		# Expand the modes into a loop
-+		logger "INFO: $opt{amode} modes will be tried\n";
-+		for my $mode ( split /,/, $opt{amode} ) {
-+			chomp( $mode );
-+			logger "INFO: Attempting to download using $mode mode\n";
-+			# RealAudio
-+			if ( $mode =~ /^(real|ra)/ ) {
-+				$return = download_programme_radio_realaudio( $ua, $pid, \%version_pids );
-+
-+			# FlashAudio
-+			} elsif ( $mode =~ /^(flash|rtmp)/ ) {
-+				$return = download_programme_radio_flashaudio( $ua, $pid, $mode, \%version_pids );
-+
-+			# iPhone
-+			} elsif ( $mode =~ /^(iphone|mp3)/ ) {
-+				$return = download_programme_radio_iphone( $ua, $pid, \%version_pids );
-+			}
-+			logger "DEBUG: Download using $mode mode return code: '$return'\n" if $opt{debug};
- 
--	# Get version => pid hash
--	my ( $type, $title, %version_pids ) = get_version_pids( $ua, $pid );
-+			# Give up trying alternative download methods
-+			return 2 if $return eq 'abort';
- 
--	# Extract Long Name, e.g.: iplayer.episode.setTitle("DIY SOS: Series 16: Swansea");
--	$prog{$pid}{longname} = $title;
-+			# Not going to allow retries here until rtmpdump/flashaudio exits correctly - so just just skip to next mode for now
-+			$return = 'next' if $return eq 'retry';
-+			## Return to retry loop if successful or retry requested 
-+			#return 'retry' if $return eq 'retry';
- 
--	# Strip off the episode name
--	$prog{$pid}{longname} =~ s/^(.+):.*?$/$1/g;
-+			# Return to retry loop and do nothing 
-+			return 'skip' if $return eq 'skip';
- 
--	# Detect if this content is for radio
--	my $usemp3 = 0;
--	if ( $type eq 'radio' ) {
-+			# Return 0 if successful 
-+			return 0 if ! $return;
- 
--		# Display media stream data if required
--		if ( $opt{streaminfo} ) {
--			get_media_stream_data( $pid, $version_pids{'default'}, 'all' );
--			return 1;
-+			# Return failed if there is no 'next'
-+			return 1 if $return ne 'next';
- 		}
-+	}
- 
--		# Type is definitely radio
--		$prog{$pid}{type} = 'radio';
--		$dir = $download_dir{ $prog{$pid}{type} };
--
--		# Check for mp3 stream  - unless realaudio option is specified
--		if ( ! $opt{realaudio} ) {
--			# Check for iphone mp3 radio stream
--			if ( get_media_stream_data( $pid, $version_pids{default}, 'iphone' ) ) {
--				$usemp3 = 1;
--				$prog{$pid}{ext} = 'mp3';
--				logger "INFO: MP3 stream media is available\n" if $opt{verbose};
--
--			# if mp3audio option is specified do not fallback to realaudio
--			} elsif ( $opt{mp3audio} ) {
--				logger "ERROR: No MP3 stream media is available - not falling back to RealAudio\n";
--				return 1;
-+	# If we get here then we have failed
-+	return 1;
-+}
- 
--			# if not then force realaudio option as fallback
--			} else {
--				$opt{realaudio} = 1;
--				logger "INFO: No MP3 stream media is available - falling back to RealAudio\n" if $opt{verbose};
--			}
--		}
- 
--		# Use realplayer stream
--		if ( $opt{realaudio} ) {
- 
--			# Check dependancies for radio programme transcoding / streaming
--			# Check if we need 'tee'
--			if ( (! exists_in_path($tee)) && $opt{stdout} && (! $opt{nowrite}) ) {
--				logger "\nERROR: $tee does not exist in path, skipping\n";
--				return 20;
--			}
--			# Check if we have mplayer and lame
--			if ( (! $opt{wav}) && (! $opt{raw}) && (! exists_in_path($lame)) ) {
--				logger "\nWARNING: Required $lame does not exist, falling back to wav mode\n";
--				$opt{wav} = 1;
--			}		
--			if (! exists_in_path($mplayer)) {
--				logger "\nERROR: Required $mplayer does not exist, skipping\n";
--				return 20;
--			}
-+sub download_programme_itv {
-+	my ( $ua, $pid ) = ( @_ );
-+	my %streamdata;
-+
-+	# Check for mplayer (required)
-+	if (! exists_in_path($mplayer)) {
-+		logger "\nERROR: Required $mplayer does not exist, skipping\n";
-+		return 21;
-+	}
- 
--			my $url_2 = get_media_stream_data( $pid, $version_pids{default}, 'realaudio' );
-+	$prog{$pid}{dir} = $download_dir{ $prog{$pid}{type} };
-+	$prog{$pid}{pid} = $pid;
-+	$prog{$pid}{ext} = 'mp4';
-+	$prog{$pid}{ext} = 'asf' if $opt{raw};
- 	
--			logger "INFO: Version = $prog{$pid}{version}\n" if $opt{verbose};
--			logger "INFO: Stage 2 URL = $url_2\n" if $opt{verbose};
-+	my @url_list = %{get_media_stream_data( $pid, undef, 'itv')}->{streamurl};
- 
--			# Report error if no versions are available
--			if ( ! $url_2 ) {
--				logger "ERROR: No Stage 2 URL\n" if $opt{verbose};
--				return 15;
--			}
-+	# Get and set more meta data - Set the %prog values from metadata if they aren't already set
-+	my %metadata = get_pid_metadata($ua, $pid);
-+	for ( qw/ name episode available duration thumbnail desc guidance / ) {
-+		$prog{$pid}{$_} = $metadata{$_} if ! $prog{$pid}{$_};
-+	}
- 
--			# Determine the correct filenames for this download
--			$prog{$pid}{ext} = 'mp3';
--			$prog{$pid}{ext} = 'ra'  if $opt{raw};
--			$prog{$pid}{ext} = 'wav' if $opt{wav};
--			$prog{$pid}{fileprefix} = generate_download_filename_prefix( $pid, ${dir}, $opt{fileprefix} || "<longname> - <episode> <pid>" );
--			logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                 \n";
--			$prog{$pid}{dir} = $dir;
--			my $file_done = "${dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
--			my $file = "${dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
--			$prog{$pid}{filename} = $file_done;
--			if ( -f $file_done ) {
--				logger "WARNING: File $file_done already exists\n\n";
--				return 1;
--			}
-+	$prog{$pid}{fileprefix} = generate_download_filename_prefix( $pid, $prog{$pid}{dir}, $opt{fileprefix} || "<name> <pid>" );
-+	logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                 \n";
-+	# Create a subdir if there are multiple parts
-+	if ($#url_list > 0) {
-+		$prog{$pid}{dir} .= "/$prog{$pid}{fileprefix}";
-+		logger "INFO: Creating subdirectory $prog{$pid}{dir} for programme\n" if $opt{verbose};
-+		mkpath $prog{$pid}{dir} if ! -d $prog{$pid}{dir};
-+	}
-+	my $file_done = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
-+	my $file = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
-+	$prog{$pid}{filename} = $file_done;
- 
--			# Skip from here if we are only testing downloads
--			return 1 if $opt{test};
-+	# Display metadata
-+	display_metadata( $prog{$pid}, qw/ pid index name duration available expiry desc / );
- 
--			# Create symlink filename if required
--			my $file_symlink;
--			if ( $opt{symlink} ) {
--				# Substitute the fields for the pid
--				$file_symlink = substitute_fields( $pid, $opt{symlink} );
--			}
-+	# Skip from here if we are only testing downloads
-+	return 1 if $opt{test};
- 
--			# Do the audio download
--			return download_rtsp_stream( $ua, $url_2, $file, $file_done, $file_symlink, $pid );
--		}
-+	return download_stream_mms_video( $ua, (join '|', @url_list), $file, $file_done, $pid );
-+}	
-+
-+
-+
-+sub download_programme_podcast {
-+	my ( $ua, $pid ) = ( @_ );
-+	my %streamdata;
-+
-+	$prog{$pid}{dir} = $download_dir{ $prog{$pid}{type} };
-+
-+	# Determine the correct filename and extension for this download
-+	my $filename_orig = $pid;
-+	$prog{$pid}{ext} = $pid;
-+	$filename_orig =~ s|^.+/(.+?)\.\w+$|$1|g;
-+	$prog{$pid}{ext} =~ s|^.*\.(\w+)$|$1|g;
-+	$prog{$pid}{fileprefix} = generate_download_filename_prefix($pid, $prog{$pid}{dir}, $opt{fileprefix} || "<longname> - <episode> $filename_orig");
-+	logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                  \n";
-+	my $file_done = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
-+	my $file = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
-+	$prog{$pid}{filename} = $file_done;
-+	if ( -f $file_done && stat($file_done)->size > $min_download_size ) {
-+		logger "WARNING: File $file_done already exists\n\n";
-+		return 1;
-+	}
-+
-+	# Skip from here if we are only testing downloads
-+	return 1 if $opt{test};
-+
-+	# Create symlink filename if required
-+	my $file_symlink;
-+	if ( $opt{symlink} ) {
-+		# Substitute the fields for the pid
-+		$file_symlink = substitute_fields( $pid, $opt{symlink} );
-+	}
-+
-+	return download_stream_podcast( $ua, $pid, $file, $file_done, $file_symlink );
-+}
-+
-+
-+
-+sub download_programme_radio_realaudio {
-+	my $ua = shift; 
-+	my $pid = shift;
-+	my %version_pids = %{@_[0]};
-+	my %streamdata;
-+
-+	# Check dependancies for radio programme transcoding / streaming
-+	# Check if we need 'tee'
-+	if ( (! exists_in_path($tee)) && $opt{stdout} && (! $opt{nowrite}) ) {
-+		logger "\nERROR: $tee does not exist in path, skipping\n";
-+		return 'abort';
-+	}
-+	if (! exists_in_path($mplayer)) {
-+		logger "\nWARNING: Required $mplayer does not exist\n";
-+		return 'next';
-+	}
-+	# Check if we have mplayer and lame
-+	if ( (! $opt{wav}) && (! $opt{raw}) && (! exists_in_path($lame)) ) {
-+		logger "\nWARNING: Required $lame does not exist, will save file in wav format\n";
-+		$opt{wav} = 1;
-+	}
-+
-+	$prog{$pid}{dir} = $download_dir{ $prog{$pid}{type} };
-+	$prog{$pid}{ext} = 'mp3';
-+	$prog{$pid}{ext} = 'ra'  if $opt{raw};
-+	$prog{$pid}{ext} = 'wav' if $opt{wav};
- 
-+	my $url_2 = %{get_media_stream_data( $pid, $version_pids{default}, 'realaudio')}->{streamurl};
-+		
-+	# Report error if no versions are available
-+	if ( ! $url_2 ) {
-+		logger "WARNING: RealAudio version not available\n";
-+		return 'next';
- 	} else {
--		# Type is definitely tv
--		$prog{$pid}{type} = 'tv';
--		$dir = $download_dir{ $prog{$pid}{type} };
-+		logger "INFO: Stage 2 URL = $url_2\n" if $opt{verbose};
-+	}
-+
-+	# Determine the correct filenames for this download
-+	$prog{$pid}{fileprefix} = generate_download_filename_prefix( $pid, $prog{$pid}{dir}, $opt{fileprefix} || "<longname> - <episode> <pid>" );
-+	logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                 \n";
-+	my $file_done = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
-+	my $file = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
-+	$prog{$pid}{filename} = $file_done;
-+	if ( -f $file_done ) {
-+		logger "WARNING: File $file_done already exists\n\n";
-+		return 'abort';
- 	}
- 
-+	# Skip from here if we are only testing downloads
-+	return 'abort' if $opt{test};
- 
--	# iPhone mp3/h.264 stream downloading...
-+	# Create symlink filename if required
-+	my $file_symlink;
-+	if ( $opt{symlink} ) {
-+		# Substitute the fields for the pid
-+		$file_symlink = substitute_fields( $pid, $opt{symlink} );
-+	}
- 
--	# Check if we have vlc - if not use iPhone mode
--	if ( $opt{n95} && (! exists_in_path($vlc)) ) {
--		logger "\nWARNING: Required $vlc does not exist, falling back to iPhone mode\n";
--		$opt{n95} = 0;
--	}		
-+	# Do the audio download
-+	return download_stream_rtsp( $ua, $url_2, $file, $file_done, $file_symlink, $pid );
-+}
- 
- 
-+	
-+sub download_programme_radio_iphone {
-+	my $ua = shift; 
-+	my $pid = shift;
-+	my %version_pids = %{@_[0]};
-+	my %streamdata;
-+	my $url_2;
-+
-+	$prog{$pid}{dir} = $download_dir{ $prog{$pid}{type} };
-+	$prog{$pid}{ext} = 'mp3';
-+
-+	my $url_2 = %{get_media_stream_data( $pid, $version_pids{ $prog{$pid}{version} }, 'iphone')}->{streamurl};
-+
-+	# Report error if no versions are available
-+	if ( ! $url_2 ) {
-+		logger "WARNING: iPhone stream media not available\n";
-+		return 'next';
-+	} else {
-+		logger "INFO: Stage 2 URL = $url_2\n" if $opt{verbose};
-+	}
-+
-+	# Determine the correct filenames for this download
-+	$prog{$pid}{fileprefix} = generate_download_filename_prefix( $pid, $prog{$pid}{dir}, $opt{fileprefix} || "<longname> - <episode> <pid> <version>" );
-+	logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                 \n";
-+	my $file_done = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
-+	my $file = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
-+	$prog{$pid}{filename} = $file_done;
-+	if ( -f $file_done ) {
-+		logger "WARNING: File $file_done already exists\n\n";
-+		return 'abort';
-+	}
-+
-+	# Skip from here if we are only testing downloads
-+	return 'abort' if $opt{test};
-+
-+	# Create symlink filename if required
-+	my $file_symlink;
-+	if ( $opt{symlink} ) {
-+		# Substitute the fields for the pid
-+		$file_symlink = substitute_fields( $pid, $opt{symlink} );
-+	}
-+
-+	my $return;
-+	# Disable proxy here if required
-+	$ua->proxy( ['http'] => undef ) if $opt{partialproxy};
-+	$return = download_stream_iphone( $ua, $url_2, $pid, $file, $file_done, $file_symlink, 0 );
-+	# Re-enable proxy here if required
-+	$ua->proxy( ['http'] => $proxy_url ) if $opt{partialproxy};
-+
-+	return $return;
-+}
-+
-+
-+
-+sub download_programme_radio_flashaudio {
-+	my $ua = shift; 
-+	my $pid = shift;
-+	my $mode = shift;
-+	my %version_pids = %{@_[0]};
-+	my %streamdata;
-+	my $url_2;
-+
-+	# Force raw mode if ffmpeg is not installed
-+	if ( ! exists_in_path($ffmpeg) ) {
-+		logger "\nWARNING: $ffmpeg does not exist - not converting flv file\n";
-+		$opt{raw} = 1;
-+	}
-+	# Disable rtmp modes if rtmpdump does not exist
-+	if ( ! exists_in_path($rtmpdump) ) {
-+		logger "\nERROR: Required program $rtmpdump does not exist (see http://linuxcentre.net/getiplayer/installation and http://linuxcentre.net/getiplayer/download)\n";
-+		return 'next';
-+	}
-+
-+	$prog{$pid}{dir} = $download_dir{ $prog{$pid}{type} };
-+	$prog{$pid}{ext} = 'mp3';
-+	$prog{$pid}{ext} = 'flv' if $opt{raw};
-+
-+	logger "INFO: Trying to get media stream metadata for flashaudio RTMP mode\n" if $opt{verbose};
-+	%streamdata = %{ get_media_stream_data( $pid, $version_pids{ $prog{$pid}{version} }, 'flashaudio') };
-+	$url_2 = $streamdata{streamurl};
-+	if ( ! $url_2 ) {
-+		logger "WARNING: No flashaudio version available\n";
-+		return 'next';
-+	}
-+
-+	# Determine the correct filenames for this download
-+	$prog{$pid}{fileprefix} = generate_download_filename_prefix( $pid, $prog{$pid}{dir}, $opt{fileprefix} || "<longname> - <episode> <pid> <version>" );
-+	logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                 \n";
-+	my $file_done = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
-+	my $file = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
-+	$prog{$pid}{filename} = $file_done;
-+	if ( -f $file_done ) {
-+		logger "WARNING: File $file_done already exists\n\n";
-+		return 'abort';
-+	}
-+
-+	# Skip from here if we are only testing downloads
-+	return 'abort' if $opt{test};
-+
-+	# Create symlink filename if required
-+	my $file_symlink;
-+	if ( $opt{symlink} ) {
-+		# Substitute the fields for the pid
-+		$file_symlink = substitute_fields( $pid, $opt{symlink} );
-+	}
-+
-+	# Do the RTMP flashaudio download
-+	return download_stream_rtmp( $ua, $streamdata{streamurl}, $pid, $mode, $streamdata{application}, $streamdata{tcurl}, $streamdata{authstring}, $streamdata{swfurl}, $file, $file_done, $file_symlink );
-+}
-+
-+
-+
-+# Usage: download_programme_tv (<pid>)
-+sub download_programme_tv {
-+	my $ua = shift; 
-+	my $pid = shift;
-+	my $mode = shift;
-+	my %version_pids = %{@_[0]};
-+	my %streamdata;
- 	my $url_2;
- 	my $got_url;
- 
-+	# Check if we have vlc - if not use iPhone mode
-+	if ( $opt{vmode} eq 'n95' && (! exists_in_path($vlc)) ) {
-+		logger "\nWARNING: Required $vlc does not exist\n";
-+		return 'next';
-+	}		
-+	# if rtmpdump does not exist
-+	if ( $mode =~ /^(rtmp|flash)/ && ! exists_in_path($rtmpdump)) {
-+		logger "WARNING: Required program $rtmpdump does not exist (see http://linuxcentre.net/getiplayer/installation and http://linuxcentre.net/getiplayer/download)\n";
-+		return 'next';
-+	}
-+	# Force raw mode if ffmpeg is not installed
-+	if ( $mode =~ /^(flash|rtmp)/ && ! exists_in_path($ffmpeg)) {
-+		logger "\nWARNING: $ffmpeg does not exist - not converting flv file\n";
-+		$opt{raw} = 1;
-+	}
-+
-+	$prog{$pid}{dir} = $download_dir{ $prog{$pid}{type} };
-+	$prog{$pid}{ext} = 'mov';
-+	# Lookup table to determine which ext to use for different download methods
-+	my %stream_ext = (
-+		iphone		=> 'mov',
-+		flashhigh 	=> 'mp4',
-+		flashnormal	=> 'avi',
-+		flashwii	=> 'avi',
-+		n95_wifi	=> '3gp',
-+		n95_3g		=> '3gp',
-+	);
-+	$prog{$pid}{ext} = $stream_ext{$mode} if not $opt{raw};
-+	$prog{$pid}{ext} = 'flv' if $mode =~ /^(flash|rtmp)/ && $opt{raw};
-+
- 	# Do this for each version tried in this order (if they appeared in the content)
- 	for my $version ( @version_search_list ) {
- 
-@@ -1528,52 +2147,41 @@
- 			logger "INFO: Checking existence of $version version\n";
- 			$prog{$pid}{version} = $version;
- 			logger "INFO: Version = $prog{$pid}{version}\n" if $opt{verbose};
--			if( ! $opt{rtmp} ) {
--				$url_2 = get_iphone_stream_download_url( $ua, $version_pids{$version} );
--			} else {
--				$url_2 = get_media_stream_data( $pid, $version_pids{ $prog{$pid}{version} }, 'flashhigh' );
--			}
--			$got_url = 1;
-+			# Try to get stream data
-+			%streamdata = %{ get_media_stream_data( $pid, $version_pids{ $prog{$pid}{version} }, $mode) };
-+			$url_2 = $streamdata{streamurl};
- 		}
- 		# Break out of loop if we have an actual URL
--		last if $got_url && $url_2;
--	}
--
--	# Report error if no versions are available
--	if ( ! $got_url ) {
--		logger "ERROR: No versions exist for download\n";
--		return 14;
-+		last if $url_2;
- 	}
- 
- 	# Display media stream data if required
- 	if ( $opt{streaminfo} ) {
--		get_media_stream_data( $pid, $version_pids{'default'}, 'all' );
--		return 1;
-+		display_stream_info( $pid, $version_pids{ $prog{$pid}{version} }, 'all' );
-+		$opt{quiet} = 1;
-+		return 'skip';
- 	}
- 
--	# Report error if failed to get URL for version
--	if ( $got_url && ! $url_2 ) {
--		logger "ERROR: No Stage 2 URL\n" if $opt{verbose};
--		# If mp3 audio stream does not exist force realaudio mode and retry
--		if ( $usemp3 && ! $opt{mp3audio}) {
--			$opt{realaudio} = 1;
--			return 'retry';
--		}
--		return 15;
-+	# Report error if no versions are available
-+	if ( ! $url_2 ) {
-+		logger "WARNING: No $mode versions available\n";
-+		return 'next';
- 	}
--	
-+
- 	# Determine the correct filenames for this download
--	$prog{$pid}{fileprefix} = generate_download_filename_prefix( $pid, $dir, $opt{fileprefix} || "<longname> - <episode> <pid> <version>" );
-+	$prog{$pid}{fileprefix} = generate_download_filename_prefix( $pid, $prog{$pid}{dir}, $opt{fileprefix} || "<longname> - <episode> <pid> <version>" );
- 	logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                 \n";
--	$prog{$pid}{dir} = $dir;
--	my $file_done = "${dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
--	my $file = "${dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
-+	my $file_done = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
-+	my $file = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
- 	$prog{$pid}{filename} = $file_done;
- 	if ( -f $file_done ) {
--		logger "WARNING: File $file_done already exists\n\n";
--		return 1;
-+		logger "ERROR: File $file_done already exists\n\n";
-+		return 'abort';
- 	}
- 
-+	# Skip from here if we are only testing downloads
-+	return 'abort' if $opt{test};
-+
- 	# Create symlink filename if required
- 	my $file_symlink;
- 	if ( $opt{symlink} ) {
-@@ -1581,53 +2189,34 @@
- 		$file_symlink = substitute_fields( $pid, $opt{symlink} );
- 	}
- 
--	# Skip from here if we are only testing downloads
--	return 1 if $opt{test};
--
--	# Get subtitles if they exist and are required
-+	# Get subtitles if they exist and are required 
-+	# best to do this before d/l of file so that the subtitles can be enjoyed while download progresses
- 	my $subfile_done;
- 	my $subfile;
- 	if ( $opt{subtitles} ) {
--		$subfile_done = "${dir}/$prog{$pid}{fileprefix}.srt";
--		$subfile = "${dir}/$prog{$pid}{fileprefix}.partial.srt";
--		download_subtitles( $ua, $subfile, $version_pids{ $prog{$pid}{version} } );
-+		$subfile_done = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.srt";
-+		$subfile = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.partial.srt";
-+		$ua->proxy( ['http'] => undef ) if $opt{partialproxy};
-+		download_stream_subtitles( $ua, $subfile, $version_pids{ $prog{$pid}{version} } );
-+		$ua->proxy( ['http'] => $proxy_url ) if $opt{partialproxy};
- 	}
- 
- 	my $return;
- 	# Do rtmp download
--	if ( $opt{rtmp} ) {
--		# Get player url
--		my %metadata = get_pid_metadata( $ua, $pid );
--		# get this redirected page and find out where it is redirected to
--		my ($ub, $request, $response, $prog_url);
--		$ub = new LWP::UserAgent;
--		$request = new HTTP::Request HEAD => $metadata{player};
--		$response = $ub->request($request);
--		$prog_url = $response->request->url;
--		$return = download_h264_rtmp_stream( $ua, $url_2, $prog_url, $file, $file_done, $file_symlink );
-+	if ( $mode =~ /^(rtmp|flash)/ ) {
-+		$return = download_stream_rtmp( $ua, $streamdata{streamurl}, $pid, $mode, $streamdata{application}, $streamdata{tcurl}, $streamdata{authstring}, $streamdata{swfurl}, $file, $file_done, $file_symlink );
- 
- 	# Do the N95 h.264 download
--	} elsif ( $opt{n95} ) {
--		my $url = get_media_stream_data( $pid, $version_pids{ $prog{$pid}{version} }, 'n95_wifi' );
--		$return = download_h264_low_stream( $ua, $url, $file, $file_done );
-+	} elsif ( $mode =~ /^n95/ ) {
-+		$return = download_stream_h264_low( $ua, $url_2, $file, $file_done, $pid, $mode );
- 
- 	# Do the iPhone h.264 download
--	} elsif ( $prog{$pid}{type} eq 'tv' ) {
--		# Disable proxy here if required
--		$ua->proxy( ['http'] => undef ) if $opt{partialproxy};
--		$return = download_iphone_stream( $ua, $url_2, $file, $file_done, $file_symlink, 1 );
--		# Re-enable proxy here if required
--		$ua->proxy( ['http'] => $proxy_url ) if $opt{partialproxy};
--
--	# Do the iPhone mp3 download
--	} elsif ( $prog{$pid}{type} eq 'radio' ) {
-+	} else {
- 		# Disable proxy here if required
- 		$ua->proxy( ['http'] => undef ) if $opt{partialproxy};
--		$return = download_iphone_stream( $ua, $url_2, $file, $file_done, $file_symlink, 0 );
-+		$return = download_stream_iphone( $ua, $url_2, $pid, $file, $file_done, $file_symlink, 1 );
- 		# Re-enable proxy here if required
- 		$ua->proxy( ['http'] => $proxy_url ) if $opt{partialproxy};
--		# If the iphone mp3 download fails then it's probably not ready yet so retry using realaudio
--		$opt{realaudio} = 1 if $return eq 'retry';
- 	}
- 	
- 	# Rename the subtitle file accordingly
-@@ -1647,13 +2236,12 @@
- 
- 
- # Download Subtitles, convert to srt(SubRip) format and apply time offset
--sub download_subtitles {
-+sub download_stream_subtitles {
- 	my ( $ua, $file, $verpid ) = @_;
- 	my $suburl;
- 	my $subs;
- 	logger "INFO: Getting Subtitle metadata for $verpid\n" if $opt{verbose};
--	$suburl = get_media_stream_data( undef, $verpid, 'subtitles' );
--
-+	$suburl = %{get_media_stream_data( undef, $verpid, 'subtitles')}->{streamurl};
- 	# Return if we have no url
- 	if (! $suburl) {
- 		logger "INFO: Subtitles not available\n";
-@@ -1793,12 +2381,12 @@
- 
- 	# Get title
- 	# <title>Amazon with Bruce Parry: Episode 1</title>
--	my ( $title, $type );
-+	my ( $title, $prog_type );
- 	$title = $1 if $xml =~ m{<title>\s*(.+?)\s*<\/title>};
- 
- 	# Get type
--	$type = 'tv' if grep /kind="programme"/, $xml;
--	$type = 'radio' if grep /kind="radioProgramme"/, $xml;
-+	$prog_type = 'tv' if grep /kind="programme"/, $xml;
-+	$prog_type = 'radio' if grep /kind="radioProgramme"/, $xml;
- 
- 	# Split into <item kind="programme"> sections
- 	for ( split /<item\s+kind="(radioProgramme|programme)"/, $xml ) {
-@@ -1812,310 +2400,389 @@
- 		$version_pids{$version} = $verpid;
- 		logger "INFO: Version: $version, VersionPid: $verpid\n" if $opt{verbose};  
- 	}
-+
-+	# Extract Long Name, e.g.: iplayer.episode.setTitle("DIY SOS: Series 16: Swansea"), Strip off the episode name
-+	$title =~ s/^(.+):.*?$/$1/g;
-+
- 	# Add to prog hash
- 	$prog{$pid}{versions} = join ',', keys %version_pids;
--	return ( $type, $title, %version_pids );
-+	return ( $prog_type, $title, %version_pids );
- }
- 
- 
- 
- # Gets media streams data for this version pid
--# $media = all|flashhigh|flashnormal|iphone|flashwii|n95_wifi|n95_3g|mobile|flashaudio|realaudio|wma|subtitles
-+# $media = all|itv|flashhigh|flashnormal|iphone|flashwii|n95_wifi|n95_3g|mobile|flashaudio|realaudio|wma|subtitles
- sub get_media_stream_data {
- 	my ( $pid, $verpid, $media ) = @_;
--	my %streams;
--	my $ua = LWP::UserAgent->new();
-+	my %data;
-+
- 	# Setup user agent with redirection enabled
--	$ua->timeout([$lwp_request_timeout]);
--	$ua->proxy( ['http'] => $proxy_url );
--	$ua->cookie_jar( HTTP::Cookies->new( file => $cookiejar, autosave => 1, ignore_discard => 1 ) );
-+	my $ua = create_ua('desktop');
- 	$opt{quiet} = 0 if $opt{streaminfo};
--	logger "INFO: Getting media stream metadata for $prog{$pid}{name} - $prog{$pid}{episode}, $verpid\n" if $pid;
--	my $xml1 = request_url_retry($ua, $media_stream_data_prefix.$verpid, 3, '', '');
--	logger "\n$xml1\n" if $opt{debug};
--	# flatten
--	$xml1 =~ s/\n/ /g;
- 
--	for my $xml ( split /<media/, $xml1 ) {
--		$xml = "<media".$xml;
-+	# ITV streams
-+	if ( $prog{$pid}{type} eq 'itv' ) {
-+		my $prog_type = 'itv';
-+		$data{$prog_type}{type} = 'ITV ASF Video stream';
-+		$opt{quiet} = 1 if $opt{streaminfo};
-+		$data{$prog_type}{streamurl} = join('|', get_stream_url_itv($ua, $pid) );
-+		$opt{quiet} = 0 if $opt{streaminfo};
-+
-+	# BBC streams
-+	} else {
-+		my $xml1 = request_url_retry($ua, $media_stream_data_prefix.$verpid, 3, '', '');
-+		logger "\n$xml1\n" if $opt{debug};
-+		# flatten
-+		$xml1 =~ s/\n/ /g;
-+		
-+		for my $xml ( split /<media/, $xml1 ) {
-+			$xml = "<media".$xml;
-+			my $prog_type;
-+			
-+			# h.264 high quality stream
-+			#	<media kind="video"
-+			#        width="640"
-+			#        height="360"
-+			#        type="video/mp4"
-+			#        encoding="h264"  >
-+			#        <connection
-+			#                priority="10"
-+			#                application="bbciplayertok"
-+			#                kind="level3"
-+			#                server="bbciplayertokfs.fplive.net"
-+			#                identifier="mp4:b000zxf4-H26490898078"
-+			#                authString="[REDACTED]"
-+			#        />
-+			# application: bbciplayertok
-+			# tcURL: rtmp://bbciplayertokfs.fplive.net:80/bbciplayertok
-+			if ( $media =~ /^(flashhigh|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/mp4".+?encoding="h264".+?application="(.+?)".+?kind="level3"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
-+				$prog_type = 'flashhigh';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{application}, $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{authstring} ) = ( $1, $2, $3, $4 );
-+				$data{$prog_type}{type} = 'Flash RTMP H.264 high quality stream';
-+				$data{$prog_type}{tcurl} = "rtmp://$data{$prog_type}{server}:80/$data{$prog_type}{application}";
-+				$data{$prog_type}{swfurl} = "http://www.bbc.co.uk/emp/9player.swf?revision=7276";
-+				$data{$prog_type}{streamurl} = "rtmp://$data{$prog_type}{server}:1935/ondemand?_fcs_vhost=$data{$prog_type}{server}&auth=$data{$prog_type}{authstring}&aifp=v001&slist=$data{$prog_type}{identifier}";
-+			}
-+			
-+			# h.264 normal quality stream
-+			#	<media kind="video"
-+			#        width="640"
-+			#        height="360"
-+			#        type="video/x-flv"
-+			#        encoding="vp6"  >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="akamai"
-+			#                server="cp41752.edgefcs.net"
-+			#                identifier="secure/b000zxf4-streaming90898078"
-+			#                authString="[REDACTED]"
-+			#        />
-+			#	</media>
-+			#
-+			# application (e.g.):            ondemand?_fcs_vhost=cp41752.edgefcs.net&auth=daEcia8aQaRardxdwb_dCbvc0cPbLavc2cL-bjw5rj-cCp-JnlDCnzn.MEqHpxF&aifp=v001&slist=secure/b000gy717streaming103693754
-+			# tcURL: rtmp://88.221.26.165:80/ondemand?_fcs_vhost=cp41752.edgefcs.net&auth=daEcia8aQaRardxdwb_dCbvc0cPbLavc.2cL-bjw5rj-cCp-JnlDCnznMEqHpxF&aifp=v001&slist=secure/b000gy717streaming103693754
-+			if ( $media =~ /^(flashnormal|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/x-flv".+?encoding="vp6".+?kind="akamai"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
-+				$prog_type = 'flashnormal';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{authstring} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{application} = "ondemand?_fcs_vhost=$data{$prog_type}{server}&auth=$data{$prog_type}{authstring}&aifp=v001&slist=$data{$prog_type}{identifier}";
-+				$data{$prog_type}{type} = 'Flash RTMP H.264 normal quality stream';
-+				$data{$prog_type}{tcurl} = "rtmp://$data{$prog_type}{server}:80/$data{$prog_type}{application}";
-+				$data{$prog_type}{swfurl} = "http://www.bbc.co.uk/emp/9player.swf?revision=7276";
-+				$data{$prog_type}{streamurl} = "rtmp://$data{$prog_type}{server}:1935/ondemand?_fcs_vhost=$data{$prog_type}{server}&auth=$data{$prog_type}{authstring}&aifp=v001&slist=$data{$prog_type}{identifier}";
-+			}
-+			
-+			# Wii h.264 standard quality stream
-+			#<media kind="video"
-+			#        width="512"
-+			#        height="288"
-+			#        type="video/x-flv"
-+			#        encoding="spark"  >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="akamai"
-+			#                server="cp41752.edgefcs.net"
-+			#                identifier="secure/5242138581547639062"
-+			#                authString="[REDACTED]"
-+			#        />
-+			#</media>
-+			# application (e.g.):               ondemand?_fcs_vhost=cp41752.edgefcs.net&auth=daEcpc6cYbhdIakdWduc6bJdPbydbazdmdp-bjxPBF-cCp-GptFAoDqJBnHvzC&aifp=v001&slist=secure/b000g884xstreaming101052333
-+			# tcURL: rtmp: //88.221.26.173:1935/ondemand?_fcs_vhost=cp41752.edgefcs.net&auth=daEcpc6cYbhdIakdWduc6bJdPbydbazdmdp-bjxPBF-cCp-GptFAoDqJBnHvzC&aifp=v001&slist=secure/b000g884xstreaming101052333
-+			# swfUrl: http://www.bbc.co.uk/emp/iplayer/7player.swf?revision=3897
-+			if ( $media =~ /^(flashwii|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/x-flv".+?encoding="spark".+?kind="akamai"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
-+				$prog_type = 'flashwii';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{authstring} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{application} = "ondemand?_fcs_vhost=$data{$prog_type}{server}&auth=$data{$prog_type}{authstring}&aifp=v001&slist=$data{$prog_type}{identifier}";
-+				$data{$prog_type}{type} = 'Flash RTMP H.264 Wii stream';
-+				$data{$prog_type}{tcurl} = "rtmp://$data{$prog_type}{server}:1935/$data{$prog_type}{application}";
-+				$data{$prog_type}{swfurl} = "http://www.bbc.co.uk/emp/iplayer/7player.swf?revision=3897";
-+				$data{$prog_type}{streamurl} = "rtmp://$data{$prog_type}{server}:1935/ondemand?_fcs_vhost=$data{$prog_type}{server}&auth=$data{$prog_type}{authstring}&aifp=v001&slist=$data{$prog_type}{identifier}";
-+			}
-+		
-+			# iPhone h.264/mp3 stream
-+			#<media kind="video"
-+			#        width="480"
-+			#        height="272"
-+			#        type="video/mp4"
-+			#        encoding="h264"  >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="sis"
-+			#                server="http://www.bbc.co.uk/mediaselector/3/auth/stream/"
-+			#                identifier="5242138581547639062"
-+			#                href="http://www.bbc.co.uk/mediaselector/3/auth/stream/5242138581547639062.mp4"
-+			#        />
-+			#</media>
-+			if ( $media =~ /^(iphone|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/mp4".+?encoding="h264".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
-+				$prog_type = 'iphone';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{streamurl} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{type} = 'iPhone stream';
-+			}
-+		
-+			# Nokia N95 h.264 low quality stream (WiFi)
-+			#<media kind="video"
-+			#        type="video/mpeg"
-+			#        encoding="h264"  >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="sis"
-+			#                server="http://www.bbc.co.uk/mediaselector/4/sdp/"
-+			#                identifier="b00108ld/iplayer_streaming_n95_wifi"
-+			#                href="http://www.bbc.co.uk/mediaselector/4/sdp/b00108ld/iplayer_streaming_n95_wifi"
-+			#        />
-+			#</media>
-+			if ( $media =~ /^(n95_wifi|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/mpeg".+?encoding="h264".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
-+				$prog_type = 'n95_wifi';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{href} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{type} = 'Nokia N95 h.264 low quality WiFi stream';
-+				$opt{quiet} = 1 if $opt{streaminfo};
-+				chomp( $data{$prog_type}{streamurl} = request_url_retry($ua, $data{$prog_type}{href}, 2, '', '') );
-+				$opt{quiet} = 0 if $opt{streaminfo};
-+			}
-+		
-+			# Nokia N95 h.264 low quality stream (3G)
-+			#<media kind="" 
-+			#        expires="2008-10-30T12:29:00+00:00"
-+			#        type="video/mpeg"                  
-+			#        encoding="h264"  >                 
-+			#        <connection                        
-+			#                priority="10"              
-+			#                kind="sis"                 
-+			#                server="http://www.bbc.co.uk/mediaselector/4/sdp/" 
-+			#                identifier="b009tzxx/iplayer_streaming_n95_3g"     
-+			#                href="http://www.bbc.co.uk/mediaselector/4/sdp/b009tzxx/iplayer_streaming_n95_3g" 
-+			#        />                                                                                        
-+			#</media>    
-+			if ( $media =~ /^(n95_3g|all)$/ && $xml =~ m{<media\s+kind="".+?type="video/mpeg".+?encoding="h264".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
-+				$prog_type = 'n95_3g';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{href} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{type} = 'Nokia N95 h.264 low quality 3G stream';
-+				$opt{quiet} = 1 if $opt{streaminfo};
-+				chomp( $data{$prog_type}{streamurl} = request_url_retry($ua, $data{$prog_type}{href}, 2, '', '') );
-+				$opt{quiet} = 0 if $opt{streaminfo};
-+			}
-+		
-+			# Mobile WMV DRM
-+			#<media kind="video"
-+			#        expires="2008-10-20T21:59:00+01:00"
-+			#        type="video/wmv"   >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="licence"
-+			#                server="http://iplayldsvip.iplayer.bbc.co.uk/WMLicenceIssuer/LicenceDelivery.asmx"
-+			#                identifier="0A1CA43B-98A8-43EA-B684-DA06672C0575"
-+			#                href="http://iplayldsvip.iplayer.bbc.co.uk/WMLicenceIssuer/LicenceDelivery.asmx/0A1CA43B-98A8-43EA-B684-DA06672C0575"
-+			#        />
-+			#<connection
-+			#                priority="10"
-+			#                kind="sis"
-+			#                server="http://directdl.iplayer.bbc.co.uk/windowsmedia/"
-+			#                identifier="AmazonwithBruceParry_Episode5_200810132100_mobile"
-+			#                href="http://directdl.iplayer.bbc.co.uk/windowsmedia/AmazonwithBruceParry_Episode5_200810132100_mobile.wmv"
-+			#        />
-+			#</media>
-+			if ( $media =~ /^(mobile|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/wmv".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
-+				$prog_type = 'mobile';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{streamurl} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{type} = 'Mobile WMV DRM stream';
-+			}
-+		
-+			# Audio rtmp mp3
-+			#<media kind="audio"
-+			#        type="audio/mpeg"
-+			#        encoding="mp3"  >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="akamai"
-+			#                server="cp48181.edgefcs.net"
-+			#                identifier="mp3:secure/radio1/RBN2_mashup_b00d67h9_2008_09_05_22_14_25"
-+			#                authString="[REDACTED]"
-+			#        />
-+			#</media>
-+			#app: ondemand?_fcs_vhost=cp48181.edgefcs.net&auth=daEasducLbidOancObacmc0amd6d7ana8c6-bjx.9v-cCp-JqlFHoEq.FBqGnxC&aifp=v001&slist=secure/radio1/RBN2_radio_1_-_wednesday_1000_b00g3xcj_2008_12_31_13_21_49
-+			#swfUrl: http://www.bbc.co.uk/emp/9player.swf?revision=7276
-+			#tcUrl: rtmp://92.122.210.173:1935/ondemand?_fcs_vhost=cp48181.edgefcs.net&auth=daEasducLbidOancObacmc0amd6d7ana8c6-bjx.9v-cCp-JqlFHoEqFBqGnxC&aifp=v001&slist=secure/radio1/RBN2_radio_1_-_wednesday_1.000_b00g3xcj_2008_12_31_13_21_49
-+			#pageUrl: http://www.bbc.co.uk/iplayer/episode/b00g3xp7/Annie_Mac_31_12_2008/
-+			if ( $media =~ /^(flashaudio|all)$/ && $xml =~ m{<media\s+kind="audio".+?type="audio/mpeg".+?encoding="mp3".+?kind="akamai"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
-+				$prog_type = 'flashaudio';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{authstring} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{streamurl} = "rtmp://$data{$prog_type}{server}:1935/ondemand?_fcs_vhost=$data{$prog_type}{server}&auth=$data{$prog_type}{authstring}&aifp=v001&slist=$data{$prog_type}{identifier}";
-+				# Remove offending mp3: at the start of the identifier (don't remove in stream url)
-+				$data{$prog_type}{identifier} =~ s/^mp3://;
-+				$data{$prog_type}{application} = "ondemand?_fcs_vhost=$data{$prog_type}{server}&auth=$data{$prog_type}{authstring}&aifp=v001&slist=$data{$prog_type}{identifier}";
-+				$data{$prog_type}{type} = 'RTMP MP3 stream';
-+				$data{$prog_type}{tcurl} = "rtmp://$data{$prog_type}{server}:1935/$data{$prog_type}{application}";
-+				$data{$prog_type}{swfurl} = "http://www.bbc.co.uk/emp/9player.swf?revision=7276";
-+			}
-+		
-+			# RealAudio stream
-+			#<media kind="audio"
-+			#       type="audio/real"
-+			#        encoding="real"  >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="sis"
-+			#                server="http://www.bbc.co.uk"
-+			#                identifier="/radio/aod/playlists/9h/76/d0/0b/2000_bbc_radio_one"
-+			#                href="http://www.bbc.co.uk/radio/aod/playlists/9h/76/d0/0b/2000_bbc_radio_one.ram"
-+			#        />
-+			#</media>
-+			# Realaudio for worldservice	
-+			#<media kind=""
-+			#type="audio/real"
-+			#encoding="real"  >
-+			#<connection
-+			#        priority="10"
-+			#        kind="edgesuite"
-+			#        server="http://http-ws.bbc.co.uk.edgesuite.net"
-+			#        identifier="/generatecssram.esi?file=/worldservice/css/nb/410060838.ra"
-+			#        href="http://http-ws.bbc.co.uk.edgesuite.net/generatecssram.esi?file=/worldservice/css/nb/410060838.ra"
-+			#/>
-+			#</media>
-+			#</mediaSelection>
-+			if ( $media =~ /^(realaudio|all)$/ && $xml =~ m{<media\s+kind="(audio|)".+?type="audio/real".+?encoding="real".+?kind="(sis|edgesuite)"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
-+				$prog_type = 'realaudio';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{href} ) = ( $3, $4, $5 );
-+				$data{$prog_type}{type} = 'RealAudio RTSP stream';
-+				$opt{quiet} = 1 if $opt{streaminfo};
-+				chomp( $data{$prog_type}{streamurl} = request_url_retry($ua, $data{$prog_type}{href}, 2, '', '') );
-+				$data{$prog_type}{streamurl} =~ s/[\s\n]//g;
-+				$opt{quiet} = 0 if $opt{streaminfo};
-+			}
-+		
-+			# Radio WMA (low quality)
-+			#<mediaSelection xmlns="http://bbc.co.uk/2008/mp/mediaselection">
-+			#<media kind=""
-+			#        type="audio/wma"
-+			#        encoding="wma"  >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="edgesuite"
-+			#                server="http://http-ws.bbc.co.uk.edgesuite.net"
-+			#                identifier="/generatecssasx.esi?file=/worldservice/css/nb/410060838"
-+			#                href="http://http-ws.bbc.co.uk.edgesuite.net/generatecssasx.esi?file=/worldservice/css/nb/410060838.wma"
-+			#        />
-+			#</media>
-+			if ( $media =~ /^(wma|all)$/ && $xml =~ m{<media\s+kind="(audio|)".+?type="audio/wma".+?encoding="wma".+?kind="(sis|edgesuite)"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
-+				$prog_type = 'wma';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{href} ) = ( $3, $4, $5 );
-+				$data{$prog_type}{type} = 'WMA MMS stream';
-+				$opt{quiet} = 1 if $opt{streaminfo};
-+				chomp( $data{$prog_type}{streamurl} = request_url_retry($ua, $data{$prog_type}{href}, 2, '', '') );
-+				$data{$prog_type}{streamurl} =~ s/[\s\n]//g;
-+				# HREF="mms://a1899.v394403.c39440.g.vm.akamaistream.net/7/1899/39440/1/bbcworldservice.download.akamai.com/39440//worldservice/css/nb/410060838.wma"
-+				$data{$prog_type}{streamurl} =~ s/^.*href=\"(.+?)\".*$/$1/gi;
-+				$opt{quiet} = 0 if $opt{streaminfo};
-+			}
-+		
-+			# Subtitles stream
-+			#<media kind="captions"
-+			#        type="application/ttaf+xml"   >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="http"
-+			#                server="http://www.bbc.co.uk/iplayer/subtitles/"
-+			#                identifier="b0008dc8rstreaming89808204.xml"
-+			#                href="http://www.bbc.co.uk/iplayer/subtitles/b0008dc8rstreaming89808204.xml"
-+			#        />
-+			#</media>
-+			if ( $media =~ /^(subtitles|all)$/ && $xml =~ m{<media\s+kind="captions".+?type="application/ttaf\+xml".+?kind="http"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
-+				$prog_type = 'subtitles';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{streamurl} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{type} = 'Subtitles stream';
-+			}	
-+		}
-+		# Do iphone redirect check regardless of an xml entry for iphone - sometimes the iphone streams exist regardless
-+		if ( my $streamurl = get_stream_url_iphone($ua, $verpid) ) {
-+			my $prog_type = 'iphone';
-+			$data{$prog_type}{type} = 'iPhone stream';
-+			# Get iphone redirect
-+			$data{$prog_type}{streamurl} = $streamurl;
-+		} else {
-+			logger "DEBUG: No iphone redirect stream\n" if $opt{verbose};
-+		}
-+
-+	}
-+	# Return a hash with media => url if 'all' is specified - otherwise just the specified url
-+	if ( $media eq 'all' ) {
-+		return %data;
-+	} else {
-+		# Make sure this hash exists before we pass it back...
-+		$data{$media}{exists} = 0 if not defined $data{$media};
-+		return $data{$media};
-+	}
-+}
-+
- 
--		my ($server, $authstring, $identifier, $href);
- 
--		# h.264 high quality stream
--		#	<media kind="video"
--		#        width="640"
--		#        height="360"
--		#        type="video/mp4"
--		#        encoding="h264"  >
--		#        <connection
--		#                priority="10"
--		#                application="bbciplayertok"
--		#                kind="level3"
--		#                server="bbciplayertokfs.fplive.net"
--		#                identifier="mp4:b000zxf4-H26490898078"
--		#                authString="[REDACTED]"
--		#        />
--		if ( $media =~ /^(flashhigh|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/mp4".+?encoding="h264".+?kind="level3"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
--			( $server, $identifier, $authstring ) = ( $1, $2, $3 );
--			logger "INFO: RTMP h.264 high quality stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  authstring=$authstring\n" if $opt{verbose};
--			$streams{'flashhigh'} = "rtmp://${server}:1935/ondemand?_fcs_vhost=${server}&auth=${authstring}&aifp=v001&slist=${identifier}";
--			logger "INFO: RTMP high quality stream URL: $streams{'flashhigh'}\n";
--		}
--
--		# h.264 normal quality stream
--		#	<media kind="video"
--		#        width="512"
--		#        height="288"
--		#        type="video/x-flv"
--		#        encoding="vp6"  >
--		#        <connection
--		#                priority="10"
--		#                kind="akamai"
--		#                server="cp41752.edgefcs.net"
--		#                identifier="secure/b000zxf4-streaming90898078"
--		#                authString="[REDACTED]"
--		#        />
--		#	</media>
--		#
--		if ( $media =~ /^(flashnormal|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/x-flv".+?encoding="vp6".+?kind="akamai"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
--			( $server, $identifier, $authstring ) = ( $1, $2, $3 );
--			logger "INFO: RTMP h.264 normal quality stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  authstring=$authstring\n" if $opt{verbose};
--			$streams{'flashnormal'} = "rtmp://${server}:1935/ondemand?_fcs_vhost=${server}&auth=${authstring}&aifp=v001&slist=${identifier}";
--			logger "INFO: RTMP normal quality stream URL: $streams{'flashnormal'}\n";
--		}
--	
--		# Wii h.264 standard quality stream
--		#<media kind="video"
--		#        width="512"
--		#        height="288"
--		#        type="video/x-flv"
--		#        encoding="spark"  >
--		#        <connection
--		#                priority="10"
--		#                kind="akamai"
--		#                server="cp41752.edgefcs.net"
--		#                identifier="secure/5242138581547639062"
--		#                authString="[REDACTED]"
--		#        />
--		#</media>
--		if ( $media =~ /^(flashwii|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/x-flv".+?encoding="spark".+?kind="akamai"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
--			( $server, $identifier, $authstring ) = ( $1, $2, $3 );
--			logger "INFO: RTMP Wii normal quality stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  authstring=$authstring\n" if $opt{verbose};
--			$streams{'flashwii'} = "rtmp://${server}:1935/ondemand?_fcs_vhost=${server}&auth=${authstring}&aifp=v001&slist=${identifier}";
--			logger "INFO: RTMP Wii normal quality stream URL: $streams{'flashwii'}\n";
--		}
--	
--		# iPhone h.264/mp3 stream
--		#<media kind="video"
--		#        width="480"
--		#        height="272"
--		#        type="video/mp4"
--		#        encoding="h264"  >
--		#        <connection
--		#                priority="10"
--		#                kind="sis"
--		#                server="http://www.bbc.co.uk/mediaselector/3/auth/stream/"
--		#                identifier="5242138581547639062"
--		#                href="http://www.bbc.co.uk/mediaselector/3/auth/stream/5242138581547639062.mp4"
--		#        />
--		#</media>
--		if ( $media =~ /^(iphone|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/mp4".+?encoding="h264".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
--			( $server, $identifier, $href ) = ( $1, $2, $3 );
--			logger "INFO: iPhone stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  href=$href\n" if $opt{verbose};
--			$streams{'iphone'} = "$href";
--			logger "INFO: iPhone stream URL: $streams{'iphone'}\n";
--		}
--	
--		# Nokia N95 h.264 low quality stream (WiFi)
--		#<media kind="video"
--		#        type="video/mpeg"
--		#        encoding="h264"  >
--		#        <connection
--		#                priority="10"
--		#                kind="sis"
--		#                server="http://www.bbc.co.uk/mediaselector/4/sdp/"
--		#                identifier="b00108ld/iplayer_streaming_n95_wifi"
--		#                href="http://www.bbc.co.uk/mediaselector/4/sdp/b00108ld/iplayer_streaming_n95_wifi"
--		#        />
--		#</media>
--		if ( $media =~ /^(n95_wifi|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/mpeg".+?encoding="h264".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
--			( $server, $identifier, $href ) = ( $1, $2, $3 );
--			$opt{quiet} = 1 if $opt{streaminfo};
--			chomp( my $rtsp = request_url_retry($ua, $href, 2, '', '') );
--			$opt{quiet} = 0 if $opt{streaminfo};
--			logger "INFO: Nokia N95 h.264 low quality WiFi stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  href=$href\n" if $opt{verbose};
--			$streams{'n95_wifi'} = "$rtsp";
--			logger "INFO: Nokia N95 h.264 low quality WiFi stream URL: $streams{'n95_wifi'}\n";
--		}
--	
--		# Nokia N95 h.264 low quality stream (3G)
--		#<media kind="" 
--		#        expires="2008-10-30T12:29:00+00:00"
--		#        type="video/mpeg"                  
--		#        encoding="h264"  >                 
--		#        <connection                        
--		#                priority="10"              
--		#                kind="sis"                 
--		#                server="http://www.bbc.co.uk/mediaselector/4/sdp/" 
--		#                identifier="b009tzxx/iplayer_streaming_n95_3g"     
--		#                href="http://www.bbc.co.uk/mediaselector/4/sdp/b009tzxx/iplayer_streaming_n95_3g" 
--		#        />                                                                                        
--		#</media>    
--		if ( $media =~ /^(n95_3g|all)$/ && $xml =~ m{<media\s+kind="".+?type="video/mpeg".+?encoding="h264".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
--			( $server, $identifier, $href ) = ( $1, $2, $3 );
--			$opt{quiet} = 1 if $opt{streaminfo};
--			chomp( my $rtsp = request_url_retry($ua, $href, 2, '', '') );
--			$opt{quiet} = 0 if $opt{streaminfo};
--			logger "INFO: Nokia N95 h.264 low quality 3G stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  href=$href\n" if $opt{verbose};
--			$streams{'n95_3g'} = "$rtsp";
--			logger "INFO: Nokia N95 h.264 low quality 3G stream URL: $streams{'n95_3g'}\n";
--		}
--	
--	
--	
--		# Mobile WMV DRM
--		#<media kind="video"
--		#        expires="2008-10-20T21:59:00+01:00"
--		#        type="video/wmv"   >
--		#        <connection
--		#                priority="10"
--		#                kind="licence"
--		#                server="http://iplayldsvip.iplayer.bbc.co.uk/WMLicenceIssuer/LicenceDelivery.asmx"
--		#                identifier="0A1CA43B-98A8-43EA-B684-DA06672C0575"
--		#                href="http://iplayldsvip.iplayer.bbc.co.uk/WMLicenceIssuer/LicenceDelivery.asmx/0A1CA43B-98A8-43EA-B684-DA06672C0575"
--		#        />
--		#<connection
--		#                priority="10"
--		#                kind="sis"
--		#                server="http://directdl.iplayer.bbc.co.uk/windowsmedia/"
--		#                identifier="AmazonwithBruceParry_Episode5_200810132100_mobile"
--		#                href="http://directdl.iplayer.bbc.co.uk/windowsmedia/AmazonwithBruceParry_Episode5_200810132100_mobile.wmv"
--		#        />
--		#</media>
--		if ( $media =~ /^(mobile|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/wmv".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
--			( $server, $identifier, $href ) = ( $1, $2, $3 );
--			logger "INFO: Mobile WMV DRM stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  href=$href\n" if $opt{verbose};
--			$streams{'mobile'} = "$href";
--			logger "INFO: Mobile WMV DRM stream URL: $streams{'mobile'}\n";
--		}
--	
--		# Audio rtmp mp3
--		#<media kind="audio"
--		#        type="audio/mpeg"
--		#        encoding="mp3"  >
--		#        <connection
--		#                priority="10"
--		#                kind="akamai"
--		#                server="cp48181.edgefcs.net"
--		#                identifier="mp3:secure/radio1/RBN2_mashup_b00d67h9_2008_09_05_22_14_25"
--		#                authString="[REDACTED]"
--		#        />
--		#</media>
--		if ( $media =~ /^(flashaudio|all)$/ && $xml =~ m{<media\s+kind="audio".+?type="audio/mpeg".+?encoding="mp3".+?kind="akamai"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
--			( $server, $identifier, $authstring ) = ( $1, $2, $3 );
--			# Remove offending mp3: at the start of the identifier
--			$identifier =~ s/^mp3://;
--			logger "INFO: RTMP MP3 stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  authstring=$authstring\n" if $opt{verbose};
--			$streams{'flashaudio'} = "rtmp://${server}:1935/ondemand?_fcs_vhost=${server}&auth=${authstring}&aifp=v001&slist=${identifier}";
--			logger "INFO: RTMP stream URL: $streams{'flashaudio'}\n";
--		}
--	
--		# RealAudio stream
--		#<media kind="audio"
--		#       type="audio/real"
--		#        encoding="real"  >
--		#        <connection
--		#                priority="10"
--		#                kind="sis"
--		#                server="http://www.bbc.co.uk"
--		#                identifier="/radio/aod/playlists/9h/76/d0/0b/2000_bbc_radio_one"
--		#                href="http://www.bbc.co.uk/radio/aod/playlists/9h/76/d0/0b/2000_bbc_radio_one.ram"
--		#        />
--		#</media>
--		# Realaudio for worldservice	
--		#<media kind=""
--		#type="audio/real"
--		#encoding="real"  >
--		#<connection
--		#        priority="10"
--		#        kind="edgesuite"
--		#        server="http://http-ws.bbc.co.uk.edgesuite.net"
--		#        identifier="/generatecssram.esi?file=/worldservice/css/nb/410060838.ra"
--		#        href="http://http-ws.bbc.co.uk.edgesuite.net/generatecssram.esi?file=/worldservice/css/nb/410060838.ra"
--		#/>
--		#</media>
--		#</mediaSelection>
--		if ( $media =~ /^(realaudio|all)$/ && $xml =~ m{<media\s+kind="(audio|)".+?type="audio/real".+?encoding="real".+?kind="(sis|edgesuite)"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
--			( $server, $identifier, $href ) = ( $3, $4, $5 );
--			$opt{quiet} = 1 if $opt{streaminfo};
--			chomp( my $rtsp = request_url_retry($ua, $href, 2, '', '') );
--			$rtsp =~ s/[\s\n]//g;
--			$opt{quiet} = 0 if $opt{streaminfo};
--			logger "INFO: RealAudio RTSP stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  href=$href\n" if $opt{verbose};
--			$streams{'realaudio'} = "$rtsp";
--			logger "INFO: RealAudio RTSP stream URL: $streams{'realaudio'}\n";
--		}
--	
--	
--		# Radio WMA (low quality)
--		#<mediaSelection xmlns="http://bbc.co.uk/2008/mp/mediaselection">
--		#<media kind=""
--		#        type="audio/wma"
--		#        encoding="wma"  >
--		#        <connection
--		#                priority="10"
--		#                kind="edgesuite"
--		#                server="http://http-ws.bbc.co.uk.edgesuite.net"
--		#                identifier="/generatecssasx.esi?file=/worldservice/css/nb/410060838"
--		#                href="http://http-ws.bbc.co.uk.edgesuite.net/generatecssasx.esi?file=/worldservice/css/nb/410060838.wma"
--		#        />
--		#</media>
--		if ( $media =~ /^(wma|all)$/ && $xml =~ m{<media\s+kind="(audio|)".+?type="audio/wma".+?encoding="wma".+?kind="(sis|edgesuite)"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
--			( $server, $identifier, $href ) = ( $3, $4, $5 );
--			$opt{quiet} = 1 if $opt{streaminfo};
--			chomp( my $mms = request_url_retry($ua, $href, 2, '', '') );
--			$mms =~ s/[\n]//g;
--			# HREF="mms://a1899.v394403.c39440.g.vm.akamaistream.net/7/1899/39440/1/bbcworldservice.download.akamai.com/39440//worldservice/css/nb/410060838.wma"
--			$mms =~ s/^.*href=\"(.+?)\".*$/$1/gi;
--			$opt{quiet} = 0 if $opt{streaminfo};
--			logger "INFO: WMA MMS stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  href=$href\n" if $opt{verbose};
--			$streams{'wma'} = "$mms";
--			logger "INFO: WMA MMS stream URL: $streams{'wma'}\n";
--		}
--	
--	
--		# Subtitles stream
--		#<media kind="captions"
--		#        type="application/ttaf+xml"   >
--		#        <connection
--		#                priority="10"
--		#                kind="http"
--		#                server="http://www.bbc.co.uk/iplayer/subtitles/"
--		#                identifier="b0008dc8rstreaming89808204.xml"
--		#                href="http://www.bbc.co.uk/iplayer/subtitles/b0008dc8rstreaming89808204.xml"
--		#        />
--		#</media>
--		if ( $media =~ /^(subtitles|all)$/ && $xml =~ m{<media\s+kind="captions".+?type="application/ttaf\+xml".+?kind="http"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
--			( $server, $identifier, $href ) = ( $1, $2, $3 );
--			logger "INFO: Subtitles stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  href=$href\n" if $opt{verbose};
--			$streams{'subtitles'} = "$href";
--			logger "INFO: Subtitles stream URL: $streams{'subtitles'}\n";
-+sub display_stream_info {
-+	my ($pid, $verpid, $media) = (@_);
-+	logger "INFO: Getting media stream metadata for $prog{$pid}{name} - $prog{$pid}{episode}, $verpid\n" if $pid;
-+	my %data = get_media_stream_data( $pid, $verpid, $media);
-+	# Print out stream data
-+	for my $prog_type (sort keys %data) {
-+		logger "stream:     $prog_type\n";
-+		for my $entry ( sort keys %{ $data{$prog_type} } ) {
-+			logger sprintf("%-11s %s\n", $entry.':', $data{$prog_type}{$entry} );
- 		}
-+		logger "\n";
- 	}
--	logger "\n" if $opt{streaminfo};
--	$opt{quiet} = 1 if $opt{streaminfo};
-+	return 0;
-+}
- 
--	# Return a hash with media => url if 'all' is specified - otherwise just the specified url
--	return %streams if $media eq 'all';
--	return $streams{$media};
-+
-+
-+# Displays specified metadata from supplied hash
-+# Usage: display_metadata( <hashref>, <array of elements to display> )
-+sub display_metadata {
-+	my %data = %{$_[0]};
-+	shift;
-+	my @keys = @_;
-+	@keys = keys %data if $#_ < 0;
-+	logger "\n";
-+	for (@keys) {
-+		logger sprintf "%-15s %s\n", ucfirst($_).':', $data{$_} if $data{$_};
-+	}
-+	return 0;
- }
- 
- 
- 
- # Actually do the h.264/mp3 downloading
- # ( $ua, $pid, $url_2, $file, $file_done, '0|1 == rearrange moov' )
--sub download_iphone_stream {
--	my ( $ua, $url_2, $file, $file_done, $file_symlink, $rearrange ) = @_;
-+sub download_stream_iphone {
-+	my ( $ua, $url_2, $pid, $file, $file_done, $file_symlink, $rearrange ) = @_;
- 
- 	# Stage 3a: Download 1st byte to get exact file length
- 	logger "INFO: Stage 3 URL = $url_2\n" if $opt{verbose};
-@@ -2132,53 +2799,44 @@
- 	my $req = HTTP::Request->new ('GET', $url_2, $h);
- 	my $res = $ua->request($req);
- 	# e.g. Content-Range: bytes 0-1/181338136 (return if no content length returned)
--	my $file_len = $res->header("Content-Range");
--	if ( ! $file_len ) {
--		logger "ERROR: No Content-Range was obtained\n" if $opt{verbose};
-+	my $download_len = $res->header("Content-Range");
-+	if ( ! $download_len ) {
-+		#logger "ERROR: No Content-Range was obtained\n" if $opt{verbose};
-+		logger "WARNING: iphone version not available\n";
- 		return 'retry'
- 	}
--	$file_len =~ s|^bytes 0-1/(\d+).*$|$1|;
--	logger "INFO: Download File Length $file_len\n" if $opt{verbose};
-+	$download_len =~ s|^bytes 0-1/(\d+).*$|$1|;
-+	logger "INFO: Download File Length $download_len\n" if $opt{verbose};
- 
- 	# Only do this if we're rearranging QT streams
- 	my $mdat_start = 0;
--	my $moov_start = $file_len + 1;
-+	# default to this if we are not rearranging (tells the download chunk loop where to stop - i.e. EOF instead of end of mdat atom)
-+	my $moov_start = $download_len + 1;
- 	my $header;
- 	if ($rearrange) {
- 		# Get ftyp+wide header etc
- 		$mdat_start = 0x1c;
- 		my $buffer = download_block(undef, $url_2, $ua, 0, $mdat_start + 4);
- 		# Get bytes upto (but not including) mdat atom start -> $header
--		$header = download_block(undef, $url_2, $ua, 0, $mdat_start - 1, $file_len);
--
-+		$header = substr($buffer, 0, $mdat_start);
-+		
- 		# Detemine moov start
--		# Get mdat_end_offset_chars from downloaded block
--		my $mdat_end_offset_chars = substr($buffer, $mdat_start, 4);
--		my $mdat_end_offset = bytestring_to_int($mdat_end_offset_chars);
--		logger "DEBUG: mdat_end_offset = ".get_hex($mdat_end_offset_chars)." = $mdat_end_offset\n" if $opt{debug};
--		logger "DEBUG: mdat_end_offset (decimal) = $mdat_end_offset\n" if $opt{debug};
-+		# Get mdat_length_chars from downloaded block
-+		my $mdat_length_chars = substr($buffer, $mdat_start, 4);
-+		my $mdat_length = bytestring_to_int($mdat_length_chars);
-+		logger "DEBUG: mdat_length = ".get_hex($mdat_length_chars)." = $mdat_length\n" if $opt{debug};
-+		logger "DEBUG: mdat_length (decimal) = $mdat_length\n" if $opt{debug};
- 		# The MOOV box starts one byte after MDAT box ends
--		$moov_start = $mdat_start + $mdat_end_offset;
--
--
--		## scan 2nd level atoms in moov atom until we get stco atom(s)
--		# We can skip first 8 bytes (moov atom header)
--		#my $i = 8;
--		#while( $i < $moov_length - 4 ) {
--		#  my $atom_len = bytestring_to_int( substr($moovdata, $i, 4) );
--		#  my $atom_name = substr($moovdata, $i+4, 4);
--		#  logger "Parsing atom: $atom_name, length: $atom_len\n";
--		#  # Increment $i by atom_len to get next atom
--		#  $i += $atom_len;
--		#}
-+		$moov_start = $mdat_start + $mdat_length;
- 	}
- 
- 	# If we have partial content and wish to stream, resume the download & spawn off STDOUT from existing file start 
- 	# Sanity check - we cannot support downloading of partial content if we're streaming also. 
- 	if ( $opt{stdout} && (! $opt{nowrite}) && -f $file ) {
- 		logger "WARNING: Partially downloaded file exists, streaming will start from the beginning of the programme\n";
--		# Don't do usual streaming code
--		$opt{stdout} = 0;
-+		# Don't do usual streaming code - also force all messages to go to stderr
-+		delete $opt{stdout};
-+		$opt{stderr} = 1;
- 		$childpid = fork();
- 		if (! $childpid) {
- 			# Child starts here
-@@ -2205,15 +2863,15 @@
- 	my $fh = open_file_append($file);
- 
- 	# If the partial file already exists, then resume from the correct mdat/download offset
--	my $restart_offset = $mdat_start;
-+	my $restart_offset = 0;
- 	my $moovdata;
- 	my $moov_length = 0;
- 
- 	if ($rearrange) {
- 		# if cookie fails then trigger a retry after deleting cookiejar
--		# Determine moov atom length so we can work out if the partially downloaded file has the moov atom in it already
-+		# Determine orginal moov atom length so we can work out if the partially downloaded file has the moov atom in it already
- 		$moov_length = bytestring_to_int( download_block( undef, $url_2, $ua, $moov_start, $moov_start+3 ) );
--		logger "INFO: moov atom length = $moov_length                          \n" if $opt{verbose};
-+		logger "INFO: original moov atom length = $moov_length                          \n" if $opt{verbose};
- 		# Sanity check this moov length - chances are that were being served up a duff file if this is > 10% of the file size or < 64k
- 		if ( $moov_length > (${moov_start}/9.0) || $moov_length < 65536 ) {
- 			logger "WARNING: Bad file download, deleting cookie                 \n";
-@@ -2222,33 +2880,73 @@
- 			unlink $file;
- 			return 'retry';
- 		}
--	}
--
--	# If we have a too-small-sized file and not stdout and not no-write then this is a partial download
--	if (-f $file && (! $opt{stdout}) && (! $opt{nowrite}) && stat($file)->size > ($moov_length+$mdat_start) ) {
--		# Calculate new start offset (considering that we've put moov first in file)
--		$restart_offset = stat($file)->size - $moov_length;
--		logger "INFO: Resuming download from $restart_offset                        \n";
--	}
- 
--	if ($rearrange) {
-+		# we still need an accurate moovlength for the already downloaded moov atom for resume restart_offset.....
- 		# If we have no existing file, a file which doesn't yet even have the moov atom, or using stdout (or no-write option)
--		if ( $opt{stdout} || $opt{nowrite} || stat($file)->size < ($moov_length+$mdat_start) ) {
-+		# (allow extra 1k on moov_length for metadata when testing)
-+		if ( $opt{stdout} || $opt{nowrite} || stat($file)->size < ($moov_length+$mdat_start+1024) ) {
- 			# get moov chunk into memory
--			$moovdata = download_block( undef, $url_2, $ua, $moov_start, (${file_len}-1) );
-+			$moovdata = download_block( undef, $url_2, $ua, $moov_start, (${download_len}-1) );
-+
-+			# Create new udta atom with child atoms for metadata
-+			my $udta_new = create_qt_atom('udta',
-+				create_qt_atom( chr(0xa9).'nam', $prog{$pid}{name}.' - '.$prog{$pid}{episode}, 'string' ).
-+				create_qt_atom( chr(0xa9).'alb', $prog{$pid}{name}, 'string' ).
-+				create_qt_atom( chr(0xa9).'trk', $prog{$pid}{episode}, 'string' ).
-+				create_qt_atom( chr(0xa9).'aut', $prog{$pid}{channel}, 'string' ).
-+				create_qt_atom( chr(0xa9).'ART', $prog{$pid}{channel}, 'string' ).
-+				create_qt_atom( chr(0xa9).'des', $prog{$pid}{desc}, 'string' ).
-+				create_qt_atom( chr(0xa9).'cmt', 'Downloaded with get_iplayer', 'string' ).
-+				create_qt_atom( chr(0xa9).'req', 'QuickTime 6.0 or greater', 'string' ).
-+				create_qt_atom( chr(0xa9).'day', (localtime())[5] + 1900, 'string' )
-+			);
-+			# Insert new udta atom over the old one and get the new $moov_length (and update moov atom size field)
-+			replace_moov_udta_atom ( $udta_new, $moovdata );
-+
- 			# Process the moov data so that we can relocate it (change the chunk offsets that are absolute)
-+			# Also update moov+_length to be accurate after metadata is added etc
- 			$moov_length = relocate_moov_chunk_offsets( $moovdata );
--			# write moov atom to file next (yes - were rearranging the file - moov+header+mdat - not header+mdat+moov)
--			logger "INFO: Appending moov+ftype+wide atoms to $file\n" if $opt{verbose};
--			# Write moov atom
--			print $fh $moovdata if ! $opt{nowrite};
--			print STDOUT $moovdata if $opt{stdout};
-+			logger "INFO: New moov atom length = $moov_length                          \n" if $opt{verbose};
-+			# write moov atom to file next (yes - were rearranging the file - header+moov+mdat - not header+mdat+moov)
-+			logger "INFO: Appending ftype+wide+moov atoms to $file\n" if $opt{verbose};
- 			# Write header atoms (ftyp, wide)
- 			print $fh $header if ! $opt{nowrite};
- 			print STDOUT $header if $opt{stdout};
-+			# Write moov atom
-+			print $fh $moovdata if ! $opt{nowrite};
-+			print STDOUT $moovdata if $opt{stdout};
-+			# If were not resuming we want to only start the download chunk loop from mdat_start 
-+			$restart_offset = $mdat_start;
-+		}
-+
-+		# Get accurate moov_length from file (unless stdout or nowrite options are specified)
-+		# Assume header+moov+mdat atom layout
-+		if ( (! $opt{stdout}) && (! $opt{nowrite}) && stat($file)->size > ($moov_length+$mdat_start) ) {
-+				logger "INFO: Getting moov atom length from partially downloaded file $file\n" if $opt{verbose};
-+				if ( ! open( MOOVDATA, "< $file" ) ) {
-+					logger "ERROR: Cannot Read partially downloaded file\n";
-+					return 4;
-+				}
-+				my $data;
-+				seek(MOOVDATA, $mdat_start, 0);
-+				if ( read(MOOVDATA, $data, 4, 0) != 4 ) {
-+					logger "ERROR: Cannot Read moov atom length from partially downloaded file\n";
-+					return 4;
-+				}
-+				close MOOVDATA;
-+				# Get moov atom size from file
-+				$moov_length = bytestring_to_int( substr($data, 0, 4) );
-+				logger "INFO: moov atom length (from partially downloaded file) = $moov_length                          \n" if $opt{verbose};
- 		}
- 	}
- 
-+	# If we have a too-small-sized file (greater than moov_length+mdat_start) and not stdout and not no-write then this is a partial download
-+	if (-f $file && (! $opt{stdout}) && (! $opt{nowrite}) && stat($file)->size > ($moov_length+$mdat_start) ) {
-+		# Calculate new start offset (considering that we've put moov first in file)
-+		$restart_offset = stat($file)->size - $moov_length;
-+		logger "INFO: Resuming download from $restart_offset                        \n";
-+	}
-+
- 	# Create symlink if required
- 	if ( $opt{symlink} ) {
- 		# remove old symlink
-@@ -2273,16 +2971,15 @@
- 			$e = $s + $chunk_size - 1;
- 		}
- 		# Get block from URL and append to $file
--		if ( download_block($file, $url_2, $ua, $s, $e, $file_len, $fh ) ) {
-+		if ( download_block($file, $url_2, $ua, $s, $e, $download_len, $fh ) ) {
- 			logger "ERROR: Could not download block $s - $e from $file\n\n";
--			return 9;
-+			return 'retry';
- 		}
- 	}
- 
- 	# end marker
- 	my $end_time = time();
- 
--	# Should now be able to concatenate header.block + mdat.block + moov.block to get movie!
- 	# Calculate average speed, duration and total bytes downloaded
- 	logger sprintf("INFO: Downloaded %.2fMB in %s at %5.0fkbps to %s\n", 
- 		($moov_start - 1 - $restart_offset) / (1024.0 * 1024.0),
-@@ -2292,57 +2989,217 @@
- 
- 	# Moving file into place as complete (if not stdout)
- 	move($file, $file_done) if ! $opt{stdout};
-+
-+	# Re-symlink file
-+	if ( $opt{symlink} ) {
-+		# remove old symlink
-+		unlink $file_symlink if -l $file_symlink;
-+		symlink $file_done, $file_symlink;
-+		logger "INFO: Created symlink from '$file_symlink' -> '$file_done'\n" if $opt{verbose};
-+	}
-+	$prog{$pid}{mode} = 'iphone';
- 	return 0;
- }
- 
- 
- 
--sub download_h264_rtmp_stream {
--        my ( $ua, $url_2, $prog_url, $file, $file_done, $file_symlink ) = @_;
--        my $file_flv = $file; # .'.flv';
-+# Actually do the RTMP stream downloading
-+sub download_stream_rtmp {
-+	my ( $ua, $url_2, $pid, $mode, $application, $tcurl, $authstring, $swfurl, $file, $file_done, $file_symlink ) = @_;
-+	my $file_tmp;
-+	my $cmd;
-+	
-+	if ( $opt{raw} ) {
-+		$file_tmp = $file;
-+	} else {
-+		$file_tmp = $file.'.flv'
-+	}
- 
--	logger "INFO: url: $url_2, prog_url: $prog_url, file: $file, file_done: $file_done\n" if $opt{verbose};
-+	# Remove failed file download (below a certain size) - hack to get around rtmpdump not returning correct exit code
-+	if ( -f $file_tmp && stat($file_tmp)->size < $min_download_size ) {
-+		unlink( $file_tmp );
-+	}
-+		
-+	logger "INFO: RTMP_URL: $url_2, tcUrl: $tcurl, application: $application, authString: $authstring, swfUrl: $swfurl, file: $file, file_done: $file_done\n" if $opt{verbose};
- 
- 	# Create symlink if required
- 	if ( $opt{symlink} ) {
- 		# remove old symlink
- 		unlink $file_symlink if -l $file_symlink;
--		symlink $file_flv, $file_symlink;
--		logger "INFO: Created symlink from '$file_symlink' -> '$file_flv'\n" if $opt{verbose};
-+		symlink $file_tmp, $file_symlink;
-+		logger "INFO: Created symlink from '$file_symlink' -> '$file_tmp'\n" if $opt{verbose};
- 	}
-+	$cmd = "$rtmpdump --resume --rtmp \"$url_2\" --auth \"$authstring\" --swfUrl \"$swfurl\" --tcUrl \"$tcurl\" --app \"$application\" -o \"$file_tmp\" >&2";
-+	logger "\n\nINFO: Command: $cmd\n" if $opt{verbose};
-+	my $return = system($cmd);
-+	# Hack to get around rtmpdump prentending to fail on successful flash downloads
-+	if ( (! -f $file_tmp) || ($return && -f $file_tmp && stat($file_tmp)->size < $min_download_size) ) {
-+		logger "\n\nINFO: Command: $cmd\n" if $opt{verbose};
-+		logger "\nWARNING: Failed to download file $file_tmp via RTMP\n";
-+		unlink $file_tmp;
-+		return 'next';
-+	}
-+	
-+	# Retain raw flv format if required
-+	if ( $opt{raw} ) {
-+		move($file_tmp, $file_done) if ! $opt{stdout};
-+		return 0;
- 
--	my $cmd = "$rtmpdump --rtmp \"$url_2\" --pageUrl \"$prog_url\" --swfUrl \"http://www.bbc.co.uk/emp/9player.swf?revision=6928_7030\" --tcUrl \"rtmp://bbciplayertokfs.fplive.net:80/bbciplayertok\" --app \"bbciplayertok\" -o \"$file_flv\" >&2";
--	#my $cmd2 = "$ffmpeg -i \"$file_flv\" -vcodec copy -acodec copy -f mp4 -y \"$file\" >&2";
--	#my $cmd2 = "$mencoder -oac copy -ovc copy -o \"$file\" \"$file_flv\" >&2";
-+	# Convert flv to mp3 for flash audio
-+	} elsif ( $mode eq 'flashaudio' ) {
-+		# We could do id3 tagging here but id3v2 does this later anyway
-+		$cmd = "$ffmpeg -i \"$file_tmp\" -vn -acodec copy -y \"$file\" >&2";
- 
--	# logger "\n\nINFO: Command1: $cmd\nINFO: Command2: $cmd2\n\n" if $opt{verbose};
--	if ( system($cmd) ) {
--		logger "\nWARNING: Failed to download file $file via RTMP\n";
--		return 1;
-+	# Convert video flv to mp4/avi if required
-+	} else {
-+		$cmd = "$ffmpeg $ffmpeg_opts -i \"$file_tmp\" -vcodec copy -acodec copy -f $prog{$pid}{ext} -y \"$file\" >&2";
-+	}
-+
-+	logger "\n\nINFO: Command: $cmd\n\n" if $opt{verbose};
-+	# Run flv conversion and delete source file on success
-+	if ( (! system($cmd)) && -f $file && stat($file)->size > $min_download_size ) {
-+			unlink( $file_tmp );
-+
-+	# If the ffmpeg conversion failed, remove the failed-converted file attempt - move the file as done anyway
-+	} else {
-+		logger "WARNING: flv conversion failed - retaining flv file\n";
-+		unlink $file;
-+		$file = $file_tmp;
-+		$file_done = $file_tmp;
-+	}
-+	# Moving file into place as complete (if not stdout)
-+	move($file, $file_done) if ! $opt{stdout};
-+	
-+	# Re-symlink file
-+	if ( $opt{symlink} ) {
-+		# remove old symlink
-+		unlink $file_symlink if -l $file_symlink;
-+		symlink $file_done, $file_symlink;
-+		logger "INFO: Created symlink from '$file_symlink' -> '$file_done'\n" if $opt{verbose};
-+	}
-+
-+	logger "INFO: Downloaded $file_done\n";
-+	$prog{$pid}{mode} = $mode;
-+	return 0;
-+}
-+
-+
-+
-+# Actually do the MMS video stream downloading
-+sub download_stream_mms_video {
-+	my ( $ua, $urls, $file, $file_done, $pid ) = @_;
-+	my $file_tmp;
-+	my $cmd;
-+	my $null;
-+	my @url_list = split /\|/, $urls;
-+	my @file_tmp_list;
-+	my %threadpid;
-+		
-+	logger "INFO: MMS_URLs: ".(join ', ', @file_tmp_list).", file: $file, file_done: $file_done\n" if $opt{verbose};
-+
-+	# Start marker
-+	my $start_time = time();
-+	# Download each mms url (multi-threaded to download in parallel)
-+	my $file_part_prefix = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}_part";
-+	for ( my $count = 0; $count <= $#url_list; $count++ ) {
-+
-+		# Create temp download filename
-+		$file_tmp = $file_part_prefix.($count+1).".asf";
-+		$file_tmp_list[$count] = $file_tmp;
-+		$null = " 2>/dev/null " if (! $opt{verbose}) && (! $opt{debug});
-+		$cmd = "$mplayer -dumpstream \"$url_list[$count]\" -dumpfile \"$file_tmp\" $null >&2 </dev/null";
-+		logger "\n\nINFO: Command: $cmd\n" if $opt{verbose};
-+
-+		my $childpid = fork();
-+		if (! $childpid) {
-+			# Child starts here
-+			logger "INFO: Downloading file $file_tmp\n";
-+			if ( system($cmd) ) {
-+				logger "\nWARNING: Failed to download file $file_tmp via MMS\n";
-+				exit 1;
-+			}
-+			logger "INFO: Download thread has completed for file $file_tmp\n";
-+			exit 0;
-+		}
-+		# Create a hash of process_id => 'count'
-+		$threadpid{$childpid} = $count;
-+	}	
-+	# Wait for all threads to complete
-+	$| = 1;
-+	# Autoreap zombies
-+	$SIG{CHLD}='IGNORE';
-+	my $done = 0;
-+	while (keys %threadpid) {
-+		my @sizes;
-+		my $total_size = 0;
-+		my $total_size_new = 0;
-+		my $format = "Threads: ";
-+		sleep 1;
-+		#logger "DEBUG: ProcessIDs: ".(join ',', keys %threadpid)."\n";
-+		for my $procid (sort keys %threadpid) {
-+			my $size = 0;
-+			# Is this child still alive?
-+			if ( kill 0 => $procid ) {
-+				logger "DEBUG Thread $threadpid{$procid} still alive ($file_tmp_list[$threadpid{$procid}])\n" if $opt{debug};
-+				# Build the status string
-+				$format .= "%d) %.3fMB   ";
-+				$size = stat($file_tmp_list[$threadpid{$procid}])->size if -f $file_tmp_list[$threadpid{$procid}];
-+				push @sizes, $threadpid{$procid}+1, $size/(1024.0*1024.0);
-+				$total_size_new += $size;
-+			} else {
-+				$size = stat($file_tmp_list[$threadpid{$procid}])->size if -f $file_tmp_list[$threadpid{$procid}];
-+				# end marker
-+				my $end_time = time();
-+				# Calculate average speed, duration and total bytes downloaded
-+				logger sprintf("INFO: Thread #%d Downloaded %.2fMB in %s at %5.0fkbps to %s\n", 
-+					($threadpid{$procid}+1),
-+					$size / (1024.0 * 1024.0),
-+					sprintf("%02d:%02d:%02d", ( gmtime($end_time - $start_time))[2,1,0] ), 
-+					$size / ($end_time - $start_time) / 1024.0 * 8.0,
-+					$file_tmp_list[$threadpid{$procid}] );
-+				# Remove from thread test list
-+				delete $threadpid{$procid};
-+			}
-+		}
-+		$format .= " downloaded (%.0fkbps)        \r";
-+		logger sprintf $format, @sizes, ($total_size_new - $total_size) / (time() - $start_time) / 1024.0 * 8.0;
- 	}
--	# Only convert to mp4 if we have mencoder in path
--	# Disable rtmp mode if rtmpdump does not exist
--	if ( ! exists_in_path($ffmpeg)) {
--		logger "\nWARNING: $ffmpeg does not exist - not converting flv file to mp4\n";
--	#} else {
--		# Run flv conversion and delete source file on success
--		#if ( ! system($cmd2) ) {
--		#	unlink( $file_flv );
--		#} else {
--		#	logger "ERROR: flv to mp4 conversion failed\n";
--		#	return 2;
--		#}
--		# Moving file into place as complete (if not stdout)
--		#move($file, $file_done) if ! $opt{stdout};
-+	logger "INFO: All download threads completed\n";	
-+	# Unset autoreap
-+	delete $SIG{CHLD};
-+	# Retain raw format if required
-+	if ( $opt{raw} ) {
-+		return 0;
- 	}
-+
-+#	# Convert video asf to mp4 if required - need to find a suitable converter...
-+#	} else {
-+#		# Create part of cmd that specifies each partial file
-+#		my $filestring;
-+#		$filestring .= " -i \"$_\" " for (@file_tmp_list);
-+#		$cmd = "$ffmpeg $ffmpeg_opts $filestring -vcodec copy -acodec copy -f $prog{$pid}{ext} -y \"$file\" >&2";
-+#	}
-+#
-+#	logger "\n\nINFO: Command: $cmd\n\n" if $opt{verbose};
-+#	# Run asf conversion and delete source file on success
-+#	if ( ! system($cmd) ) {
-+#		unlink( @file_tmp_list );
-+#	} else {
-+#		logger "ERROR: asf conversion failed - retaining files ".(join ', ', @file_tmp_list)."\n";
-+#		return 2;
-+#	}
-+#	# Moving file into place as complete (if not stdout)
-+#	move($file, $file_done) if ! $opt{stdout};
-+
-+	$prog{$pid}{mode} = 'itv';
- 	return 0;
- }
- 
- 
- 
- # Actually do the N95 h.264 downloading
--sub download_h264_low_stream {
--	my ( $ua, $url_2, $file, $file_done ) = @_;
-+sub download_stream_h264_low {
-+	my ( $ua, $url_2, $file, $file_done, $pid, $mode ) = @_;
- 
- 	# Change filename extension
- 	$file =~ s/mov$/mpg/gi;
-@@ -2353,7 +3210,7 @@
- 		logger "INFO: Downloading Low Quality H.264 stream\n";
- 		my $cmd = "$vlc $vlc_opts --sout file/ts:${file} $url_2 1>&2";
- 		if ( system($cmd) ) {
--			return 2;
-+			return 'next';
- 		}
- 
- 	# to STDOUT
-@@ -2361,19 +3218,21 @@
- 		logger "INFO: Streaming Low Quality H.264 stream to stdout\n";
- 		my $cmd = "$vlc $vlc_opts --sout file/ts:- $url_2 1>&2";
- 		if ( system($cmd) ) {
--			return 2;
-+			return 'next';
- 		}	
- 	}
- 	logger "INFO: Downloaded $file_done\n";
- 	# Moving file into place as complete (if not stdout)
- 	move($file, $file_done) if ! $opt{stdout};
-+
-+	$prog{$pid}{mode} = $mode;
- 	return 0;
- }
- 
- 
- 
- # Actually do the rtsp downloading
--sub download_rtsp_stream {
-+sub download_stream_rtsp {
- 	my ( $ua, $url, $file, $file_done, $file_symlink, $pid ) = @_;
- 	my $childpid;
- 
-@@ -2389,7 +3248,7 @@
- 	# Create ID3 tagging options for lame (escape " for shell)
- 	my ( $id3_name, $id3_episode, $id3_desc, $id3_channel ) = ( $prog{$pid}{name}, $prog{$pid}{episode}, $prog{$pid}{desc}, $prog{$pid}{channel} );
- 	$id3_name =~ s|"|\"|g for ($id3_name, $id3_episode, $id3_desc, $id3_channel);
--	$lame_opts .= "--ignore-tag-errors --ty ".( (localtime())[5] + 1900 )." --tl \"$id3_name\" --tt \"$id3_episode\" --ta \"$id3_channel\" --tc \"$id3_desc\" ";
-+	$lame_opts .= " --ignore-tag-errors --ty ".( (localtime())[5] + 1900 )." --tl \"$id3_name\" --tt \"$id3_episode\" --ta \"$id3_channel\" --tc \"$id3_desc\" ";
- 
- 	# Use post-download transcoding using lame if namedpipes are not supported (i.e. ActivePerl/Windows)
- 	# (Fallback if no namedpipe support and raw/wav not specified)
-@@ -2402,14 +3261,14 @@
- 		logger "INFO: Downloading wav format (followed by transcoding)\n";
- 		$cmd = "$mplayer $mplayer_opts -cache 128 -bandwidth $bandwidth -vc null -vo null -ao pcm:waveheader:fast:file=\"${file}.wav\" \"$url\" 1>&2";
- 		if ( system($cmd) ) {
--			return 2;
-+			return 'next';
- 		}
- 		# Transcode
- 		logger "INFO: Transcoding ${file}.wav\n";
- 		$cmd = "$lame $lame_opts \"${file}.wav\" \"${file}.mp3\" 1>&2";
- 		logger "DEGUG: Running $cmd\n" if $opt{debug};
--		if ( system($cmd) ) {
--			return 2;
-+		if ( system($cmd) || (-f "${file}.wav" && stat("${file}.wav")->size < $min_download_size) ) {
-+			return 'next';
- 		}
- 		unlink "${file}.wav";
- 		move "${file}.mp3", $file_done;
-@@ -2425,7 +3284,7 @@
- 		my $cmd = "$mplayer $mplayer_opts -cache 128 -bandwidth $bandwidth -vc null -vo null -ao pcm:waveheader:fast:file=\"$file\" \"$url\" 1>&2";
- 		logger "DEGUG: Running $cmd\n" if $opt{debug};
- 		if ( system($cmd) ) {
--			return 2;
-+			return 'next';
- 		}
- 		# Move file to done state
- 		move $file, $file_done if ! $opt{nowrite};
-@@ -2438,7 +3297,7 @@
- 		my $cmd = "$mplayer $mplayer_opts -cache 128 -bandwidth $bandwidth -dumpstream -dumpfile \"$file\" \"$url\" 1>&2";
- 		logger "DEGUG: Running $cmd\n" if $opt{debug};
- 		if ( system($cmd) ) {
--			return 2;
-+			return 'next';
- 		}
- 		# Move file to done state
- 		move $file, $file_done if ! $opt{nowrite};
-@@ -2498,7 +3357,7 @@
- 			if ( system($cmd) ) {
- 				# If we fail then kill off child processes
- 				kill 9, $childpid;
--				return 2;
-+				return 'next';
- 			}
- 		# WAV / mp3 mode
- 		} else {
-@@ -2506,7 +3365,7 @@
- 			if ( system($cmd) ) {
- 				# If we fail then kill off child processes
- 				kill 9, $childpid;
--				return 2;
-+				return 'next';
- 			}
- 		}
- 		# Wait for child processes to prevent zombies
-@@ -2522,13 +3381,14 @@
- 		logger "INFO: Created symlink from '$file_symlink' -> '$file_done'\n" if $opt{verbose};
- 	}
- 
-+	$prog{$pid}{mode} = 'realaudio';
- 	return 0;
- }
- 
- 
- 
- # Actually do the podcast downloading
--sub download_podcast_stream {
-+sub download_stream_podcast {
- 	my ( $ua, $url_2, $file, $file_done, $file_symlink ) = @_;
- 	my $start_time = time();
- 
-@@ -2548,7 +3408,7 @@
- 
- 	if ( download_block($file, $url_2, $ua, $start, undef, undef, $fh) != 0 ) {
- 		logger "ERROR: Download failed\n";
--		return 22;
-+		return 'next';
- 	} else {
- 		# end marker
- 		my $end_time = time();
-@@ -2569,111 +3429,98 @@
- 			logger "INFO: Created symlink from '$file_symlink' -> '$file_done'\n" if $opt{verbose};
- 		}
- 	}
-+
-+	$prog{$url_2}{mode} = 'podcast';
- 	return 0;
- }
- 
- 
- 
- # Get streaming iphone URL
--sub get_iphone_stream_download_url {
--		my $ua = shift;
--		my $pid = shift;
--
--		# Create url with appended 6 digit random number
--		my $url_1 = ${iphone_download_prefix}.'/'.${pid}.'?'.(sprintf "%06.0f", 1000000*rand(0)).'%20';
--		logger "INFO: media stream download URL = $url_1\n" if $opt{verbose};
--		
--		# Stage 2: e.g. "Location: http://download.iplayer.bbc.co.uk/iplayer_streaming_http_mp4/121285241910131406.mp4?token=iVXexp1yQt4jalB2Hkl%2BMqI25nz2WKiSsqD7LzRmowrwXGe%2Bq94k8KPsm7pI8kDkLslodvHySUyU%0ApM76%2BxEGtoQTF20ZdFjuqo1%2B3b7Qmb2StOGniozptrHEVQl%2FYebFKVNINg%3D%3D%0A"
--		logger "\rGetting iplayer download URL         " if ! $opt{verbose};
--		my $h = new HTTP::Headers(
--			'User-Agent'	=> $user_agent{coremedia},
--			'Accept'	=> '*/*',
--			'Range'		=> 'bytes=0-1',
--		);
--		my $req = HTTP::Request->new ('GET', $url_1, $h);
--		# send request
--		my $res = $ua->request($req);
--		# Get resulting Location header (i.e. redirect URL)
--		my $url_2 = $res->header("location");
--		if ( ! $res->is_redirect ) {
--			logger "ERROR: Failed to get redirect from iplayer site\n\n";
--			return '';
--		}
--		# Extract redirection Location URL
--		$url_2 =~ s/^Location: (.*)$/$1/g;
--		# If we get a Redirection containing statuscode=404 then this prog is not yet ready
--		if ( $url_2 =~ /statuscode=404/ ) {
--			logger "\rERROR: Programme is not yet ready for download\n";
--			return '';
--		}
--
--		return $url_2;
--}
--
--
-+sub get_stream_url_iphone {
-+	my $ua = shift;
-+	my $pid = shift;
- 
--# Get streaming audio URL (Real => rtsp)
--#<media kind="audio"
--#        type="audio/real"
--#        encoding="real"  >
--#        <connection
--#                priority="10"
--#                kind="sis"
--#                server="http://www.bbc.co.uk"
--#                identifier="/radio/aod/playlists/gs/5d/c0/0b/0900_bbc_radio_two"
--#                href="http://www.bbc.co.uk/radio/aod/playlists/gs/5d/c0/0b/0900_bbc_radio_two.ram"
--#        />
--#</media>
--# OR
--#<media kind=""
--#        type="audio/real"
--#        encoding="real"  >
--#        <connection
--#                priority="10"
--#                kind="edgesuite"
--#                server="http://http-ws.bbc.co.uk.edgesuite.net"
--#                identifier="/generatecssram.esi?file=/worldservice/css/nb/410591221152760.ra"
--#                href="http://http-ws.bbc.co.uk.edgesuite.net/generatecssram.esi?file=/worldservice/css/nb/410591221152760.ra"
--#        />
--#</media>
--#
--sub get_audio_stream_download_url {
--		my $ua = shift;
--		my $url_1 = shift;
--		my $url_2;
-+	# Create url with appended 6 digit random number
-+	my $url_1 = ${iphone_download_prefix}.'/'.${pid}.'?'.(sprintf "%06.0f", 1000000*rand(0)).'%20';
-+	logger "INFO: media stream download URL = $url_1\n" if $opt{verbose};
- 		
--		logger "\rGetting iplayer download URL         " if ! $opt{verbose};
--		my $h = new HTTP::Headers(
--			'User-Agent'	=> $user_agent{coremedia},
--			'Accept'	=> '*/*',
--			'Range'		=> 'bytes=0-',
--		);
--		my $req = HTTP::Request->new ('GET', $url_1, $h);
--		# send request
--		my $res = $ua->request($req);
--		# Get resulting content 
--		my $content = $res->content;
--		# Flatten
--		$content =~ s/\n/ /g;
--		if ( ! $res->is_success ) {
--			logger "ERROR: Failed to get audio url from iplayer site\n\n";
--			return '';
--		}
--		# If we get a Redirection containing statuscode=404 then this prog is not yet ready
--		if ( $content =~ /statuscode=404/ ) {
--			logger "\rERROR: Programme is not yet ready for download\n";
--			return '';
--		}
--		# extract ram URL
--		$url_2 = $2 if $content =~ m{<media kind="(|audio)"\s*type="audio/real".*href="(.+?)"\s*};
--
--		# If we cannot see 'encoding="real"...' then we don't have real audio transcoded format then skip
--		if ( ! $url_2 ) {
--			logger "\rERROR: Programme is not yet ready for download in RealAudio format\n";
--			return '';
--		}
--
--		return $url_2;
-+	# Stage 2: e.g. "Location: http://download.iplayer.bbc.co.uk/iplayer_streaming_http_mp4/121285241910131406.mp4?token=iVXexp1yQt4jalB2Hkl%2BMqI25nz2WKiSsqD7LzRmowrwXGe%2Bq94k8KPsm7pI8kDkLslodvHySUyU%0ApM76%2BxEGtoQTF20ZdFjuqo1%2B3b7Qmb2StOGniozptrHEVQl%2FYebFKVNINg%3D%3D%0A"
-+	logger "\rGetting iplayer download URL         " if (! $opt{verbose}) && ! $opt{streaminfo};
-+	my $h = new HTTP::Headers(
-+		'User-Agent'	=> $user_agent{coremedia},
-+		'Accept'	=> '*/*',
-+		'Range'		=> 'bytes=0-1',
-+	);
-+	my $req = HTTP::Request->new ('GET', $url_1, $h);
-+	# send request (use simple_request here because that will not allow redirects)
-+	my $res = $ua->simple_request($req);
-+	# Get resulting Location header (i.e. redirect URL)
-+	my $url_2 = $res->header("location");
-+	if ( ! $res->is_redirect ) {
-+		logger "ERROR: Failed to get redirect from iplayer site\n\n";
-+		return '';
-+	}
-+	# Extract redirection Location URL
-+	$url_2 =~ s/^Location: (.*)$/$1/g;
-+	# If we get a Redirection containing statuscode=404 then this prog is not yet ready
-+	if ( $url_2 =~ /statuscode=404/ ) {
-+		logger "\rERROR: Programme is not yet ready for download\n" if $opt{verbose};
-+		return '';
-+	}
-+
-+	return $url_2;
-+}
-+
-+
-+
-+sub get_stream_url_itv {
-+	my ( $ua, $pid ) = ( @_ );
-+
-+	my ( $response, $url_1, $url_2, $url_3, $url_4 );
-+	my $part;
-+	my $duration;
-+	my $filename;
-+	my @url_list;
-+
-+	# construct stage 1 request url
-+	$url_1 = 'http://www.itv.com/_app/video/GetMediaItem.ashx?vodcrid=crid://itv.com/'.$pid.'&bitrate=384&adparams=SITE=ITV/AREA=CATCHUP.VIDEO/SEG=CATCHUP.VIDEO%20HTTP/1.1';
-+
-+	# Extract '<LicencePlaylist>(.+?) HTTP/1.1</LicencePlaylist>'
-+	logger "INFO: ITV Video Stage 1 URL: $url_1\n" if $opt{verbose};
-+	$response = request_url_retry($ua, $url_1, 2, '', '');
-+	logger "DEBUG: Response data: $response\n" if $opt{debug};
-+	$url_2 = $1 if $response =~ m{<LicencePlaylist>(.+?) HTTP/1.1</LicencePlaylist>};
-+	# replace '&amp;' with '&' and append '%20HTTP/1.1'
-+	$url_2 =~ s/&amp;/&/g;
-+	$url_2 .= '%20HTTP/1.1';
-+	logger "INFO: ITV Video Stage 2 URL: $url_2\n" if $opt{verbose};
-+	$response = request_url_retry($ua, $url_2, 2, '', '');
-+	logger "DEBUG: Response data: $response\n" if $opt{debug};
-+
-+	# Extract hrefs and names. There are multiple entries for parts of prog (due to ads):
-+	# e.g. <asx><Title>Doctor Zhivago</Title><EntryRef href="HTTP://SAM.ITV.COM/XTSERVER/ACC_RANDOM=1231194223/SITE=ITV/AREA=CATCHUP.VIDEO/SEG=CATCHUP.VIDEO HTTP/1.1/SOURCE=CATCH.UP/GENRE=DRAMA/PROGNAME=DOCTOR.ZHIVAGO/PROGID=33105/SERIES=DOCTOR.ZHIVAGO/EPNUM=/EPTITLE=/BREAKNUM=0/ADPOS=1/PAGEID=01231194223/DENTON=0/CUSTOMRATING=/TOTDUR=90/PREDUR=0/POSDUR=905/GENERIC=6e0536bf-7883-4aaa-9230-94ecc4aea403/AAMSZ=VIDEO" /><EntryRef href="HTTP://SAM.ITV.COM/XTSERVER/ACC_RANDOM=1231194223/SITE=ITV/AREA=CATCHUP.VIDEO/SEG=CATCHUP.VIDEOHTTP/1.1/SOURCE=CATCH.UP/GENRE=DRAMA/PROGNAME=DOCTOR.ZHIVAGO/PROGID=33105/SERIES=DOCTOR.ZHIVAGO/EPNUM=/EPTITLE=/BREAKNUM=0/ADPOS=LAST/PAGEID=01231194223/DENTON=0/CUSTOMRATING=/TOTDUR=90/PREDUR=0/POSDUR=905/GENERIC=6e0536bf-7883-4aaa-9230-94ecc4aea403/AAMSZ=VIDEO" />
-+	$prog{$pid}{name} = $1 if $response =~ m{<Title>(.+?)<\/Title>};
-+	for my $entry (split /<Entry><ref\s+href=/, $response) {
-+		logger "DEBUG: Entry data: $entry\n" if $opt{debug};
-+		$entry .= '<Entry><ref href='.$entry;
-+
-+		( $url_3, $part, $filename, $duration ) = ( $1, $2, $3, $4 ) if $entry =~ m{<Entry><ref\s+href="(.+?)"\s+\/><param\s+value="true"\s+name="Prebuffer"\s+\/>\s*<PARAM\s+NAME="PrgPartNumber"\s+VALUE="(.+?)"\s*\/><PARAM\s+NAME="FileName"\s+VALUE="(.+?)"\s*\/><PARAM\s+NAME="PrgLength"\s+VALUE="(.+?)"\s*\/>};
-+		next if not $url_3;
-+		# Replace '&amp;' with '&' in url
-+		$url_3 =~ s/&amp;/&/g;
-+		logger "INFO: ITV Video Name: $part\n";
-+
-+		logger "INFO: ITV Video Stage 3 URL: $url_3\n" if $opt{verbose};
-+		$entry = request_url_retry($ua, $url_3, 2, '', '');
-+		logger "DEBUG: Response data: $entry\n" if $opt{debug};
-+
-+		# Extract mms (replace 'http' with 'mms') url: e.g.: Ref1=http://itvbrdbnd.wmod.llnwd.net/a1379/o21/ucontent/2007/6/22/1549_384_1_2.wmv?MSWMExt=.asf
-+		chomp( $url_4 = 'mms'.$1 ) if $entry =~ m{Ref1=http(.+?)[\r\n]+};
-+		logger "INFO: ITV Video URL: $url_4\n" if $opt{verbose};
-+		push @url_list, $url_4;
-+	}
-+	return @url_list;
- }
- 
- 
-@@ -2711,7 +3558,7 @@
- 	# Change all the chunk offsets in moov->stco atoms and add moov_length to them all
- 	# get moov atom length
- 	my $moov_length = bytestring_to_int( substr($moovdata, 0, 4) );
--	# Use index() to seatch for a string within a string
-+	# Use index() to search for a string within a string
- 	my $i = -1;
- 	while (($i = index($moovdata, 'stco', $i)) > -1) {
- 
-@@ -2725,10 +3572,11 @@
- 			#logger "chunk_offset @ $i, $j = '".get_hex( substr($moovdata, $j, 4) )."',	$chunk_offset + $moov_length = ";
- 			$chunk_offset += $moov_length;
- 			# write back bytes into $moovdata
--			substr($moovdata, $j+0, 1) = chr( ($chunk_offset >> 24) & 0xFF );
--			substr($moovdata, $j+1, 1) = chr( ($chunk_offset >> 16) & 0xFF );
--			substr($moovdata, $j+2, 1) = chr( ($chunk_offset >>  8) & 0xFF );
--			substr($moovdata, $j+3, 1) = chr( ($chunk_offset >>  0) & 0xFF );
-+			#substr($moovdata, $j+0, 1) = chr( ($chunk_offset >> 24) & 0xFF );
-+			#substr($moovdata, $j+1, 1) = chr( ($chunk_offset >> 16) & 0xFF );
-+			#substr($moovdata, $j+2, 1) = chr( ($chunk_offset >>  8) & 0xFF );
-+			#substr($moovdata, $j+3, 1) = chr( ($chunk_offset >>  0) & 0xFF );
-+			write_msb_value_at_offset( $moovdata, $j, $chunk_offset );
- 			#$chunk_offset = bytestring_to_int( substr($moovdata, $j, 4) );
- 			#logger "$chunk_offset\n";
- 		}
-@@ -2743,6 +3591,86 @@
- 
- 
- 
-+# Replace the moov->udta atom with a new user-supplied one and update the moov atom size
-+# Usage: replace_moov_udta_atom ( $udta_new, $moovdata )
-+sub replace_moov_udta_atom {
-+	my $udta_new = $_[0];
-+	my $moovdata = $_[1];
-+
-+	# get moov atom length
-+	my $moov_length = bytestring_to_int( substr($moovdata, 0, 4) );
-+
-+	# Find the original udta atom start 
-+	# Use index() to search for a string within a string ($i will point at the beginning of the atom)
-+	my $i = index($moovdata, 'udta', -1) - 4;
-+
-+	# determine length of atom (4 bytes preceding the name)
-+	my $udta_len = bytestring_to_int( substr($moovdata, $i, 4) );
-+	logger "INFO: Found udta atom at moov atom offset: $i length $udta_len\n" if $opt{verbose};
-+
-+	# Save the data before the udta atom
-+	my $moovdata_before_udta = substr($moovdata, 0, $i);
-+
-+	# Save the remainder portion of data after the udta atom for later
-+	my $moovdata_after_udta = substr($moovdata, $i, $moovdata - $i + $udta_len);
-+
-+	# Old udta atom should we need it
-+	### my $udta_old = substr($moovdata, $i, $udta_len);
-+
-+	# Create new moov atom
-+	$moovdata = $moovdata_before_udta.$udta_new.$moovdata_after_udta;
-+	
-+	# Recalculate the moov size and insert into moovdata
-+	write_msb_value_at_offset( $moovdata, 0, length($moovdata) );
-+	
-+	# Write $moovdata back to calling string
-+	$_[1] = $moovdata;
-+
-+	return 0;
-+}
-+
-+
-+
-+# Write the msb 4 byte $value starting at $offset into the passed string
-+# Usage: write_msb_value($string, $offset, $value)
-+sub write_msb_value_at_offset {
-+	my $offset = $_[1];
-+	my $value = $_[2];
-+	substr($_[0], $offset+0, 1) = chr( ($value >> 24) & 0xFF );
-+	substr($_[0], $offset+1, 1) = chr( ($value >> 16) & 0xFF );
-+	substr($_[0], $offset+2, 1) = chr( ($value >>  8) & 0xFF );
-+	substr($_[0], $offset+3, 1) = chr( ($value >>  0) & 0xFF );
-+	return 0;
-+}
-+
-+
-+
-+# Returns a string containing an QT atom
-+# Usage: create_qt_atom(<atome name>, <atom data>, ['string'])
-+sub create_qt_atom {
-+	my ($name, $data, $prog_type) = (@_);
-+	if (length($name) != 4) {
-+		logger "ERROR: Inavlid QT atom name length '$name'\n";
-+		exit 1;
-+	}
-+	# prepend string length if this is a string type
-+	if ( $prog_type eq 'string' ) {
-+		my $value = length($data);
-+		$data = '1111'.$data;
-+		# overwrite '1111' with total atom length in 2-byte MSB + 0x0 0x0
-+		substr($data, 0, 1) = chr( ($value >> 8) & 0xFF );
-+		substr($data, 1, 1) = chr( ($value >> 0) & 0xFF );
-+		substr($data, 2, 1) = chr(0);
-+		substr($data, 3, 1) = chr(0);
-+	}
-+	my $atom = '0000'.$name.$data;
-+	# overwrite '0000' with total atom length in MSB
-+	write_msb_value_at_offset( $atom, 0, length($name.$data) + 4 );
-+	return $atom;
-+}
-+
-+
-+
- # Usage download_block($file, $url_2, $ua, $start, $end, $file_len, $fh);
- #  ensure filehandle $fh is open in append mode
- # or, $content = download_block(undef, $url_2, $ua, $start, $end, $file_len);
-@@ -2811,7 +3739,7 @@
- 			$rate = sprintf("%5.0fkbps", (8.0 / 1024.0) * $rate_bps);
- 			$time = sprintf("%02d:%02d:%02d", ( gmtime( ($file_len - $size) / $rate_bps ) )[2,1,0] );
- 		}
--		printf STDERR "%8.2fMB / %.2fMB %s %5.1f%%, %s remaining         \r", 
-+		logger sprintf "%8.2fMB / %.2fMB %s %5.1f%%, %s remaining         \r", 
- 			$size / 1024.0 / 1024.0, 
- 			$file_len / 1024.0 / 1024.0,
- 			$rate,
-@@ -2851,7 +3779,7 @@
- 				$time = sprintf("%02d:%02d:%02d", ( gmtime( ($file_len - $size) / $rate_bps ) )[2,1,0] );
- 			}
- 			# time remaining
--			printf STDERR "%8.2fMB / %.2fMB %s %5.1f%%, %s remaining         \r", 
-+			logger sprintf "%8.2fMB / %.2fMB %s %5.1f%%, %s remaining         \r", 
- 				$size / 1024.0 / 1024.0,
- 				$file_len / 1024.0 / 1024.0,
- 				$rate,
-@@ -2865,7 +3793,7 @@
- 			} else {
- 				$rate = sprintf("%5.0fkbps", (8.0 / 1024.0) * $size / ($timecalled - $now) );
- 			}
--			printf STDERR "%8.2fMB %s         \r", $size / 1024.0 / 1024.0, $rate;
-+			logger sprintf "%8.2fMB %s         \r", $size / 1024.0 / 1024.0, $rate;
- 		}
- 	};
- 
-@@ -2901,6 +3829,19 @@
- 
- 
- 
-+sub create_ua {
-+	my $agent = shift;
-+	my $ua = LWP::UserAgent->new;
-+	$ua->timeout([$lwp_request_timeout]);
-+	$ua->proxy( ['http'] => $proxy_url );
-+	$ua->agent( $user_agent{$agent} );
-+	$ua->conn_cache(LWP::ConnCache->new());
-+	$ua->cookie_jar( HTTP::Cookies->new( file => $cookiejar, autosave => 1, ignore_discard => 1 ) );
-+	return $ua;
-+};	
-+
-+
-+
- # Converts a string of chars to it's HEX representation
- sub get_hex {
-         my $buf = shift || '';
-@@ -2985,11 +3926,7 @@
- sub update_script {
- 	# Get version URL
- 	my $script_file = $0;
--	my $ua = LWP::UserAgent->new;
--	$ua->timeout([$lwp_request_timeout]);
--	$ua->proxy( ['http'] => $proxy_url );
--	$ua->agent( $user_agent{update} );
--	$ua->conn_cache(LWP::ConnCache->new());
-+	my $ua = create_ua('update');
- 	logger "INFO: Current version is $version\n";
- 	logger "INFO: Checking for latest version from linuxcentre.net\n";
- 	my $res = $ua->request( HTTP::Request->new( GET => $version_url ) );
-@@ -3070,10 +4007,8 @@
- 						<video><url id=\"p1\">${pid}.mov<playlist/></url></video>
- 						<info><description>${desc}</description></info>
- 					</movie>\n" if $opt{fxd};
--					my $newtitle = ${title} ;
--					$newtitle =~ s/\&//g ;
- 					print XML "<Stream>
--						<Name>\"$newtitle\"</Name>
-+						<Name>\"${title}\"</Name>
- 						<url>${pid}.mov</url>
- 						<Subtitle></Subtitle>
- 						<Synopsis>${desc}</Synopsis>
-@@ -3294,6 +4229,7 @@
- 	my $pid = shift;
- 	my $metadata;
- 	my $entry3;
-+	my ($name, $episode, $duration, $available, $channel, $expiry, $longdesc, $versions, $guidance, $prog_type, $categories, $player, $thumbnail);
- 
- 	# This URL works for all prog types:
- 	# http://www.bbc.co.uk/iplayer/playlist/${pid}
-@@ -3307,97 +4243,162 @@
- 	# This URL works for tv/radio prog types:
- 	# $prog_feed_url = http://feeds.bbc.co.uk/iplayer/episode/$pid
- 
--	if ( $prog{$pid}{type} =~ /(tv|radio)/i ) {
-+	if ( $prog{$pid}{type} =~ /^(tv|radio)$/i ) {
- 		$entry3 = request_url_retry($ua, $prog_feed_url.$pid, 3, '', '');
- 		decode_entities($entry3);
- 		logger "DEBUG: $prog_feed_url.$pid:\n$entry3\n\n" if $opt{debug};
- 		# Flatten
- 		$entry3 =~ s|\n| |g;
--	}
- 
--	# Entry3 format
--	#<?xml version="1.0" encoding="utf-8"?>                                      
--	#<?xml-stylesheet href="http://www.bbc.co.uk/iplayer/style/rss.css" type="text/css"?>
--	#<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:media="http://search.yahoo.com/mrss/" xml:lang="en-GB">
--	#  <title>BBC iPlayer - Episode Detail: Edith Bowman: 22/09/2008</title>                                                                          
--	#  <subtitle>Sara Cox sits in for Edith with another Cryptic Randomizer.</subtitle>
--	#  <updated>2008-09-29T10:59:45Z</updated>
--	#  <id>tag:feeds.bbc.co.uk,2008:/iplayer/feed/episode/b00djtfh</id>
--	#  <link rel="related" href="http://www.bbc.co.uk/iplayer" type="text/html" />
--	#  <link rel="self" href="http://feeds.bbc.co.uk/iplayer/episode/b00djtfh" type="application/atom+xml" />
--	#  <author>
--	#    <name>BBC</name>
--	#    <uri>http://www.bbc.co.uk</uri>
--	#  </author>
--	#  <entry>
--	#    <title type="text">Edith Bowman: 22/09/2008</title>
--	#    <id>tag:feeds.bbc.co.uk,2008:PIPS:b00djtfh</id>
--	#    <updated>2008-09-15T01:28:36Z</updated>
--	#    <summary>Sara Cox sits in for Edith with another Cryptic Randomizer.</summary>
--	#    <content type="html">
--	#      &lt;p&gt;
--	#        &lt;a href=&quot;http://www.bbc.co.uk/iplayer/episode/b00djtfh?src=a_syn30&quot;&gt;
--	#          &lt;img src=&quot;http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_150_84.jpg&quot; alt=&quot;Edith Bowman: 22/09/2008&quot; /&gt;
--	#        &lt;/a&gt;
--	#      &lt;/p&gt;
--	#      &lt;p&gt;
--	#        Sara Cox sits in for Edith with movie reviews and great new music, plus another Cryptic Randomizer.
--	#      &lt;/p&gt;
--	#    </content>
--	#    <link rel="alternate" href="http://www.bbc.co.uk/iplayer/episode/b00djtfh?src=a_syn31" type="text/html" title="Edith Bowman: 22/09/2008">
--	#      <media:content medium="audio" duration="10800">
--	#        <media:title>Edith Bowman: 22/09/2008</media:title>
--	#        <media:description>Sara Cox sits in for Edith with movie reviews and great new music, plus another Cryptic Randomizer.</media:description>
--	#        <media:player url="http://www.bbc.co.uk/iplayer/episode/b00djtfh?src=a_syn31" />
--	#        <media:category scheme="urn:bbc:metadata:cs:iPlayerUXCategoriesCS" label="Entertainment">9100099</media:category>
--	#        <media:category scheme="urn:bbc:metadata:cs:iPlayerUXCategoriesCS" label="Music">9100006</media:category>
--	#        <media:category scheme="urn:bbc:metadata:cs:iPlayerUXCategoriesCS" label="Pop &amp; Chart">9200069</media:category>
--	#        <media:credit role="Production Department" scheme="urn:ebu">BBC Radio 1</media:credit>
--	#        <media:credit role="Publishing Company" scheme="urn:ebu">BBC Radio 1</media:credit>
--	#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_86_48.jpg" width="86" height="48" />
--	#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_150_84.jpg" width="150" height="84" />
--	#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_178_100.jpg" width="178" height="100" />
--	#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_512_288.jpg" width="512" height="288" />
--	#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_528_297.jpg" width="528" height="297" />
--	#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_640_360.jpg" width="640" height="360" />
--	#        <dcterms:valid>
--	#          start=2008-09-22T15:44:20Z;
--	#          end=2008-09-29T15:02:00Z;
--	#          scheme=W3C-DTF
--	#        </dcterms:valid>
--	#      </media:content>
--	#    </link>
--	#    <link rel="self" href="http://feeds.bbc.co.uk/iplayer/episode/b00djtfh?format=atom" type="application/atom+xml" title="22/09/2008" />
--	#    <link rel="related" href="http://www.bbc.co.uk/programmes/b006wks4/microsite" type="text/html" title="Edith Bowman" />
--	#    <link rel="parent" href="http://feeds.bbc.co.uk/iplayer/programme_set/b006wks4" type="application/atom+xml" title="Edith Bowman" />
--	#  </entry>
--	#</feed>
--
--	my ($duration, $available, $channel, $expiry, $longdesc, $versions, $guidance, $type, $categories, $player, $thumbnail);
--
--	$expiry = $1 if $entry3 =~ m{<dcterms:valid>\s*start=.+?;\s*end=(.*?);};
--	$available = $1 if $entry3 =~ m{<dcterms:valid>\s*start=(.+?);\s*end=.*?;};
--	$duration = $1 if $entry3 =~ m{duration=\"(\d+?)\"};
--	$type = $1 if $entry3 =~ m{medium=\"(\w+?)\"};
--	$longdesc = $1 if $entry3 =~ m{<media:description>\s*(.*?)\s*<\/media:description>};
--	$guidance = $1 if $entry3 =~ m{<media:rating scheme="urn:simple">(.+?)<\/media:rating>};
--	$player = $1 if $entry3 =~ m{<media:player\s*url=\"(.*?)\"\s*\/>};
--	$thumbnail = $1 if $entry3 =~ m{<media:thumbnail url="([^"]+?)"\s+width="150"\s+height="84"\s*/>};
--	
--	my @cats;
--	for (split /<media:category scheme=\".+?\"/, $entry3) {
--		push @cats, $1 if m{\s*label="(.+?)">\d+<\/media:category>};
--	}
--	$categories = join ',', @cats;
-+		# Entry3 format
-+		#<?xml version="1.0" encoding="utf-8"?>                                      
-+		#<?xml-stylesheet href="http://www.bbc.co.uk/iplayer/style/rss.css" type="text/css"?>
-+		#<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:media="http://search.yahoo.com/mrss/" xml:lang="en-GB">
-+		#  <title>BBC iPlayer - Episode Detail: Edith Bowman: 22/09/2008</title>                                                                          
-+		#  <subtitle>Sara Cox sits in for Edith with another Cryptic Randomizer.</subtitle>
-+		#  <updated>2008-09-29T10:59:45Z</updated>
-+		#  <id>tag:feeds.bbc.co.uk,2008:/iplayer/feed/episode/b00djtfh</id>
-+		#  <link rel="related" href="http://www.bbc.co.uk/iplayer" type="text/html" />
-+		#  <link rel="self" href="http://feeds.bbc.co.uk/iplayer/episode/b00djtfh" type="application/atom+xml" />
-+		#  <author>
-+		#    <name>BBC</name>
-+		#    <uri>http://www.bbc.co.uk</uri>
-+		#  </author>
-+		#  <entry>
-+		#    <title type="text">Edith Bowman: 22/09/2008</title>
-+		#    <id>tag:feeds.bbc.co.uk,2008:PIPS:b00djtfh</id>
-+		#    <updated>2008-09-15T01:28:36Z</updated>
-+		#    <summary>Sara Cox sits in for Edith with another Cryptic Randomizer.</summary>
-+		#    <content type="html">
-+		#      &lt;p&gt;
-+		#        &lt;a href=&quot;http://www.bbc.co.uk/iplayer/episode/b00djtfh?src=a_syn30&quot;&gt;
-+		#          &lt;img src=&quot;http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_150_84.jpg&quot; alt=&quot;Edith Bowman: 22/09/2008&quot; /&gt;
-+		#        &lt;/a&gt;
-+		#      &lt;/p&gt;
-+		#      &lt;p&gt;
-+		#        Sara Cox sits in for Edith with movie reviews and great new music, plus another Cryptic Randomizer.
-+		#      &lt;/p&gt;
-+		#    </content>
-+		#    <link rel="alternate" href="http://www.bbc.co.uk/iplayer/episode/b00djtfh?src=a_syn31" type="text/html" title="Edith Bowman: 22/09/2008">
-+		#      <media:content medium="audio" duration="10800">
-+		#        <media:title>Edith Bowman: 22/09/2008</media:title>
-+		#        <media:description>Sara Cox sits in for Edith with movie reviews and great new music, plus another Cryptic Randomizer.</media:description>
-+		#        <media:player url="http://www.bbc.co.uk/iplayer/episode/b00djtfh?src=a_syn31" />
-+		#        <media:category scheme="urn:bbc:metadata:cs:iPlayerUXCategoriesCS" label="Entertainment">9100099</media:category>
-+		#        <media:category scheme="urn:bbc:metadata:cs:iPlayerUXCategoriesCS" label="Music">9100006</media:category>
-+		#        <media:category scheme="urn:bbc:metadata:cs:iPlayerUXCategoriesCS" label="Pop &amp; Chart">9200069</media:category>
-+		#        <media:credit role="Production Department" scheme="urn:ebu">BBC Radio 1</media:credit>
-+		#        <media:credit role="Publishing Company" scheme="urn:ebu">BBC Radio 1</media:credit>
-+		#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_86_48.jpg" width="86" height="48" />
-+		#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_150_84.jpg" width="150" height="84" />
-+		#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_178_100.jpg" width="178" height="100" />
-+		#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_512_288.jpg" width="512" height="288" />
-+		#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_528_297.jpg" width="528" height="297" />
-+		#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_640_360.jpg" width="640" height="360" />
-+		#        <dcterms:valid>
-+		#          start=2008-09-22T15:44:20Z;
-+		#          end=2008-09-29T15:02:00Z;
-+		#          scheme=W3C-DTF
-+		#        </dcterms:valid>
-+		#      </media:content>
-+		#    </link>
-+		#    <link rel="self" href="http://feeds.bbc.co.uk/iplayer/episode/b00djtfh?format=atom" type="application/atom+xml" title="22/09/2008" />
-+		#    <link rel="related" href="http://www.bbc.co.uk/programmes/b006wks4/microsite" type="text/html" title="Edith Bowman" />
-+		#    <link rel="parent" href="http://feeds.bbc.co.uk/iplayer/programme_set/b006wks4" type="application/atom+xml" title="Edith Bowman" />
-+		#  </entry>
-+		#</feed>
-+			
-+		$expiry = $1 if $entry3 =~ m{<dcterms:valid>\s*start=.+?;\s*end=(.*?);};
-+		$available = $1 if $entry3 =~ m{<dcterms:valid>\s*start=(.+?);\s*end=.*?;};
-+		$duration = $1 if $entry3 =~ m{duration=\"(\d+?)\"};
-+		$prog_type = $1 if $entry3 =~ m{medium=\"(\w+?)\"};
-+		$longdesc = $1 if $entry3 =~ m{<media:description>\s*(.*?)\s*<\/media:description>};
-+		$guidance = $1 if $entry3 =~ m{<media:rating scheme="urn:simple">(.+?)<\/media:rating>};
-+		$player = $1 if $entry3 =~ m{<media:player\s*url=\"(.*?)\"\s*\/>};
-+		$thumbnail = $1 if $entry3 =~ m{<media:thumbnail url="([^"]+?)"\s+width="150"\s+height="84"\s*/>};
-+	
-+		my @cats;
-+		for (split /<media:category scheme=\".+?\"/, $entry3) {
-+			push @cats, $1 if m{\s*label="(.+?)">\d+<\/media:category>};
-+		}
-+		$categories = join ',', @cats;
-+
-+		# populate version pid metadata 
-+		get_version_pids($ua, $pid);
-+
-+	# ITV Catch-Up metadata
-+	} elsif ( $prog{$pid}{type} eq 'itv' ) {
-+		my $prog_metadata_url_itv = 'http://www.itv.com/_app/Dynamic/CatchUpData.ashx?ViewType=5&Filter='; # +<pid>
-+		$entry3 = request_url_retry($ua, "${prog_metadata_url_itv}${pid}", 3, '', '');
-+		decode_entities($entry3);
-+		logger "DEBUG: ${prog_metadata_url_itv}${pid}:\n$entry3\n\n" if $opt{debug};
-+		# Flatten
-+		$entry3 =~ s|[\r\n]||g;
-+
-+		#div class="itvCatchUpPlayerPanel" xmlns:ms="urn:schemas-microsoft-com:xslt">
-+		#  <div class="cu-sponsor"><a href="http://sam.itv.com/accipiter/adclick/CID=000040d70000000000000000/acc_random=1/SITE=CLICKTRACK/AREAITVCATCHUP.VIDEO=CLICKTRACK..FREEVIEW.SPONSORBUTTON.OCT08/AAMSZ=120X60/pageid=1" title="ITV Player in assocation with Freeview"><img src="/_app/img/catchup/catchup_video_freeview2.jpg" alt="ITV Player is sponsored by Freeview"></a></div>
-+		#  <h2>Doctor Zhivago</h2>
-+		#  <p>Part 1 of 3. Dramatisation of the epic novel by Boris Pasternak. Growing up in Moscow with his uncle, aunt and cousin Tonya, Yury is captivated by a stunning young girl called ...</p>
-+		#  <p class="timings"><span class="date">Mon 29 Dec 2008</span><br /><br /><span>
-+		#
-+		#        Duration: 1hr 30 min |
-+		#                                Expires in
-+		#                                <strong>22</strong>
-+		#                                                days
-+		#                                        </span></p>
-+		#  <p><a href="http://www.itv.com/CatchUp/Programmes/default.html?ViewType=1&amp;Filter=2352">3 Episodes Available
-+		#        </a><br></br></p>
-+		#  <p class="channelLogo"><img src="/_app/img/logos/itv3-black.gif" alt="ITV 4"></p>
-+		#  <div id="cu-2-0-VideoID">33105</div>
-+		#  <div id="cu-2-0-DentonId">17</div>
-+		#  <div id="cu-2-0-ItemMediaUrl">http://www.itv.com//img/480x272/Doctor-Zhivago-c47828f8-a1af-4cd2-b5a2-40c18eb7e63c.jpg</div>
-+		#</div><script language="javascript" type="text/javascript" xmlns:ms="urn:schemas-microsoft-com:xslt">
-+		#                        SetCatchUpModuleID(0);
-+		#                </script>
-+		#
- 
--	# populate version pid metadata 
--	get_version_pids($ua, $pid);
-+		#<div class="itvCatchUpPlayerPanel" xmlns:ms="urn:schemas-microsoft-com:xslt">
-+		#  <div class="cu-sponsor"><a href="http://sam.itv.com/accipiter/adclick/CID=000040d70000000000000000/acc_random=1/SITE=CLICKTRACK/AREAITVCATCHUP.VIDEO=CLICKTRACK..FREEVIEW.SPONSORBUTTON.OCT08/AAMSZ=120X60/pageid=1" title="ITV Player in assocation with Freeview"><img src="/_app/img/catchup/catchup_video_freeview2.jpg" alt="ITV Player is sponsored by Freeview"></a></div>
-+		#  <h2>Affinity</h2>
-+		#  <p>Victorian period drama with a murderous, pyschological twist.</p>
-+		#  <p class="timings"><span class="date">Sun 28 Dec 2008</span><br /><br /><span>
-+		#
-+		#        Duration: 2hr 00 min |
-+		#                                Expires in
-+		#                                <strong>21</strong>
-+		#                                                days
-+		#                                        </span></p>
-+		#  <p class="channelLogo"><img src="/_app/img/logos/itv1-black.gif" alt="ITV 2"></p>
-+		#  <div class="guidance">
-+		#    <div><strong>ITV Video Guidance</strong><p>This programme contains strong language and scenes of a sexual nature                                                                                                                           </p>
-+		#    </div>
-+		#  </div>
-+		#  <div id="cu-2-0-VideoID">33076</div>
-+		#  <div id="cu-2-0-DentonId">11</div>
-+		#  <div id="cu-2-0-ItemMediaUrl">http://www.itv.com//img/480x272/Affinity-9624033b-6e05-4784-85f7-114be0559b24.jpg</div>
-+		#</div><script language="javascript" type="text/javascript" xmlns:ms="urn:schemas-microsoft-com:xslt">
-+		#                        SetCatchUpModuleID(0);
-+		#                </script>
-+		#
-+
-+		#$expiry = $1 if $entry3 =~ m{<dcterms:valid>\s*start=.+?;\s*end=(.*?);};
-+		$available = $1 if $entry3 =~ m{<p\s+class="timings">\s*<span\s+class="date">(.+?)<\/span>};
-+		$duration = $1 if $entry3 =~ m{Duration:\s*(.+?)\s+\|};
-+		#$prog_type = $1 if $entry3 =~ m{medium=\"(\w+?)\"};
-+		$longdesc = $1 if $entry3 =~ m{<p>(.+?)<\/p>}i;
-+		$guidance = $1 if $entry3 =~ m{ITV Video Guidance<\/strong><p>\s*(.+?)[\W\s]*<\/p>};
-+		#$player = $1 if $entry3 =~ m{<media:player\s*url=\"(.*?)\"\s*\/>};
-+		$thumbnail = $1 if $entry3 =~ m{<div id="cu-2-0-ItemMediaUrl">(.+?)</div>};
-+		$name = $1 if $entry3 =~ m{<h2>(.+?)</h2>};
-+	}
- 
- 	# Fill in from cache if not got from metadata
- 	my %metadata;
- 	$metadata{pid}		= $pid;
- 	$metadata{index}	= $prog{$pid}{index};
--	$metadata{type}		= $type || $prog{$pid}{type};
-+	$metadata{name}		= $name || $prog{$pid}{name};
-+	$metadata{episode}	= $episode || $prog{$pid}{episode};
-+	$metadata{type}		= $prog_type || $prog{$pid}{type};
- 	$metadata{duration}	= $duration || $prog{$pid}{duration};
- 	$metadata{channel}	= $channel || $prog{$pid}{channel};
- 	$metadata{available}	= $available || $prog{$pid}{available};
-@@ -3492,7 +4493,7 @@
- 		logger "WARNING: Cannot write or append to $historyfile\n\n";
- 		return 1;
- 	}
--	print HIST "$pid|$prog{$pid}{name}|$prog{$pid}{episode}|$prog{$pid}{type}|".time()."\n";
-+	print HIST "$pid|$prog{$pid}{name}|$prog{$pid}{episode}|$prog{$pid}{type}|".time()."|$prog{$pid}{mode}\n";
- 	close HIST;
- 	return 0;
- }
-@@ -3555,7 +4556,10 @@
- # Add id3 tag to MP3 files if required
- sub tag_file {
- 	my $pid = shift;
-+
- 	if ( $prog{$pid}{ext} eq 'mp3' ) {
-+		# Return if file does not exist
-+		return if ! -f $prog{$pid}{filename};
- 		# Create ID3 tagging options for external tagger program (escape " for shell)
- 		my ( $id3_name, $id3_episode, $id3_desc, $id3_channel ) = ( $prog{$pid}{name}, $prog{$pid}{episode}, $prog{$pid}{desc}, $prog{$pid}{channel} );
- 		$id3_name =~ s|"|\"|g for ($id3_name, $id3_episode, $id3_desc, $id3_channel);
-@@ -3580,9 +4584,16 @@
- sub list_unique_element_counts {
- 	my $element_name = shift;
- 	my %elements;
--	logger "INFO: $opt{type} $element_name List:\n" if $opt{verbose};
-+	logger "INFO: ".(join ',', keys %type)." $element_name List:\n" if $opt{verbose};
- 	for my $pid (keys %prog) {
--		for my $element ( split /,/, $prog{$pid}{$element_name} ) {
-+		my @element;
-+		# Need to separate the categories
-+		if ($element_name eq 'categories') {
-+			@element = split /,/, $prog{$pid}{$element_name};
-+		} else {
-+			@element[0] = $prog{$pid}{$element_name};
-+		}
-+		for my $element (@element) {
- 			$elements{ $element }++;
- 		}
- 	}
-@@ -3659,6 +4670,7 @@
- 
- 
- 
-+
- # Save the options on the cmdline as a PVR search with the specified name
- sub pvr_add {
- 	my $name = shift;
-@@ -3670,7 +4682,7 @@
- 		return 1;
- 	}
- 	# Parse valid options and create array (ignore options from the options files that have not been overriden on the cmdline)
--	for (grep /^(long|output.*|proxy|subdir|whitespace|versions|type|(exclude)?category|(exclude)?channel|command|realaudio|mp3audio|wav|raw|bandwidth|subtitles|suboffset|since|versionlist|verbose)$/, sort {$a <=> $b} keys %opt_cmdline) {
-+	for (grep /^(amode|vmode|long|output.*|proxy|subdir|whitespace|versions|type|(exclude)?category|(exclude)?channel|command|realaudio|mp3audio|wav|raw|bandwidth|subtitles|suboffset|since|versionlist|verbose)$/, sort {lc $a cmp lc $b} keys %opt_cmdline) {
- 		if ( defined $opt_cmdline{$_} ) {
- 				push @options, "$_ $opt_cmdline{$_}";
- 				logger "DEBUG: Adding option $_ = $opt_cmdline{$_}\n" if $opt{debug};
-@@ -3715,7 +4727,7 @@
- 	pvr_load_list();
- 	# Print out list
- 	logger "All PVR Searches:\n\n";
--	for my $name ( sort {$a <=> $b} keys %pvrsearches ) {
-+	for my $name ( sort {lc $a cmp lc $b} keys %pvrsearches ) {
- 		# Report whether disabled
- 		if ( $pvrsearches{$name}{disable} ) {
- 			logger "(Disabled) PVR Search '$name':\n";
-diff -ruaN mythvodka.orig/scripts/gethulu.pl mythvodka/scripts/gethulu.pl
---- mythvodka.orig/scripts/gethulu.pl	2009-01-06 19:26:30.000000000 +0000
-+++ mythvodka/scripts/gethulu.pl	2009-02-12 07:27:44.000000000 +0000
-@@ -123,7 +123,8 @@
-       if($ephtml =~ m/thumbnail_url: "(.+?)"/)  { $epimg=$1 } ;
- 
-       print MYTHMENU "<Stream>\n";
--      print MYTHMENU "<Name>$eptitle</Name>\n";
-+      print MYTHMENU "<Name>$title-$eptitle</Name>\n";
-+      #print MYTHMENU "<Name>$eptitle</Name>\n";
-       print MYTHMENU "<Url>http://www.hulu.com/watch/$epid</Url>\n";
-       print MYTHMENU "<Subtitle>$season - $epno</Subtitle>\n";
-       print MYTHMENU "<Synopsis>$epdate - $epdesc</Synopsis>\n";
-diff -ruaN mythvodka.orig/scripts/hulu mythvodka/scripts/hulu
---- mythvodka.orig/scripts/hulu	2009-01-04 15:25:24.000000000 +0000
-+++ mythvodka/scripts/hulu	2009-02-12 07:27:44.000000000 +0000
-@@ -22,6 +22,7 @@
- html=get_HTML(cid)
- cidSoup=BeautifulStoneSoup(html)
- pid=cidSoup.findAll('pid')[0].contents[0]
-+logfile="/var/log/mythtv/hulu_quality.log"
- 
- smilURL = "http://releasegeo.hulu.com/content.select?pid=" + pid + "&mbr=true&format=smil"
- print smilURL
-@@ -34,18 +35,58 @@
- #label streams
- i=0
- quality=0
-+qual_medium=-1; qual_high=-1; qual_h264=-1; command2="echo hulu done."
-+os.system("rm -f "+logfile+".0")
-+os.system("mv -f "+logfile+" "+logfile+".0")
-+f=open(logfile,'w')
-+os.system("chmod a+rw "+logfile)
-+print >>f, "Debug debug"
-+print >>f, "hulu ",url, " ", fileout
-+#
-+# Find the various quality choices that are available
-+#
- for stream in video:
--    if "480K" in stream['src'] or "480k" in stream['src']:
-+    print >>f, stream
-+    if "H264" in stream['src'] or "h264" in stream['src'] or "h264" in stream['profile'] or "H264" in stream['profile']:
-+        streams.append(['H264',stream['src']])
-+	qual_h264=i
-+	print >>f, "DebugQual h264", i
-+	print >>f, ""
-+    elif "480K" in stream['src'] or "480k" in stream['src']:
-         streams.append(['Flash (480k)',stream['src']])
-+	qual_medium=i
-+	print >>f, "DebugQual medium", i
-+	print >>f, ""
-     elif "700K" in stream['src'] or "700k" in stream['src']:
-         streams.append(['Flash (700k)',stream['src']])
- 	quality=i
--    elif "H264" in stream['src'] or "h264" in stream['src']:
--        streams.append(['H264',stream['src']])
-+	qual_high=i
-+	print >>f, "DebugQual high", i
-+	print >>f, ""
-+    elif "medium" in stream['profile'] or "Medium" in stream['profile']:
-+	streams.append(['Flash (Medium)',stream['src']])
-+	if qual_medium==-1: qual_medium=i
-+        print >>f, "DebugQual Medium", i, qual_medium
-+        print >>f, ""
-+    elif "high" in stream['profile'] or "High" in stream['profile']:
-+        streams.append(['Flash (High)',stream['src']])
-+	if qual_high==-1: qual_high=i
-+	print >>f, "DebugQual High", i, qual_high
-+	print >>f, ""
-     else:
-         streams.append(['unkown quality: '+stream['src'].split('/')[-1],stream['src']])
-+	print >>f, "DebugQual Unknown", i
-+	print >>f, ""
-     i=i+1
- 
-+if qual_high>-1: 
-+    quality=qual_high
-+elif qual_medium>-1:
-+    quality=qual_medium
-+
-+print >>f, "DebugQualVars: h264, high, medium, selected=",qual_h264,qual_high,qual_medium,quality
-+
-+
- if quality!=-1:
-     print "stream url"
- #generate random code
-@@ -104,4 +145,9 @@
-     command=command.replace(';','\\;')
- 
-     print command
--    os.system(command)
-+    print >>f,"Command is ",command
-+    print >>f,"command2 is ",command2
-+    f.close()
-+    os.system(command + "; " + command2)
-+else:
-+    f.close()
-diff -ruaN mythvodka.orig/scripts/mythvodka_player.sh mythvodka/scripts/mythvodka_player.sh
---- mythvodka.orig/scripts/mythvodka_player.sh	1970-01-01 00:00:00.000000000 +0000
-+++ mythvodka/scripts/mythvodka_player.sh	2009-02-12 07:27:44.000000000 +0000
-@@ -0,0 +1,38 @@
-+#! /bin/bash
-+#
-+log=/var/log/mythtv/mythvodka_player.log
-+player_list="/usr/local/bin/mplayer_h264 /usr/local/bin/mplayer \
-+             /usr/bin/mplayer /bin/mplayer"
-+#
-+player_list="/usr/local/bin/mplayer /usr/bin/mplayer /bin/mplayer"
-+f="$1"
-+shift
-+rm -f $log
-+echo "Request to play $f on `date`" >> $log
-+player=""
-+for player in $player_list; do
-+  if [ -x "$player" ]; then
-+    echo "Found player $player" >> $log
-+    break
-+  fi
-+done
-+if [ ! -x $player ]; then
-+  echo "ERROR -- not able to find mplayer on your system. " >> $log
-+  echo "I searched the following list" >> $log
-+  echo "  $player_list" >> $log
-+  exit 1
-+fi
-+for pass in 1 2 4 8 10; do
-+  size="0"
-+  if [ -e $f ]; then
-+    size=$( du --apparent-size -sD "$f" | awk '{ print $1 }' )
-+    if [ $size -gt 1500 ]; then
-+      break
-+    fi
-+  fi
-+  echo "Pass $pass, filesize is $size kbytes, sleep $pass seconds" >> $log
-+  sleep $pass
-+done
-+size=$( du --apparent-size -sD "$f" | awk '{ print $1 }' )
-+echo "Reached $size kb on pass $pass `date`" >> $log
-+$player -fs -vo xv $f
diff --git a/abs/extra/mythvodka/mythvodka.install b/abs/extra/mythvodka/mythvodka.install
deleted file mode 100644
index 4a9827e..0000000
--- a/abs/extra/mythvodka/mythvodka.install
+++ /dev/null
@@ -1,47 +0,0 @@
-# arg 1:  the new package version
-post_install() {
-  mv /usr/share/mythtv/is.xml /tmp
-  grep -v -e /mythmenu /tmp/is.xml > /tmp/is.xml.tmp
-  echo "<!--#MythVodka-->" >> /tmp/is.xml.tmp
-  echo "   <button>" >> /tmp/is.xml.tmp
-  echo "     <type>STREAM</type>" >> /tmp/is.xml.tmp
-  echo "     <text>Myth Vodka</text>" >> /tmp/is.xml.tmp
-  echo "     <action>PLUGIN mythvodka</action>" >> /tmp/is.xml.tmp 
-  echo "     <depends>mythvodka</depends>" >> /tmp/is.xml.tmp 
-  echo "   </button>" >> /tmp/is.xml.tmp
-  echo "<!--#MythVodka-->" >> /tmp/is.xml.tmp
-  echo "" >> /tmp/is.xml.tmp
-  echo "</mythmenu>" >> /tmp/is.xml.tmp
-  mv /tmp/is.xml.tmp /usr/share/mythtv/is.xml
-
-  mv /usr/share/mythtv/media_settings.xml /tmp
-  grep -v -e /mythmenu /tmp/media_settings.xml > /tmp/ms.xml.tmp
-  echo "<!--#MythVodka-->" >> /tmp/ms.xml.tmp
-  echo "   <button>" >> /tmp/ms.xml.tmp
-  echo "     <type>SETTINGS MYTHVODKA</type>" >> /tmp/ms.xml.tmp
-  echo "     <text>MythVodka Settings</text>" >> /tmp/ms.xml.tmp
-  echo "     <action>CONFIGPLUGIN mythvodka</action>" >> /tmp/ms.xml.tmp 
-  echo "     <depends>mythvodka</depends>" >> /tmp/ms.xml.tmp 
-  echo "   </button>" >> /tmp/ms.xml.tmp
-  echo "<!--#MythVodka-->" >> /tmp/ms.xml.tmp
-  echo "" >> /tmp/ms.xml.tmp
-  echo "</mythmenu>" >> /tmp/ms.xml.tmp
-  mv /tmp/ms.xml.tmp /usr/share/mythtv/media_settings.xml
-}
-# arg 1:  the new package version
-# arg 2:  the old package version
-post_upgrade() {
-	/bin/true
-}
-
-# arg 1:  the old package version
-post_remove() {
-	mv /usr/share/mythtv/is.xml /tmp/is.xml.tmp
-	sed -e '/\#MythVodka/,/\#MythVodka/d' < /tmp/is.xml.tmp > /usr/share/mythtv/is.xml
-	mv /usr/share/mythtv/media_settings.xml /tmp/ms.xml.tmp
-	sed -e '/\#MythVodka/,/\#MythVodka/d' < /tmp/ms.xml.tmp > /usr/share/mythtv/media_settings.xml
-}
-
-op=$1
-shift
-$op $*
-- 
cgit v0.12


From 1d0b04a8f4c435eae65307d26195cf8e380aba90 Mon Sep 17 00:00:00 2001
From: James Meyer <james.meyer@operamail.com>
Date: Sun, 31 Jan 2010 14:57:48 -0600
Subject: mythvodka: dropped from repo.

---
 abs/extra-testing/mythvodka/PKGBUILD          |   36 -
 abs/extra-testing/mythvodka/hulu_grabber.sh   |   16 -
 abs/extra-testing/mythvodka/mythvodka.diff    | 3933 -------------------------
 abs/extra-testing/mythvodka/mythvodka.install |   47 -
 abs/extra/mythvodka/PKGBUILD                  |   36 -
 abs/extra/mythvodka/hulu_grabber.sh           |   16 -
 abs/extra/mythvodka/mythvodka.diff            | 3933 -------------------------
 abs/extra/mythvodka/mythvodka.install         |   47 -
 8 files changed, 8064 deletions(-)
 delete mode 100644 abs/extra-testing/mythvodka/PKGBUILD
 delete mode 100755 abs/extra-testing/mythvodka/hulu_grabber.sh
 delete mode 100644 abs/extra-testing/mythvodka/mythvodka.diff
 delete mode 100644 abs/extra-testing/mythvodka/mythvodka.install
 delete mode 100644 abs/extra/mythvodka/PKGBUILD
 delete mode 100755 abs/extra/mythvodka/hulu_grabber.sh
 delete mode 100644 abs/extra/mythvodka/mythvodka.diff
 delete mode 100644 abs/extra/mythvodka/mythvodka.install

diff --git a/abs/extra-testing/mythvodka/PKGBUILD b/abs/extra-testing/mythvodka/PKGBUILD
deleted file mode 100644
index 0832093..0000000
--- a/abs/extra-testing/mythvodka/PKGBUILD
+++ /dev/null
@@ -1,36 +0,0 @@
-# $Id: PKGBUILD 5936 2008-07-21 20:24:16Z thomas $
-# Maintainer: Cecil Watson<knoppmyth@gmail.com>
-
-pkgname=mythvodka
-pkgver=0.7
-pkgrel=11
-pkgdesc="MythVodka (Video On Demand Killer App) is a plugin for MythTV allowing streaming of BBC iPlayer, Hulu, HTTP and NZB content."
-arch=('i686' 'x86_64')
-license=('GPL2')
-url="http://code.google.com/p/mythvodka/"
-depends=('rtmpdump' 'perl-xml-dom' 'beautiful-soup')
-install=mythvodka.install
-source=('http://mythvodka.googlecode.com/files/mythvodka.07.tar.gz' 'mythvodka.diff' 'hulu_grabber.sh' 'http://ftp.knoppmyth/R6/sources/huludata.tar.bz2')
-
-build() {
-	patch -p0 < mythvodka.diff
-	cd $startdir/src/mythvodka/mythvodka
-	rm -fr Makefile
-	qmake mythvodka.pro
-	make
-	mkdir -p $startdir/pkg/usr/lib/mythtv/plugins/
-	cp libmythvodka.so $startdir/pkg/usr/lib/mythtv/plugins/
-	strip --strip-unneeded $startdir/pkg/usr/lib/mythtv/plugins/libmythvodka.so
-	mkdir -p $startdir/pkg/usr/share/mythtv/themes/default/
-	cp streams-ui.xml $startdir/pkg/usr/share/mythtv/themes/default/
-	mkdir -p $startdir/pkg/usr/share/mythtv/themes/default-wide/
-	cp theme-wide/streams-ui.xml $startdir/pkg/usr/share/mythtv/themes/default-wide/
-	mkdir -p $startdir/pkg/usr/local/bin
-	chmod a+x ../scripts/*
-	cp -p ../scripts/* $startdir/pkg/usr/local/bin
-	mkdir -p $startdir/pkg/etc/cron.daily/
-	chmod 755 ../../hulu_grabber.sh
-	cp ../../hulu_grabber.sh $startdir/pkg/etc/cron.daily/
-	mkdir -p $startdir/pkg/var/tmp
-	cp $startdir/src/huludata.xml $startdir/pkg/var/tmp
-}
diff --git a/abs/extra-testing/mythvodka/hulu_grabber.sh b/abs/extra-testing/mythvodka/hulu_grabber.sh
deleted file mode 100755
index 4840dc0..0000000
--- a/abs/extra-testing/mythvodka/hulu_grabber.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#! /bin/bash
-log=/var/log/mythtv/hulu_grabber.log
-out=/var/tmp/huludata.xml
-rm -f $log
-echo "Start on `date`" >>$log 2>&1
-/usr/local/bin/gethulu.pl $out.new >>$log 2>&1
-stat=$?
-if [ $stat -ne 0 ]; then
-  echo "Bad status $stat from gethulu.pl" >>$log 2>&1
-  exit 1
-fi
-rm -f $out.old
-mv $out $out.old
-mv $out.new $out
-echo "Done on `date`" >>$log 2>&1
-ls -lh $out >>$log 2>&1
diff --git a/abs/extra-testing/mythvodka/mythvodka.diff b/abs/extra-testing/mythvodka/mythvodka.diff
deleted file mode 100644
index 5735a42..0000000
--- a/abs/extra-testing/mythvodka/mythvodka.diff
+++ /dev/null
@@ -1,3933 +0,0 @@
-diff -ruaN mythvodka.orig/mythvodka/streamsui.cpp mythvodka/mythvodka/streamsui.cpp
---- mythvodka.orig/mythvodka/streamsui.cpp	2009-01-06 00:18:35.000000000 +0000
-+++ mythvodka/mythvodka/streamsui.cpp	2009-02-12 07:28:31.000000000 +0000
-@@ -646,7 +646,7 @@
-     
-         MythProgressDialog *buffer_progress;
-         buffer_progress = new MythProgressDialog(
--            QObject::tr("If she kicks you in the balls, you have the ability and the right..."), bufferSize, true, this, SLOT(cancelPressed()));
-+            QObject::tr("Buffering... Just a moment please."), bufferSize, true, this, SLOT(cancelPressed()));
-     
-         QFile file(filename);
-     
-@@ -729,7 +729,7 @@
-     
-         MythProgressDialog *buffer_progress;
-         buffer_progress = new MythProgressDialog(
--            QObject::tr("Nascar Sucks / Hillary For President / Man Love Rules Ok"), bufferSize, true, this, SLOT(cancelPressed()));
-+            QObject::tr("Your video is being loaded..."), bufferSize, true, this, SLOT(cancelPressed()));
-     
-         QFile file(filename);
-     
-@@ -822,7 +822,7 @@
-     
-         MythProgressDialog *buffer_progress;
-         buffer_progress = new MythProgressDialog(
--            QObject::tr("RING RING... I FUCKED YOUR GRANDDAUGHTER"), bufferSizemov, true, this, SLOT(cancelPressed()));
-+            QObject::tr("We seem to have hit some sort of problem..."), bufferSizemov, true, this, SLOT(cancelPressed()));
-     
-         QFile filemov(filenamemov);
-     
-diff -ruaN mythvodka.orig/scripts/get_iplayer mythvodka/scripts/get_iplayer
---- mythvodka.orig/scripts/get_iplayer	2009-01-06 19:11:24.000000000 +0000
-+++ mythvodka/scripts/get_iplayer	2009-02-12 07:27:44.000000000 +0000
-@@ -3,16 +3,17 @@
- # get_iplayer
- #
- # Lists and downloads BBC iPlayer audio and video streams
--# 
-+# + Downloads ITVplayer Catch-Up video streams
-+#
- # Author: Phil Lewis
- # Email: iplayer (at sign) linuxcentre.net
- # Web: http://linuxcentre.net/iplayer
- # License: GPLv3 (see LICENSE.txt)
- #
- # Other credits:
--# RTMP additions: Andrej Stepanchuk
-+#  RTMP additions: Andrej Stepanchuk
- #
--my $version = 1.04;
-+my $version = 1.17;
- #
- # Help:
- #	./get_iplayer --help
-@@ -29,13 +30,16 @@
- # * Index/Download live radio streams w/schedule feeds to assist timing
- # * Podcasts for 'local' stations are missing (only a handful). They use a number of different station ids which will involve reading html to determine rss feed. 
- # * Remove all rtsp/mplayer/lame/tee dross when realaudio streams become obselete (not quite yet)
--# * Cope with radio via rtmp
- # * Stdout mode with rtmp
--#
-+# * Do subtitle downloading after programme download so that rtmp auth doesn't timeout
-+
- # Known Issues:
- # * In ActivePerl/windows downloaded iPhone video files do not get renamed (remain with .partial.mov)
- # * vlc does not quit after downloading an rtsp N95 video stream (ctrl-c is required) - need a --play-and-quit option if such a thing exists
--# * flv conversions from rtmp downloads aren't quite right yet. A/V sync issues?
-+# * rtmpdump (v1.2) of flashaudio fails at end of stream => non-zero exit code
-+# * if ffmpeg trys to convert flv to mp3 it succeeds but => non-zero exit code
-+# * Some rtmpdump downloads always give a non-zero exit code regardless of success (using a min-filesize workaround for now)
-+# * resuming a flashaudio download fails
- 
- use Env qw[@PATH];
- use Fcntl;
-@@ -62,10 +66,17 @@
- my %opt_cmdline = (); # a hash of which options came from the cmdline rather than the options files
- my %opt_file = (); # a hash of which options came from the options files rather than the cmdline
- 
--# Print to STDERR if not quiet unless verbose or debug
-+# Print to STDERR/STDOUT if not quiet unless verbose or debug
- sub logger(@) {
- 	# Make sure quiet can be overridden by verbose and debug options
--	print STDERR $_[0] if (! $opt{quiet}) || $opt{verbose} || $opt{debug};
-+	if ( $opt{verbose} || $opt{debug} || ! $opt{quiet} ) {
-+		# Only send messages to STDERR if pvr or stdout options are being used.
-+		if ( $opt{stdout} || $opt{pvr} || $opt{stderr} ) {
-+			print STDERR $_[0];
-+		} else {
-+			print STDOUT $_[0];
-+		}
-+	}
- }
- 
- sub usage {
-@@ -74,7 +85,7 @@
- Search Programmes:  get_iplayer [<search options>] [<regex|index|pid|pidurl> ...]
- Download files:     get_iplayer --get [<search options>] <regex|index|pid|pidurl> ...
-                     get_iplayer --pid <pid|pidurl> [<options>]
--Stream Downloads:   get_iplayer --stdout [<options>] <regex|index|pid|pidurl> | mplayer -cache 2048 -
-+Stream Downloads:   get_iplayer --stdout [<options>] <regex|index|pid|pidurl> | mplayer -cache 3072 -
- Update get_iplayer: get_iplayer --update
- 
- Search Options:
-@@ -83,9 +94,10 @@
-  --channel <regex>             Narrow search to matched channel(s)
-  --category <regex>            Narrow search to matched categories
-  --versions <regex>            Narrow search to matched programme version(s)
-+ --exclude <regex>             Narrow search to exclude matched programme names
-  --exclude-channel <regex>     Narrow search to exclude matched channel(s)
-  --exclude-category <regex>    Narrow search to exclude matched catogories
-- --type <radio|tv|podcast|all> Only search in these types of programmes (tv is default)
-+ --type <type>                 Only search in these types of programmes: radio, tv, podcast, all, itv (tv is default)
-  --since <hours>               Limit search to programmes added to the cache in the last N hours
-  
- Display Options:
-@@ -95,26 +107,25 @@
-  -i, --info                    Show full programme metadata (only if number of matches < 50)
-  --list <categories|channel>   Show a list of available categories/channels for the selected type and exit
-  --hide                        Hide previously downloaded programmes
-+ --streaminfo                  Returns all of the media stream urls of the programme(s)
- 
- Download Options:
-  -g, --get                     Download matching programmes
-  -x, --stdout                  Additionally stream to STDOUT (so you can pipe output to a player)
-  -p, --proxy <url>             Web proxy URL spec
-  --partial-proxy               Works around for some broken web proxies (try this extra option if your proxy fails)
-- --pid <pid|url>               Download an arbitrary pid that does not appear in the index
-+ --pid <pid|url>               Download an arbitrary pid that does not appear in the index (itv:<pid> for itv programmes)
-  --force-download              Ignore download history (unsets --hide option also)
-- --realaudio                   Use the RealAudio radio stream and not the MP3 stream
-- --mp3audio                    Use the MP3 radio stream for radio and dont fallback to the RealAudio stream
-+ --amode <mode>,<mode>,...     Audio Download mode(s): iphone,flashaudio,realaudio (default: iphone,flashaudio,realaudio)
-+ --vmode <mode>,<mode>,...     Video Download mode(s): iphone,rtmp,flashhigh,flashnormal,flashwii,n95_wifi (default: iphone,flashhigh,flashnormal)
-  --wav                         In radio realaudio mode output as wav and don't transcode to mp3
-- --raw                         In radio/realaudio or iPhone/video mode don't transcode or change the downloaded stream in any way
-- --n95                         In TV mode download/stream low quality Nokia N95 H.264 stream (alpha)
-- --rtmp                        In TV mode download/stream high quality flash stream (alpha)
-+ --raw                         Don't transcode or change the downloaded stream in any way (i.e. radio/realaudio, rtmp/flv, iphone/mov)
-  --bandwidth                   In radio realaudio mode specify the link bandwidth in bps for rtsp streaming (default 512000)
-  --subtitles                   In TV mode, download subtitles into srt/SubRip format if available
-  --suboffset <offset>          Offset the subtitle timestamps by the specified number of milliseconds
-  --version-list <versions>     Override the version of programme to download (e.g. '--version-list signed,default')
-  -t, --test                    Test only - no download (will show programme type)
-- 
-+
- PVR Options:
-  --pvr                         Runs the PVR download using all saved PVR searches (intended to be run every hour from cron etc)
-  --pvradd <search name>        Add the current search terms to the named PVR search
-@@ -139,18 +150,18 @@
-  -f, --flush, --refresh        Refresh cache
-  -e, --expiry <secs>           Cache expiry in seconds (default 4hrs)
-  --symlink <file>              Create symlink to <file> once we have the header of the download
-- --fxd <file>                  Create Freevo FXD XML in specified file
-- --mythtv <file>               Create Mythtv streams XML in specified file
-+ --fxd <file>                  Create Freevo FXD XML of matching programmes in specified file
-+ --mythtv <file>               Create Mythtv streams XML of matching programmes in specified file
-  --xml-channels                Create freevo/Mythtv menu of channels -> programme names -> episodes
-  --xml-names                   Create freevo/Mythtv menu of programme names -> episodes
-  --xml-alpha                   Create freevo/Mythtv menu sorted alphabetically by programme name
-- --html <file>                 Create basic HTML index of programmes in specified file
-+ --html <file>                 Create basic HTML index of matching programmes in specified file
-  --mplayer <path>              Location of mplayer binary
-+ --ffmpeg <path>               Location of ffmpeg binary
-  --lame <path>                 Location of lame binary
-  --id3v2 <path>                Location of id3v2 binary
-  --rtmpdump <path>             Location of rtmpdump binary
-- --vlc <path>                  Location of vlc binary
-- --streaminfo                  Returns all of the media stream urls of the programme(s)
-+ --vlc <path>                  Location of vlc or cvlc binary
-  -v, --verbose                 Verbose
-  -u, --update                  Update get_iplayer if a newer one exists
-  -h, --help                    Help
-@@ -192,14 +203,17 @@
- Getopt::Long::Configure ("bundling");
- # cmdline opts take precedence
- GetOptions(
-+	"amode=s"			=> \$opt_cmdline{amode},
- 	"bandwidth=n"			=> \$opt_cmdline{bandwidth},
- 	"category=s"			=> \$opt_cmdline{category},
- 	"channel=s"			=> \$opt_cmdline{channel},
- 	"c|command=s"			=> \$opt_cmdline{command},
- 	"debug"				=> \$opt_cmdline{debug},
-+	"exclude=s"			=> \$opt_cmdline{exclude},
- 	"exclude-category=s"		=> \$opt_cmdline{excludecategory},
- 	"exclude-channel=s"		=> \$opt_cmdline{excludechannel},
- 	"expiry|e=n"			=> \$opt_cmdline{expiry},
-+	"ffmpeg=s"			=> \$opt_cmdline{ffmpeg},
- 	"file-prefix|fileprefix=s"	=> \$opt_cmdline{fileprefix},
- 	"flush|refresh|f"		=> \$opt_cmdline{flush},
- 	"force-download"		=> \$opt_cmdline{forcedownload},
-@@ -238,7 +252,7 @@
- 	"rtmpdump=s"			=> \$opt_cmdline{rtmpdump},
- 	"save"				=> \$save,
- 	"since=n"			=> \$opt_cmdline{since},
--	"stdout|stream|x"		=> \$opt_cmdline{stdout},
-+	"stdout|x"			=> \$opt_cmdline{stdout},
- 	"streaminfo"			=> \$opt_cmdline{streaminfo},
- 	"subdirs|subdir|s"		=> \$opt_cmdline{subdir},
- 	"suboffset=n"			=> \$opt_cmdline{suboffset},
-@@ -253,6 +267,7 @@
- 	"versions=s"			=> \$opt_cmdline{versions},
- 	"verbose|v"			=> \$opt_cmdline{verbose},
- 	"vlc=s"				=> \$opt_cmdline{vlc},
-+	"vmode=s"			=> \$opt_cmdline{vmode},
- 	"wav"				=> \$opt_cmdline{wav},
- 	"whitespace|ws|w"		=> \$opt_cmdline{whitespace},
- 	"xml-channels|fxd-channels"	=> \$opt_cmdline{xmlchannels},
-@@ -269,7 +284,7 @@
- save_options_file( $optfile ) if $save;
- 
- 
--# Global vars
-+### Global vars ###
- 
- # Programme data structure
- # $prog{$pid} = {
-@@ -283,7 +298,7 @@
- #	'thumbnail'	=> <programme thumbnail url>
- #	'channel	=> <channel>
- #	'categories'	=> <Comma separated list of categories>
--# 	'type'		=> <Type: tv, radio or podcast>
-+# 	'type'		=> <Type: tv, radio, itv or podcast>
- #	'timeadded'	=> <timestamp when programme was added to cache>
- #	'longname'	=> <Long name (only parsed in stage 1 download)>,
- #	'version'	=> <selected version e.g default, signed, etc - only set before d/load>
-@@ -292,11 +307,35 @@
- #	'fileprefix'	=> <Filename Prefix of saved file - set only while downloading>
- #	'ext'		=> <Filename Extension of saved file - set only while downloading>
- #};
-+
-+# Define cache file format
-+my @cache_format = qw/index type name pid available episode versions duration desc channel categories thumbnail timeadded guidance/;
-+
-+# List of all types
-+my @all_prog_types = qw/ tv radio podcast itv /;
-+
-+# Ranges of numbers used in the indicies for each programme type
-+my %index_range;
-+$index_range{tv}{min} 		= 1;
-+$index_range{tv}{max} 		= 9999;
-+$index_range{radio}{min} 	= 10001;
-+$index_range{radio}{max} 	= 19999;
-+$index_range{podcast}{min} 	= 20001;
-+$index_range{podcast}{max} 	= 29999;
-+$index_range{itv}{min} 		= 100001;
-+$index_range{itv}{max} 		= 199999;
-+# Set maximun index number
-+my $max_index;
-+for (@all_prog_types) {
-+	$max_index = $index_range{$_}{max} if $index_range{$_}{max} > $max_index;
-+}
- my %prog;
-+my %type;
- my %pids_history;
- my %index_pid; # Hash to obtain pid given an index
- my $now;
- my $childpid;
-+my $min_download_size = 1000000;
- 
- # Static URLs
- my $channel_feed_url		= 'http://feeds.bbc.co.uk/iplayer'; # /$channel/list/limit/400
-@@ -396,6 +435,18 @@
- 	'bbc_radio_jersey'			=> 'radio|BBC Jersey',
- };
- 
-+$channels{itv} = {
-+	'crime'					=> 'itv|TV Classics Crime Drama',
-+	'perioddrama'				=> 'itv|TV Classics Period Drama',
-+	'familydrama'				=> 'itv|TV Classics Family Drama',
-+	'documentary'				=> 'itv|TV Classics Documentaries',
-+	'comedy'				=> 'itv|TV Classics Comedy',
-+	'kids'					=> 'itv|TV Classics Children\'s TV',
-+	'soaps'					=> 'itv|TV Classics Soaps',
-+	'/'					=> 'itv|TV Classics',
-+};
-+
-+
- # User Agents
- my %user_agent = (
-   	coremedia	=> 'Apple iPhone v1.1.1 CoreMedia v1.0.0.3A110a',
-@@ -410,6 +461,7 @@
- 
- # Other Non-option dependant vars
- my %cachefile = (
-+	'itv'		=> "${profile_dir}/itv.cache",
- 	'tv'		=> "${profile_dir}/tv.cache",
- 	'radio'		=> "${profile_dir}/radio.cache",
- 	'podcast'	=> "${profile_dir}/podcast.cache",
-@@ -430,6 +482,7 @@
- my $mplayer;
- #my $mencoder;
- my $ffmpeg;
-+my $ffmpeg_opts;
- my $rtmpdump;
- my $mplayer_opts;
- my $lame;
-@@ -480,7 +533,7 @@
- 	# Display default options
- 	display_default_options();
- 	# For each PVR search
--	for my $name ( sort {$a <=> $b} keys %pvrsearches ) {
-+	for my $name ( sort {lc $a cmp lc $b} keys %pvrsearches ) {
- 		# Ignore if this search is disabled
- 		if ( $pvrsearches{$name}{disable} ) {
- 			logger "\nSkipping disabled PVR Search '$name'\n" if $opt{verbose};
-@@ -519,27 +572,29 @@
- 	# Option dependant vars
- 	%download_dir	= (
- 		'tv'		=> $opt{outputtv} || $opt{output} || $ENV{IPLAYER_OUTDIR} || '.',
-+		'itv'		=> $opt{outputtv} || $opt{output} || $ENV{IPLAYER_OUTDIR} || '.',
- 		'radio'		=> $opt{outputradio} || $opt{output} || $ENV{IPLAYER_OUTDIR} || '.',
- 		'podcast'	=> $opt{outputpodcast} || $opt{output} || $ENV{IPLAYER_OUTDIR} || '.',
- 	);
--	# Default to type=tv
--	$opt{type} 		= 'tv' if ! $opt{type};
--	# Expand 'all' to various prog types
--	$opt{type} 		= 'tv,radio,podcast' if $opt{type} =~ /(all|any)/i;
-+
- 	# Ensure lowercase
--	$opt{type} = lc( $opt{type} );
-+	$opt{type}		= lc( $opt{type} );
-+	# Expand 'all' to comma separated list all prog types
-+	$opt{type} 		= join(',', @all_prog_types) if $opt{type} =~ /(all|any)/i;
-+	# Hash to store specified prog types
-+	%type = ();
-+	$type{$_} = 1 for split /,/, $opt{type};
-+	# Default to type=tv if no type option is set
-+	$type{tv}		= 1 if keys %type == 0;
- 	$cache_secs 		= $opt{expiry} || 14400;
- 	$mplayer		= $opt{mplayer} || 'mplayer';
- 	$mplayer_opts		= '-nolirc';
- 	$mplayer_opts		.= ' -really-quiet' if $opt{quiet};
--	# Assume mencoder/ffmpeg is in the same path as mplayer
--#	$mencoder		= $mplayer;
--#	$mencoder		=~ s|^(.*?)mplayer|$1mencoder|g;
--	$ffmpeg			= $mplayer;
--	$ffmpeg			=~ s|^(.*?)mplayer|$1ffmpeg|g;
-+	$ffmpeg			= $opt{ffmpeg} || 'ffmpeg';
-+	$ffmpeg_opts		= '';
- 	$lame			= $opt{lame} || 'lame';
--	$lame_opts		= '-f ';
--	$lame_opts		.= '--quiet ' if $opt{quiet};
-+	$lame_opts		= '-f';
-+	$lame_opts		.= ' --quiet ' if $opt{quiet};
- 	$vlc			= $opt{vlc} || 'cvlc';
- 	$vlc_opts		= '-vv';
- 	$id3v2			= $opt{id3v2} || 'id3v2';
-@@ -562,11 +617,11 @@
- 		exit 1;
- 	}
- 
--	# Disable rtmp mode if rtmpdump does not exist
--	if ( $opt{rtmp} && ! exists_in_path($rtmpdump)) {
--		logger "\nERROR: Required program $rtmpdump does not exist (see http://linuxcentre.net/getiplayer/installation and http://linuxcentre.net/getiplayer/download), falling back to iphone mode\n";
--		delete $opt{rtmp};
--	}
-+	# Backward compatability options - to be removed eventually
-+	$opt{vmode} = 'rtmp' if $opt{rtmp};
-+	$opt{vmode} = 'n95_wifi' if $opt{n95};
-+	$opt{amode} = 'realaudio' if $opt{realaudio};
-+	$opt{amode} = 'iphone' if $opt{mp3audio};
- 
- 	# Web proxy
- 	$proxy_url = $opt{proxy} || $ENV{HTTP_PROXY} || $ENV{http_proxy} || '';
-@@ -585,8 +640,21 @@
- 		}
- 	}
- 
--	# Get arbitrary pid
-+	# Get prog by arbitrary pid (then exit)
- 	if ( $opt{pid} ) {
-+
-+		# Temporary hack to get 'ITV Catch-up' downloads specified as --pid itv:<pid>
-+		$type{itv} = 1 if $opt{pid} =~ m{^itv:(.+?)$};
-+		if ( $type{itv} ) {
-+			exit 1 if ( ! $opt{streaminfo} ) && check_download_history( $opt{pid} );
-+			# Remove leading itv: tag (backwards compat)
-+			$opt{pid} =~ s/^itv:(.+?)$/$1/ig;
-+			# Force prog type to itv
-+			$prog{$opt{pid}}{type} = 'itv';
-+			download_programme( $opt{pid} );
-+			exit 0;
-+		}
-+
- 		# Remove any url parts from the pid
- 		$opt{pid} =~ s/^.*(b0[a-z,0-9]{6}).*$/$1/g;
- 		# Retry loop
-@@ -594,21 +662,29 @@
- 		my $retries = 3;
- 		my $retcode;
- 		exit 1 if ( ! $opt{streaminfo} ) && check_download_history( $opt{pid} );
--		while ( $count < $retries && ($retcode = download_programme( $opt{pid} )) eq 'retry' ) {
--			logger "WARNING: Retrying download for PID $opt{pid}\n";
--			$count++;
-+		for ($count = 1; $count <= $retries; $count++) {
-+			$retcode = download_programme( $opt{pid} );
-+			return 0 if $retcode eq 'skip';
-+			if ( $retcode eq 'retry' && $count < $retries ) {
-+				logger "WARNING: Retrying download for PID $opt{pid}\n";
-+			} else {
-+				$retcode = 1 if $retcode eq 'retry';
-+				last;
-+			}
- 		}
- 		# Add to history, tag and Run post download command if download was successful
- 		if ($retcode == 0) {
- 			add_to_download_history( $opt{pid} );
- 			tag_file( $opt{pid} );
- 			run_user_command( $opt{pid}, $opt{command} ) if $opt{command};
--		}	
-+		} elsif (! $opt{test}) {
-+			logger "ERROR: Failed to download PID $opt{pid}\n";
-+		}
- 		exit 0;
- 	}
- 
- 	# Get stream links from BBC iplayer site or from cache (also populates all hashes) specified in --type option
--	get_links( $_ ) for split /,/, $opt{type};
-+	get_links( $_ ) for keys %type;
- 
- 	# List elements (i.e. 'channel' 'categories') if required and exit
- 	if ( $opt{list} ) {
-@@ -616,18 +692,13 @@
- 		exit 0;
- 	}
- 
--	# Write HTML and XML files if required
--	create_html( sort {$a <=> $b} keys %index_pid ) if $opt{html};
--	create_xml( $opt{fxd}, sort {$a <=> $b} keys %index_pid ) if $opt{fxd};
--	create_xml( $opt{mythtv}, sort {$a <=> $b} keys %index_pid ) if $opt{mythtv};
--
- 	# Parse remaining args
- 	my @match_list;
- 	for ( @search_args ) {
- 		chomp();
--	
--		# If Numerical value < 30000
--		if ( /^[\d]+$/ && $_ < 30000) {
-+
-+		# If Numerical value < $max_index
-+		if ( /^[\d]+$/ && $_ <= $max_index) {
- 			push @match_list, $_;
- 	
- 		# If PID then find matching programmes with this PID
-@@ -649,24 +720,29 @@
- 	# Go get the cached data for other programme types if the index numbers require it
- 	my %require;
- 	for ( @match_list ) {
--		$require{tv} = 1 if $_ >= 1 && $_ < 10000 && ( ! $require{tv} ) && $opt{type} !~ /tv/;
--		$require{radio} = 1 if $_ >= 10000 && $_ < 20000 && ( ! $require{radio} ) && $opt{type} !~ /radio/;
--		$require{podcast} = 1 if $_ >= 20000 && $_ < 30000 && ( ! $require{podcast} ) && $opt{type} !~ /podcast/;
-+		for my $types ( @all_prog_types ) {
-+			$require{$types} = 1 if $_ >= $index_range{$types}{min} && $_ <= $index_range{$types}{max} && ( ! $require{$types} ) && ( ! $type{$types} );
-+		}
- 	}
-+
- 	# Get extra required programme caches
- 	logger "INFO: Additionally getting cached programme data for ".(join ', ', keys %require)."\n" if %require > 0;
- 	# Get stream links from BBC iplayer site or from cache (also populates all hashes)
- 	for (keys %require) {
- 		# Get $_ stream links
- 		get_links( $_ );
--		# Add new prog types to the type option
--		$opt{type} .= ",$_";
-+		# Add new prog types to the type list
-+		$type{$_} = 1;
- 	}
--
- 	# Display list for download
- 	logger "Matches:\n" if @match_list;
- 	@match_list = list_progs( @match_list );
- 
-+	# Write HTML and XML files if required (with search options applied)
-+	create_html( @match_list ) if $opt{html};
-+	create_xml( $opt{fxd}, @match_list ) if $opt{fxd};
-+	create_xml( $opt{mythtv}, @match_list ) if $opt{mythtv};
-+
- 	# Do the downloads based on list of index numbers if required
- 	if ( $opt{get} || $opt{stdout} ) {
- 		for (@match_list) {
-@@ -681,16 +757,27 @@
- 				logger "ERROR: No PID for index $_ (try using --type option ?)\n";
- 				next;
- 			}
--			while ( $count < $retries && $pid && ($retcode = download_programme( $pid )) eq 'retry' ) {
--				logger "WARNING: Retrying download for '$prog{$pid}{name} - $prog{$pid}{episode}'\n";
--				$count++;
-+			for ($count = 1; $count <= $retries; $count++) {
-+				$retcode = download_programme( $pid );
-+				last if $retcode eq 'skip';
-+				if ( $retcode eq 'retry' && $count < $retries ) {
-+					logger "WARNING: Retrying download for '$prog{$pid}{name} - $prog{$pid}{episode}'\n";
-+				} else {
-+					$retcode = 1 if $retcode eq 'retry';
-+					last;
-+				}
- 			}
- 			# Add to history, tag file, and run post download command if download was successful
--			if ($retcode eq '0') {
-+			if ($retcode == 0) {
- 				add_to_download_history( $pid );
- 				tag_file( $pid );
- 				run_user_command( $pid, $opt{command} ) if $opt{command};
- 				pvr_report( $pid ) if $opt{pvr};
-+			# Next match if 'skip' was returned
-+			} elsif ( $retcode eq 'skip' ) {
-+				last;
-+			} elsif (! $opt{test}) {
-+				logger "ERROR: Failed to download '$prog{$pid}{name} - $prog{$pid}{episode}'\n";
- 			}
- 		}
- 	}
-@@ -702,16 +789,11 @@
- 
- # Lists progs given an array of index numbers, also returns an array with non-existent entries removed
- sub list_progs {
--	my $ua;
-+	my $ua = create_ua('desktop');
- 	my @checked;
- 	my %names;
- 	# Setup user agent for a persistent connection to get programme metadata
- 	if ( $opt{info} ) {
--		$ua = LWP::UserAgent->new;
--		$ua->timeout([$lwp_request_timeout]);
--		$ua->proxy( ['http'] => $proxy_url );
--		$ua->agent( $user_agent{desktop} );
--		$ua->conn_cache(LWP::ConnCache->new());
- 		# Truncate array if were lisiting info and > $info_limit entries are requested - be nice to the beeb!
- 		if ( $#_ >= $info_limit ) {
- 			$#_ = $info_limit - 1;
-@@ -733,18 +815,7 @@
- 		push @checked, $_;
- 		if ( $opt{info} ) {
- 			my %metadata = get_pid_metadata( $ua, $pid );
--			logger "\nPid:\t\t$metadata{pid}\n";
--			logger "Index:\t\t$metadata{index}\n";
--			logger "Type:\t\t$metadata{type}\n";
--			logger "Duration:\t$metadata{duration}\n";
--			logger "Channel:\t$metadata{channel}\n";
--			logger "Available:\t$metadata{available}\n";
--			logger "Expires:\t$metadata{expiry}\n";
--			logger "Versions:\t$metadata{versions}\n";
--			logger "Guidance:\t$metadata{guidance}\n";
--			logger "Categories:\t$metadata{categories}\n";
--			logger "Description:\t$metadata{desc}\n";
--			logger "Player:\t\t$metadata{player}\n";
-+			display_metadata( \%metadata, qw/ pid index type duration channel available expiry versions guidance categories desc player / );
- 		}
- 	}
- 	logger "\n";
-@@ -758,8 +829,9 @@
- # Display a line containing programme info (using long, terse, and type options)
- sub list_prog_entry {
- 	my ( $pid, $prefix, $tree ) = ( @_ );
--	my $type = '';
--	$type = "$prog{$pid}{type}, " if $opt{type} !~ /^(tv|radio|podcast)$/i;
-+	my $prog_type = '';
-+	# Show the type field if >1 type has been specified
-+	$prog_type = "$prog{$pid}{type}, " if keys %type > 1;
- 	my $name;
- 	# If tree view
- 	if ( $opt{tree} ) {
-@@ -768,20 +840,21 @@
- 	} else {
- 		$name = "$prog{$pid}{name} - ";
- 	}
--	# Remove some info depending on type
-+	# Remove some info depending on prog_type
- 	my $optional;
- 	$optional = ", '$prog{$pid}{channel}', $prog{$pid}{categories}, $prog{$pid}{versions}" if $prog{$pid}{type} eq 'tv';
-+	$optional = ", '$prog{$pid}{channel}'" if $prog{$pid}{type} eq 'itv';
- 	$optional = ", '$prog{$pid}{channel}', $prog{$pid}{categories}" if $prog{$pid}{type} eq 'radio';
- 	$optional = ", '$prog{$pid}{available}', '$prog{$pid}{channel}', $prog{$pid}{categories}" if $prog{$pid}{type} eq 'podcast';
--	logger "\n${type}$prog{$pid}{name}\n" if $opt{tree} && ! $tree;
-+	logger "\n${prog_type}$prog{$pid}{name}\n" if $opt{tree} && ! $tree;
- 	# Display based on output options
- 	if ( $opt{long} ) {
- 		my @time = gmtime( time() - $prog{$pid}{timeadded} );
--		logger "${prefix}$prog{$pid}{index}:\t${type}${name}$prog{$pid}{episode}${optional}, $time[7] days $time[2] hours ago - $prog{$pid}{desc}\n";
-+		logger "${prefix}$prog{$pid}{index}:\t${prog_type}${name}$prog{$pid}{episode}${optional}, $time[7] days $time[2] hours ago - $prog{$pid}{desc}\n";
- 	} elsif ( $opt{terse} ) {
--		logger "${prefix}$prog{$pid}{index}:\t${type}${name}$prog{$pid}{episode}\n";
-+		logger "${prefix}$prog{$pid}{index}:\t${prog_type}${name}$prog{$pid}{episode}\n";
- 	} else {
--		logger "${prefix}$prog{$pid}{index}:\t${type}${name}$prog{$pid}{episode}${optional}\n";
-+		logger "${prefix}$prog{$pid}{index}:\t${prog_type}${name}$prog{$pid}{episode}${optional}\n";
- 	}
- 	return 0;
- }
-@@ -795,6 +868,7 @@
- 	my $channel_regex = $opt{channel} || '.*';
- 	my $category_regex = $opt{category} || '.*';
- 	my $versions_regex = $opt{versions} || '.*';
-+	my $exclude_regex = $opt{exclude} || '^ROGUE$';
- 	my $channel_exclude_regex = $opt{excludechannel} || '^ROGUE$';
- 	my $category_exclude_regex = $opt{excludecategory} || '^ROGUE$';
- 	my $since = $opt{since} || 99999;
-@@ -808,6 +882,7 @@
- 		  && $prog{$pid}{categories} =~ /$category_regex/i
- 		  && $prog{$pid}{versions} =~ /$versions_regex/i
- 		  && $prog{$pid}{channel} !~ /$channel_exclude_regex/i
-+		  && $prog{$pid}{name} !~ /$exclude_regex/i
- 		  && $prog{$pid}{categories} !~ /$category_exclude_regex/i
- 		  && $prog{$pid}{timeadded} >= $now - ($since * 3600)
- 		) {
-@@ -828,25 +903,22 @@
- 			);
- 		}
- 	}
-+
- 	return sort {$a <=> $b} keys %download_hash;
- }
- 
- 
--# get_links_atom (%channels)
--sub get_links_atom {
--	my $type = shift;
-+# get_links_bbciplayer (%channels)
-+sub get_links_bbciplayer {
-+	my $prog_type = shift;
- 	my %channels = %{$_[0]};
- 
- 	my $xml;
- 	my $feed_data;
- 	my $res;
--	logger "INFO: Getting $type Index Feeds\n";
-+	logger "INFO: Getting $prog_type Index Feeds\n";
- 	# Setup User agent
--	my $ua = LWP::UserAgent->new;
--	$ua->timeout([$lwp_request_timeout]);
--	$ua->proxy( ['http'] => $proxy_url );
--	$ua->agent( $user_agent{desktop} );
--	$ua->conn_cache(LWP::ConnCache->new());
-+	my $ua = create_ua('desktop');
- 
- 	# Download index feed
- 	# Sort feeds so that category based feeds are done last - this makes sure that the channels get defined correctly if there are dups
-@@ -909,7 +981,7 @@
- 		# Discard first element == header
- 		shift @entries;
- 
--		my ( $name, $episode, $desc, $pid, $available, $channel, $duration, $thumbnail, $type, $versions );
-+		my ( $name, $episode, $desc, $pid, $available, $channel, $duration, $thumbnail, $prog_type, $versions );
- 		foreach my $entry (@entries) {
- 
- 			my $entry_flat = $entry;
-@@ -939,7 +1011,7 @@
- 			}
- 
- 			# Extract channel and type
--			($type, $channel) = (split /\|/, $channels{$_})[0,1];
-+			($prog_type, $channel) = (split /\|/, $channels{$_})[0,1];
- 
- 			logger "DEBUG: '$pid, $name - $episode, $channel'\n" if $opt{debug};
- 
-@@ -980,7 +1052,7 @@
- 				'thumbnail'	=> "${thumbnail_prefix}/${pid}_150_84.jpg",
- 				'channel'	=> $channel,
- 				'categories'	=> join(',', @category),
--				'type'		=> $type,
-+				'type'		=> $prog_type,
- 			};
- 		}
- 	}
-@@ -996,13 +1068,8 @@
- 
- 	# Add index field based on alphabetical sorting by prog name
- 	my %index;
--	$index{tv} = 1;
--	
--	# Start index counter at 10001 for radio progs
--	$index{radio} = 10001;
--
--	# Start index counter at 20001 for podcast progs
--	$index{podcast} = 20001;
-+	# Start index counter at 'min' for each prog type
-+	$index{$_} = $index_range{$_}{min} for @all_prog_types;
- 
- 	my @prog_pid;
- 
-@@ -1013,10 +1080,10 @@
- 	for (sort @prog_pid) {
- 		# Extract pid
- 		my $pid = (split /\|/)[1];
--		my $type = $prog{$pid}{type};
--		$index_pid{ $index{$type} } = $pid;
--		$prog{$pid}{index} = $index{$type};
--		$index{$type}++;
-+		my $prog_type = $prog{$pid}{type};
-+		$index_pid{ $index{$prog_type} } = $pid;
-+		$prog{$pid}{index} = $index{$prog_type};
-+		$index{$prog_type}++;
- 	}
- 	return 0;
- }
-@@ -1024,18 +1091,14 @@
- 
- 
- # Uses: $podcast_index_feed_url
--# get_podcast_links ()
--sub get_podcast_links {
-+# get_links_bbcpodcast ()
-+sub get_links_bbcpodcast {
- 
- 	my $xml;
- 	my $res;
- 	logger "INFO: Getting podcast Index Feeds\n";
- 	# Setup User agent
--	my $ua = LWP::UserAgent->new;
--	$ua->timeout([$lwp_request_timeout]);
--	$ua->proxy( ['http'] => $proxy_url );
--	$ua->agent( $user_agent{get_iplayer} );
--	$ua->conn_cache(LWP::ConnCache->new());
-+	my $ua = create_ua('get_iplayer');
- 	
- 	# Method
- 	# $podcast_index_feed_url (gets list of rss feeds for each podcast prog) =>
-@@ -1224,6 +1287,302 @@
- 
- 
- 
-+# Uses:
-+# get_links_itv ()
-+sub get_links_itv {
-+	my %channels = %{$_[0]};
-+	my $xml;
-+	my $res;
-+	my %series_pid;
-+	my %episode_pid;
-+	logger "INFO: Getting itv Index Feeds\n";
-+	# Setup User agent
-+	my $ua = create_ua('desktop');
-+
-+	# Method
-+	# http://www.itv.com/_data/xml/CatchUpData/CatchUp360/CatchUpMenu.xml (gets list of urls for each prog series) =>
-+	#  =>
-+	
-+	# Download index feed
-+	my $itv_index_shows_url = 'http://www.itv.com/ClassicTVshows/'; # $channel/default.html
-+	my $itv_index_feed_url = 'http://www.itv.com/_data/xml/CatchUpData/CatchUp360/CatchUpMenu.xml';
-+
-+	# Sort feeds so that pages are done last - this makes sure that the channels get defined correctly if there are dups
-+	my @channel_list;
-+	push @channel_list, grep !/\//, keys %channels;
-+	push @channel_list, grep  /\//, keys %channels;
-+	# ITV ClassicShows parsing
-+	for my $channel ( @channel_list ) {
-+		# <li class="first-child"><a href="http://www.itv.com/ClassicTVshows/comedy/ABitofaDo/default.html">A Bit of a Do</a><br></li>
-+		# <li><a href="http://www.itv.com/ClassicTVshows/familydrama/achristmascarol/default.html">A Christmas Carol</a><br></li>
-+		# Get page, search for relevent lines which contain series links and loop through each matching line
-+		for my $s_line ( grep /(<li><a\s+href=".+?"><img\s+src=".+?"\s+alt=".+?"><\/a><h4>|<li.*?><a href=".+?">.+?<\/a><br><\/li>)/, ( split /\n/, request_url_retry($ua, $itv_index_shows_url.${channel}.'/default.html', 3, '.', "WARNING: Failed to get itv ${channel} index from site\n") ) ) {
-+			my ($url, $name);
-+			# Extract series url + series description
-+			($url, $name) = ($1, $2) if $s_line =~ m{<li><a\s+href="\s*(.+?)\s*"><img\s+src=".+?"\s+alt="\s*(.+?)\s*"><\/a><h4>};
-+			($url, $name) = ($1, $2) if $s_line =~ m{<li.*?><a href="\s*(.+?)\s*">\s*(.+?)\s*<\/a><br><\/li>};
-+			chomp($url);
-+			chomp($name);
-+			next if ! ($url && $name);
-+			logger "DEBUG: Channel: '$channel' Series: '$name' URL: '$url'\n" if $opt{verbose};
-+
-+			# Get list of episodes for this series
-+			# e.g. <li class="first-child"><a title="Play" href="?vodcrid=crid://itv.com/993&amp;DF=0">Episode one</a><br>The Sun in a Bottle</li>
-+			#      <li><a title="Play" href="?vodcrid=crid://itv.com/994&amp;DF=0">Episode two</a><br>Castle Saburac</li>
-+			#      <li class="first-child"><a class="nsat" title="This programme contains strong language and violence       " href="?vodcrid=crid://itv.com/588&amp;G=10&amp;DF=0">Episode one</a><br>The Dead of Jericho</li>
-+			#
-+			# e.g. <li><a class="playVideo" title="Play" href="?vodcrid=crid://itv.com/1232&amp;DF=0"><img src="img/60x45/Crossroads-Rosemary-shoots-David-efeef7cd-8d41-416c-9e30-26ce1b3d625c.jpg" alt="Crossroads: Rosemary shoots David"><span>Play</span></a><h4>
-+			#      vodcrid=crid://itv.com/971&amp;DF=0"><img src="img/60x45/9d20fd47-5d4b-44f5-9188-856505de0d0f.jpg" alt="Emmerdale  2002 Louise kills Ray"
-+			#
-+			# e.g. <a class="playVideo" title="Play" href="?vodcrid=crid://itv.com/1854&amp;DF=1"><img src="img/157x104/140c456c-d8bd-49d5-90f8-f7cc6d86f132.jpg" alt="Soldier Soldier "><span>Play</span></a><h2>Soldier Soldier</h2>
-+			#
-+			for my $e_line ( grep /vodcrid=crid/, ( split /\n/, request_url_retry($ua, $url, 3, '.', "WARNING: Failed to get ${name} index from site\n") ) ) {
-+				my ($guidance, $pid, $episode, $thumbnail);
-+				logger "DEBUG: Match Line: $e_line\n" if $opt{debug};
-+				# Extract episode data
-+				($guidance, $pid, $episode)  = ($2, $3, $4) if $e_line =~ m{<li.*?><a\s+(class="nsat"\s+)?title="\s*(.+?)\s*"\s+href="\?vodcrid=crid://itv.com/(\d+?)&.+?>\s*(.+?)\s*<};
-+				($pid, $thumbnail, $episode) = ($1, $2, $3) if $e_line =~ m{vodcrid=crid://itv.com/(\d+?)&.+?><img\s+src="(.+?)"\s+alt="\s*(.+?)\s*"};
-+				next if ! ($pid && $episode);
-+				# Remove 'Play'
-+				$guidance =~ s/^Play$//ig;
-+				# Strip non-printables
-+				$guidance =~ s/[\s\x00\xc2\xa0]+$//ig;
-+				#$guidance =~ s|[^\w\s\-\!"£\$\\/%\^&\*\(\)\+=,\.\?':;@~\[\]]+||gi;
-+				#$guidance =~ s/(\s\s)+//g;
-+				logger "DEBUG: PID: '$pid' Episode: '$episode' Guidance: '$guidance'\n" if $opt{debug};
-+
-+				# Skip if this pid is a duplicate
-+				if ( defined $prog{$pid} ) {
-+					logger "WARNING: '$pid, $prog{$pid}{name} - $prog{$pid}{episode}, $prog{$pid}{channel}' already exists (this channel = $channel)\n" if $opt{verbose};
-+					# Merge data (hack)
-+					#$prog{$pid}{episode} .= ','.$episode;
-+					my $oldname = $prog{$pid}{name};
-+					$prog{$pid}{episode} = $episode if (! $prog{$pid}{episode}) || $prog{$pid}{episode} =~ /$oldname/i;
-+					$prog{$pid}{thumbnail} = $thumbnail if ! $prog{$pid}{thumbnail};
-+					$prog{$pid}{guidance} = $guidance if ! $prog{$pid}{guidance};
-+					next;
-+				}
-+
-+				# build data structure
-+				$prog{$pid} = {
-+					'name'		=> $name,
-+					'versions'	=> 'default',
-+					'episode'	=> $episode,
-+					'channel'	=> (split /\|/, $channels{$channel})[1],
-+					'guidance'	=> $guidance,
-+					'categories'	=> (split /\|/, $channels{$channel})[1],
-+					'type'		=> 'itv',
-+				};
-+			}
-+		}
-+	}
-+
-+	my $xmlindex = request_url_retry($ua, $itv_index_feed_url, 3, '.', "WARNING: Failed to get itv index from site\n");
-+	$xmlindex =~ s/[\n\r]//g;
-+
-+	# This gives a list of programme series (sometimes episodes)
-+	#    <ITVCatchUpProgramme>
-+	#      <ProgrammeId>50</ProgrammeId>
-+	#      <ProgrammeTitle>A CHRISTMAS CAROL</ProgrammeTitle>
-+	#      <ProgrammeMediaId>615915</ProgrammeMediaId>
-+	#      <ProgrammeMediaUrl>
-+	#      http://www.itv.com//img/150x113/A-Christmas-Carol-2f16d25a-de1d-4a3a-90cb-d47489eee98e.jpg</ProgrammeMediaUrl>
-+	#      <LastUpdated>2009-01-06T12:24:22.7419643+00:00</LastUpdated>
-+	#      <Url>
-+	#      http://www.itv.com/CatchUp/Video/default.html?ViewType=5&amp;Filter=32910</Url>
-+	#      <EpisodeCount>1</EpisodeCount>
-+	#      <VideoID>32910</VideoID>
-+	#      <DentonID>-1</DentonID>
-+	#      <DentonRating></DentonRating>
-+	#      <AdditionalContentUrl />
-+	#      <AdditionalContentUrlText />
-+	#    </ITVCatchUpProgramme>
-+
-+	for my $feedxml ( split /<ITVCatchUpProgramme>/, $xmlindex ) {
-+		# Extract feed data
-+		my ($episodecount, $viewtype, $videoid, $url);
-+		my @entries;
-+
-+		logger "\n\nDEBUG: XML: $feedxml\n"  if $opt{debug}; 
-+
-+		# <EpisodeCount>1</EpisodeCount>
-+		$episodecount = $1 if $feedxml =~ m{<EpisodeCount>\s*(\d+)\s*<\/EpisodeCount>};
-+
-+		# <Url>http://www.itv.com/CatchUp/Video/default.html?ViewType=5&amp;Filter=32910</Url>
-+		($viewtype, $videoid) = ($1, $2) if $feedxml =~ m{<Url>\s*.+?ViewType=(\d+).+?Filter=(\d+)\s*<\/Url>}i;
-+
-+		## <VideoID>32910</VideoID>
-+		#$videoid = $1 if $feedxml =~ m{<VideoID>\s*(\d+)\s*<\/VideoID>};
-+
-+		# Skip if there is no feed data for channel
-+		next if ($viewtype =~ /^0*$/ || $videoid =~ /^0*$/ );
-+
-+		logger "DEBUG: Got ViewType=$viewtype VideoId=$videoid EpisodeCount=$episodecount\n" if $opt{debug};
-+
-+		my $url = "http://www.itv.com/_app/Dynamic/CatchUpData.ashx?ViewType=${viewtype}&Filter=${videoid}";
-+
-+		# Add response from episode metadata url to list to be parsed if this is an episode link
-+		if ( $viewtype == 5 ) {
-+			next if $episode_pid{$videoid};
-+			$episode_pid{$videoid} = 1;
-+			# Get metadata pages for episode
-+
-+			my ( $name, $guidance, $channel, $episode, $desc, $pid, $available, $duration, $thumbnail );
-+
-+			$pid = $videoid;
-+			$channel = 'ITV Catch-up';
-+
-+			# Skip if this pid is a duplicate
-+			if ( defined $prog{$pid} ) {
-+				logger "WARNING: '$pid, $prog{$pid}{name} - $prog{$pid}{episode}, $prog{$pid}{channel}' already exists (this channel = $channel)\n" if $opt{verbose};
-+				next;
-+			}
-+
-+			$name = $1 if $feedxml =~ m{<ProgrammeTitle>\s*(.+?)\s*<\/ProgrammeTitle>};
-+			$guidance = $1 if $feedxml =~ m{<DentonRating>\s*(.+?)\s*<\/DentonRating>};
-+			$thumbnail = $1 if $feedxml =~ m{<ProgrammeMediaUrl>\s*(.+?)\s*<\/ProgrammeMediaUrl>};
-+			$episode = $pid;
-+			# Strip non-printable chars
-+			$guidance =~ s/[\s\x00\xc2\xa0]+$//ig;
-+
-+			# build data structure
-+			$prog{$pid} = {
-+				'name'		=> $name,
-+				'versions'	=> 'default',
-+				'episode'	=> $episode,
-+				'guidance'	=> $guidance,
-+				'desc'		=> $desc,
-+				'available'	=> $available,
-+				'duration'	=> $duration,
-+				'thumbnail'	=> $thumbnail,
-+				'channel'	=> $channel,
-+				'categories'	=> 'TV',
-+				'type'		=> 'itv',
-+			};
-+
-+
-+
-+
-+
-+		# Get next episode list and parse
-+		#     <div class="listItem highlight contain">
-+		#      <div class="floatLeft"><a href="http://www.itv.com/CatchUp/Video/default.html?ViewType=5&amp;Filter=33383"><img src="http://www.itv.com//img/157x88/P7-67e0b86f-b335-4f6b-8db
-+		#      <div class="content">
-+		#        <h3><a href="http://www.itv.com/CatchUp/Video/default.html?ViewType=5&amp;Filter=33383">Emmerdale</a></h3>
-+		#        <p class="date">Mon 05 Jan 2009</p>
-+		#        <p class="progDesc">Donna is stunned to learn Marlon has pointed the finger at Ross. Aaron defaces Tom King's grave.</p>
-+		#        <ul class="progDetails">
-+		#          <li>
-+		#                          Duration: 30 min
-+		#          </li>
-+		#          <li class="days">
-+		#            Expires in
-+		#                        <strong>29</strong>
-+		#                                        days
-+		#                                </li>
-+		#        </ul>
-+		#      </div>
-+		#    </div>
-+		#    <div class="listItem contain">
-+		#      <div class="floatLeft"><a href="http://www.itv.com/CatchUp/Video/default.html?ViewType=5&amp;Filter=33245"><img src="http://www.itv.com//img/157x88/Marlon-Dingle-742c50b3-3b
-+		#      <div class="content">
-+		#        <h3><a href="http://www.itv.com/CatchUp/Video/default.html?ViewType=5&amp;Filter=33245">Emmerdale</a></h3>
-+		#        <p class="date">Fri 02 Jan 2009</p>
-+		#        <p class="progDesc">Marlon gets his revenge on Ross. The King brothers struggle to restart their business without Matthew. Scarlett is fed up with Victoria getting all Daz
-+		#        <ul class="progDetails">
-+		#          <li>
-+		#                          Duration: 30 min
-+		#          </li>
-+		#          <li class="days">
-+		#            Expires in
-+		#                        <strong>26</strong>
-+		#                                        days
-+		#                                </li>
-+		#        </ul>
-+		#      </div>
-+		#    </div>
-+		# 
-+		} elsif ( $viewtype == 1 ) {
-+			# Make sure we don't duplicate parsing a series
-+			next if $series_pid{$videoid};
-+			$series_pid{$videoid} = 1;
-+
-+			# Get metadata pages for each series
-+			logger "DEBUG: Getting series metadata $url\n" if $opt{debug};
-+			$xml = request_url_retry($ua, $url, 2, '.', "WARNING: Failed to get itv series data for ${videoid} from itv site\n") if $opt{verbose};
-+			$xml = request_url_retry($ua, $url, 2, '.', '') if ! $opt{verbose};
-+
-+			# skip if no data
-+			next if ! $xml;
-+
-+			decode_entities($xml);
-+			# Flatten entry
-+			$xml =~ s/[\n\r]//g;
-+
-+			# Extract Filter (pids) from this list
-+			# e.g. <h3><a href="http://www.itv.com/CatchUp/Video/default.html?ViewType=5&amp;Filter=32042">Emmerdale</a></h3>
-+			my @videoids = (split /<h3><a href=.+?Filter=/, $xml);
-+
-+			# Get episode data for each videoid
-+			$viewtype = 5;
-+
-+			my @episode_data = split/<h3><a href=.+?Filter=/, $xml;
-+			# Ignore first entry
-+			shift @episode_data;
-+			logger "INFO: Got ".($#episode_data+1)." programmes\n" if $opt{verbose};
-+
-+			for my $xml (@episode_data) {
-+				$videoid = $1 if $xml =~ m{^(\d+?)".+$}i;
-+
-+				# Make sure we don't duplicate parsing an episode
-+				next if $episode_pid{$videoid};
-+				$episode_pid{$videoid} = 1;
-+
-+				my ( $name, $guidance, $channel, $episode, $desc, $pid, $available, $duration, $thumbnail );
-+	
-+				$pid = $videoid;
-+				$channel = 'ITV Catch-up';
-+	
-+				# Skip if this pid is a duplicate
-+				if ( defined $prog{$pid} ) {
-+					logger "WARNING: '$pid, $prog{$pid}{name} - $prog{$pid}{episode}, $prog{$pid}{channel}' already exists (this channel = $channel)\n" if $opt{verbose};
-+					next;
-+				}
-+				$name = $1 if $feedxml =~ m{<ProgrammeTitle>\s*(.+?)\s*<\/ProgrammeTitle>};
-+				$available = $1 if $xml =~ m{<p\s+class="date">(.+?)<\/p>}i;
-+				$episode = $available;
-+				$duration = $1 if $xml =~ m{<li>Duration:\s*(.+?)\s*<\/li>}i;
-+				$desc = $1 if $xml =~ m{<p\s+class="progDesc">(.+?)\s*<\/p>};
-+				$guidance = $1 if $feedxml =~ m{<DentonRating>\s*(.+?)\s*<\/DentonRating>};
-+				$thumbnail = $1 if $feedxml =~ m{<ProgrammeMediaUrl>\s*(.+?)\s*<\/ProgrammeMediaUrl>};
-+				$guidance =~ s/[\s\x00\xc2\xa0]+$//ig;
-+
-+				logger "DEBUG: name='$name' episode='$episode' pid=$pid available='$available' \n" if $opt{debug};	
-+	
-+				# build data structure
-+				$prog{$pid} = {
-+					'name'		=> $name,
-+					'versions'	=> 'default',
-+					'episode'	=> $episode,
-+					'guidance'	=> $guidance,
-+					'desc'		=> $desc,
-+					'available'	=> $available,
-+					'duration'	=> $duration,
-+					'thumbnail'	=> $thumbnail,
-+					'channel'	=> $channel,
-+					'categories'	=> 'TV',
-+					'type'		=> 'itv',
-+				};
-+			}
-+		}	
-+
-+	}
-+	logger "\n";
-+	return 0;
-+}
-+
-+
-+
- # Feed info:
- #	# Also see http://derivadow.com/2008/07/18/interesting-bbc-data-to-hack-with/
- #	# All podcasts menu (iphone)
-@@ -1261,14 +1620,14 @@
- #	http://www.bbc.co.uk/cbbc/programmes/genres/childrens/player
- #	http://www.bbc.co.uk/programmes/genres/childrens/schedules/upcoming.ics
- #
--# get_links( <radio|tv|podcast> )
-+# get_links( <prog_type> )
- sub get_links {
- 	my @cache;
- 	my $now = time();
--	my $type = shift;
-+	my $prog_type = shift;
- 
- 	# Open cache file (need to verify we can even read this)
--	if ( open(CACHE, "< $cachefile{$type}") ) {
-+	if ( open(CACHE, "< $cachefile{$prog_type}") ) {
- 		# Get file contents less any comments
- 		@cache = grep !/^[\#\s]/, <CACHE>;
- 		close (CACHE);
-@@ -1281,47 +1640,40 @@
- 		for (@cache) {
- 			# Populate %prog from cache
- 			chomp();
--			my ($index, $type, $name, $pid, $available, $episode, $versions, $duration, $desc, $channel, $categories, $thumbnail, $timeadded) = split /\|/;
--			# Create data structure with prog data
--			$prog_old{$pid} = {
--				'index'		=> $index,
--				'name'		=> $name,
--				'episode'	=> $episode,
--				'desc'		=> $desc,
--				'available'	=> $available,
--				'duration'	=> $duration,
--				'versions'	=> $versions,
--				'channel'	=> $channel,
--				'categories'	=> $categories,
--				'thumbnail'	=> $thumbnail,
--				'type'		=> $type,
--				'timeadded'	=> $timeadded,
--			};
--			$index_pid_old{$index}	= $pid;
-+			# Get cache line
-+			my @record = split /\|/;
-+			my %record_entries;
-+			# Update fields in %prog hash for $pid
-+			$record_entries{$_} = shift @record for @cache_format;
-+			$prog_old{ $record_entries{pid} } = \%record_entries;
-+			$index_pid_old{ $record_entries{index} }  = $record_entries{pid};
- 		}
- 	}
- 
- 	# if a cache file doesn't exist/corrupted, flush option is specified or original file is older than $cache_sec then download new data
--	if ( (! @cache) || (! -f $cachefile{$type}) || $opt{flush} || ($now >= ( stat($cachefile{$type})->mtime + $cache_secs )) ) {
-+	if ( (! @cache) || (! -f $cachefile{$prog_type}) || $opt{flush} || ($now >= ( stat($cachefile{$prog_type})->mtime + $cache_secs )) ) {
- 
--		# Podcast only
--		get_podcast_links() if $type eq 'podcast';
-+		# BBC Podcast only
-+		get_links_bbcpodcast() if $prog_type eq 'podcast';
- 
--		# Radio and TV
--		get_links_atom( $type, \%{$channels{$type}} ) if $type =~ /(tv|radio)/;
-+		# ITV only
-+		get_links_itv( \%{$channels{$prog_type}} ) if $prog_type eq 'itv';
-+
-+		# BBC Radio and TV
-+		get_links_bbciplayer( $prog_type, \%{$channels{$prog_type}} ) if $prog_type =~ /^(tv|radio)$/;
- 
- 		# Sort indexes
- 		sort_indexes();
- 		
- 		# Open cache file for writing
--		unlink $cachefile{$type};
-+		unlink $cachefile{$prog_type};
- 		my $now = time();
--		if ( open(CACHE, "> $cachefile{$type}") ) {
--			print CACHE "#Index|Type|Name|Pid|Available|Episode|Versions|Duration|Desc|Channel|Categories|Thumbnail|TimeAdded\n";
-+		if ( open(CACHE, "> $cachefile{$prog_type}") ) {
-+			print CACHE "#".(join '|', @cache_format)."\n";
- 			for (sort {$a <=> $b} keys %index_pid) {
- 				my $pid = $index_pid{$_};
- 				# Only write entries for correct prog type
--				if ($prog{$pid}{type} eq $type) {
-+				if ($prog{$pid}{type} eq $prog_type) {
- 					# Merge old and new data to retain timestamps
- 					# if the entry was in old cache then retain timestamp from old entry
- 					if ( $prog_old{$pid}{timeadded} ) {
-@@ -1332,12 +1684,17 @@
- 						list_prog_entry( $pid, 'Added: ' );
- 					}
- 					# write to cache file
--					print CACHE "$_|$prog{$pid}{type}|$prog{$pid}{name}|$pid|$prog{$pid}{available}|$prog{$pid}{episode}|$prog{$pid}{versions}|$prog{$pid}{duration}|$prog{$pid}{desc}|$prog{$pid}{channel}|$prog{$pid}{categories}|$prog{$pid}{thumbnail}|$prog{$pid}{timeadded}\n";
-+					$prog{$pid}{pid} = $pid;
-+					# Write each field into cache line
-+					for my $field (@cache_format) {
-+						print CACHE $prog{$pid}{$field}.'|';
-+					}
-+					print CACHE "\n";
- 				}
- 			}
- 			close (CACHE);
- 		} else {
--			logger "WARNING: Couldn't open cache file '$cachefile{$type}' for writing\n";
-+			logger "WARNING: Couldn't open cache file '$cachefile{$prog_type}' for writing\n";
- 		}
- 
- 
-@@ -1354,172 +1711,434 @@
- # Usage: download_programme (<pid>)
- sub download_programme {
- 	my $pid = shift;
-+	my %streamdata;
-+	my %version_pids;
-+	my $return;
- 
- 	# Setup user-agent
--	# Switch off automatic redirects
--	my $ua = LWP::UserAgent->new( requests_redirectable => [] );
--	# Setup user agent
--	$ua->timeout([$lwp_request_timeout]);
--	$ua->proxy( ['http'] => $proxy_url );
--	$ua->cookie_jar( HTTP::Cookies->new( file => $cookiejar, autosave => 1, ignore_discard => 1 ) );
-+	my $ua = create_ua('desktop');
- 
--	my $dir = $download_dir{ $prog{$pid}{type} };
--	$prog{$pid}{ext} = 'mov';
-+	# download depending on the prog type
-+	logger "INFO: Attempting to Download $prog{$pid}{type}: $prog{$pid}{name} - $prog{$pid}{episode}\n";
- 
--	# If were a podcast...
-+	# ITV TV
-+	if ( $prog{$pid}{type} eq 'itv' ) {
-+		# stream data
-+		# Display media stream data if required
-+		if ( $opt{streaminfo} ) {
-+			display_stream_info( $pid, undef, 'all' );
-+			$opt{quiet} = 1;
-+			return 'skip';
-+		}
-+		return download_programme_itv( $ua, $pid );
-+	}
-+
-+	# BBC Podcasts
- 	if ( $prog{$pid}{type} eq 'podcast' ) {
--		# Determine the correct filename and extension for this download
--		my $filename_orig = $pid;
--		$prog{$pid}{ext} = $pid;
--		$filename_orig =~ s|^.+/(.+?)\.\w+$|$1|g;
--		$prog{$pid}{ext} =~ s|^.*\.(\w+)$|$1|g;
--		$prog{$pid}{fileprefix} = generate_download_filename_prefix($pid, $dir, $opt{fileprefix} || "<longname> - <episode> $filename_orig");
--		$prog{$pid}{dir} = $dir;
--		logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                  \n";
--		my $file_done = "${dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
--		my $file = "${dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
--		$prog{$pid}{filename} = $file_done;
--		if ( -f $file_done ) {
--			logger "WARNING: File $file_done already exists\n\n";
--			return 1;
-+		# stream data not available
-+		return 'skip' if $opt{streaminfo};
-+		return download_programme_podcast( $ua, $pid );
-+	}
-+
-+	# For BBC Radio/TV we might have a pid with no prog_type - determine here first
-+	( $prog{$pid}{type}, $prog{$pid}{longname}, %version_pids ) = get_version_pids( $ua, $pid );
-+
-+	# BBC TV
-+	if ( $prog{$pid}{type} eq 'tv' ) {
-+
-+		# Deal with BBC TV fallback modes
-+		# Valid modes are iphone,rtmp,flashhigh,flashnormal,flashwii,n95_wifi
-+		$opt{vmode} = 'flashhigh,flashnormal' if $opt{vmode} eq 'rtmp' || $opt{vmode} eq 'flash';
-+		# Defaults
-+		if ( $opt{vmode} eq 'auto' || ! $opt{vmode} ) {
-+			if ( ! exists_in_path($rtmpdump) ) {
-+				$opt{vmode} = 'iphone';	
-+			} else {
-+				$opt{vmode} = 'iphone,flashhigh,flashnormal';
-+			}
- 		}
-+		# Expand the modes into a loop
-+		logger "INFO: $opt{vmode} modes will be tried\n";
-+		for my $mode ( split /,/, $opt{vmode} ) {
-+			chomp( $mode );
-+			logger "INFO: Attempting to download using $mode mode\n";
-+			$return = download_programme_tv( $ua, $pid, $mode, \%version_pids );
-+			logger "DEBUG: Download using $mode mode return code: '$return'\n" if $opt{debug};
- 
--		# Skip from here if we are only testing downloads
--		return 1 if $opt{test};
-+			# Give up trying alternative download methods
-+			return 2 if $return eq 'abort';
- 
--		# Create symlink filename if required
--		my $file_symlink;
--		if ( $opt{symlink} ) {
--			# Substitute the fields for the pid
--			$file_symlink = substitute_fields( $pid, $opt{symlink} );
-+			# Return to retry loop if successful or retry requested 
-+			return 'retry' if $return eq 'retry';
-+
-+			# Return to retry loop and do nothing 
-+			return 'skip' if $return eq 'skip';
-+
-+			# Return 0 if successful 
-+			return 0 if ! $return;
-+
-+			# Return failed if there is no 'next'
-+			return 1 if $return ne 'next';
- 		}
--		
--		return download_podcast_stream( $ua, $pid, $file, $file_done, $file_symlink );
- 	}
- 
--	logger "INFO: Attempting to Download: $prog{$pid}{name} - $prog{$pid}{episode}\n";
-+	# BBC Radio
-+	if ( $prog{$pid}{type} eq 'radio' ) {
-+		# This will always be the pid version for radio
-+		$prog{$pid}{version} = 'default';
-+		# Display media stream data if required
-+		if ( $opt{streaminfo} ) {
-+			display_stream_info( $pid, $version_pids{default}, 'all' );
-+			$opt{quiet} = 1;
-+			return 'skip';
-+		}
-+
-+		# Deal with radio fallback modes
-+		# Valid modes are mp3|iphone,flash|rtmp,real|ra
-+		# Defaults
-+		$opt{amode} = 'iphone,flash,real' if $opt{amode} eq 'auto' || ! $opt{amode};
-+
-+		# Expand the modes into a loop
-+		logger "INFO: $opt{amode} modes will be tried\n";
-+		for my $mode ( split /,/, $opt{amode} ) {
-+			chomp( $mode );
-+			logger "INFO: Attempting to download using $mode mode\n";
-+			# RealAudio
-+			if ( $mode =~ /^(real|ra)/ ) {
-+				$return = download_programme_radio_realaudio( $ua, $pid, \%version_pids );
-+
-+			# FlashAudio
-+			} elsif ( $mode =~ /^(flash|rtmp)/ ) {
-+				$return = download_programme_radio_flashaudio( $ua, $pid, $mode, \%version_pids );
-+
-+			# iPhone
-+			} elsif ( $mode =~ /^(iphone|mp3)/ ) {
-+				$return = download_programme_radio_iphone( $ua, $pid, \%version_pids );
-+			}
-+			logger "DEBUG: Download using $mode mode return code: '$return'\n" if $opt{debug};
- 
--	# Get version => pid hash
--	my ( $type, $title, %version_pids ) = get_version_pids( $ua, $pid );
-+			# Give up trying alternative download methods
-+			return 2 if $return eq 'abort';
- 
--	# Extract Long Name, e.g.: iplayer.episode.setTitle("DIY SOS: Series 16: Swansea");
--	$prog{$pid}{longname} = $title;
-+			# Not going to allow retries here until rtmpdump/flashaudio exits correctly - so just just skip to next mode for now
-+			$return = 'next' if $return eq 'retry';
-+			## Return to retry loop if successful or retry requested 
-+			#return 'retry' if $return eq 'retry';
- 
--	# Strip off the episode name
--	$prog{$pid}{longname} =~ s/^(.+):.*?$/$1/g;
-+			# Return to retry loop and do nothing 
-+			return 'skip' if $return eq 'skip';
- 
--	# Detect if this content is for radio
--	my $usemp3 = 0;
--	if ( $type eq 'radio' ) {
-+			# Return 0 if successful 
-+			return 0 if ! $return;
- 
--		# Display media stream data if required
--		if ( $opt{streaminfo} ) {
--			get_media_stream_data( $pid, $version_pids{'default'}, 'all' );
--			return 1;
-+			# Return failed if there is no 'next'
-+			return 1 if $return ne 'next';
- 		}
-+	}
- 
--		# Type is definitely radio
--		$prog{$pid}{type} = 'radio';
--		$dir = $download_dir{ $prog{$pid}{type} };
--
--		# Check for mp3 stream  - unless realaudio option is specified
--		if ( ! $opt{realaudio} ) {
--			# Check for iphone mp3 radio stream
--			if ( get_media_stream_data( $pid, $version_pids{default}, 'iphone' ) ) {
--				$usemp3 = 1;
--				$prog{$pid}{ext} = 'mp3';
--				logger "INFO: MP3 stream media is available\n" if $opt{verbose};
--
--			# if mp3audio option is specified do not fallback to realaudio
--			} elsif ( $opt{mp3audio} ) {
--				logger "ERROR: No MP3 stream media is available - not falling back to RealAudio\n";
--				return 1;
-+	# If we get here then we have failed
-+	return 1;
-+}
- 
--			# if not then force realaudio option as fallback
--			} else {
--				$opt{realaudio} = 1;
--				logger "INFO: No MP3 stream media is available - falling back to RealAudio\n" if $opt{verbose};
--			}
--		}
- 
--		# Use realplayer stream
--		if ( $opt{realaudio} ) {
- 
--			# Check dependancies for radio programme transcoding / streaming
--			# Check if we need 'tee'
--			if ( (! exists_in_path($tee)) && $opt{stdout} && (! $opt{nowrite}) ) {
--				logger "\nERROR: $tee does not exist in path, skipping\n";
--				return 20;
--			}
--			# Check if we have mplayer and lame
--			if ( (! $opt{wav}) && (! $opt{raw}) && (! exists_in_path($lame)) ) {
--				logger "\nWARNING: Required $lame does not exist, falling back to wav mode\n";
--				$opt{wav} = 1;
--			}		
--			if (! exists_in_path($mplayer)) {
--				logger "\nERROR: Required $mplayer does not exist, skipping\n";
--				return 20;
--			}
-+sub download_programme_itv {
-+	my ( $ua, $pid ) = ( @_ );
-+	my %streamdata;
-+
-+	# Check for mplayer (required)
-+	if (! exists_in_path($mplayer)) {
-+		logger "\nERROR: Required $mplayer does not exist, skipping\n";
-+		return 21;
-+	}
- 
--			my $url_2 = get_media_stream_data( $pid, $version_pids{default}, 'realaudio' );
-+	$prog{$pid}{dir} = $download_dir{ $prog{$pid}{type} };
-+	$prog{$pid}{pid} = $pid;
-+	$prog{$pid}{ext} = 'mp4';
-+	$prog{$pid}{ext} = 'asf' if $opt{raw};
- 	
--			logger "INFO: Version = $prog{$pid}{version}\n" if $opt{verbose};
--			logger "INFO: Stage 2 URL = $url_2\n" if $opt{verbose};
-+	my @url_list = %{get_media_stream_data( $pid, undef, 'itv')}->{streamurl};
- 
--			# Report error if no versions are available
--			if ( ! $url_2 ) {
--				logger "ERROR: No Stage 2 URL\n" if $opt{verbose};
--				return 15;
--			}
-+	# Get and set more meta data - Set the %prog values from metadata if they aren't already set
-+	my %metadata = get_pid_metadata($ua, $pid);
-+	for ( qw/ name episode available duration thumbnail desc guidance / ) {
-+		$prog{$pid}{$_} = $metadata{$_} if ! $prog{$pid}{$_};
-+	}
- 
--			# Determine the correct filenames for this download
--			$prog{$pid}{ext} = 'mp3';
--			$prog{$pid}{ext} = 'ra'  if $opt{raw};
--			$prog{$pid}{ext} = 'wav' if $opt{wav};
--			$prog{$pid}{fileprefix} = generate_download_filename_prefix( $pid, ${dir}, $opt{fileprefix} || "<longname> - <episode> <pid>" );
--			logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                 \n";
--			$prog{$pid}{dir} = $dir;
--			my $file_done = "${dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
--			my $file = "${dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
--			$prog{$pid}{filename} = $file_done;
--			if ( -f $file_done ) {
--				logger "WARNING: File $file_done already exists\n\n";
--				return 1;
--			}
-+	$prog{$pid}{fileprefix} = generate_download_filename_prefix( $pid, $prog{$pid}{dir}, $opt{fileprefix} || "<name> <pid>" );
-+	logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                 \n";
-+	# Create a subdir if there are multiple parts
-+	if ($#url_list > 0) {
-+		$prog{$pid}{dir} .= "/$prog{$pid}{fileprefix}";
-+		logger "INFO: Creating subdirectory $prog{$pid}{dir} for programme\n" if $opt{verbose};
-+		mkpath $prog{$pid}{dir} if ! -d $prog{$pid}{dir};
-+	}
-+	my $file_done = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
-+	my $file = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
-+	$prog{$pid}{filename} = $file_done;
- 
--			# Skip from here if we are only testing downloads
--			return 1 if $opt{test};
-+	# Display metadata
-+	display_metadata( $prog{$pid}, qw/ pid index name duration available expiry desc / );
- 
--			# Create symlink filename if required
--			my $file_symlink;
--			if ( $opt{symlink} ) {
--				# Substitute the fields for the pid
--				$file_symlink = substitute_fields( $pid, $opt{symlink} );
--			}
-+	# Skip from here if we are only testing downloads
-+	return 1 if $opt{test};
- 
--			# Do the audio download
--			return download_rtsp_stream( $ua, $url_2, $file, $file_done, $file_symlink, $pid );
--		}
-+	return download_stream_mms_video( $ua, (join '|', @url_list), $file, $file_done, $pid );
-+}	
-+
-+
-+
-+sub download_programme_podcast {
-+	my ( $ua, $pid ) = ( @_ );
-+	my %streamdata;
-+
-+	$prog{$pid}{dir} = $download_dir{ $prog{$pid}{type} };
-+
-+	# Determine the correct filename and extension for this download
-+	my $filename_orig = $pid;
-+	$prog{$pid}{ext} = $pid;
-+	$filename_orig =~ s|^.+/(.+?)\.\w+$|$1|g;
-+	$prog{$pid}{ext} =~ s|^.*\.(\w+)$|$1|g;
-+	$prog{$pid}{fileprefix} = generate_download_filename_prefix($pid, $prog{$pid}{dir}, $opt{fileprefix} || "<longname> - <episode> $filename_orig");
-+	logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                  \n";
-+	my $file_done = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
-+	my $file = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
-+	$prog{$pid}{filename} = $file_done;
-+	if ( -f $file_done && stat($file_done)->size > $min_download_size ) {
-+		logger "WARNING: File $file_done already exists\n\n";
-+		return 1;
-+	}
-+
-+	# Skip from here if we are only testing downloads
-+	return 1 if $opt{test};
-+
-+	# Create symlink filename if required
-+	my $file_symlink;
-+	if ( $opt{symlink} ) {
-+		# Substitute the fields for the pid
-+		$file_symlink = substitute_fields( $pid, $opt{symlink} );
-+	}
-+
-+	return download_stream_podcast( $ua, $pid, $file, $file_done, $file_symlink );
-+}
-+
-+
-+
-+sub download_programme_radio_realaudio {
-+	my $ua = shift; 
-+	my $pid = shift;
-+	my %version_pids = %{@_[0]};
-+	my %streamdata;
-+
-+	# Check dependancies for radio programme transcoding / streaming
-+	# Check if we need 'tee'
-+	if ( (! exists_in_path($tee)) && $opt{stdout} && (! $opt{nowrite}) ) {
-+		logger "\nERROR: $tee does not exist in path, skipping\n";
-+		return 'abort';
-+	}
-+	if (! exists_in_path($mplayer)) {
-+		logger "\nWARNING: Required $mplayer does not exist\n";
-+		return 'next';
-+	}
-+	# Check if we have mplayer and lame
-+	if ( (! $opt{wav}) && (! $opt{raw}) && (! exists_in_path($lame)) ) {
-+		logger "\nWARNING: Required $lame does not exist, will save file in wav format\n";
-+		$opt{wav} = 1;
-+	}
-+
-+	$prog{$pid}{dir} = $download_dir{ $prog{$pid}{type} };
-+	$prog{$pid}{ext} = 'mp3';
-+	$prog{$pid}{ext} = 'ra'  if $opt{raw};
-+	$prog{$pid}{ext} = 'wav' if $opt{wav};
- 
-+	my $url_2 = %{get_media_stream_data( $pid, $version_pids{default}, 'realaudio')}->{streamurl};
-+		
-+	# Report error if no versions are available
-+	if ( ! $url_2 ) {
-+		logger "WARNING: RealAudio version not available\n";
-+		return 'next';
- 	} else {
--		# Type is definitely tv
--		$prog{$pid}{type} = 'tv';
--		$dir = $download_dir{ $prog{$pid}{type} };
-+		logger "INFO: Stage 2 URL = $url_2\n" if $opt{verbose};
-+	}
-+
-+	# Determine the correct filenames for this download
-+	$prog{$pid}{fileprefix} = generate_download_filename_prefix( $pid, $prog{$pid}{dir}, $opt{fileprefix} || "<longname> - <episode> <pid>" );
-+	logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                 \n";
-+	my $file_done = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
-+	my $file = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
-+	$prog{$pid}{filename} = $file_done;
-+	if ( -f $file_done ) {
-+		logger "WARNING: File $file_done already exists\n\n";
-+		return 'abort';
- 	}
- 
-+	# Skip from here if we are only testing downloads
-+	return 'abort' if $opt{test};
- 
--	# iPhone mp3/h.264 stream downloading...
-+	# Create symlink filename if required
-+	my $file_symlink;
-+	if ( $opt{symlink} ) {
-+		# Substitute the fields for the pid
-+		$file_symlink = substitute_fields( $pid, $opt{symlink} );
-+	}
- 
--	# Check if we have vlc - if not use iPhone mode
--	if ( $opt{n95} && (! exists_in_path($vlc)) ) {
--		logger "\nWARNING: Required $vlc does not exist, falling back to iPhone mode\n";
--		$opt{n95} = 0;
--	}		
-+	# Do the audio download
-+	return download_stream_rtsp( $ua, $url_2, $file, $file_done, $file_symlink, $pid );
-+}
- 
- 
-+	
-+sub download_programme_radio_iphone {
-+	my $ua = shift; 
-+	my $pid = shift;
-+	my %version_pids = %{@_[0]};
-+	my %streamdata;
-+	my $url_2;
-+
-+	$prog{$pid}{dir} = $download_dir{ $prog{$pid}{type} };
-+	$prog{$pid}{ext} = 'mp3';
-+
-+	my $url_2 = %{get_media_stream_data( $pid, $version_pids{ $prog{$pid}{version} }, 'iphone')}->{streamurl};
-+
-+	# Report error if no versions are available
-+	if ( ! $url_2 ) {
-+		logger "WARNING: iPhone stream media not available\n";
-+		return 'next';
-+	} else {
-+		logger "INFO: Stage 2 URL = $url_2\n" if $opt{verbose};
-+	}
-+
-+	# Determine the correct filenames for this download
-+	$prog{$pid}{fileprefix} = generate_download_filename_prefix( $pid, $prog{$pid}{dir}, $opt{fileprefix} || "<longname> - <episode> <pid> <version>" );
-+	logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                 \n";
-+	my $file_done = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
-+	my $file = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
-+	$prog{$pid}{filename} = $file_done;
-+	if ( -f $file_done ) {
-+		logger "WARNING: File $file_done already exists\n\n";
-+		return 'abort';
-+	}
-+
-+	# Skip from here if we are only testing downloads
-+	return 'abort' if $opt{test};
-+
-+	# Create symlink filename if required
-+	my $file_symlink;
-+	if ( $opt{symlink} ) {
-+		# Substitute the fields for the pid
-+		$file_symlink = substitute_fields( $pid, $opt{symlink} );
-+	}
-+
-+	my $return;
-+	# Disable proxy here if required
-+	$ua->proxy( ['http'] => undef ) if $opt{partialproxy};
-+	$return = download_stream_iphone( $ua, $url_2, $pid, $file, $file_done, $file_symlink, 0 );
-+	# Re-enable proxy here if required
-+	$ua->proxy( ['http'] => $proxy_url ) if $opt{partialproxy};
-+
-+	return $return;
-+}
-+
-+
-+
-+sub download_programme_radio_flashaudio {
-+	my $ua = shift; 
-+	my $pid = shift;
-+	my $mode = shift;
-+	my %version_pids = %{@_[0]};
-+	my %streamdata;
-+	my $url_2;
-+
-+	# Force raw mode if ffmpeg is not installed
-+	if ( ! exists_in_path($ffmpeg) ) {
-+		logger "\nWARNING: $ffmpeg does not exist - not converting flv file\n";
-+		$opt{raw} = 1;
-+	}
-+	# Disable rtmp modes if rtmpdump does not exist
-+	if ( ! exists_in_path($rtmpdump) ) {
-+		logger "\nERROR: Required program $rtmpdump does not exist (see http://linuxcentre.net/getiplayer/installation and http://linuxcentre.net/getiplayer/download)\n";
-+		return 'next';
-+	}
-+
-+	$prog{$pid}{dir} = $download_dir{ $prog{$pid}{type} };
-+	$prog{$pid}{ext} = 'mp3';
-+	$prog{$pid}{ext} = 'flv' if $opt{raw};
-+
-+	logger "INFO: Trying to get media stream metadata for flashaudio RTMP mode\n" if $opt{verbose};
-+	%streamdata = %{ get_media_stream_data( $pid, $version_pids{ $prog{$pid}{version} }, 'flashaudio') };
-+	$url_2 = $streamdata{streamurl};
-+	if ( ! $url_2 ) {
-+		logger "WARNING: No flashaudio version available\n";
-+		return 'next';
-+	}
-+
-+	# Determine the correct filenames for this download
-+	$prog{$pid}{fileprefix} = generate_download_filename_prefix( $pid, $prog{$pid}{dir}, $opt{fileprefix} || "<longname> - <episode> <pid> <version>" );
-+	logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                 \n";
-+	my $file_done = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
-+	my $file = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
-+	$prog{$pid}{filename} = $file_done;
-+	if ( -f $file_done ) {
-+		logger "WARNING: File $file_done already exists\n\n";
-+		return 'abort';
-+	}
-+
-+	# Skip from here if we are only testing downloads
-+	return 'abort' if $opt{test};
-+
-+	# Create symlink filename if required
-+	my $file_symlink;
-+	if ( $opt{symlink} ) {
-+		# Substitute the fields for the pid
-+		$file_symlink = substitute_fields( $pid, $opt{symlink} );
-+	}
-+
-+	# Do the RTMP flashaudio download
-+	return download_stream_rtmp( $ua, $streamdata{streamurl}, $pid, $mode, $streamdata{application}, $streamdata{tcurl}, $streamdata{authstring}, $streamdata{swfurl}, $file, $file_done, $file_symlink );
-+}
-+
-+
-+
-+# Usage: download_programme_tv (<pid>)
-+sub download_programme_tv {
-+	my $ua = shift; 
-+	my $pid = shift;
-+	my $mode = shift;
-+	my %version_pids = %{@_[0]};
-+	my %streamdata;
- 	my $url_2;
- 	my $got_url;
- 
-+	# Check if we have vlc - if not use iPhone mode
-+	if ( $opt{vmode} eq 'n95' && (! exists_in_path($vlc)) ) {
-+		logger "\nWARNING: Required $vlc does not exist\n";
-+		return 'next';
-+	}		
-+	# if rtmpdump does not exist
-+	if ( $mode =~ /^(rtmp|flash)/ && ! exists_in_path($rtmpdump)) {
-+		logger "WARNING: Required program $rtmpdump does not exist (see http://linuxcentre.net/getiplayer/installation and http://linuxcentre.net/getiplayer/download)\n";
-+		return 'next';
-+	}
-+	# Force raw mode if ffmpeg is not installed
-+	if ( $mode =~ /^(flash|rtmp)/ && ! exists_in_path($ffmpeg)) {
-+		logger "\nWARNING: $ffmpeg does not exist - not converting flv file\n";
-+		$opt{raw} = 1;
-+	}
-+
-+	$prog{$pid}{dir} = $download_dir{ $prog{$pid}{type} };
-+	$prog{$pid}{ext} = 'mov';
-+	# Lookup table to determine which ext to use for different download methods
-+	my %stream_ext = (
-+		iphone		=> 'mov',
-+		flashhigh 	=> 'mp4',
-+		flashnormal	=> 'avi',
-+		flashwii	=> 'avi',
-+		n95_wifi	=> '3gp',
-+		n95_3g		=> '3gp',
-+	);
-+	$prog{$pid}{ext} = $stream_ext{$mode} if not $opt{raw};
-+	$prog{$pid}{ext} = 'flv' if $mode =~ /^(flash|rtmp)/ && $opt{raw};
-+
- 	# Do this for each version tried in this order (if they appeared in the content)
- 	for my $version ( @version_search_list ) {
- 
-@@ -1528,52 +2147,41 @@
- 			logger "INFO: Checking existence of $version version\n";
- 			$prog{$pid}{version} = $version;
- 			logger "INFO: Version = $prog{$pid}{version}\n" if $opt{verbose};
--			if( ! $opt{rtmp} ) {
--				$url_2 = get_iphone_stream_download_url( $ua, $version_pids{$version} );
--			} else {
--				$url_2 = get_media_stream_data( $pid, $version_pids{ $prog{$pid}{version} }, 'flashhigh' );
--			}
--			$got_url = 1;
-+			# Try to get stream data
-+			%streamdata = %{ get_media_stream_data( $pid, $version_pids{ $prog{$pid}{version} }, $mode) };
-+			$url_2 = $streamdata{streamurl};
- 		}
- 		# Break out of loop if we have an actual URL
--		last if $got_url && $url_2;
--	}
--
--	# Report error if no versions are available
--	if ( ! $got_url ) {
--		logger "ERROR: No versions exist for download\n";
--		return 14;
-+		last if $url_2;
- 	}
- 
- 	# Display media stream data if required
- 	if ( $opt{streaminfo} ) {
--		get_media_stream_data( $pid, $version_pids{'default'}, 'all' );
--		return 1;
-+		display_stream_info( $pid, $version_pids{ $prog{$pid}{version} }, 'all' );
-+		$opt{quiet} = 1;
-+		return 'skip';
- 	}
- 
--	# Report error if failed to get URL for version
--	if ( $got_url && ! $url_2 ) {
--		logger "ERROR: No Stage 2 URL\n" if $opt{verbose};
--		# If mp3 audio stream does not exist force realaudio mode and retry
--		if ( $usemp3 && ! $opt{mp3audio}) {
--			$opt{realaudio} = 1;
--			return 'retry';
--		}
--		return 15;
-+	# Report error if no versions are available
-+	if ( ! $url_2 ) {
-+		logger "WARNING: No $mode versions available\n";
-+		return 'next';
- 	}
--	
-+
- 	# Determine the correct filenames for this download
--	$prog{$pid}{fileprefix} = generate_download_filename_prefix( $pid, $dir, $opt{fileprefix} || "<longname> - <episode> <pid> <version>" );
-+	$prog{$pid}{fileprefix} = generate_download_filename_prefix( $pid, $prog{$pid}{dir}, $opt{fileprefix} || "<longname> - <episode> <pid> <version>" );
- 	logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                 \n";
--	$prog{$pid}{dir} = $dir;
--	my $file_done = "${dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
--	my $file = "${dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
-+	my $file_done = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
-+	my $file = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
- 	$prog{$pid}{filename} = $file_done;
- 	if ( -f $file_done ) {
--		logger "WARNING: File $file_done already exists\n\n";
--		return 1;
-+		logger "ERROR: File $file_done already exists\n\n";
-+		return 'abort';
- 	}
- 
-+	# Skip from here if we are only testing downloads
-+	return 'abort' if $opt{test};
-+
- 	# Create symlink filename if required
- 	my $file_symlink;
- 	if ( $opt{symlink} ) {
-@@ -1581,53 +2189,34 @@
- 		$file_symlink = substitute_fields( $pid, $opt{symlink} );
- 	}
- 
--	# Skip from here if we are only testing downloads
--	return 1 if $opt{test};
--
--	# Get subtitles if they exist and are required
-+	# Get subtitles if they exist and are required 
-+	# best to do this before d/l of file so that the subtitles can be enjoyed while download progresses
- 	my $subfile_done;
- 	my $subfile;
- 	if ( $opt{subtitles} ) {
--		$subfile_done = "${dir}/$prog{$pid}{fileprefix}.srt";
--		$subfile = "${dir}/$prog{$pid}{fileprefix}.partial.srt";
--		download_subtitles( $ua, $subfile, $version_pids{ $prog{$pid}{version} } );
-+		$subfile_done = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.srt";
-+		$subfile = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.partial.srt";
-+		$ua->proxy( ['http'] => undef ) if $opt{partialproxy};
-+		download_stream_subtitles( $ua, $subfile, $version_pids{ $prog{$pid}{version} } );
-+		$ua->proxy( ['http'] => $proxy_url ) if $opt{partialproxy};
- 	}
- 
- 	my $return;
- 	# Do rtmp download
--	if ( $opt{rtmp} ) {
--		# Get player url
--		my %metadata = get_pid_metadata( $ua, $pid );
--		# get this redirected page and find out where it is redirected to
--		my ($ub, $request, $response, $prog_url);
--		$ub = new LWP::UserAgent;
--		$request = new HTTP::Request HEAD => $metadata{player};
--		$response = $ub->request($request);
--		$prog_url = $response->request->url;
--		$return = download_h264_rtmp_stream( $ua, $url_2, $prog_url, $file, $file_done, $file_symlink );
-+	if ( $mode =~ /^(rtmp|flash)/ ) {
-+		$return = download_stream_rtmp( $ua, $streamdata{streamurl}, $pid, $mode, $streamdata{application}, $streamdata{tcurl}, $streamdata{authstring}, $streamdata{swfurl}, $file, $file_done, $file_symlink );
- 
- 	# Do the N95 h.264 download
--	} elsif ( $opt{n95} ) {
--		my $url = get_media_stream_data( $pid, $version_pids{ $prog{$pid}{version} }, 'n95_wifi' );
--		$return = download_h264_low_stream( $ua, $url, $file, $file_done );
-+	} elsif ( $mode =~ /^n95/ ) {
-+		$return = download_stream_h264_low( $ua, $url_2, $file, $file_done, $pid, $mode );
- 
- 	# Do the iPhone h.264 download
--	} elsif ( $prog{$pid}{type} eq 'tv' ) {
--		# Disable proxy here if required
--		$ua->proxy( ['http'] => undef ) if $opt{partialproxy};
--		$return = download_iphone_stream( $ua, $url_2, $file, $file_done, $file_symlink, 1 );
--		# Re-enable proxy here if required
--		$ua->proxy( ['http'] => $proxy_url ) if $opt{partialproxy};
--
--	# Do the iPhone mp3 download
--	} elsif ( $prog{$pid}{type} eq 'radio' ) {
-+	} else {
- 		# Disable proxy here if required
- 		$ua->proxy( ['http'] => undef ) if $opt{partialproxy};
--		$return = download_iphone_stream( $ua, $url_2, $file, $file_done, $file_symlink, 0 );
-+		$return = download_stream_iphone( $ua, $url_2, $pid, $file, $file_done, $file_symlink, 1 );
- 		# Re-enable proxy here if required
- 		$ua->proxy( ['http'] => $proxy_url ) if $opt{partialproxy};
--		# If the iphone mp3 download fails then it's probably not ready yet so retry using realaudio
--		$opt{realaudio} = 1 if $return eq 'retry';
- 	}
- 	
- 	# Rename the subtitle file accordingly
-@@ -1647,13 +2236,12 @@
- 
- 
- # Download Subtitles, convert to srt(SubRip) format and apply time offset
--sub download_subtitles {
-+sub download_stream_subtitles {
- 	my ( $ua, $file, $verpid ) = @_;
- 	my $suburl;
- 	my $subs;
- 	logger "INFO: Getting Subtitle metadata for $verpid\n" if $opt{verbose};
--	$suburl = get_media_stream_data( undef, $verpid, 'subtitles' );
--
-+	$suburl = %{get_media_stream_data( undef, $verpid, 'subtitles')}->{streamurl};
- 	# Return if we have no url
- 	if (! $suburl) {
- 		logger "INFO: Subtitles not available\n";
-@@ -1793,12 +2381,12 @@
- 
- 	# Get title
- 	# <title>Amazon with Bruce Parry: Episode 1</title>
--	my ( $title, $type );
-+	my ( $title, $prog_type );
- 	$title = $1 if $xml =~ m{<title>\s*(.+?)\s*<\/title>};
- 
- 	# Get type
--	$type = 'tv' if grep /kind="programme"/, $xml;
--	$type = 'radio' if grep /kind="radioProgramme"/, $xml;
-+	$prog_type = 'tv' if grep /kind="programme"/, $xml;
-+	$prog_type = 'radio' if grep /kind="radioProgramme"/, $xml;
- 
- 	# Split into <item kind="programme"> sections
- 	for ( split /<item\s+kind="(radioProgramme|programme)"/, $xml ) {
-@@ -1812,310 +2400,389 @@
- 		$version_pids{$version} = $verpid;
- 		logger "INFO: Version: $version, VersionPid: $verpid\n" if $opt{verbose};  
- 	}
-+
-+	# Extract Long Name, e.g.: iplayer.episode.setTitle("DIY SOS: Series 16: Swansea"), Strip off the episode name
-+	$title =~ s/^(.+):.*?$/$1/g;
-+
- 	# Add to prog hash
- 	$prog{$pid}{versions} = join ',', keys %version_pids;
--	return ( $type, $title, %version_pids );
-+	return ( $prog_type, $title, %version_pids );
- }
- 
- 
- 
- # Gets media streams data for this version pid
--# $media = all|flashhigh|flashnormal|iphone|flashwii|n95_wifi|n95_3g|mobile|flashaudio|realaudio|wma|subtitles
-+# $media = all|itv|flashhigh|flashnormal|iphone|flashwii|n95_wifi|n95_3g|mobile|flashaudio|realaudio|wma|subtitles
- sub get_media_stream_data {
- 	my ( $pid, $verpid, $media ) = @_;
--	my %streams;
--	my $ua = LWP::UserAgent->new();
-+	my %data;
-+
- 	# Setup user agent with redirection enabled
--	$ua->timeout([$lwp_request_timeout]);
--	$ua->proxy( ['http'] => $proxy_url );
--	$ua->cookie_jar( HTTP::Cookies->new( file => $cookiejar, autosave => 1, ignore_discard => 1 ) );
-+	my $ua = create_ua('desktop');
- 	$opt{quiet} = 0 if $opt{streaminfo};
--	logger "INFO: Getting media stream metadata for $prog{$pid}{name} - $prog{$pid}{episode}, $verpid\n" if $pid;
--	my $xml1 = request_url_retry($ua, $media_stream_data_prefix.$verpid, 3, '', '');
--	logger "\n$xml1\n" if $opt{debug};
--	# flatten
--	$xml1 =~ s/\n/ /g;
- 
--	for my $xml ( split /<media/, $xml1 ) {
--		$xml = "<media".$xml;
-+	# ITV streams
-+	if ( $prog{$pid}{type} eq 'itv' ) {
-+		my $prog_type = 'itv';
-+		$data{$prog_type}{type} = 'ITV ASF Video stream';
-+		$opt{quiet} = 1 if $opt{streaminfo};
-+		$data{$prog_type}{streamurl} = join('|', get_stream_url_itv($ua, $pid) );
-+		$opt{quiet} = 0 if $opt{streaminfo};
-+
-+	# BBC streams
-+	} else {
-+		my $xml1 = request_url_retry($ua, $media_stream_data_prefix.$verpid, 3, '', '');
-+		logger "\n$xml1\n" if $opt{debug};
-+		# flatten
-+		$xml1 =~ s/\n/ /g;
-+		
-+		for my $xml ( split /<media/, $xml1 ) {
-+			$xml = "<media".$xml;
-+			my $prog_type;
-+			
-+			# h.264 high quality stream
-+			#	<media kind="video"
-+			#        width="640"
-+			#        height="360"
-+			#        type="video/mp4"
-+			#        encoding="h264"  >
-+			#        <connection
-+			#                priority="10"
-+			#                application="bbciplayertok"
-+			#                kind="level3"
-+			#                server="bbciplayertokfs.fplive.net"
-+			#                identifier="mp4:b000zxf4-H26490898078"
-+			#                authString="[REDACTED]"
-+			#        />
-+			# application: bbciplayertok
-+			# tcURL: rtmp://bbciplayertokfs.fplive.net:80/bbciplayertok
-+			if ( $media =~ /^(flashhigh|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/mp4".+?encoding="h264".+?application="(.+?)".+?kind="level3"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
-+				$prog_type = 'flashhigh';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{application}, $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{authstring} ) = ( $1, $2, $3, $4 );
-+				$data{$prog_type}{type} = 'Flash RTMP H.264 high quality stream';
-+				$data{$prog_type}{tcurl} = "rtmp://$data{$prog_type}{server}:80/$data{$prog_type}{application}";
-+				$data{$prog_type}{swfurl} = "http://www.bbc.co.uk/emp/9player.swf?revision=7276";
-+				$data{$prog_type}{streamurl} = "rtmp://$data{$prog_type}{server}:1935/ondemand?_fcs_vhost=$data{$prog_type}{server}&auth=$data{$prog_type}{authstring}&aifp=v001&slist=$data{$prog_type}{identifier}";
-+			}
-+			
-+			# h.264 normal quality stream
-+			#	<media kind="video"
-+			#        width="640"
-+			#        height="360"
-+			#        type="video/x-flv"
-+			#        encoding="vp6"  >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="akamai"
-+			#                server="cp41752.edgefcs.net"
-+			#                identifier="secure/b000zxf4-streaming90898078"
-+			#                authString="[REDACTED]"
-+			#        />
-+			#	</media>
-+			#
-+			# application (e.g.):            ondemand?_fcs_vhost=cp41752.edgefcs.net&auth=daEcia8aQaRardxdwb_dCbvc0cPbLavc2cL-bjw5rj-cCp-JnlDCnzn.MEqHpxF&aifp=v001&slist=secure/b000gy717streaming103693754
-+			# tcURL: rtmp://88.221.26.165:80/ondemand?_fcs_vhost=cp41752.edgefcs.net&auth=daEcia8aQaRardxdwb_dCbvc0cPbLavc.2cL-bjw5rj-cCp-JnlDCnznMEqHpxF&aifp=v001&slist=secure/b000gy717streaming103693754
-+			if ( $media =~ /^(flashnormal|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/x-flv".+?encoding="vp6".+?kind="akamai"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
-+				$prog_type = 'flashnormal';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{authstring} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{application} = "ondemand?_fcs_vhost=$data{$prog_type}{server}&auth=$data{$prog_type}{authstring}&aifp=v001&slist=$data{$prog_type}{identifier}";
-+				$data{$prog_type}{type} = 'Flash RTMP H.264 normal quality stream';
-+				$data{$prog_type}{tcurl} = "rtmp://$data{$prog_type}{server}:80/$data{$prog_type}{application}";
-+				$data{$prog_type}{swfurl} = "http://www.bbc.co.uk/emp/9player.swf?revision=7276";
-+				$data{$prog_type}{streamurl} = "rtmp://$data{$prog_type}{server}:1935/ondemand?_fcs_vhost=$data{$prog_type}{server}&auth=$data{$prog_type}{authstring}&aifp=v001&slist=$data{$prog_type}{identifier}";
-+			}
-+			
-+			# Wii h.264 standard quality stream
-+			#<media kind="video"
-+			#        width="512"
-+			#        height="288"
-+			#        type="video/x-flv"
-+			#        encoding="spark"  >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="akamai"
-+			#                server="cp41752.edgefcs.net"
-+			#                identifier="secure/5242138581547639062"
-+			#                authString="[REDACTED]"
-+			#        />
-+			#</media>
-+			# application (e.g.):               ondemand?_fcs_vhost=cp41752.edgefcs.net&auth=daEcpc6cYbhdIakdWduc6bJdPbydbazdmdp-bjxPBF-cCp-GptFAoDqJBnHvzC&aifp=v001&slist=secure/b000g884xstreaming101052333
-+			# tcURL: rtmp: //88.221.26.173:1935/ondemand?_fcs_vhost=cp41752.edgefcs.net&auth=daEcpc6cYbhdIakdWduc6bJdPbydbazdmdp-bjxPBF-cCp-GptFAoDqJBnHvzC&aifp=v001&slist=secure/b000g884xstreaming101052333
-+			# swfUrl: http://www.bbc.co.uk/emp/iplayer/7player.swf?revision=3897
-+			if ( $media =~ /^(flashwii|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/x-flv".+?encoding="spark".+?kind="akamai"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
-+				$prog_type = 'flashwii';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{authstring} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{application} = "ondemand?_fcs_vhost=$data{$prog_type}{server}&auth=$data{$prog_type}{authstring}&aifp=v001&slist=$data{$prog_type}{identifier}";
-+				$data{$prog_type}{type} = 'Flash RTMP H.264 Wii stream';
-+				$data{$prog_type}{tcurl} = "rtmp://$data{$prog_type}{server}:1935/$data{$prog_type}{application}";
-+				$data{$prog_type}{swfurl} = "http://www.bbc.co.uk/emp/iplayer/7player.swf?revision=3897";
-+				$data{$prog_type}{streamurl} = "rtmp://$data{$prog_type}{server}:1935/ondemand?_fcs_vhost=$data{$prog_type}{server}&auth=$data{$prog_type}{authstring}&aifp=v001&slist=$data{$prog_type}{identifier}";
-+			}
-+		
-+			# iPhone h.264/mp3 stream
-+			#<media kind="video"
-+			#        width="480"
-+			#        height="272"
-+			#        type="video/mp4"
-+			#        encoding="h264"  >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="sis"
-+			#                server="http://www.bbc.co.uk/mediaselector/3/auth/stream/"
-+			#                identifier="5242138581547639062"
-+			#                href="http://www.bbc.co.uk/mediaselector/3/auth/stream/5242138581547639062.mp4"
-+			#        />
-+			#</media>
-+			if ( $media =~ /^(iphone|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/mp4".+?encoding="h264".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
-+				$prog_type = 'iphone';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{streamurl} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{type} = 'iPhone stream';
-+			}
-+		
-+			# Nokia N95 h.264 low quality stream (WiFi)
-+			#<media kind="video"
-+			#        type="video/mpeg"
-+			#        encoding="h264"  >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="sis"
-+			#                server="http://www.bbc.co.uk/mediaselector/4/sdp/"
-+			#                identifier="b00108ld/iplayer_streaming_n95_wifi"
-+			#                href="http://www.bbc.co.uk/mediaselector/4/sdp/b00108ld/iplayer_streaming_n95_wifi"
-+			#        />
-+			#</media>
-+			if ( $media =~ /^(n95_wifi|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/mpeg".+?encoding="h264".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
-+				$prog_type = 'n95_wifi';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{href} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{type} = 'Nokia N95 h.264 low quality WiFi stream';
-+				$opt{quiet} = 1 if $opt{streaminfo};
-+				chomp( $data{$prog_type}{streamurl} = request_url_retry($ua, $data{$prog_type}{href}, 2, '', '') );
-+				$opt{quiet} = 0 if $opt{streaminfo};
-+			}
-+		
-+			# Nokia N95 h.264 low quality stream (3G)
-+			#<media kind="" 
-+			#        expires="2008-10-30T12:29:00+00:00"
-+			#        type="video/mpeg"                  
-+			#        encoding="h264"  >                 
-+			#        <connection                        
-+			#                priority="10"              
-+			#                kind="sis"                 
-+			#                server="http://www.bbc.co.uk/mediaselector/4/sdp/" 
-+			#                identifier="b009tzxx/iplayer_streaming_n95_3g"     
-+			#                href="http://www.bbc.co.uk/mediaselector/4/sdp/b009tzxx/iplayer_streaming_n95_3g" 
-+			#        />                                                                                        
-+			#</media>    
-+			if ( $media =~ /^(n95_3g|all)$/ && $xml =~ m{<media\s+kind="".+?type="video/mpeg".+?encoding="h264".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
-+				$prog_type = 'n95_3g';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{href} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{type} = 'Nokia N95 h.264 low quality 3G stream';
-+				$opt{quiet} = 1 if $opt{streaminfo};
-+				chomp( $data{$prog_type}{streamurl} = request_url_retry($ua, $data{$prog_type}{href}, 2, '', '') );
-+				$opt{quiet} = 0 if $opt{streaminfo};
-+			}
-+		
-+			# Mobile WMV DRM
-+			#<media kind="video"
-+			#        expires="2008-10-20T21:59:00+01:00"
-+			#        type="video/wmv"   >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="licence"
-+			#                server="http://iplayldsvip.iplayer.bbc.co.uk/WMLicenceIssuer/LicenceDelivery.asmx"
-+			#                identifier="0A1CA43B-98A8-43EA-B684-DA06672C0575"
-+			#                href="http://iplayldsvip.iplayer.bbc.co.uk/WMLicenceIssuer/LicenceDelivery.asmx/0A1CA43B-98A8-43EA-B684-DA06672C0575"
-+			#        />
-+			#<connection
-+			#                priority="10"
-+			#                kind="sis"
-+			#                server="http://directdl.iplayer.bbc.co.uk/windowsmedia/"
-+			#                identifier="AmazonwithBruceParry_Episode5_200810132100_mobile"
-+			#                href="http://directdl.iplayer.bbc.co.uk/windowsmedia/AmazonwithBruceParry_Episode5_200810132100_mobile.wmv"
-+			#        />
-+			#</media>
-+			if ( $media =~ /^(mobile|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/wmv".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
-+				$prog_type = 'mobile';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{streamurl} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{type} = 'Mobile WMV DRM stream';
-+			}
-+		
-+			# Audio rtmp mp3
-+			#<media kind="audio"
-+			#        type="audio/mpeg"
-+			#        encoding="mp3"  >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="akamai"
-+			#                server="cp48181.edgefcs.net"
-+			#                identifier="mp3:secure/radio1/RBN2_mashup_b00d67h9_2008_09_05_22_14_25"
-+			#                authString="[REDACTED]"
-+			#        />
-+			#</media>
-+			#app: ondemand?_fcs_vhost=cp48181.edgefcs.net&auth=daEasducLbidOancObacmc0amd6d7ana8c6-bjx.9v-cCp-JqlFHoEq.FBqGnxC&aifp=v001&slist=secure/radio1/RBN2_radio_1_-_wednesday_1000_b00g3xcj_2008_12_31_13_21_49
-+			#swfUrl: http://www.bbc.co.uk/emp/9player.swf?revision=7276
-+			#tcUrl: rtmp://92.122.210.173:1935/ondemand?_fcs_vhost=cp48181.edgefcs.net&auth=daEasducLbidOancObacmc0amd6d7ana8c6-bjx.9v-cCp-JqlFHoEqFBqGnxC&aifp=v001&slist=secure/radio1/RBN2_radio_1_-_wednesday_1.000_b00g3xcj_2008_12_31_13_21_49
-+			#pageUrl: http://www.bbc.co.uk/iplayer/episode/b00g3xp7/Annie_Mac_31_12_2008/
-+			if ( $media =~ /^(flashaudio|all)$/ && $xml =~ m{<media\s+kind="audio".+?type="audio/mpeg".+?encoding="mp3".+?kind="akamai"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
-+				$prog_type = 'flashaudio';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{authstring} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{streamurl} = "rtmp://$data{$prog_type}{server}:1935/ondemand?_fcs_vhost=$data{$prog_type}{server}&auth=$data{$prog_type}{authstring}&aifp=v001&slist=$data{$prog_type}{identifier}";
-+				# Remove offending mp3: at the start of the identifier (don't remove in stream url)
-+				$data{$prog_type}{identifier} =~ s/^mp3://;
-+				$data{$prog_type}{application} = "ondemand?_fcs_vhost=$data{$prog_type}{server}&auth=$data{$prog_type}{authstring}&aifp=v001&slist=$data{$prog_type}{identifier}";
-+				$data{$prog_type}{type} = 'RTMP MP3 stream';
-+				$data{$prog_type}{tcurl} = "rtmp://$data{$prog_type}{server}:1935/$data{$prog_type}{application}";
-+				$data{$prog_type}{swfurl} = "http://www.bbc.co.uk/emp/9player.swf?revision=7276";
-+			}
-+		
-+			# RealAudio stream
-+			#<media kind="audio"
-+			#       type="audio/real"
-+			#        encoding="real"  >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="sis"
-+			#                server="http://www.bbc.co.uk"
-+			#                identifier="/radio/aod/playlists/9h/76/d0/0b/2000_bbc_radio_one"
-+			#                href="http://www.bbc.co.uk/radio/aod/playlists/9h/76/d0/0b/2000_bbc_radio_one.ram"
-+			#        />
-+			#</media>
-+			# Realaudio for worldservice	
-+			#<media kind=""
-+			#type="audio/real"
-+			#encoding="real"  >
-+			#<connection
-+			#        priority="10"
-+			#        kind="edgesuite"
-+			#        server="http://http-ws.bbc.co.uk.edgesuite.net"
-+			#        identifier="/generatecssram.esi?file=/worldservice/css/nb/410060838.ra"
-+			#        href="http://http-ws.bbc.co.uk.edgesuite.net/generatecssram.esi?file=/worldservice/css/nb/410060838.ra"
-+			#/>
-+			#</media>
-+			#</mediaSelection>
-+			if ( $media =~ /^(realaudio|all)$/ && $xml =~ m{<media\s+kind="(audio|)".+?type="audio/real".+?encoding="real".+?kind="(sis|edgesuite)"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
-+				$prog_type = 'realaudio';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{href} ) = ( $3, $4, $5 );
-+				$data{$prog_type}{type} = 'RealAudio RTSP stream';
-+				$opt{quiet} = 1 if $opt{streaminfo};
-+				chomp( $data{$prog_type}{streamurl} = request_url_retry($ua, $data{$prog_type}{href}, 2, '', '') );
-+				$data{$prog_type}{streamurl} =~ s/[\s\n]//g;
-+				$opt{quiet} = 0 if $opt{streaminfo};
-+			}
-+		
-+			# Radio WMA (low quality)
-+			#<mediaSelection xmlns="http://bbc.co.uk/2008/mp/mediaselection">
-+			#<media kind=""
-+			#        type="audio/wma"
-+			#        encoding="wma"  >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="edgesuite"
-+			#                server="http://http-ws.bbc.co.uk.edgesuite.net"
-+			#                identifier="/generatecssasx.esi?file=/worldservice/css/nb/410060838"
-+			#                href="http://http-ws.bbc.co.uk.edgesuite.net/generatecssasx.esi?file=/worldservice/css/nb/410060838.wma"
-+			#        />
-+			#</media>
-+			if ( $media =~ /^(wma|all)$/ && $xml =~ m{<media\s+kind="(audio|)".+?type="audio/wma".+?encoding="wma".+?kind="(sis|edgesuite)"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
-+				$prog_type = 'wma';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{href} ) = ( $3, $4, $5 );
-+				$data{$prog_type}{type} = 'WMA MMS stream';
-+				$opt{quiet} = 1 if $opt{streaminfo};
-+				chomp( $data{$prog_type}{streamurl} = request_url_retry($ua, $data{$prog_type}{href}, 2, '', '') );
-+				$data{$prog_type}{streamurl} =~ s/[\s\n]//g;
-+				# HREF="mms://a1899.v394403.c39440.g.vm.akamaistream.net/7/1899/39440/1/bbcworldservice.download.akamai.com/39440//worldservice/css/nb/410060838.wma"
-+				$data{$prog_type}{streamurl} =~ s/^.*href=\"(.+?)\".*$/$1/gi;
-+				$opt{quiet} = 0 if $opt{streaminfo};
-+			}
-+		
-+			# Subtitles stream
-+			#<media kind="captions"
-+			#        type="application/ttaf+xml"   >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="http"
-+			#                server="http://www.bbc.co.uk/iplayer/subtitles/"
-+			#                identifier="b0008dc8rstreaming89808204.xml"
-+			#                href="http://www.bbc.co.uk/iplayer/subtitles/b0008dc8rstreaming89808204.xml"
-+			#        />
-+			#</media>
-+			if ( $media =~ /^(subtitles|all)$/ && $xml =~ m{<media\s+kind="captions".+?type="application/ttaf\+xml".+?kind="http"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
-+				$prog_type = 'subtitles';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{streamurl} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{type} = 'Subtitles stream';
-+			}	
-+		}
-+		# Do iphone redirect check regardless of an xml entry for iphone - sometimes the iphone streams exist regardless
-+		if ( my $streamurl = get_stream_url_iphone($ua, $verpid) ) {
-+			my $prog_type = 'iphone';
-+			$data{$prog_type}{type} = 'iPhone stream';
-+			# Get iphone redirect
-+			$data{$prog_type}{streamurl} = $streamurl;
-+		} else {
-+			logger "DEBUG: No iphone redirect stream\n" if $opt{verbose};
-+		}
-+
-+	}
-+	# Return a hash with media => url if 'all' is specified - otherwise just the specified url
-+	if ( $media eq 'all' ) {
-+		return %data;
-+	} else {
-+		# Make sure this hash exists before we pass it back...
-+		$data{$media}{exists} = 0 if not defined $data{$media};
-+		return $data{$media};
-+	}
-+}
-+
- 
--		my ($server, $authstring, $identifier, $href);
- 
--		# h.264 high quality stream
--		#	<media kind="video"
--		#        width="640"
--		#        height="360"
--		#        type="video/mp4"
--		#        encoding="h264"  >
--		#        <connection
--		#                priority="10"
--		#                application="bbciplayertok"
--		#                kind="level3"
--		#                server="bbciplayertokfs.fplive.net"
--		#                identifier="mp4:b000zxf4-H26490898078"
--		#                authString="[REDACTED]"
--		#        />
--		if ( $media =~ /^(flashhigh|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/mp4".+?encoding="h264".+?kind="level3"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
--			( $server, $identifier, $authstring ) = ( $1, $2, $3 );
--			logger "INFO: RTMP h.264 high quality stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  authstring=$authstring\n" if $opt{verbose};
--			$streams{'flashhigh'} = "rtmp://${server}:1935/ondemand?_fcs_vhost=${server}&auth=${authstring}&aifp=v001&slist=${identifier}";
--			logger "INFO: RTMP high quality stream URL: $streams{'flashhigh'}\n";
--		}
--
--		# h.264 normal quality stream
--		#	<media kind="video"
--		#        width="512"
--		#        height="288"
--		#        type="video/x-flv"
--		#        encoding="vp6"  >
--		#        <connection
--		#                priority="10"
--		#                kind="akamai"
--		#                server="cp41752.edgefcs.net"
--		#                identifier="secure/b000zxf4-streaming90898078"
--		#                authString="[REDACTED]"
--		#        />
--		#	</media>
--		#
--		if ( $media =~ /^(flashnormal|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/x-flv".+?encoding="vp6".+?kind="akamai"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
--			( $server, $identifier, $authstring ) = ( $1, $2, $3 );
--			logger "INFO: RTMP h.264 normal quality stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  authstring=$authstring\n" if $opt{verbose};
--			$streams{'flashnormal'} = "rtmp://${server}:1935/ondemand?_fcs_vhost=${server}&auth=${authstring}&aifp=v001&slist=${identifier}";
--			logger "INFO: RTMP normal quality stream URL: $streams{'flashnormal'}\n";
--		}
--	
--		# Wii h.264 standard quality stream
--		#<media kind="video"
--		#        width="512"
--		#        height="288"
--		#        type="video/x-flv"
--		#        encoding="spark"  >
--		#        <connection
--		#                priority="10"
--		#                kind="akamai"
--		#                server="cp41752.edgefcs.net"
--		#                identifier="secure/5242138581547639062"
--		#                authString="[REDACTED]"
--		#        />
--		#</media>
--		if ( $media =~ /^(flashwii|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/x-flv".+?encoding="spark".+?kind="akamai"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
--			( $server, $identifier, $authstring ) = ( $1, $2, $3 );
--			logger "INFO: RTMP Wii normal quality stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  authstring=$authstring\n" if $opt{verbose};
--			$streams{'flashwii'} = "rtmp://${server}:1935/ondemand?_fcs_vhost=${server}&auth=${authstring}&aifp=v001&slist=${identifier}";
--			logger "INFO: RTMP Wii normal quality stream URL: $streams{'flashwii'}\n";
--		}
--	
--		# iPhone h.264/mp3 stream
--		#<media kind="video"
--		#        width="480"
--		#        height="272"
--		#        type="video/mp4"
--		#        encoding="h264"  >
--		#        <connection
--		#                priority="10"
--		#                kind="sis"
--		#                server="http://www.bbc.co.uk/mediaselector/3/auth/stream/"
--		#                identifier="5242138581547639062"
--		#                href="http://www.bbc.co.uk/mediaselector/3/auth/stream/5242138581547639062.mp4"
--		#        />
--		#</media>
--		if ( $media =~ /^(iphone|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/mp4".+?encoding="h264".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
--			( $server, $identifier, $href ) = ( $1, $2, $3 );
--			logger "INFO: iPhone stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  href=$href\n" if $opt{verbose};
--			$streams{'iphone'} = "$href";
--			logger "INFO: iPhone stream URL: $streams{'iphone'}\n";
--		}
--	
--		# Nokia N95 h.264 low quality stream (WiFi)
--		#<media kind="video"
--		#        type="video/mpeg"
--		#        encoding="h264"  >
--		#        <connection
--		#                priority="10"
--		#                kind="sis"
--		#                server="http://www.bbc.co.uk/mediaselector/4/sdp/"
--		#                identifier="b00108ld/iplayer_streaming_n95_wifi"
--		#                href="http://www.bbc.co.uk/mediaselector/4/sdp/b00108ld/iplayer_streaming_n95_wifi"
--		#        />
--		#</media>
--		if ( $media =~ /^(n95_wifi|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/mpeg".+?encoding="h264".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
--			( $server, $identifier, $href ) = ( $1, $2, $3 );
--			$opt{quiet} = 1 if $opt{streaminfo};
--			chomp( my $rtsp = request_url_retry($ua, $href, 2, '', '') );
--			$opt{quiet} = 0 if $opt{streaminfo};
--			logger "INFO: Nokia N95 h.264 low quality WiFi stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  href=$href\n" if $opt{verbose};
--			$streams{'n95_wifi'} = "$rtsp";
--			logger "INFO: Nokia N95 h.264 low quality WiFi stream URL: $streams{'n95_wifi'}\n";
--		}
--	
--		# Nokia N95 h.264 low quality stream (3G)
--		#<media kind="" 
--		#        expires="2008-10-30T12:29:00+00:00"
--		#        type="video/mpeg"                  
--		#        encoding="h264"  >                 
--		#        <connection                        
--		#                priority="10"              
--		#                kind="sis"                 
--		#                server="http://www.bbc.co.uk/mediaselector/4/sdp/" 
--		#                identifier="b009tzxx/iplayer_streaming_n95_3g"     
--		#                href="http://www.bbc.co.uk/mediaselector/4/sdp/b009tzxx/iplayer_streaming_n95_3g" 
--		#        />                                                                                        
--		#</media>    
--		if ( $media =~ /^(n95_3g|all)$/ && $xml =~ m{<media\s+kind="".+?type="video/mpeg".+?encoding="h264".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
--			( $server, $identifier, $href ) = ( $1, $2, $3 );
--			$opt{quiet} = 1 if $opt{streaminfo};
--			chomp( my $rtsp = request_url_retry($ua, $href, 2, '', '') );
--			$opt{quiet} = 0 if $opt{streaminfo};
--			logger "INFO: Nokia N95 h.264 low quality 3G stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  href=$href\n" if $opt{verbose};
--			$streams{'n95_3g'} = "$rtsp";
--			logger "INFO: Nokia N95 h.264 low quality 3G stream URL: $streams{'n95_3g'}\n";
--		}
--	
--	
--	
--		# Mobile WMV DRM
--		#<media kind="video"
--		#        expires="2008-10-20T21:59:00+01:00"
--		#        type="video/wmv"   >
--		#        <connection
--		#                priority="10"
--		#                kind="licence"
--		#                server="http://iplayldsvip.iplayer.bbc.co.uk/WMLicenceIssuer/LicenceDelivery.asmx"
--		#                identifier="0A1CA43B-98A8-43EA-B684-DA06672C0575"
--		#                href="http://iplayldsvip.iplayer.bbc.co.uk/WMLicenceIssuer/LicenceDelivery.asmx/0A1CA43B-98A8-43EA-B684-DA06672C0575"
--		#        />
--		#<connection
--		#                priority="10"
--		#                kind="sis"
--		#                server="http://directdl.iplayer.bbc.co.uk/windowsmedia/"
--		#                identifier="AmazonwithBruceParry_Episode5_200810132100_mobile"
--		#                href="http://directdl.iplayer.bbc.co.uk/windowsmedia/AmazonwithBruceParry_Episode5_200810132100_mobile.wmv"
--		#        />
--		#</media>
--		if ( $media =~ /^(mobile|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/wmv".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
--			( $server, $identifier, $href ) = ( $1, $2, $3 );
--			logger "INFO: Mobile WMV DRM stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  href=$href\n" if $opt{verbose};
--			$streams{'mobile'} = "$href";
--			logger "INFO: Mobile WMV DRM stream URL: $streams{'mobile'}\n";
--		}
--	
--		# Audio rtmp mp3
--		#<media kind="audio"
--		#        type="audio/mpeg"
--		#        encoding="mp3"  >
--		#        <connection
--		#                priority="10"
--		#                kind="akamai"
--		#                server="cp48181.edgefcs.net"
--		#                identifier="mp3:secure/radio1/RBN2_mashup_b00d67h9_2008_09_05_22_14_25"
--		#                authString="[REDACTED]"
--		#        />
--		#</media>
--		if ( $media =~ /^(flashaudio|all)$/ && $xml =~ m{<media\s+kind="audio".+?type="audio/mpeg".+?encoding="mp3".+?kind="akamai"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
--			( $server, $identifier, $authstring ) = ( $1, $2, $3 );
--			# Remove offending mp3: at the start of the identifier
--			$identifier =~ s/^mp3://;
--			logger "INFO: RTMP MP3 stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  authstring=$authstring\n" if $opt{verbose};
--			$streams{'flashaudio'} = "rtmp://${server}:1935/ondemand?_fcs_vhost=${server}&auth=${authstring}&aifp=v001&slist=${identifier}";
--			logger "INFO: RTMP stream URL: $streams{'flashaudio'}\n";
--		}
--	
--		# RealAudio stream
--		#<media kind="audio"
--		#       type="audio/real"
--		#        encoding="real"  >
--		#        <connection
--		#                priority="10"
--		#                kind="sis"
--		#                server="http://www.bbc.co.uk"
--		#                identifier="/radio/aod/playlists/9h/76/d0/0b/2000_bbc_radio_one"
--		#                href="http://www.bbc.co.uk/radio/aod/playlists/9h/76/d0/0b/2000_bbc_radio_one.ram"
--		#        />
--		#</media>
--		# Realaudio for worldservice	
--		#<media kind=""
--		#type="audio/real"
--		#encoding="real"  >
--		#<connection
--		#        priority="10"
--		#        kind="edgesuite"
--		#        server="http://http-ws.bbc.co.uk.edgesuite.net"
--		#        identifier="/generatecssram.esi?file=/worldservice/css/nb/410060838.ra"
--		#        href="http://http-ws.bbc.co.uk.edgesuite.net/generatecssram.esi?file=/worldservice/css/nb/410060838.ra"
--		#/>
--		#</media>
--		#</mediaSelection>
--		if ( $media =~ /^(realaudio|all)$/ && $xml =~ m{<media\s+kind="(audio|)".+?type="audio/real".+?encoding="real".+?kind="(sis|edgesuite)"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
--			( $server, $identifier, $href ) = ( $3, $4, $5 );
--			$opt{quiet} = 1 if $opt{streaminfo};
--			chomp( my $rtsp = request_url_retry($ua, $href, 2, '', '') );
--			$rtsp =~ s/[\s\n]//g;
--			$opt{quiet} = 0 if $opt{streaminfo};
--			logger "INFO: RealAudio RTSP stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  href=$href\n" if $opt{verbose};
--			$streams{'realaudio'} = "$rtsp";
--			logger "INFO: RealAudio RTSP stream URL: $streams{'realaudio'}\n";
--		}
--	
--	
--		# Radio WMA (low quality)
--		#<mediaSelection xmlns="http://bbc.co.uk/2008/mp/mediaselection">
--		#<media kind=""
--		#        type="audio/wma"
--		#        encoding="wma"  >
--		#        <connection
--		#                priority="10"
--		#                kind="edgesuite"
--		#                server="http://http-ws.bbc.co.uk.edgesuite.net"
--		#                identifier="/generatecssasx.esi?file=/worldservice/css/nb/410060838"
--		#                href="http://http-ws.bbc.co.uk.edgesuite.net/generatecssasx.esi?file=/worldservice/css/nb/410060838.wma"
--		#        />
--		#</media>
--		if ( $media =~ /^(wma|all)$/ && $xml =~ m{<media\s+kind="(audio|)".+?type="audio/wma".+?encoding="wma".+?kind="(sis|edgesuite)"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
--			( $server, $identifier, $href ) = ( $3, $4, $5 );
--			$opt{quiet} = 1 if $opt{streaminfo};
--			chomp( my $mms = request_url_retry($ua, $href, 2, '', '') );
--			$mms =~ s/[\n]//g;
--			# HREF="mms://a1899.v394403.c39440.g.vm.akamaistream.net/7/1899/39440/1/bbcworldservice.download.akamai.com/39440//worldservice/css/nb/410060838.wma"
--			$mms =~ s/^.*href=\"(.+?)\".*$/$1/gi;
--			$opt{quiet} = 0 if $opt{streaminfo};
--			logger "INFO: WMA MMS stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  href=$href\n" if $opt{verbose};
--			$streams{'wma'} = "$mms";
--			logger "INFO: WMA MMS stream URL: $streams{'wma'}\n";
--		}
--	
--	
--		# Subtitles stream
--		#<media kind="captions"
--		#        type="application/ttaf+xml"   >
--		#        <connection
--		#                priority="10"
--		#                kind="http"
--		#                server="http://www.bbc.co.uk/iplayer/subtitles/"
--		#                identifier="b0008dc8rstreaming89808204.xml"
--		#                href="http://www.bbc.co.uk/iplayer/subtitles/b0008dc8rstreaming89808204.xml"
--		#        />
--		#</media>
--		if ( $media =~ /^(subtitles|all)$/ && $xml =~ m{<media\s+kind="captions".+?type="application/ttaf\+xml".+?kind="http"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
--			( $server, $identifier, $href ) = ( $1, $2, $3 );
--			logger "INFO: Subtitles stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  href=$href\n" if $opt{verbose};
--			$streams{'subtitles'} = "$href";
--			logger "INFO: Subtitles stream URL: $streams{'subtitles'}\n";
-+sub display_stream_info {
-+	my ($pid, $verpid, $media) = (@_);
-+	logger "INFO: Getting media stream metadata for $prog{$pid}{name} - $prog{$pid}{episode}, $verpid\n" if $pid;
-+	my %data = get_media_stream_data( $pid, $verpid, $media);
-+	# Print out stream data
-+	for my $prog_type (sort keys %data) {
-+		logger "stream:     $prog_type\n";
-+		for my $entry ( sort keys %{ $data{$prog_type} } ) {
-+			logger sprintf("%-11s %s\n", $entry.':', $data{$prog_type}{$entry} );
- 		}
-+		logger "\n";
- 	}
--	logger "\n" if $opt{streaminfo};
--	$opt{quiet} = 1 if $opt{streaminfo};
-+	return 0;
-+}
- 
--	# Return a hash with media => url if 'all' is specified - otherwise just the specified url
--	return %streams if $media eq 'all';
--	return $streams{$media};
-+
-+
-+# Displays specified metadata from supplied hash
-+# Usage: display_metadata( <hashref>, <array of elements to display> )
-+sub display_metadata {
-+	my %data = %{$_[0]};
-+	shift;
-+	my @keys = @_;
-+	@keys = keys %data if $#_ < 0;
-+	logger "\n";
-+	for (@keys) {
-+		logger sprintf "%-15s %s\n", ucfirst($_).':', $data{$_} if $data{$_};
-+	}
-+	return 0;
- }
- 
- 
- 
- # Actually do the h.264/mp3 downloading
- # ( $ua, $pid, $url_2, $file, $file_done, '0|1 == rearrange moov' )
--sub download_iphone_stream {
--	my ( $ua, $url_2, $file, $file_done, $file_symlink, $rearrange ) = @_;
-+sub download_stream_iphone {
-+	my ( $ua, $url_2, $pid, $file, $file_done, $file_symlink, $rearrange ) = @_;
- 
- 	# Stage 3a: Download 1st byte to get exact file length
- 	logger "INFO: Stage 3 URL = $url_2\n" if $opt{verbose};
-@@ -2132,53 +2799,44 @@
- 	my $req = HTTP::Request->new ('GET', $url_2, $h);
- 	my $res = $ua->request($req);
- 	# e.g. Content-Range: bytes 0-1/181338136 (return if no content length returned)
--	my $file_len = $res->header("Content-Range");
--	if ( ! $file_len ) {
--		logger "ERROR: No Content-Range was obtained\n" if $opt{verbose};
-+	my $download_len = $res->header("Content-Range");
-+	if ( ! $download_len ) {
-+		#logger "ERROR: No Content-Range was obtained\n" if $opt{verbose};
-+		logger "WARNING: iphone version not available\n";
- 		return 'retry'
- 	}
--	$file_len =~ s|^bytes 0-1/(\d+).*$|$1|;
--	logger "INFO: Download File Length $file_len\n" if $opt{verbose};
-+	$download_len =~ s|^bytes 0-1/(\d+).*$|$1|;
-+	logger "INFO: Download File Length $download_len\n" if $opt{verbose};
- 
- 	# Only do this if we're rearranging QT streams
- 	my $mdat_start = 0;
--	my $moov_start = $file_len + 1;
-+	# default to this if we are not rearranging (tells the download chunk loop where to stop - i.e. EOF instead of end of mdat atom)
-+	my $moov_start = $download_len + 1;
- 	my $header;
- 	if ($rearrange) {
- 		# Get ftyp+wide header etc
- 		$mdat_start = 0x1c;
- 		my $buffer = download_block(undef, $url_2, $ua, 0, $mdat_start + 4);
- 		# Get bytes upto (but not including) mdat atom start -> $header
--		$header = download_block(undef, $url_2, $ua, 0, $mdat_start - 1, $file_len);
--
-+		$header = substr($buffer, 0, $mdat_start);
-+		
- 		# Detemine moov start
--		# Get mdat_end_offset_chars from downloaded block
--		my $mdat_end_offset_chars = substr($buffer, $mdat_start, 4);
--		my $mdat_end_offset = bytestring_to_int($mdat_end_offset_chars);
--		logger "DEBUG: mdat_end_offset = ".get_hex($mdat_end_offset_chars)." = $mdat_end_offset\n" if $opt{debug};
--		logger "DEBUG: mdat_end_offset (decimal) = $mdat_end_offset\n" if $opt{debug};
-+		# Get mdat_length_chars from downloaded block
-+		my $mdat_length_chars = substr($buffer, $mdat_start, 4);
-+		my $mdat_length = bytestring_to_int($mdat_length_chars);
-+		logger "DEBUG: mdat_length = ".get_hex($mdat_length_chars)." = $mdat_length\n" if $opt{debug};
-+		logger "DEBUG: mdat_length (decimal) = $mdat_length\n" if $opt{debug};
- 		# The MOOV box starts one byte after MDAT box ends
--		$moov_start = $mdat_start + $mdat_end_offset;
--
--
--		## scan 2nd level atoms in moov atom until we get stco atom(s)
--		# We can skip first 8 bytes (moov atom header)
--		#my $i = 8;
--		#while( $i < $moov_length - 4 ) {
--		#  my $atom_len = bytestring_to_int( substr($moovdata, $i, 4) );
--		#  my $atom_name = substr($moovdata, $i+4, 4);
--		#  logger "Parsing atom: $atom_name, length: $atom_len\n";
--		#  # Increment $i by atom_len to get next atom
--		#  $i += $atom_len;
--		#}
-+		$moov_start = $mdat_start + $mdat_length;
- 	}
- 
- 	# If we have partial content and wish to stream, resume the download & spawn off STDOUT from existing file start 
- 	# Sanity check - we cannot support downloading of partial content if we're streaming also. 
- 	if ( $opt{stdout} && (! $opt{nowrite}) && -f $file ) {
- 		logger "WARNING: Partially downloaded file exists, streaming will start from the beginning of the programme\n";
--		# Don't do usual streaming code
--		$opt{stdout} = 0;
-+		# Don't do usual streaming code - also force all messages to go to stderr
-+		delete $opt{stdout};
-+		$opt{stderr} = 1;
- 		$childpid = fork();
- 		if (! $childpid) {
- 			# Child starts here
-@@ -2205,15 +2863,15 @@
- 	my $fh = open_file_append($file);
- 
- 	# If the partial file already exists, then resume from the correct mdat/download offset
--	my $restart_offset = $mdat_start;
-+	my $restart_offset = 0;
- 	my $moovdata;
- 	my $moov_length = 0;
- 
- 	if ($rearrange) {
- 		# if cookie fails then trigger a retry after deleting cookiejar
--		# Determine moov atom length so we can work out if the partially downloaded file has the moov atom in it already
-+		# Determine orginal moov atom length so we can work out if the partially downloaded file has the moov atom in it already
- 		$moov_length = bytestring_to_int( download_block( undef, $url_2, $ua, $moov_start, $moov_start+3 ) );
--		logger "INFO: moov atom length = $moov_length                          \n" if $opt{verbose};
-+		logger "INFO: original moov atom length = $moov_length                          \n" if $opt{verbose};
- 		# Sanity check this moov length - chances are that were being served up a duff file if this is > 10% of the file size or < 64k
- 		if ( $moov_length > (${moov_start}/9.0) || $moov_length < 65536 ) {
- 			logger "WARNING: Bad file download, deleting cookie                 \n";
-@@ -2222,33 +2880,73 @@
- 			unlink $file;
- 			return 'retry';
- 		}
--	}
--
--	# If we have a too-small-sized file and not stdout and not no-write then this is a partial download
--	if (-f $file && (! $opt{stdout}) && (! $opt{nowrite}) && stat($file)->size > ($moov_length+$mdat_start) ) {
--		# Calculate new start offset (considering that we've put moov first in file)
--		$restart_offset = stat($file)->size - $moov_length;
--		logger "INFO: Resuming download from $restart_offset                        \n";
--	}
- 
--	if ($rearrange) {
-+		# we still need an accurate moovlength for the already downloaded moov atom for resume restart_offset.....
- 		# If we have no existing file, a file which doesn't yet even have the moov atom, or using stdout (or no-write option)
--		if ( $opt{stdout} || $opt{nowrite} || stat($file)->size < ($moov_length+$mdat_start) ) {
-+		# (allow extra 1k on moov_length for metadata when testing)
-+		if ( $opt{stdout} || $opt{nowrite} || stat($file)->size < ($moov_length+$mdat_start+1024) ) {
- 			# get moov chunk into memory
--			$moovdata = download_block( undef, $url_2, $ua, $moov_start, (${file_len}-1) );
-+			$moovdata = download_block( undef, $url_2, $ua, $moov_start, (${download_len}-1) );
-+
-+			# Create new udta atom with child atoms for metadata
-+			my $udta_new = create_qt_atom('udta',
-+				create_qt_atom( chr(0xa9).'nam', $prog{$pid}{name}.' - '.$prog{$pid}{episode}, 'string' ).
-+				create_qt_atom( chr(0xa9).'alb', $prog{$pid}{name}, 'string' ).
-+				create_qt_atom( chr(0xa9).'trk', $prog{$pid}{episode}, 'string' ).
-+				create_qt_atom( chr(0xa9).'aut', $prog{$pid}{channel}, 'string' ).
-+				create_qt_atom( chr(0xa9).'ART', $prog{$pid}{channel}, 'string' ).
-+				create_qt_atom( chr(0xa9).'des', $prog{$pid}{desc}, 'string' ).
-+				create_qt_atom( chr(0xa9).'cmt', 'Downloaded with get_iplayer', 'string' ).
-+				create_qt_atom( chr(0xa9).'req', 'QuickTime 6.0 or greater', 'string' ).
-+				create_qt_atom( chr(0xa9).'day', (localtime())[5] + 1900, 'string' )
-+			);
-+			# Insert new udta atom over the old one and get the new $moov_length (and update moov atom size field)
-+			replace_moov_udta_atom ( $udta_new, $moovdata );
-+
- 			# Process the moov data so that we can relocate it (change the chunk offsets that are absolute)
-+			# Also update moov+_length to be accurate after metadata is added etc
- 			$moov_length = relocate_moov_chunk_offsets( $moovdata );
--			# write moov atom to file next (yes - were rearranging the file - moov+header+mdat - not header+mdat+moov)
--			logger "INFO: Appending moov+ftype+wide atoms to $file\n" if $opt{verbose};
--			# Write moov atom
--			print $fh $moovdata if ! $opt{nowrite};
--			print STDOUT $moovdata if $opt{stdout};
-+			logger "INFO: New moov atom length = $moov_length                          \n" if $opt{verbose};
-+			# write moov atom to file next (yes - were rearranging the file - header+moov+mdat - not header+mdat+moov)
-+			logger "INFO: Appending ftype+wide+moov atoms to $file\n" if $opt{verbose};
- 			# Write header atoms (ftyp, wide)
- 			print $fh $header if ! $opt{nowrite};
- 			print STDOUT $header if $opt{stdout};
-+			# Write moov atom
-+			print $fh $moovdata if ! $opt{nowrite};
-+			print STDOUT $moovdata if $opt{stdout};
-+			# If were not resuming we want to only start the download chunk loop from mdat_start 
-+			$restart_offset = $mdat_start;
-+		}
-+
-+		# Get accurate moov_length from file (unless stdout or nowrite options are specified)
-+		# Assume header+moov+mdat atom layout
-+		if ( (! $opt{stdout}) && (! $opt{nowrite}) && stat($file)->size > ($moov_length+$mdat_start) ) {
-+				logger "INFO: Getting moov atom length from partially downloaded file $file\n" if $opt{verbose};
-+				if ( ! open( MOOVDATA, "< $file" ) ) {
-+					logger "ERROR: Cannot Read partially downloaded file\n";
-+					return 4;
-+				}
-+				my $data;
-+				seek(MOOVDATA, $mdat_start, 0);
-+				if ( read(MOOVDATA, $data, 4, 0) != 4 ) {
-+					logger "ERROR: Cannot Read moov atom length from partially downloaded file\n";
-+					return 4;
-+				}
-+				close MOOVDATA;
-+				# Get moov atom size from file
-+				$moov_length = bytestring_to_int( substr($data, 0, 4) );
-+				logger "INFO: moov atom length (from partially downloaded file) = $moov_length                          \n" if $opt{verbose};
- 		}
- 	}
- 
-+	# If we have a too-small-sized file (greater than moov_length+mdat_start) and not stdout and not no-write then this is a partial download
-+	if (-f $file && (! $opt{stdout}) && (! $opt{nowrite}) && stat($file)->size > ($moov_length+$mdat_start) ) {
-+		# Calculate new start offset (considering that we've put moov first in file)
-+		$restart_offset = stat($file)->size - $moov_length;
-+		logger "INFO: Resuming download from $restart_offset                        \n";
-+	}
-+
- 	# Create symlink if required
- 	if ( $opt{symlink} ) {
- 		# remove old symlink
-@@ -2273,16 +2971,15 @@
- 			$e = $s + $chunk_size - 1;
- 		}
- 		# Get block from URL and append to $file
--		if ( download_block($file, $url_2, $ua, $s, $e, $file_len, $fh ) ) {
-+		if ( download_block($file, $url_2, $ua, $s, $e, $download_len, $fh ) ) {
- 			logger "ERROR: Could not download block $s - $e from $file\n\n";
--			return 9;
-+			return 'retry';
- 		}
- 	}
- 
- 	# end marker
- 	my $end_time = time();
- 
--	# Should now be able to concatenate header.block + mdat.block + moov.block to get movie!
- 	# Calculate average speed, duration and total bytes downloaded
- 	logger sprintf("INFO: Downloaded %.2fMB in %s at %5.0fkbps to %s\n", 
- 		($moov_start - 1 - $restart_offset) / (1024.0 * 1024.0),
-@@ -2292,57 +2989,217 @@
- 
- 	# Moving file into place as complete (if not stdout)
- 	move($file, $file_done) if ! $opt{stdout};
-+
-+	# Re-symlink file
-+	if ( $opt{symlink} ) {
-+		# remove old symlink
-+		unlink $file_symlink if -l $file_symlink;
-+		symlink $file_done, $file_symlink;
-+		logger "INFO: Created symlink from '$file_symlink' -> '$file_done'\n" if $opt{verbose};
-+	}
-+	$prog{$pid}{mode} = 'iphone';
- 	return 0;
- }
- 
- 
- 
--sub download_h264_rtmp_stream {
--        my ( $ua, $url_2, $prog_url, $file, $file_done, $file_symlink ) = @_;
--        my $file_flv = $file; # .'.flv';
-+# Actually do the RTMP stream downloading
-+sub download_stream_rtmp {
-+	my ( $ua, $url_2, $pid, $mode, $application, $tcurl, $authstring, $swfurl, $file, $file_done, $file_symlink ) = @_;
-+	my $file_tmp;
-+	my $cmd;
-+	
-+	if ( $opt{raw} ) {
-+		$file_tmp = $file;
-+	} else {
-+		$file_tmp = $file.'.flv'
-+	}
- 
--	logger "INFO: url: $url_2, prog_url: $prog_url, file: $file, file_done: $file_done\n" if $opt{verbose};
-+	# Remove failed file download (below a certain size) - hack to get around rtmpdump not returning correct exit code
-+	if ( -f $file_tmp && stat($file_tmp)->size < $min_download_size ) {
-+		unlink( $file_tmp );
-+	}
-+		
-+	logger "INFO: RTMP_URL: $url_2, tcUrl: $tcurl, application: $application, authString: $authstring, swfUrl: $swfurl, file: $file, file_done: $file_done\n" if $opt{verbose};
- 
- 	# Create symlink if required
- 	if ( $opt{symlink} ) {
- 		# remove old symlink
- 		unlink $file_symlink if -l $file_symlink;
--		symlink $file_flv, $file_symlink;
--		logger "INFO: Created symlink from '$file_symlink' -> '$file_flv'\n" if $opt{verbose};
-+		symlink $file_tmp, $file_symlink;
-+		logger "INFO: Created symlink from '$file_symlink' -> '$file_tmp'\n" if $opt{verbose};
- 	}
-+	$cmd = "$rtmpdump --resume --rtmp \"$url_2\" --auth \"$authstring\" --swfUrl \"$swfurl\" --tcUrl \"$tcurl\" --app \"$application\" -o \"$file_tmp\" >&2";
-+	logger "\n\nINFO: Command: $cmd\n" if $opt{verbose};
-+	my $return = system($cmd);
-+	# Hack to get around rtmpdump prentending to fail on successful flash downloads
-+	if ( (! -f $file_tmp) || ($return && -f $file_tmp && stat($file_tmp)->size < $min_download_size) ) {
-+		logger "\n\nINFO: Command: $cmd\n" if $opt{verbose};
-+		logger "\nWARNING: Failed to download file $file_tmp via RTMP\n";
-+		unlink $file_tmp;
-+		return 'next';
-+	}
-+	
-+	# Retain raw flv format if required
-+	if ( $opt{raw} ) {
-+		move($file_tmp, $file_done) if ! $opt{stdout};
-+		return 0;
- 
--	my $cmd = "$rtmpdump --rtmp \"$url_2\" --pageUrl \"$prog_url\" --swfUrl \"http://www.bbc.co.uk/emp/9player.swf?revision=6928_7030\" --tcUrl \"rtmp://bbciplayertokfs.fplive.net:80/bbciplayertok\" --app \"bbciplayertok\" -o \"$file_flv\" >&2";
--	#my $cmd2 = "$ffmpeg -i \"$file_flv\" -vcodec copy -acodec copy -f mp4 -y \"$file\" >&2";
--	#my $cmd2 = "$mencoder -oac copy -ovc copy -o \"$file\" \"$file_flv\" >&2";
-+	# Convert flv to mp3 for flash audio
-+	} elsif ( $mode eq 'flashaudio' ) {
-+		# We could do id3 tagging here but id3v2 does this later anyway
-+		$cmd = "$ffmpeg -i \"$file_tmp\" -vn -acodec copy -y \"$file\" >&2";
- 
--	# logger "\n\nINFO: Command1: $cmd\nINFO: Command2: $cmd2\n\n" if $opt{verbose};
--	if ( system($cmd) ) {
--		logger "\nWARNING: Failed to download file $file via RTMP\n";
--		return 1;
-+	# Convert video flv to mp4/avi if required
-+	} else {
-+		$cmd = "$ffmpeg $ffmpeg_opts -i \"$file_tmp\" -vcodec copy -acodec copy -f $prog{$pid}{ext} -y \"$file\" >&2";
-+	}
-+
-+	logger "\n\nINFO: Command: $cmd\n\n" if $opt{verbose};
-+	# Run flv conversion and delete source file on success
-+	if ( (! system($cmd)) && -f $file && stat($file)->size > $min_download_size ) {
-+			unlink( $file_tmp );
-+
-+	# If the ffmpeg conversion failed, remove the failed-converted file attempt - move the file as done anyway
-+	} else {
-+		logger "WARNING: flv conversion failed - retaining flv file\n";
-+		unlink $file;
-+		$file = $file_tmp;
-+		$file_done = $file_tmp;
-+	}
-+	# Moving file into place as complete (if not stdout)
-+	move($file, $file_done) if ! $opt{stdout};
-+	
-+	# Re-symlink file
-+	if ( $opt{symlink} ) {
-+		# remove old symlink
-+		unlink $file_symlink if -l $file_symlink;
-+		symlink $file_done, $file_symlink;
-+		logger "INFO: Created symlink from '$file_symlink' -> '$file_done'\n" if $opt{verbose};
-+	}
-+
-+	logger "INFO: Downloaded $file_done\n";
-+	$prog{$pid}{mode} = $mode;
-+	return 0;
-+}
-+
-+
-+
-+# Actually do the MMS video stream downloading
-+sub download_stream_mms_video {
-+	my ( $ua, $urls, $file, $file_done, $pid ) = @_;
-+	my $file_tmp;
-+	my $cmd;
-+	my $null;
-+	my @url_list = split /\|/, $urls;
-+	my @file_tmp_list;
-+	my %threadpid;
-+		
-+	logger "INFO: MMS_URLs: ".(join ', ', @file_tmp_list).", file: $file, file_done: $file_done\n" if $opt{verbose};
-+
-+	# Start marker
-+	my $start_time = time();
-+	# Download each mms url (multi-threaded to download in parallel)
-+	my $file_part_prefix = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}_part";
-+	for ( my $count = 0; $count <= $#url_list; $count++ ) {
-+
-+		# Create temp download filename
-+		$file_tmp = $file_part_prefix.($count+1).".asf";
-+		$file_tmp_list[$count] = $file_tmp;
-+		$null = " 2>/dev/null " if (! $opt{verbose}) && (! $opt{debug});
-+		$cmd = "$mplayer -dumpstream \"$url_list[$count]\" -dumpfile \"$file_tmp\" $null >&2 </dev/null";
-+		logger "\n\nINFO: Command: $cmd\n" if $opt{verbose};
-+
-+		my $childpid = fork();
-+		if (! $childpid) {
-+			# Child starts here
-+			logger "INFO: Downloading file $file_tmp\n";
-+			if ( system($cmd) ) {
-+				logger "\nWARNING: Failed to download file $file_tmp via MMS\n";
-+				exit 1;
-+			}
-+			logger "INFO: Download thread has completed for file $file_tmp\n";
-+			exit 0;
-+		}
-+		# Create a hash of process_id => 'count'
-+		$threadpid{$childpid} = $count;
-+	}	
-+	# Wait for all threads to complete
-+	$| = 1;
-+	# Autoreap zombies
-+	$SIG{CHLD}='IGNORE';
-+	my $done = 0;
-+	while (keys %threadpid) {
-+		my @sizes;
-+		my $total_size = 0;
-+		my $total_size_new = 0;
-+		my $format = "Threads: ";
-+		sleep 1;
-+		#logger "DEBUG: ProcessIDs: ".(join ',', keys %threadpid)."\n";
-+		for my $procid (sort keys %threadpid) {
-+			my $size = 0;
-+			# Is this child still alive?
-+			if ( kill 0 => $procid ) {
-+				logger "DEBUG Thread $threadpid{$procid} still alive ($file_tmp_list[$threadpid{$procid}])\n" if $opt{debug};
-+				# Build the status string
-+				$format .= "%d) %.3fMB   ";
-+				$size = stat($file_tmp_list[$threadpid{$procid}])->size if -f $file_tmp_list[$threadpid{$procid}];
-+				push @sizes, $threadpid{$procid}+1, $size/(1024.0*1024.0);
-+				$total_size_new += $size;
-+			} else {
-+				$size = stat($file_tmp_list[$threadpid{$procid}])->size if -f $file_tmp_list[$threadpid{$procid}];
-+				# end marker
-+				my $end_time = time();
-+				# Calculate average speed, duration and total bytes downloaded
-+				logger sprintf("INFO: Thread #%d Downloaded %.2fMB in %s at %5.0fkbps to %s\n", 
-+					($threadpid{$procid}+1),
-+					$size / (1024.0 * 1024.0),
-+					sprintf("%02d:%02d:%02d", ( gmtime($end_time - $start_time))[2,1,0] ), 
-+					$size / ($end_time - $start_time) / 1024.0 * 8.0,
-+					$file_tmp_list[$threadpid{$procid}] );
-+				# Remove from thread test list
-+				delete $threadpid{$procid};
-+			}
-+		}
-+		$format .= " downloaded (%.0fkbps)        \r";
-+		logger sprintf $format, @sizes, ($total_size_new - $total_size) / (time() - $start_time) / 1024.0 * 8.0;
- 	}
--	# Only convert to mp4 if we have mencoder in path
--	# Disable rtmp mode if rtmpdump does not exist
--	if ( ! exists_in_path($ffmpeg)) {
--		logger "\nWARNING: $ffmpeg does not exist - not converting flv file to mp4\n";
--	#} else {
--		# Run flv conversion and delete source file on success
--		#if ( ! system($cmd2) ) {
--		#	unlink( $file_flv );
--		#} else {
--		#	logger "ERROR: flv to mp4 conversion failed\n";
--		#	return 2;
--		#}
--		# Moving file into place as complete (if not stdout)
--		#move($file, $file_done) if ! $opt{stdout};
-+	logger "INFO: All download threads completed\n";	
-+	# Unset autoreap
-+	delete $SIG{CHLD};
-+	# Retain raw format if required
-+	if ( $opt{raw} ) {
-+		return 0;
- 	}
-+
-+#	# Convert video asf to mp4 if required - need to find a suitable converter...
-+#	} else {
-+#		# Create part of cmd that specifies each partial file
-+#		my $filestring;
-+#		$filestring .= " -i \"$_\" " for (@file_tmp_list);
-+#		$cmd = "$ffmpeg $ffmpeg_opts $filestring -vcodec copy -acodec copy -f $prog{$pid}{ext} -y \"$file\" >&2";
-+#	}
-+#
-+#	logger "\n\nINFO: Command: $cmd\n\n" if $opt{verbose};
-+#	# Run asf conversion and delete source file on success
-+#	if ( ! system($cmd) ) {
-+#		unlink( @file_tmp_list );
-+#	} else {
-+#		logger "ERROR: asf conversion failed - retaining files ".(join ', ', @file_tmp_list)."\n";
-+#		return 2;
-+#	}
-+#	# Moving file into place as complete (if not stdout)
-+#	move($file, $file_done) if ! $opt{stdout};
-+
-+	$prog{$pid}{mode} = 'itv';
- 	return 0;
- }
- 
- 
- 
- # Actually do the N95 h.264 downloading
--sub download_h264_low_stream {
--	my ( $ua, $url_2, $file, $file_done ) = @_;
-+sub download_stream_h264_low {
-+	my ( $ua, $url_2, $file, $file_done, $pid, $mode ) = @_;
- 
- 	# Change filename extension
- 	$file =~ s/mov$/mpg/gi;
-@@ -2353,7 +3210,7 @@
- 		logger "INFO: Downloading Low Quality H.264 stream\n";
- 		my $cmd = "$vlc $vlc_opts --sout file/ts:${file} $url_2 1>&2";
- 		if ( system($cmd) ) {
--			return 2;
-+			return 'next';
- 		}
- 
- 	# to STDOUT
-@@ -2361,19 +3218,21 @@
- 		logger "INFO: Streaming Low Quality H.264 stream to stdout\n";
- 		my $cmd = "$vlc $vlc_opts --sout file/ts:- $url_2 1>&2";
- 		if ( system($cmd) ) {
--			return 2;
-+			return 'next';
- 		}	
- 	}
- 	logger "INFO: Downloaded $file_done\n";
- 	# Moving file into place as complete (if not stdout)
- 	move($file, $file_done) if ! $opt{stdout};
-+
-+	$prog{$pid}{mode} = $mode;
- 	return 0;
- }
- 
- 
- 
- # Actually do the rtsp downloading
--sub download_rtsp_stream {
-+sub download_stream_rtsp {
- 	my ( $ua, $url, $file, $file_done, $file_symlink, $pid ) = @_;
- 	my $childpid;
- 
-@@ -2389,7 +3248,7 @@
- 	# Create ID3 tagging options for lame (escape " for shell)
- 	my ( $id3_name, $id3_episode, $id3_desc, $id3_channel ) = ( $prog{$pid}{name}, $prog{$pid}{episode}, $prog{$pid}{desc}, $prog{$pid}{channel} );
- 	$id3_name =~ s|"|\"|g for ($id3_name, $id3_episode, $id3_desc, $id3_channel);
--	$lame_opts .= "--ignore-tag-errors --ty ".( (localtime())[5] + 1900 )." --tl \"$id3_name\" --tt \"$id3_episode\" --ta \"$id3_channel\" --tc \"$id3_desc\" ";
-+	$lame_opts .= " --ignore-tag-errors --ty ".( (localtime())[5] + 1900 )." --tl \"$id3_name\" --tt \"$id3_episode\" --ta \"$id3_channel\" --tc \"$id3_desc\" ";
- 
- 	# Use post-download transcoding using lame if namedpipes are not supported (i.e. ActivePerl/Windows)
- 	# (Fallback if no namedpipe support and raw/wav not specified)
-@@ -2402,14 +3261,14 @@
- 		logger "INFO: Downloading wav format (followed by transcoding)\n";
- 		$cmd = "$mplayer $mplayer_opts -cache 128 -bandwidth $bandwidth -vc null -vo null -ao pcm:waveheader:fast:file=\"${file}.wav\" \"$url\" 1>&2";
- 		if ( system($cmd) ) {
--			return 2;
-+			return 'next';
- 		}
- 		# Transcode
- 		logger "INFO: Transcoding ${file}.wav\n";
- 		$cmd = "$lame $lame_opts \"${file}.wav\" \"${file}.mp3\" 1>&2";
- 		logger "DEGUG: Running $cmd\n" if $opt{debug};
--		if ( system($cmd) ) {
--			return 2;
-+		if ( system($cmd) || (-f "${file}.wav" && stat("${file}.wav")->size < $min_download_size) ) {
-+			return 'next';
- 		}
- 		unlink "${file}.wav";
- 		move "${file}.mp3", $file_done;
-@@ -2425,7 +3284,7 @@
- 		my $cmd = "$mplayer $mplayer_opts -cache 128 -bandwidth $bandwidth -vc null -vo null -ao pcm:waveheader:fast:file=\"$file\" \"$url\" 1>&2";
- 		logger "DEGUG: Running $cmd\n" if $opt{debug};
- 		if ( system($cmd) ) {
--			return 2;
-+			return 'next';
- 		}
- 		# Move file to done state
- 		move $file, $file_done if ! $opt{nowrite};
-@@ -2438,7 +3297,7 @@
- 		my $cmd = "$mplayer $mplayer_opts -cache 128 -bandwidth $bandwidth -dumpstream -dumpfile \"$file\" \"$url\" 1>&2";
- 		logger "DEGUG: Running $cmd\n" if $opt{debug};
- 		if ( system($cmd) ) {
--			return 2;
-+			return 'next';
- 		}
- 		# Move file to done state
- 		move $file, $file_done if ! $opt{nowrite};
-@@ -2498,7 +3357,7 @@
- 			if ( system($cmd) ) {
- 				# If we fail then kill off child processes
- 				kill 9, $childpid;
--				return 2;
-+				return 'next';
- 			}
- 		# WAV / mp3 mode
- 		} else {
-@@ -2506,7 +3365,7 @@
- 			if ( system($cmd) ) {
- 				# If we fail then kill off child processes
- 				kill 9, $childpid;
--				return 2;
-+				return 'next';
- 			}
- 		}
- 		# Wait for child processes to prevent zombies
-@@ -2522,13 +3381,14 @@
- 		logger "INFO: Created symlink from '$file_symlink' -> '$file_done'\n" if $opt{verbose};
- 	}
- 
-+	$prog{$pid}{mode} = 'realaudio';
- 	return 0;
- }
- 
- 
- 
- # Actually do the podcast downloading
--sub download_podcast_stream {
-+sub download_stream_podcast {
- 	my ( $ua, $url_2, $file, $file_done, $file_symlink ) = @_;
- 	my $start_time = time();
- 
-@@ -2548,7 +3408,7 @@
- 
- 	if ( download_block($file, $url_2, $ua, $start, undef, undef, $fh) != 0 ) {
- 		logger "ERROR: Download failed\n";
--		return 22;
-+		return 'next';
- 	} else {
- 		# end marker
- 		my $end_time = time();
-@@ -2569,111 +3429,98 @@
- 			logger "INFO: Created symlink from '$file_symlink' -> '$file_done'\n" if $opt{verbose};
- 		}
- 	}
-+
-+	$prog{$url_2}{mode} = 'podcast';
- 	return 0;
- }
- 
- 
- 
- # Get streaming iphone URL
--sub get_iphone_stream_download_url {
--		my $ua = shift;
--		my $pid = shift;
--
--		# Create url with appended 6 digit random number
--		my $url_1 = ${iphone_download_prefix}.'/'.${pid}.'?'.(sprintf "%06.0f", 1000000*rand(0)).'%20';
--		logger "INFO: media stream download URL = $url_1\n" if $opt{verbose};
--		
--		# Stage 2: e.g. "Location: http://download.iplayer.bbc.co.uk/iplayer_streaming_http_mp4/121285241910131406.mp4?token=iVXexp1yQt4jalB2Hkl%2BMqI25nz2WKiSsqD7LzRmowrwXGe%2Bq94k8KPsm7pI8kDkLslodvHySUyU%0ApM76%2BxEGtoQTF20ZdFjuqo1%2B3b7Qmb2StOGniozptrHEVQl%2FYebFKVNINg%3D%3D%0A"
--		logger "\rGetting iplayer download URL         " if ! $opt{verbose};
--		my $h = new HTTP::Headers(
--			'User-Agent'	=> $user_agent{coremedia},
--			'Accept'	=> '*/*',
--			'Range'		=> 'bytes=0-1',
--		);
--		my $req = HTTP::Request->new ('GET', $url_1, $h);
--		# send request
--		my $res = $ua->request($req);
--		# Get resulting Location header (i.e. redirect URL)
--		my $url_2 = $res->header("location");
--		if ( ! $res->is_redirect ) {
--			logger "ERROR: Failed to get redirect from iplayer site\n\n";
--			return '';
--		}
--		# Extract redirection Location URL
--		$url_2 =~ s/^Location: (.*)$/$1/g;
--		# If we get a Redirection containing statuscode=404 then this prog is not yet ready
--		if ( $url_2 =~ /statuscode=404/ ) {
--			logger "\rERROR: Programme is not yet ready for download\n";
--			return '';
--		}
--
--		return $url_2;
--}
--
--
-+sub get_stream_url_iphone {
-+	my $ua = shift;
-+	my $pid = shift;
- 
--# Get streaming audio URL (Real => rtsp)
--#<media kind="audio"
--#        type="audio/real"
--#        encoding="real"  >
--#        <connection
--#                priority="10"
--#                kind="sis"
--#                server="http://www.bbc.co.uk"
--#                identifier="/radio/aod/playlists/gs/5d/c0/0b/0900_bbc_radio_two"
--#                href="http://www.bbc.co.uk/radio/aod/playlists/gs/5d/c0/0b/0900_bbc_radio_two.ram"
--#        />
--#</media>
--# OR
--#<media kind=""
--#        type="audio/real"
--#        encoding="real"  >
--#        <connection
--#                priority="10"
--#                kind="edgesuite"
--#                server="http://http-ws.bbc.co.uk.edgesuite.net"
--#                identifier="/generatecssram.esi?file=/worldservice/css/nb/410591221152760.ra"
--#                href="http://http-ws.bbc.co.uk.edgesuite.net/generatecssram.esi?file=/worldservice/css/nb/410591221152760.ra"
--#        />
--#</media>
--#
--sub get_audio_stream_download_url {
--		my $ua = shift;
--		my $url_1 = shift;
--		my $url_2;
-+	# Create url with appended 6 digit random number
-+	my $url_1 = ${iphone_download_prefix}.'/'.${pid}.'?'.(sprintf "%06.0f", 1000000*rand(0)).'%20';
-+	logger "INFO: media stream download URL = $url_1\n" if $opt{verbose};
- 		
--		logger "\rGetting iplayer download URL         " if ! $opt{verbose};
--		my $h = new HTTP::Headers(
--			'User-Agent'	=> $user_agent{coremedia},
--			'Accept'	=> '*/*',
--			'Range'		=> 'bytes=0-',
--		);
--		my $req = HTTP::Request->new ('GET', $url_1, $h);
--		# send request
--		my $res = $ua->request($req);
--		# Get resulting content 
--		my $content = $res->content;
--		# Flatten
--		$content =~ s/\n/ /g;
--		if ( ! $res->is_success ) {
--			logger "ERROR: Failed to get audio url from iplayer site\n\n";
--			return '';
--		}
--		# If we get a Redirection containing statuscode=404 then this prog is not yet ready
--		if ( $content =~ /statuscode=404/ ) {
--			logger "\rERROR: Programme is not yet ready for download\n";
--			return '';
--		}
--		# extract ram URL
--		$url_2 = $2 if $content =~ m{<media kind="(|audio)"\s*type="audio/real".*href="(.+?)"\s*};
--
--		# If we cannot see 'encoding="real"...' then we don't have real audio transcoded format then skip
--		if ( ! $url_2 ) {
--			logger "\rERROR: Programme is not yet ready for download in RealAudio format\n";
--			return '';
--		}
--
--		return $url_2;
-+	# Stage 2: e.g. "Location: http://download.iplayer.bbc.co.uk/iplayer_streaming_http_mp4/121285241910131406.mp4?token=iVXexp1yQt4jalB2Hkl%2BMqI25nz2WKiSsqD7LzRmowrwXGe%2Bq94k8KPsm7pI8kDkLslodvHySUyU%0ApM76%2BxEGtoQTF20ZdFjuqo1%2B3b7Qmb2StOGniozptrHEVQl%2FYebFKVNINg%3D%3D%0A"
-+	logger "\rGetting iplayer download URL         " if (! $opt{verbose}) && ! $opt{streaminfo};
-+	my $h = new HTTP::Headers(
-+		'User-Agent'	=> $user_agent{coremedia},
-+		'Accept'	=> '*/*',
-+		'Range'		=> 'bytes=0-1',
-+	);
-+	my $req = HTTP::Request->new ('GET', $url_1, $h);
-+	# send request (use simple_request here because that will not allow redirects)
-+	my $res = $ua->simple_request($req);
-+	# Get resulting Location header (i.e. redirect URL)
-+	my $url_2 = $res->header("location");
-+	if ( ! $res->is_redirect ) {
-+		logger "ERROR: Failed to get redirect from iplayer site\n\n";
-+		return '';
-+	}
-+	# Extract redirection Location URL
-+	$url_2 =~ s/^Location: (.*)$/$1/g;
-+	# If we get a Redirection containing statuscode=404 then this prog is not yet ready
-+	if ( $url_2 =~ /statuscode=404/ ) {
-+		logger "\rERROR: Programme is not yet ready for download\n" if $opt{verbose};
-+		return '';
-+	}
-+
-+	return $url_2;
-+}
-+
-+
-+
-+sub get_stream_url_itv {
-+	my ( $ua, $pid ) = ( @_ );
-+
-+	my ( $response, $url_1, $url_2, $url_3, $url_4 );
-+	my $part;
-+	my $duration;
-+	my $filename;
-+	my @url_list;
-+
-+	# construct stage 1 request url
-+	$url_1 = 'http://www.itv.com/_app/video/GetMediaItem.ashx?vodcrid=crid://itv.com/'.$pid.'&bitrate=384&adparams=SITE=ITV/AREA=CATCHUP.VIDEO/SEG=CATCHUP.VIDEO%20HTTP/1.1';
-+
-+	# Extract '<LicencePlaylist>(.+?) HTTP/1.1</LicencePlaylist>'
-+	logger "INFO: ITV Video Stage 1 URL: $url_1\n" if $opt{verbose};
-+	$response = request_url_retry($ua, $url_1, 2, '', '');
-+	logger "DEBUG: Response data: $response\n" if $opt{debug};
-+	$url_2 = $1 if $response =~ m{<LicencePlaylist>(.+?) HTTP/1.1</LicencePlaylist>};
-+	# replace '&amp;' with '&' and append '%20HTTP/1.1'
-+	$url_2 =~ s/&amp;/&/g;
-+	$url_2 .= '%20HTTP/1.1';
-+	logger "INFO: ITV Video Stage 2 URL: $url_2\n" if $opt{verbose};
-+	$response = request_url_retry($ua, $url_2, 2, '', '');
-+	logger "DEBUG: Response data: $response\n" if $opt{debug};
-+
-+	# Extract hrefs and names. There are multiple entries for parts of prog (due to ads):
-+	# e.g. <asx><Title>Doctor Zhivago</Title><EntryRef href="HTTP://SAM.ITV.COM/XTSERVER/ACC_RANDOM=1231194223/SITE=ITV/AREA=CATCHUP.VIDEO/SEG=CATCHUP.VIDEO HTTP/1.1/SOURCE=CATCH.UP/GENRE=DRAMA/PROGNAME=DOCTOR.ZHIVAGO/PROGID=33105/SERIES=DOCTOR.ZHIVAGO/EPNUM=/EPTITLE=/BREAKNUM=0/ADPOS=1/PAGEID=01231194223/DENTON=0/CUSTOMRATING=/TOTDUR=90/PREDUR=0/POSDUR=905/GENERIC=6e0536bf-7883-4aaa-9230-94ecc4aea403/AAMSZ=VIDEO" /><EntryRef href="HTTP://SAM.ITV.COM/XTSERVER/ACC_RANDOM=1231194223/SITE=ITV/AREA=CATCHUP.VIDEO/SEG=CATCHUP.VIDEOHTTP/1.1/SOURCE=CATCH.UP/GENRE=DRAMA/PROGNAME=DOCTOR.ZHIVAGO/PROGID=33105/SERIES=DOCTOR.ZHIVAGO/EPNUM=/EPTITLE=/BREAKNUM=0/ADPOS=LAST/PAGEID=01231194223/DENTON=0/CUSTOMRATING=/TOTDUR=90/PREDUR=0/POSDUR=905/GENERIC=6e0536bf-7883-4aaa-9230-94ecc4aea403/AAMSZ=VIDEO" />
-+	$prog{$pid}{name} = $1 if $response =~ m{<Title>(.+?)<\/Title>};
-+	for my $entry (split /<Entry><ref\s+href=/, $response) {
-+		logger "DEBUG: Entry data: $entry\n" if $opt{debug};
-+		$entry .= '<Entry><ref href='.$entry;
-+
-+		( $url_3, $part, $filename, $duration ) = ( $1, $2, $3, $4 ) if $entry =~ m{<Entry><ref\s+href="(.+?)"\s+\/><param\s+value="true"\s+name="Prebuffer"\s+\/>\s*<PARAM\s+NAME="PrgPartNumber"\s+VALUE="(.+?)"\s*\/><PARAM\s+NAME="FileName"\s+VALUE="(.+?)"\s*\/><PARAM\s+NAME="PrgLength"\s+VALUE="(.+?)"\s*\/>};
-+		next if not $url_3;
-+		# Replace '&amp;' with '&' in url
-+		$url_3 =~ s/&amp;/&/g;
-+		logger "INFO: ITV Video Name: $part\n";
-+
-+		logger "INFO: ITV Video Stage 3 URL: $url_3\n" if $opt{verbose};
-+		$entry = request_url_retry($ua, $url_3, 2, '', '');
-+		logger "DEBUG: Response data: $entry\n" if $opt{debug};
-+
-+		# Extract mms (replace 'http' with 'mms') url: e.g.: Ref1=http://itvbrdbnd.wmod.llnwd.net/a1379/o21/ucontent/2007/6/22/1549_384_1_2.wmv?MSWMExt=.asf
-+		chomp( $url_4 = 'mms'.$1 ) if $entry =~ m{Ref1=http(.+?)[\r\n]+};
-+		logger "INFO: ITV Video URL: $url_4\n" if $opt{verbose};
-+		push @url_list, $url_4;
-+	}
-+	return @url_list;
- }
- 
- 
-@@ -2711,7 +3558,7 @@
- 	# Change all the chunk offsets in moov->stco atoms and add moov_length to them all
- 	# get moov atom length
- 	my $moov_length = bytestring_to_int( substr($moovdata, 0, 4) );
--	# Use index() to seatch for a string within a string
-+	# Use index() to search for a string within a string
- 	my $i = -1;
- 	while (($i = index($moovdata, 'stco', $i)) > -1) {
- 
-@@ -2725,10 +3572,11 @@
- 			#logger "chunk_offset @ $i, $j = '".get_hex( substr($moovdata, $j, 4) )."',	$chunk_offset + $moov_length = ";
- 			$chunk_offset += $moov_length;
- 			# write back bytes into $moovdata
--			substr($moovdata, $j+0, 1) = chr( ($chunk_offset >> 24) & 0xFF );
--			substr($moovdata, $j+1, 1) = chr( ($chunk_offset >> 16) & 0xFF );
--			substr($moovdata, $j+2, 1) = chr( ($chunk_offset >>  8) & 0xFF );
--			substr($moovdata, $j+3, 1) = chr( ($chunk_offset >>  0) & 0xFF );
-+			#substr($moovdata, $j+0, 1) = chr( ($chunk_offset >> 24) & 0xFF );
-+			#substr($moovdata, $j+1, 1) = chr( ($chunk_offset >> 16) & 0xFF );
-+			#substr($moovdata, $j+2, 1) = chr( ($chunk_offset >>  8) & 0xFF );
-+			#substr($moovdata, $j+3, 1) = chr( ($chunk_offset >>  0) & 0xFF );
-+			write_msb_value_at_offset( $moovdata, $j, $chunk_offset );
- 			#$chunk_offset = bytestring_to_int( substr($moovdata, $j, 4) );
- 			#logger "$chunk_offset\n";
- 		}
-@@ -2743,6 +3591,86 @@
- 
- 
- 
-+# Replace the moov->udta atom with a new user-supplied one and update the moov atom size
-+# Usage: replace_moov_udta_atom ( $udta_new, $moovdata )
-+sub replace_moov_udta_atom {
-+	my $udta_new = $_[0];
-+	my $moovdata = $_[1];
-+
-+	# get moov atom length
-+	my $moov_length = bytestring_to_int( substr($moovdata, 0, 4) );
-+
-+	# Find the original udta atom start 
-+	# Use index() to search for a string within a string ($i will point at the beginning of the atom)
-+	my $i = index($moovdata, 'udta', -1) - 4;
-+
-+	# determine length of atom (4 bytes preceding the name)
-+	my $udta_len = bytestring_to_int( substr($moovdata, $i, 4) );
-+	logger "INFO: Found udta atom at moov atom offset: $i length $udta_len\n" if $opt{verbose};
-+
-+	# Save the data before the udta atom
-+	my $moovdata_before_udta = substr($moovdata, 0, $i);
-+
-+	# Save the remainder portion of data after the udta atom for later
-+	my $moovdata_after_udta = substr($moovdata, $i, $moovdata - $i + $udta_len);
-+
-+	# Old udta atom should we need it
-+	### my $udta_old = substr($moovdata, $i, $udta_len);
-+
-+	# Create new moov atom
-+	$moovdata = $moovdata_before_udta.$udta_new.$moovdata_after_udta;
-+	
-+	# Recalculate the moov size and insert into moovdata
-+	write_msb_value_at_offset( $moovdata, 0, length($moovdata) );
-+	
-+	# Write $moovdata back to calling string
-+	$_[1] = $moovdata;
-+
-+	return 0;
-+}
-+
-+
-+
-+# Write the msb 4 byte $value starting at $offset into the passed string
-+# Usage: write_msb_value($string, $offset, $value)
-+sub write_msb_value_at_offset {
-+	my $offset = $_[1];
-+	my $value = $_[2];
-+	substr($_[0], $offset+0, 1) = chr( ($value >> 24) & 0xFF );
-+	substr($_[0], $offset+1, 1) = chr( ($value >> 16) & 0xFF );
-+	substr($_[0], $offset+2, 1) = chr( ($value >>  8) & 0xFF );
-+	substr($_[0], $offset+3, 1) = chr( ($value >>  0) & 0xFF );
-+	return 0;
-+}
-+
-+
-+
-+# Returns a string containing an QT atom
-+# Usage: create_qt_atom(<atome name>, <atom data>, ['string'])
-+sub create_qt_atom {
-+	my ($name, $data, $prog_type) = (@_);
-+	if (length($name) != 4) {
-+		logger "ERROR: Inavlid QT atom name length '$name'\n";
-+		exit 1;
-+	}
-+	# prepend string length if this is a string type
-+	if ( $prog_type eq 'string' ) {
-+		my $value = length($data);
-+		$data = '1111'.$data;
-+		# overwrite '1111' with total atom length in 2-byte MSB + 0x0 0x0
-+		substr($data, 0, 1) = chr( ($value >> 8) & 0xFF );
-+		substr($data, 1, 1) = chr( ($value >> 0) & 0xFF );
-+		substr($data, 2, 1) = chr(0);
-+		substr($data, 3, 1) = chr(0);
-+	}
-+	my $atom = '0000'.$name.$data;
-+	# overwrite '0000' with total atom length in MSB
-+	write_msb_value_at_offset( $atom, 0, length($name.$data) + 4 );
-+	return $atom;
-+}
-+
-+
-+
- # Usage download_block($file, $url_2, $ua, $start, $end, $file_len, $fh);
- #  ensure filehandle $fh is open in append mode
- # or, $content = download_block(undef, $url_2, $ua, $start, $end, $file_len);
-@@ -2811,7 +3739,7 @@
- 			$rate = sprintf("%5.0fkbps", (8.0 / 1024.0) * $rate_bps);
- 			$time = sprintf("%02d:%02d:%02d", ( gmtime( ($file_len - $size) / $rate_bps ) )[2,1,0] );
- 		}
--		printf STDERR "%8.2fMB / %.2fMB %s %5.1f%%, %s remaining         \r", 
-+		logger sprintf "%8.2fMB / %.2fMB %s %5.1f%%, %s remaining         \r", 
- 			$size / 1024.0 / 1024.0, 
- 			$file_len / 1024.0 / 1024.0,
- 			$rate,
-@@ -2851,7 +3779,7 @@
- 				$time = sprintf("%02d:%02d:%02d", ( gmtime( ($file_len - $size) / $rate_bps ) )[2,1,0] );
- 			}
- 			# time remaining
--			printf STDERR "%8.2fMB / %.2fMB %s %5.1f%%, %s remaining         \r", 
-+			logger sprintf "%8.2fMB / %.2fMB %s %5.1f%%, %s remaining         \r", 
- 				$size / 1024.0 / 1024.0,
- 				$file_len / 1024.0 / 1024.0,
- 				$rate,
-@@ -2865,7 +3793,7 @@
- 			} else {
- 				$rate = sprintf("%5.0fkbps", (8.0 / 1024.0) * $size / ($timecalled - $now) );
- 			}
--			printf STDERR "%8.2fMB %s         \r", $size / 1024.0 / 1024.0, $rate;
-+			logger sprintf "%8.2fMB %s         \r", $size / 1024.0 / 1024.0, $rate;
- 		}
- 	};
- 
-@@ -2901,6 +3829,19 @@
- 
- 
- 
-+sub create_ua {
-+	my $agent = shift;
-+	my $ua = LWP::UserAgent->new;
-+	$ua->timeout([$lwp_request_timeout]);
-+	$ua->proxy( ['http'] => $proxy_url );
-+	$ua->agent( $user_agent{$agent} );
-+	$ua->conn_cache(LWP::ConnCache->new());
-+	$ua->cookie_jar( HTTP::Cookies->new( file => $cookiejar, autosave => 1, ignore_discard => 1 ) );
-+	return $ua;
-+};	
-+
-+
-+
- # Converts a string of chars to it's HEX representation
- sub get_hex {
-         my $buf = shift || '';
-@@ -2985,11 +3926,7 @@
- sub update_script {
- 	# Get version URL
- 	my $script_file = $0;
--	my $ua = LWP::UserAgent->new;
--	$ua->timeout([$lwp_request_timeout]);
--	$ua->proxy( ['http'] => $proxy_url );
--	$ua->agent( $user_agent{update} );
--	$ua->conn_cache(LWP::ConnCache->new());
-+	my $ua = create_ua('update');
- 	logger "INFO: Current version is $version\n";
- 	logger "INFO: Checking for latest version from linuxcentre.net\n";
- 	my $res = $ua->request( HTTP::Request->new( GET => $version_url ) );
-@@ -3070,10 +4007,8 @@
- 						<video><url id=\"p1\">${pid}.mov<playlist/></url></video>
- 						<info><description>${desc}</description></info>
- 					</movie>\n" if $opt{fxd};
--					my $newtitle = ${title} ;
--					$newtitle =~ s/\&//g ;
- 					print XML "<Stream>
--						<Name>\"$newtitle\"</Name>
-+						<Name>\"${title}\"</Name>
- 						<url>${pid}.mov</url>
- 						<Subtitle></Subtitle>
- 						<Synopsis>${desc}</Synopsis>
-@@ -3294,6 +4229,7 @@
- 	my $pid = shift;
- 	my $metadata;
- 	my $entry3;
-+	my ($name, $episode, $duration, $available, $channel, $expiry, $longdesc, $versions, $guidance, $prog_type, $categories, $player, $thumbnail);
- 
- 	# This URL works for all prog types:
- 	# http://www.bbc.co.uk/iplayer/playlist/${pid}
-@@ -3307,97 +4243,162 @@
- 	# This URL works for tv/radio prog types:
- 	# $prog_feed_url = http://feeds.bbc.co.uk/iplayer/episode/$pid
- 
--	if ( $prog{$pid}{type} =~ /(tv|radio)/i ) {
-+	if ( $prog{$pid}{type} =~ /^(tv|radio)$/i ) {
- 		$entry3 = request_url_retry($ua, $prog_feed_url.$pid, 3, '', '');
- 		decode_entities($entry3);
- 		logger "DEBUG: $prog_feed_url.$pid:\n$entry3\n\n" if $opt{debug};
- 		# Flatten
- 		$entry3 =~ s|\n| |g;
--	}
- 
--	# Entry3 format
--	#<?xml version="1.0" encoding="utf-8"?>                                      
--	#<?xml-stylesheet href="http://www.bbc.co.uk/iplayer/style/rss.css" type="text/css"?>
--	#<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:media="http://search.yahoo.com/mrss/" xml:lang="en-GB">
--	#  <title>BBC iPlayer - Episode Detail: Edith Bowman: 22/09/2008</title>                                                                          
--	#  <subtitle>Sara Cox sits in for Edith with another Cryptic Randomizer.</subtitle>
--	#  <updated>2008-09-29T10:59:45Z</updated>
--	#  <id>tag:feeds.bbc.co.uk,2008:/iplayer/feed/episode/b00djtfh</id>
--	#  <link rel="related" href="http://www.bbc.co.uk/iplayer" type="text/html" />
--	#  <link rel="self" href="http://feeds.bbc.co.uk/iplayer/episode/b00djtfh" type="application/atom+xml" />
--	#  <author>
--	#    <name>BBC</name>
--	#    <uri>http://www.bbc.co.uk</uri>
--	#  </author>
--	#  <entry>
--	#    <title type="text">Edith Bowman: 22/09/2008</title>
--	#    <id>tag:feeds.bbc.co.uk,2008:PIPS:b00djtfh</id>
--	#    <updated>2008-09-15T01:28:36Z</updated>
--	#    <summary>Sara Cox sits in for Edith with another Cryptic Randomizer.</summary>
--	#    <content type="html">
--	#      &lt;p&gt;
--	#        &lt;a href=&quot;http://www.bbc.co.uk/iplayer/episode/b00djtfh?src=a_syn30&quot;&gt;
--	#          &lt;img src=&quot;http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_150_84.jpg&quot; alt=&quot;Edith Bowman: 22/09/2008&quot; /&gt;
--	#        &lt;/a&gt;
--	#      &lt;/p&gt;
--	#      &lt;p&gt;
--	#        Sara Cox sits in for Edith with movie reviews and great new music, plus another Cryptic Randomizer.
--	#      &lt;/p&gt;
--	#    </content>
--	#    <link rel="alternate" href="http://www.bbc.co.uk/iplayer/episode/b00djtfh?src=a_syn31" type="text/html" title="Edith Bowman: 22/09/2008">
--	#      <media:content medium="audio" duration="10800">
--	#        <media:title>Edith Bowman: 22/09/2008</media:title>
--	#        <media:description>Sara Cox sits in for Edith with movie reviews and great new music, plus another Cryptic Randomizer.</media:description>
--	#        <media:player url="http://www.bbc.co.uk/iplayer/episode/b00djtfh?src=a_syn31" />
--	#        <media:category scheme="urn:bbc:metadata:cs:iPlayerUXCategoriesCS" label="Entertainment">9100099</media:category>
--	#        <media:category scheme="urn:bbc:metadata:cs:iPlayerUXCategoriesCS" label="Music">9100006</media:category>
--	#        <media:category scheme="urn:bbc:metadata:cs:iPlayerUXCategoriesCS" label="Pop &amp; Chart">9200069</media:category>
--	#        <media:credit role="Production Department" scheme="urn:ebu">BBC Radio 1</media:credit>
--	#        <media:credit role="Publishing Company" scheme="urn:ebu">BBC Radio 1</media:credit>
--	#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_86_48.jpg" width="86" height="48" />
--	#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_150_84.jpg" width="150" height="84" />
--	#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_178_100.jpg" width="178" height="100" />
--	#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_512_288.jpg" width="512" height="288" />
--	#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_528_297.jpg" width="528" height="297" />
--	#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_640_360.jpg" width="640" height="360" />
--	#        <dcterms:valid>
--	#          start=2008-09-22T15:44:20Z;
--	#          end=2008-09-29T15:02:00Z;
--	#          scheme=W3C-DTF
--	#        </dcterms:valid>
--	#      </media:content>
--	#    </link>
--	#    <link rel="self" href="http://feeds.bbc.co.uk/iplayer/episode/b00djtfh?format=atom" type="application/atom+xml" title="22/09/2008" />
--	#    <link rel="related" href="http://www.bbc.co.uk/programmes/b006wks4/microsite" type="text/html" title="Edith Bowman" />
--	#    <link rel="parent" href="http://feeds.bbc.co.uk/iplayer/programme_set/b006wks4" type="application/atom+xml" title="Edith Bowman" />
--	#  </entry>
--	#</feed>
--
--	my ($duration, $available, $channel, $expiry, $longdesc, $versions, $guidance, $type, $categories, $player, $thumbnail);
--
--	$expiry = $1 if $entry3 =~ m{<dcterms:valid>\s*start=.+?;\s*end=(.*?);};
--	$available = $1 if $entry3 =~ m{<dcterms:valid>\s*start=(.+?);\s*end=.*?;};
--	$duration = $1 if $entry3 =~ m{duration=\"(\d+?)\"};
--	$type = $1 if $entry3 =~ m{medium=\"(\w+?)\"};
--	$longdesc = $1 if $entry3 =~ m{<media:description>\s*(.*?)\s*<\/media:description>};
--	$guidance = $1 if $entry3 =~ m{<media:rating scheme="urn:simple">(.+?)<\/media:rating>};
--	$player = $1 if $entry3 =~ m{<media:player\s*url=\"(.*?)\"\s*\/>};
--	$thumbnail = $1 if $entry3 =~ m{<media:thumbnail url="([^"]+?)"\s+width="150"\s+height="84"\s*/>};
--	
--	my @cats;
--	for (split /<media:category scheme=\".+?\"/, $entry3) {
--		push @cats, $1 if m{\s*label="(.+?)">\d+<\/media:category>};
--	}
--	$categories = join ',', @cats;
-+		# Entry3 format
-+		#<?xml version="1.0" encoding="utf-8"?>                                      
-+		#<?xml-stylesheet href="http://www.bbc.co.uk/iplayer/style/rss.css" type="text/css"?>
-+		#<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:media="http://search.yahoo.com/mrss/" xml:lang="en-GB">
-+		#  <title>BBC iPlayer - Episode Detail: Edith Bowman: 22/09/2008</title>                                                                          
-+		#  <subtitle>Sara Cox sits in for Edith with another Cryptic Randomizer.</subtitle>
-+		#  <updated>2008-09-29T10:59:45Z</updated>
-+		#  <id>tag:feeds.bbc.co.uk,2008:/iplayer/feed/episode/b00djtfh</id>
-+		#  <link rel="related" href="http://www.bbc.co.uk/iplayer" type="text/html" />
-+		#  <link rel="self" href="http://feeds.bbc.co.uk/iplayer/episode/b00djtfh" type="application/atom+xml" />
-+		#  <author>
-+		#    <name>BBC</name>
-+		#    <uri>http://www.bbc.co.uk</uri>
-+		#  </author>
-+		#  <entry>
-+		#    <title type="text">Edith Bowman: 22/09/2008</title>
-+		#    <id>tag:feeds.bbc.co.uk,2008:PIPS:b00djtfh</id>
-+		#    <updated>2008-09-15T01:28:36Z</updated>
-+		#    <summary>Sara Cox sits in for Edith with another Cryptic Randomizer.</summary>
-+		#    <content type="html">
-+		#      &lt;p&gt;
-+		#        &lt;a href=&quot;http://www.bbc.co.uk/iplayer/episode/b00djtfh?src=a_syn30&quot;&gt;
-+		#          &lt;img src=&quot;http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_150_84.jpg&quot; alt=&quot;Edith Bowman: 22/09/2008&quot; /&gt;
-+		#        &lt;/a&gt;
-+		#      &lt;/p&gt;
-+		#      &lt;p&gt;
-+		#        Sara Cox sits in for Edith with movie reviews and great new music, plus another Cryptic Randomizer.
-+		#      &lt;/p&gt;
-+		#    </content>
-+		#    <link rel="alternate" href="http://www.bbc.co.uk/iplayer/episode/b00djtfh?src=a_syn31" type="text/html" title="Edith Bowman: 22/09/2008">
-+		#      <media:content medium="audio" duration="10800">
-+		#        <media:title>Edith Bowman: 22/09/2008</media:title>
-+		#        <media:description>Sara Cox sits in for Edith with movie reviews and great new music, plus another Cryptic Randomizer.</media:description>
-+		#        <media:player url="http://www.bbc.co.uk/iplayer/episode/b00djtfh?src=a_syn31" />
-+		#        <media:category scheme="urn:bbc:metadata:cs:iPlayerUXCategoriesCS" label="Entertainment">9100099</media:category>
-+		#        <media:category scheme="urn:bbc:metadata:cs:iPlayerUXCategoriesCS" label="Music">9100006</media:category>
-+		#        <media:category scheme="urn:bbc:metadata:cs:iPlayerUXCategoriesCS" label="Pop &amp; Chart">9200069</media:category>
-+		#        <media:credit role="Production Department" scheme="urn:ebu">BBC Radio 1</media:credit>
-+		#        <media:credit role="Publishing Company" scheme="urn:ebu">BBC Radio 1</media:credit>
-+		#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_86_48.jpg" width="86" height="48" />
-+		#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_150_84.jpg" width="150" height="84" />
-+		#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_178_100.jpg" width="178" height="100" />
-+		#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_512_288.jpg" width="512" height="288" />
-+		#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_528_297.jpg" width="528" height="297" />
-+		#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_640_360.jpg" width="640" height="360" />
-+		#        <dcterms:valid>
-+		#          start=2008-09-22T15:44:20Z;
-+		#          end=2008-09-29T15:02:00Z;
-+		#          scheme=W3C-DTF
-+		#        </dcterms:valid>
-+		#      </media:content>
-+		#    </link>
-+		#    <link rel="self" href="http://feeds.bbc.co.uk/iplayer/episode/b00djtfh?format=atom" type="application/atom+xml" title="22/09/2008" />
-+		#    <link rel="related" href="http://www.bbc.co.uk/programmes/b006wks4/microsite" type="text/html" title="Edith Bowman" />
-+		#    <link rel="parent" href="http://feeds.bbc.co.uk/iplayer/programme_set/b006wks4" type="application/atom+xml" title="Edith Bowman" />
-+		#  </entry>
-+		#</feed>
-+			
-+		$expiry = $1 if $entry3 =~ m{<dcterms:valid>\s*start=.+?;\s*end=(.*?);};
-+		$available = $1 if $entry3 =~ m{<dcterms:valid>\s*start=(.+?);\s*end=.*?;};
-+		$duration = $1 if $entry3 =~ m{duration=\"(\d+?)\"};
-+		$prog_type = $1 if $entry3 =~ m{medium=\"(\w+?)\"};
-+		$longdesc = $1 if $entry3 =~ m{<media:description>\s*(.*?)\s*<\/media:description>};
-+		$guidance = $1 if $entry3 =~ m{<media:rating scheme="urn:simple">(.+?)<\/media:rating>};
-+		$player = $1 if $entry3 =~ m{<media:player\s*url=\"(.*?)\"\s*\/>};
-+		$thumbnail = $1 if $entry3 =~ m{<media:thumbnail url="([^"]+?)"\s+width="150"\s+height="84"\s*/>};
-+	
-+		my @cats;
-+		for (split /<media:category scheme=\".+?\"/, $entry3) {
-+			push @cats, $1 if m{\s*label="(.+?)">\d+<\/media:category>};
-+		}
-+		$categories = join ',', @cats;
-+
-+		# populate version pid metadata 
-+		get_version_pids($ua, $pid);
-+
-+	# ITV Catch-Up metadata
-+	} elsif ( $prog{$pid}{type} eq 'itv' ) {
-+		my $prog_metadata_url_itv = 'http://www.itv.com/_app/Dynamic/CatchUpData.ashx?ViewType=5&Filter='; # +<pid>
-+		$entry3 = request_url_retry($ua, "${prog_metadata_url_itv}${pid}", 3, '', '');
-+		decode_entities($entry3);
-+		logger "DEBUG: ${prog_metadata_url_itv}${pid}:\n$entry3\n\n" if $opt{debug};
-+		# Flatten
-+		$entry3 =~ s|[\r\n]||g;
-+
-+		#div class="itvCatchUpPlayerPanel" xmlns:ms="urn:schemas-microsoft-com:xslt">
-+		#  <div class="cu-sponsor"><a href="http://sam.itv.com/accipiter/adclick/CID=000040d70000000000000000/acc_random=1/SITE=CLICKTRACK/AREAITVCATCHUP.VIDEO=CLICKTRACK..FREEVIEW.SPONSORBUTTON.OCT08/AAMSZ=120X60/pageid=1" title="ITV Player in assocation with Freeview"><img src="/_app/img/catchup/catchup_video_freeview2.jpg" alt="ITV Player is sponsored by Freeview"></a></div>
-+		#  <h2>Doctor Zhivago</h2>
-+		#  <p>Part 1 of 3. Dramatisation of the epic novel by Boris Pasternak. Growing up in Moscow with his uncle, aunt and cousin Tonya, Yury is captivated by a stunning young girl called ...</p>
-+		#  <p class="timings"><span class="date">Mon 29 Dec 2008</span><br /><br /><span>
-+		#
-+		#        Duration: 1hr 30 min |
-+		#                                Expires in
-+		#                                <strong>22</strong>
-+		#                                                days
-+		#                                        </span></p>
-+		#  <p><a href="http://www.itv.com/CatchUp/Programmes/default.html?ViewType=1&amp;Filter=2352">3 Episodes Available
-+		#        </a><br></br></p>
-+		#  <p class="channelLogo"><img src="/_app/img/logos/itv3-black.gif" alt="ITV 4"></p>
-+		#  <div id="cu-2-0-VideoID">33105</div>
-+		#  <div id="cu-2-0-DentonId">17</div>
-+		#  <div id="cu-2-0-ItemMediaUrl">http://www.itv.com//img/480x272/Doctor-Zhivago-c47828f8-a1af-4cd2-b5a2-40c18eb7e63c.jpg</div>
-+		#</div><script language="javascript" type="text/javascript" xmlns:ms="urn:schemas-microsoft-com:xslt">
-+		#                        SetCatchUpModuleID(0);
-+		#                </script>
-+		#
- 
--	# populate version pid metadata 
--	get_version_pids($ua, $pid);
-+		#<div class="itvCatchUpPlayerPanel" xmlns:ms="urn:schemas-microsoft-com:xslt">
-+		#  <div class="cu-sponsor"><a href="http://sam.itv.com/accipiter/adclick/CID=000040d70000000000000000/acc_random=1/SITE=CLICKTRACK/AREAITVCATCHUP.VIDEO=CLICKTRACK..FREEVIEW.SPONSORBUTTON.OCT08/AAMSZ=120X60/pageid=1" title="ITV Player in assocation with Freeview"><img src="/_app/img/catchup/catchup_video_freeview2.jpg" alt="ITV Player is sponsored by Freeview"></a></div>
-+		#  <h2>Affinity</h2>
-+		#  <p>Victorian period drama with a murderous, pyschological twist.</p>
-+		#  <p class="timings"><span class="date">Sun 28 Dec 2008</span><br /><br /><span>
-+		#
-+		#        Duration: 2hr 00 min |
-+		#                                Expires in
-+		#                                <strong>21</strong>
-+		#                                                days
-+		#                                        </span></p>
-+		#  <p class="channelLogo"><img src="/_app/img/logos/itv1-black.gif" alt="ITV 2"></p>
-+		#  <div class="guidance">
-+		#    <div><strong>ITV Video Guidance</strong><p>This programme contains strong language and scenes of a sexual nature                                                                                                                           </p>
-+		#    </div>
-+		#  </div>
-+		#  <div id="cu-2-0-VideoID">33076</div>
-+		#  <div id="cu-2-0-DentonId">11</div>
-+		#  <div id="cu-2-0-ItemMediaUrl">http://www.itv.com//img/480x272/Affinity-9624033b-6e05-4784-85f7-114be0559b24.jpg</div>
-+		#</div><script language="javascript" type="text/javascript" xmlns:ms="urn:schemas-microsoft-com:xslt">
-+		#                        SetCatchUpModuleID(0);
-+		#                </script>
-+		#
-+
-+		#$expiry = $1 if $entry3 =~ m{<dcterms:valid>\s*start=.+?;\s*end=(.*?);};
-+		$available = $1 if $entry3 =~ m{<p\s+class="timings">\s*<span\s+class="date">(.+?)<\/span>};
-+		$duration = $1 if $entry3 =~ m{Duration:\s*(.+?)\s+\|};
-+		#$prog_type = $1 if $entry3 =~ m{medium=\"(\w+?)\"};
-+		$longdesc = $1 if $entry3 =~ m{<p>(.+?)<\/p>}i;
-+		$guidance = $1 if $entry3 =~ m{ITV Video Guidance<\/strong><p>\s*(.+?)[\W\s]*<\/p>};
-+		#$player = $1 if $entry3 =~ m{<media:player\s*url=\"(.*?)\"\s*\/>};
-+		$thumbnail = $1 if $entry3 =~ m{<div id="cu-2-0-ItemMediaUrl">(.+?)</div>};
-+		$name = $1 if $entry3 =~ m{<h2>(.+?)</h2>};
-+	}
- 
- 	# Fill in from cache if not got from metadata
- 	my %metadata;
- 	$metadata{pid}		= $pid;
- 	$metadata{index}	= $prog{$pid}{index};
--	$metadata{type}		= $type || $prog{$pid}{type};
-+	$metadata{name}		= $name || $prog{$pid}{name};
-+	$metadata{episode}	= $episode || $prog{$pid}{episode};
-+	$metadata{type}		= $prog_type || $prog{$pid}{type};
- 	$metadata{duration}	= $duration || $prog{$pid}{duration};
- 	$metadata{channel}	= $channel || $prog{$pid}{channel};
- 	$metadata{available}	= $available || $prog{$pid}{available};
-@@ -3492,7 +4493,7 @@
- 		logger "WARNING: Cannot write or append to $historyfile\n\n";
- 		return 1;
- 	}
--	print HIST "$pid|$prog{$pid}{name}|$prog{$pid}{episode}|$prog{$pid}{type}|".time()."\n";
-+	print HIST "$pid|$prog{$pid}{name}|$prog{$pid}{episode}|$prog{$pid}{type}|".time()."|$prog{$pid}{mode}\n";
- 	close HIST;
- 	return 0;
- }
-@@ -3555,7 +4556,10 @@
- # Add id3 tag to MP3 files if required
- sub tag_file {
- 	my $pid = shift;
-+
- 	if ( $prog{$pid}{ext} eq 'mp3' ) {
-+		# Return if file does not exist
-+		return if ! -f $prog{$pid}{filename};
- 		# Create ID3 tagging options for external tagger program (escape " for shell)
- 		my ( $id3_name, $id3_episode, $id3_desc, $id3_channel ) = ( $prog{$pid}{name}, $prog{$pid}{episode}, $prog{$pid}{desc}, $prog{$pid}{channel} );
- 		$id3_name =~ s|"|\"|g for ($id3_name, $id3_episode, $id3_desc, $id3_channel);
-@@ -3580,9 +4584,16 @@
- sub list_unique_element_counts {
- 	my $element_name = shift;
- 	my %elements;
--	logger "INFO: $opt{type} $element_name List:\n" if $opt{verbose};
-+	logger "INFO: ".(join ',', keys %type)." $element_name List:\n" if $opt{verbose};
- 	for my $pid (keys %prog) {
--		for my $element ( split /,/, $prog{$pid}{$element_name} ) {
-+		my @element;
-+		# Need to separate the categories
-+		if ($element_name eq 'categories') {
-+			@element = split /,/, $prog{$pid}{$element_name};
-+		} else {
-+			@element[0] = $prog{$pid}{$element_name};
-+		}
-+		for my $element (@element) {
- 			$elements{ $element }++;
- 		}
- 	}
-@@ -3659,6 +4670,7 @@
- 
- 
- 
-+
- # Save the options on the cmdline as a PVR search with the specified name
- sub pvr_add {
- 	my $name = shift;
-@@ -3670,7 +4682,7 @@
- 		return 1;
- 	}
- 	# Parse valid options and create array (ignore options from the options files that have not been overriden on the cmdline)
--	for (grep /^(long|output.*|proxy|subdir|whitespace|versions|type|(exclude)?category|(exclude)?channel|command|realaudio|mp3audio|wav|raw|bandwidth|subtitles|suboffset|since|versionlist|verbose)$/, sort {$a <=> $b} keys %opt_cmdline) {
-+	for (grep /^(amode|vmode|long|output.*|proxy|subdir|whitespace|versions|type|(exclude)?category|(exclude)?channel|command|realaudio|mp3audio|wav|raw|bandwidth|subtitles|suboffset|since|versionlist|verbose)$/, sort {lc $a cmp lc $b} keys %opt_cmdline) {
- 		if ( defined $opt_cmdline{$_} ) {
- 				push @options, "$_ $opt_cmdline{$_}";
- 				logger "DEBUG: Adding option $_ = $opt_cmdline{$_}\n" if $opt{debug};
-@@ -3715,7 +4727,7 @@
- 	pvr_load_list();
- 	# Print out list
- 	logger "All PVR Searches:\n\n";
--	for my $name ( sort {$a <=> $b} keys %pvrsearches ) {
-+	for my $name ( sort {lc $a cmp lc $b} keys %pvrsearches ) {
- 		# Report whether disabled
- 		if ( $pvrsearches{$name}{disable} ) {
- 			logger "(Disabled) PVR Search '$name':\n";
-diff -ruaN mythvodka.orig/scripts/gethulu.pl mythvodka/scripts/gethulu.pl
---- mythvodka.orig/scripts/gethulu.pl	2009-01-06 19:26:30.000000000 +0000
-+++ mythvodka/scripts/gethulu.pl	2009-02-12 07:27:44.000000000 +0000
-@@ -123,7 +123,8 @@
-       if($ephtml =~ m/thumbnail_url: "(.+?)"/)  { $epimg=$1 } ;
- 
-       print MYTHMENU "<Stream>\n";
--      print MYTHMENU "<Name>$eptitle</Name>\n";
-+      print MYTHMENU "<Name>$title-$eptitle</Name>\n";
-+      #print MYTHMENU "<Name>$eptitle</Name>\n";
-       print MYTHMENU "<Url>http://www.hulu.com/watch/$epid</Url>\n";
-       print MYTHMENU "<Subtitle>$season - $epno</Subtitle>\n";
-       print MYTHMENU "<Synopsis>$epdate - $epdesc</Synopsis>\n";
-diff -ruaN mythvodka.orig/scripts/hulu mythvodka/scripts/hulu
---- mythvodka.orig/scripts/hulu	2009-01-04 15:25:24.000000000 +0000
-+++ mythvodka/scripts/hulu	2009-02-12 07:27:44.000000000 +0000
-@@ -22,6 +22,7 @@
- html=get_HTML(cid)
- cidSoup=BeautifulStoneSoup(html)
- pid=cidSoup.findAll('pid')[0].contents[0]
-+logfile="/var/log/mythtv/hulu_quality.log"
- 
- smilURL = "http://releasegeo.hulu.com/content.select?pid=" + pid + "&mbr=true&format=smil"
- print smilURL
-@@ -34,18 +35,58 @@
- #label streams
- i=0
- quality=0
-+qual_medium=-1; qual_high=-1; qual_h264=-1; command2="echo hulu done."
-+os.system("rm -f "+logfile+".0")
-+os.system("mv -f "+logfile+" "+logfile+".0")
-+f=open(logfile,'w')
-+os.system("chmod a+rw "+logfile)
-+print >>f, "Debug debug"
-+print >>f, "hulu ",url, " ", fileout
-+#
-+# Find the various quality choices that are available
-+#
- for stream in video:
--    if "480K" in stream['src'] or "480k" in stream['src']:
-+    print >>f, stream
-+    if "H264" in stream['src'] or "h264" in stream['src'] or "h264" in stream['profile'] or "H264" in stream['profile']:
-+        streams.append(['H264',stream['src']])
-+	qual_h264=i
-+	print >>f, "DebugQual h264", i
-+	print >>f, ""
-+    elif "480K" in stream['src'] or "480k" in stream['src']:
-         streams.append(['Flash (480k)',stream['src']])
-+	qual_medium=i
-+	print >>f, "DebugQual medium", i
-+	print >>f, ""
-     elif "700K" in stream['src'] or "700k" in stream['src']:
-         streams.append(['Flash (700k)',stream['src']])
- 	quality=i
--    elif "H264" in stream['src'] or "h264" in stream['src']:
--        streams.append(['H264',stream['src']])
-+	qual_high=i
-+	print >>f, "DebugQual high", i
-+	print >>f, ""
-+    elif "medium" in stream['profile'] or "Medium" in stream['profile']:
-+	streams.append(['Flash (Medium)',stream['src']])
-+	if qual_medium==-1: qual_medium=i
-+        print >>f, "DebugQual Medium", i, qual_medium
-+        print >>f, ""
-+    elif "high" in stream['profile'] or "High" in stream['profile']:
-+        streams.append(['Flash (High)',stream['src']])
-+	if qual_high==-1: qual_high=i
-+	print >>f, "DebugQual High", i, qual_high
-+	print >>f, ""
-     else:
-         streams.append(['unkown quality: '+stream['src'].split('/')[-1],stream['src']])
-+	print >>f, "DebugQual Unknown", i
-+	print >>f, ""
-     i=i+1
- 
-+if qual_high>-1: 
-+    quality=qual_high
-+elif qual_medium>-1:
-+    quality=qual_medium
-+
-+print >>f, "DebugQualVars: h264, high, medium, selected=",qual_h264,qual_high,qual_medium,quality
-+
-+
- if quality!=-1:
-     print "stream url"
- #generate random code
-@@ -104,4 +145,9 @@
-     command=command.replace(';','\\;')
- 
-     print command
--    os.system(command)
-+    print >>f,"Command is ",command
-+    print >>f,"command2 is ",command2
-+    f.close()
-+    os.system(command + "; " + command2)
-+else:
-+    f.close()
-diff -ruaN mythvodka.orig/scripts/mythvodka_player.sh mythvodka/scripts/mythvodka_player.sh
---- mythvodka.orig/scripts/mythvodka_player.sh	1970-01-01 00:00:00.000000000 +0000
-+++ mythvodka/scripts/mythvodka_player.sh	2009-02-12 07:27:44.000000000 +0000
-@@ -0,0 +1,38 @@
-+#! /bin/bash
-+#
-+log=/var/log/mythtv/mythvodka_player.log
-+player_list="/usr/local/bin/mplayer_h264 /usr/local/bin/mplayer \
-+             /usr/bin/mplayer /bin/mplayer"
-+#
-+player_list="/usr/local/bin/mplayer /usr/bin/mplayer /bin/mplayer"
-+f="$1"
-+shift
-+rm -f $log
-+echo "Request to play $f on `date`" >> $log
-+player=""
-+for player in $player_list; do
-+  if [ -x "$player" ]; then
-+    echo "Found player $player" >> $log
-+    break
-+  fi
-+done
-+if [ ! -x $player ]; then
-+  echo "ERROR -- not able to find mplayer on your system. " >> $log
-+  echo "I searched the following list" >> $log
-+  echo "  $player_list" >> $log
-+  exit 1
-+fi
-+for pass in 1 2 4 8 10; do
-+  size="0"
-+  if [ -e $f ]; then
-+    size=$( du --apparent-size -sD "$f" | awk '{ print $1 }' )
-+    if [ $size -gt 1500 ]; then
-+      break
-+    fi
-+  fi
-+  echo "Pass $pass, filesize is $size kbytes, sleep $pass seconds" >> $log
-+  sleep $pass
-+done
-+size=$( du --apparent-size -sD "$f" | awk '{ print $1 }' )
-+echo "Reached $size kb on pass $pass `date`" >> $log
-+$player -fs -vo xv $f
diff --git a/abs/extra-testing/mythvodka/mythvodka.install b/abs/extra-testing/mythvodka/mythvodka.install
deleted file mode 100644
index 4a9827e..0000000
--- a/abs/extra-testing/mythvodka/mythvodka.install
+++ /dev/null
@@ -1,47 +0,0 @@
-# arg 1:  the new package version
-post_install() {
-  mv /usr/share/mythtv/is.xml /tmp
-  grep -v -e /mythmenu /tmp/is.xml > /tmp/is.xml.tmp
-  echo "<!--#MythVodka-->" >> /tmp/is.xml.tmp
-  echo "   <button>" >> /tmp/is.xml.tmp
-  echo "     <type>STREAM</type>" >> /tmp/is.xml.tmp
-  echo "     <text>Myth Vodka</text>" >> /tmp/is.xml.tmp
-  echo "     <action>PLUGIN mythvodka</action>" >> /tmp/is.xml.tmp 
-  echo "     <depends>mythvodka</depends>" >> /tmp/is.xml.tmp 
-  echo "   </button>" >> /tmp/is.xml.tmp
-  echo "<!--#MythVodka-->" >> /tmp/is.xml.tmp
-  echo "" >> /tmp/is.xml.tmp
-  echo "</mythmenu>" >> /tmp/is.xml.tmp
-  mv /tmp/is.xml.tmp /usr/share/mythtv/is.xml
-
-  mv /usr/share/mythtv/media_settings.xml /tmp
-  grep -v -e /mythmenu /tmp/media_settings.xml > /tmp/ms.xml.tmp
-  echo "<!--#MythVodka-->" >> /tmp/ms.xml.tmp
-  echo "   <button>" >> /tmp/ms.xml.tmp
-  echo "     <type>SETTINGS MYTHVODKA</type>" >> /tmp/ms.xml.tmp
-  echo "     <text>MythVodka Settings</text>" >> /tmp/ms.xml.tmp
-  echo "     <action>CONFIGPLUGIN mythvodka</action>" >> /tmp/ms.xml.tmp 
-  echo "     <depends>mythvodka</depends>" >> /tmp/ms.xml.tmp 
-  echo "   </button>" >> /tmp/ms.xml.tmp
-  echo "<!--#MythVodka-->" >> /tmp/ms.xml.tmp
-  echo "" >> /tmp/ms.xml.tmp
-  echo "</mythmenu>" >> /tmp/ms.xml.tmp
-  mv /tmp/ms.xml.tmp /usr/share/mythtv/media_settings.xml
-}
-# arg 1:  the new package version
-# arg 2:  the old package version
-post_upgrade() {
-	/bin/true
-}
-
-# arg 1:  the old package version
-post_remove() {
-	mv /usr/share/mythtv/is.xml /tmp/is.xml.tmp
-	sed -e '/\#MythVodka/,/\#MythVodka/d' < /tmp/is.xml.tmp > /usr/share/mythtv/is.xml
-	mv /usr/share/mythtv/media_settings.xml /tmp/ms.xml.tmp
-	sed -e '/\#MythVodka/,/\#MythVodka/d' < /tmp/ms.xml.tmp > /usr/share/mythtv/media_settings.xml
-}
-
-op=$1
-shift
-$op $*
diff --git a/abs/extra/mythvodka/PKGBUILD b/abs/extra/mythvodka/PKGBUILD
deleted file mode 100644
index 0832093..0000000
--- a/abs/extra/mythvodka/PKGBUILD
+++ /dev/null
@@ -1,36 +0,0 @@
-# $Id: PKGBUILD 5936 2008-07-21 20:24:16Z thomas $
-# Maintainer: Cecil Watson<knoppmyth@gmail.com>
-
-pkgname=mythvodka
-pkgver=0.7
-pkgrel=11
-pkgdesc="MythVodka (Video On Demand Killer App) is a plugin for MythTV allowing streaming of BBC iPlayer, Hulu, HTTP and NZB content."
-arch=('i686' 'x86_64')
-license=('GPL2')
-url="http://code.google.com/p/mythvodka/"
-depends=('rtmpdump' 'perl-xml-dom' 'beautiful-soup')
-install=mythvodka.install
-source=('http://mythvodka.googlecode.com/files/mythvodka.07.tar.gz' 'mythvodka.diff' 'hulu_grabber.sh' 'http://ftp.knoppmyth/R6/sources/huludata.tar.bz2')
-
-build() {
-	patch -p0 < mythvodka.diff
-	cd $startdir/src/mythvodka/mythvodka
-	rm -fr Makefile
-	qmake mythvodka.pro
-	make
-	mkdir -p $startdir/pkg/usr/lib/mythtv/plugins/
-	cp libmythvodka.so $startdir/pkg/usr/lib/mythtv/plugins/
-	strip --strip-unneeded $startdir/pkg/usr/lib/mythtv/plugins/libmythvodka.so
-	mkdir -p $startdir/pkg/usr/share/mythtv/themes/default/
-	cp streams-ui.xml $startdir/pkg/usr/share/mythtv/themes/default/
-	mkdir -p $startdir/pkg/usr/share/mythtv/themes/default-wide/
-	cp theme-wide/streams-ui.xml $startdir/pkg/usr/share/mythtv/themes/default-wide/
-	mkdir -p $startdir/pkg/usr/local/bin
-	chmod a+x ../scripts/*
-	cp -p ../scripts/* $startdir/pkg/usr/local/bin
-	mkdir -p $startdir/pkg/etc/cron.daily/
-	chmod 755 ../../hulu_grabber.sh
-	cp ../../hulu_grabber.sh $startdir/pkg/etc/cron.daily/
-	mkdir -p $startdir/pkg/var/tmp
-	cp $startdir/src/huludata.xml $startdir/pkg/var/tmp
-}
diff --git a/abs/extra/mythvodka/hulu_grabber.sh b/abs/extra/mythvodka/hulu_grabber.sh
deleted file mode 100755
index 4840dc0..0000000
--- a/abs/extra/mythvodka/hulu_grabber.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#! /bin/bash
-log=/var/log/mythtv/hulu_grabber.log
-out=/var/tmp/huludata.xml
-rm -f $log
-echo "Start on `date`" >>$log 2>&1
-/usr/local/bin/gethulu.pl $out.new >>$log 2>&1
-stat=$?
-if [ $stat -ne 0 ]; then
-  echo "Bad status $stat from gethulu.pl" >>$log 2>&1
-  exit 1
-fi
-rm -f $out.old
-mv $out $out.old
-mv $out.new $out
-echo "Done on `date`" >>$log 2>&1
-ls -lh $out >>$log 2>&1
diff --git a/abs/extra/mythvodka/mythvodka.diff b/abs/extra/mythvodka/mythvodka.diff
deleted file mode 100644
index 5735a42..0000000
--- a/abs/extra/mythvodka/mythvodka.diff
+++ /dev/null
@@ -1,3933 +0,0 @@
-diff -ruaN mythvodka.orig/mythvodka/streamsui.cpp mythvodka/mythvodka/streamsui.cpp
---- mythvodka.orig/mythvodka/streamsui.cpp	2009-01-06 00:18:35.000000000 +0000
-+++ mythvodka/mythvodka/streamsui.cpp	2009-02-12 07:28:31.000000000 +0000
-@@ -646,7 +646,7 @@
-     
-         MythProgressDialog *buffer_progress;
-         buffer_progress = new MythProgressDialog(
--            QObject::tr("If she kicks you in the balls, you have the ability and the right..."), bufferSize, true, this, SLOT(cancelPressed()));
-+            QObject::tr("Buffering... Just a moment please."), bufferSize, true, this, SLOT(cancelPressed()));
-     
-         QFile file(filename);
-     
-@@ -729,7 +729,7 @@
-     
-         MythProgressDialog *buffer_progress;
-         buffer_progress = new MythProgressDialog(
--            QObject::tr("Nascar Sucks / Hillary For President / Man Love Rules Ok"), bufferSize, true, this, SLOT(cancelPressed()));
-+            QObject::tr("Your video is being loaded..."), bufferSize, true, this, SLOT(cancelPressed()));
-     
-         QFile file(filename);
-     
-@@ -822,7 +822,7 @@
-     
-         MythProgressDialog *buffer_progress;
-         buffer_progress = new MythProgressDialog(
--            QObject::tr("RING RING... I FUCKED YOUR GRANDDAUGHTER"), bufferSizemov, true, this, SLOT(cancelPressed()));
-+            QObject::tr("We seem to have hit some sort of problem..."), bufferSizemov, true, this, SLOT(cancelPressed()));
-     
-         QFile filemov(filenamemov);
-     
-diff -ruaN mythvodka.orig/scripts/get_iplayer mythvodka/scripts/get_iplayer
---- mythvodka.orig/scripts/get_iplayer	2009-01-06 19:11:24.000000000 +0000
-+++ mythvodka/scripts/get_iplayer	2009-02-12 07:27:44.000000000 +0000
-@@ -3,16 +3,17 @@
- # get_iplayer
- #
- # Lists and downloads BBC iPlayer audio and video streams
--# 
-+# + Downloads ITVplayer Catch-Up video streams
-+#
- # Author: Phil Lewis
- # Email: iplayer (at sign) linuxcentre.net
- # Web: http://linuxcentre.net/iplayer
- # License: GPLv3 (see LICENSE.txt)
- #
- # Other credits:
--# RTMP additions: Andrej Stepanchuk
-+#  RTMP additions: Andrej Stepanchuk
- #
--my $version = 1.04;
-+my $version = 1.17;
- #
- # Help:
- #	./get_iplayer --help
-@@ -29,13 +30,16 @@
- # * Index/Download live radio streams w/schedule feeds to assist timing
- # * Podcasts for 'local' stations are missing (only a handful). They use a number of different station ids which will involve reading html to determine rss feed. 
- # * Remove all rtsp/mplayer/lame/tee dross when realaudio streams become obselete (not quite yet)
--# * Cope with radio via rtmp
- # * Stdout mode with rtmp
--#
-+# * Do subtitle downloading after programme download so that rtmp auth doesn't timeout
-+
- # Known Issues:
- # * In ActivePerl/windows downloaded iPhone video files do not get renamed (remain with .partial.mov)
- # * vlc does not quit after downloading an rtsp N95 video stream (ctrl-c is required) - need a --play-and-quit option if such a thing exists
--# * flv conversions from rtmp downloads aren't quite right yet. A/V sync issues?
-+# * rtmpdump (v1.2) of flashaudio fails at end of stream => non-zero exit code
-+# * if ffmpeg trys to convert flv to mp3 it succeeds but => non-zero exit code
-+# * Some rtmpdump downloads always give a non-zero exit code regardless of success (using a min-filesize workaround for now)
-+# * resuming a flashaudio download fails
- 
- use Env qw[@PATH];
- use Fcntl;
-@@ -62,10 +66,17 @@
- my %opt_cmdline = (); # a hash of which options came from the cmdline rather than the options files
- my %opt_file = (); # a hash of which options came from the options files rather than the cmdline
- 
--# Print to STDERR if not quiet unless verbose or debug
-+# Print to STDERR/STDOUT if not quiet unless verbose or debug
- sub logger(@) {
- 	# Make sure quiet can be overridden by verbose and debug options
--	print STDERR $_[0] if (! $opt{quiet}) || $opt{verbose} || $opt{debug};
-+	if ( $opt{verbose} || $opt{debug} || ! $opt{quiet} ) {
-+		# Only send messages to STDERR if pvr or stdout options are being used.
-+		if ( $opt{stdout} || $opt{pvr} || $opt{stderr} ) {
-+			print STDERR $_[0];
-+		} else {
-+			print STDOUT $_[0];
-+		}
-+	}
- }
- 
- sub usage {
-@@ -74,7 +85,7 @@
- Search Programmes:  get_iplayer [<search options>] [<regex|index|pid|pidurl> ...]
- Download files:     get_iplayer --get [<search options>] <regex|index|pid|pidurl> ...
-                     get_iplayer --pid <pid|pidurl> [<options>]
--Stream Downloads:   get_iplayer --stdout [<options>] <regex|index|pid|pidurl> | mplayer -cache 2048 -
-+Stream Downloads:   get_iplayer --stdout [<options>] <regex|index|pid|pidurl> | mplayer -cache 3072 -
- Update get_iplayer: get_iplayer --update
- 
- Search Options:
-@@ -83,9 +94,10 @@
-  --channel <regex>             Narrow search to matched channel(s)
-  --category <regex>            Narrow search to matched categories
-  --versions <regex>            Narrow search to matched programme version(s)
-+ --exclude <regex>             Narrow search to exclude matched programme names
-  --exclude-channel <regex>     Narrow search to exclude matched channel(s)
-  --exclude-category <regex>    Narrow search to exclude matched catogories
-- --type <radio|tv|podcast|all> Only search in these types of programmes (tv is default)
-+ --type <type>                 Only search in these types of programmes: radio, tv, podcast, all, itv (tv is default)
-  --since <hours>               Limit search to programmes added to the cache in the last N hours
-  
- Display Options:
-@@ -95,26 +107,25 @@
-  -i, --info                    Show full programme metadata (only if number of matches < 50)
-  --list <categories|channel>   Show a list of available categories/channels for the selected type and exit
-  --hide                        Hide previously downloaded programmes
-+ --streaminfo                  Returns all of the media stream urls of the programme(s)
- 
- Download Options:
-  -g, --get                     Download matching programmes
-  -x, --stdout                  Additionally stream to STDOUT (so you can pipe output to a player)
-  -p, --proxy <url>             Web proxy URL spec
-  --partial-proxy               Works around for some broken web proxies (try this extra option if your proxy fails)
-- --pid <pid|url>               Download an arbitrary pid that does not appear in the index
-+ --pid <pid|url>               Download an arbitrary pid that does not appear in the index (itv:<pid> for itv programmes)
-  --force-download              Ignore download history (unsets --hide option also)
-- --realaudio                   Use the RealAudio radio stream and not the MP3 stream
-- --mp3audio                    Use the MP3 radio stream for radio and dont fallback to the RealAudio stream
-+ --amode <mode>,<mode>,...     Audio Download mode(s): iphone,flashaudio,realaudio (default: iphone,flashaudio,realaudio)
-+ --vmode <mode>,<mode>,...     Video Download mode(s): iphone,rtmp,flashhigh,flashnormal,flashwii,n95_wifi (default: iphone,flashhigh,flashnormal)
-  --wav                         In radio realaudio mode output as wav and don't transcode to mp3
-- --raw                         In radio/realaudio or iPhone/video mode don't transcode or change the downloaded stream in any way
-- --n95                         In TV mode download/stream low quality Nokia N95 H.264 stream (alpha)
-- --rtmp                        In TV mode download/stream high quality flash stream (alpha)
-+ --raw                         Don't transcode or change the downloaded stream in any way (i.e. radio/realaudio, rtmp/flv, iphone/mov)
-  --bandwidth                   In radio realaudio mode specify the link bandwidth in bps for rtsp streaming (default 512000)
-  --subtitles                   In TV mode, download subtitles into srt/SubRip format if available
-  --suboffset <offset>          Offset the subtitle timestamps by the specified number of milliseconds
-  --version-list <versions>     Override the version of programme to download (e.g. '--version-list signed,default')
-  -t, --test                    Test only - no download (will show programme type)
-- 
-+
- PVR Options:
-  --pvr                         Runs the PVR download using all saved PVR searches (intended to be run every hour from cron etc)
-  --pvradd <search name>        Add the current search terms to the named PVR search
-@@ -139,18 +150,18 @@
-  -f, --flush, --refresh        Refresh cache
-  -e, --expiry <secs>           Cache expiry in seconds (default 4hrs)
-  --symlink <file>              Create symlink to <file> once we have the header of the download
-- --fxd <file>                  Create Freevo FXD XML in specified file
-- --mythtv <file>               Create Mythtv streams XML in specified file
-+ --fxd <file>                  Create Freevo FXD XML of matching programmes in specified file
-+ --mythtv <file>               Create Mythtv streams XML of matching programmes in specified file
-  --xml-channels                Create freevo/Mythtv menu of channels -> programme names -> episodes
-  --xml-names                   Create freevo/Mythtv menu of programme names -> episodes
-  --xml-alpha                   Create freevo/Mythtv menu sorted alphabetically by programme name
-- --html <file>                 Create basic HTML index of programmes in specified file
-+ --html <file>                 Create basic HTML index of matching programmes in specified file
-  --mplayer <path>              Location of mplayer binary
-+ --ffmpeg <path>               Location of ffmpeg binary
-  --lame <path>                 Location of lame binary
-  --id3v2 <path>                Location of id3v2 binary
-  --rtmpdump <path>             Location of rtmpdump binary
-- --vlc <path>                  Location of vlc binary
-- --streaminfo                  Returns all of the media stream urls of the programme(s)
-+ --vlc <path>                  Location of vlc or cvlc binary
-  -v, --verbose                 Verbose
-  -u, --update                  Update get_iplayer if a newer one exists
-  -h, --help                    Help
-@@ -192,14 +203,17 @@
- Getopt::Long::Configure ("bundling");
- # cmdline opts take precedence
- GetOptions(
-+	"amode=s"			=> \$opt_cmdline{amode},
- 	"bandwidth=n"			=> \$opt_cmdline{bandwidth},
- 	"category=s"			=> \$opt_cmdline{category},
- 	"channel=s"			=> \$opt_cmdline{channel},
- 	"c|command=s"			=> \$opt_cmdline{command},
- 	"debug"				=> \$opt_cmdline{debug},
-+	"exclude=s"			=> \$opt_cmdline{exclude},
- 	"exclude-category=s"		=> \$opt_cmdline{excludecategory},
- 	"exclude-channel=s"		=> \$opt_cmdline{excludechannel},
- 	"expiry|e=n"			=> \$opt_cmdline{expiry},
-+	"ffmpeg=s"			=> \$opt_cmdline{ffmpeg},
- 	"file-prefix|fileprefix=s"	=> \$opt_cmdline{fileprefix},
- 	"flush|refresh|f"		=> \$opt_cmdline{flush},
- 	"force-download"		=> \$opt_cmdline{forcedownload},
-@@ -238,7 +252,7 @@
- 	"rtmpdump=s"			=> \$opt_cmdline{rtmpdump},
- 	"save"				=> \$save,
- 	"since=n"			=> \$opt_cmdline{since},
--	"stdout|stream|x"		=> \$opt_cmdline{stdout},
-+	"stdout|x"			=> \$opt_cmdline{stdout},
- 	"streaminfo"			=> \$opt_cmdline{streaminfo},
- 	"subdirs|subdir|s"		=> \$opt_cmdline{subdir},
- 	"suboffset=n"			=> \$opt_cmdline{suboffset},
-@@ -253,6 +267,7 @@
- 	"versions=s"			=> \$opt_cmdline{versions},
- 	"verbose|v"			=> \$opt_cmdline{verbose},
- 	"vlc=s"				=> \$opt_cmdline{vlc},
-+	"vmode=s"			=> \$opt_cmdline{vmode},
- 	"wav"				=> \$opt_cmdline{wav},
- 	"whitespace|ws|w"		=> \$opt_cmdline{whitespace},
- 	"xml-channels|fxd-channels"	=> \$opt_cmdline{xmlchannels},
-@@ -269,7 +284,7 @@
- save_options_file( $optfile ) if $save;
- 
- 
--# Global vars
-+### Global vars ###
- 
- # Programme data structure
- # $prog{$pid} = {
-@@ -283,7 +298,7 @@
- #	'thumbnail'	=> <programme thumbnail url>
- #	'channel	=> <channel>
- #	'categories'	=> <Comma separated list of categories>
--# 	'type'		=> <Type: tv, radio or podcast>
-+# 	'type'		=> <Type: tv, radio, itv or podcast>
- #	'timeadded'	=> <timestamp when programme was added to cache>
- #	'longname'	=> <Long name (only parsed in stage 1 download)>,
- #	'version'	=> <selected version e.g default, signed, etc - only set before d/load>
-@@ -292,11 +307,35 @@
- #	'fileprefix'	=> <Filename Prefix of saved file - set only while downloading>
- #	'ext'		=> <Filename Extension of saved file - set only while downloading>
- #};
-+
-+# Define cache file format
-+my @cache_format = qw/index type name pid available episode versions duration desc channel categories thumbnail timeadded guidance/;
-+
-+# List of all types
-+my @all_prog_types = qw/ tv radio podcast itv /;
-+
-+# Ranges of numbers used in the indicies for each programme type
-+my %index_range;
-+$index_range{tv}{min} 		= 1;
-+$index_range{tv}{max} 		= 9999;
-+$index_range{radio}{min} 	= 10001;
-+$index_range{radio}{max} 	= 19999;
-+$index_range{podcast}{min} 	= 20001;
-+$index_range{podcast}{max} 	= 29999;
-+$index_range{itv}{min} 		= 100001;
-+$index_range{itv}{max} 		= 199999;
-+# Set maximun index number
-+my $max_index;
-+for (@all_prog_types) {
-+	$max_index = $index_range{$_}{max} if $index_range{$_}{max} > $max_index;
-+}
- my %prog;
-+my %type;
- my %pids_history;
- my %index_pid; # Hash to obtain pid given an index
- my $now;
- my $childpid;
-+my $min_download_size = 1000000;
- 
- # Static URLs
- my $channel_feed_url		= 'http://feeds.bbc.co.uk/iplayer'; # /$channel/list/limit/400
-@@ -396,6 +435,18 @@
- 	'bbc_radio_jersey'			=> 'radio|BBC Jersey',
- };
- 
-+$channels{itv} = {
-+	'crime'					=> 'itv|TV Classics Crime Drama',
-+	'perioddrama'				=> 'itv|TV Classics Period Drama',
-+	'familydrama'				=> 'itv|TV Classics Family Drama',
-+	'documentary'				=> 'itv|TV Classics Documentaries',
-+	'comedy'				=> 'itv|TV Classics Comedy',
-+	'kids'					=> 'itv|TV Classics Children\'s TV',
-+	'soaps'					=> 'itv|TV Classics Soaps',
-+	'/'					=> 'itv|TV Classics',
-+};
-+
-+
- # User Agents
- my %user_agent = (
-   	coremedia	=> 'Apple iPhone v1.1.1 CoreMedia v1.0.0.3A110a',
-@@ -410,6 +461,7 @@
- 
- # Other Non-option dependant vars
- my %cachefile = (
-+	'itv'		=> "${profile_dir}/itv.cache",
- 	'tv'		=> "${profile_dir}/tv.cache",
- 	'radio'		=> "${profile_dir}/radio.cache",
- 	'podcast'	=> "${profile_dir}/podcast.cache",
-@@ -430,6 +482,7 @@
- my $mplayer;
- #my $mencoder;
- my $ffmpeg;
-+my $ffmpeg_opts;
- my $rtmpdump;
- my $mplayer_opts;
- my $lame;
-@@ -480,7 +533,7 @@
- 	# Display default options
- 	display_default_options();
- 	# For each PVR search
--	for my $name ( sort {$a <=> $b} keys %pvrsearches ) {
-+	for my $name ( sort {lc $a cmp lc $b} keys %pvrsearches ) {
- 		# Ignore if this search is disabled
- 		if ( $pvrsearches{$name}{disable} ) {
- 			logger "\nSkipping disabled PVR Search '$name'\n" if $opt{verbose};
-@@ -519,27 +572,29 @@
- 	# Option dependant vars
- 	%download_dir	= (
- 		'tv'		=> $opt{outputtv} || $opt{output} || $ENV{IPLAYER_OUTDIR} || '.',
-+		'itv'		=> $opt{outputtv} || $opt{output} || $ENV{IPLAYER_OUTDIR} || '.',
- 		'radio'		=> $opt{outputradio} || $opt{output} || $ENV{IPLAYER_OUTDIR} || '.',
- 		'podcast'	=> $opt{outputpodcast} || $opt{output} || $ENV{IPLAYER_OUTDIR} || '.',
- 	);
--	# Default to type=tv
--	$opt{type} 		= 'tv' if ! $opt{type};
--	# Expand 'all' to various prog types
--	$opt{type} 		= 'tv,radio,podcast' if $opt{type} =~ /(all|any)/i;
-+
- 	# Ensure lowercase
--	$opt{type} = lc( $opt{type} );
-+	$opt{type}		= lc( $opt{type} );
-+	# Expand 'all' to comma separated list all prog types
-+	$opt{type} 		= join(',', @all_prog_types) if $opt{type} =~ /(all|any)/i;
-+	# Hash to store specified prog types
-+	%type = ();
-+	$type{$_} = 1 for split /,/, $opt{type};
-+	# Default to type=tv if no type option is set
-+	$type{tv}		= 1 if keys %type == 0;
- 	$cache_secs 		= $opt{expiry} || 14400;
- 	$mplayer		= $opt{mplayer} || 'mplayer';
- 	$mplayer_opts		= '-nolirc';
- 	$mplayer_opts		.= ' -really-quiet' if $opt{quiet};
--	# Assume mencoder/ffmpeg is in the same path as mplayer
--#	$mencoder		= $mplayer;
--#	$mencoder		=~ s|^(.*?)mplayer|$1mencoder|g;
--	$ffmpeg			= $mplayer;
--	$ffmpeg			=~ s|^(.*?)mplayer|$1ffmpeg|g;
-+	$ffmpeg			= $opt{ffmpeg} || 'ffmpeg';
-+	$ffmpeg_opts		= '';
- 	$lame			= $opt{lame} || 'lame';
--	$lame_opts		= '-f ';
--	$lame_opts		.= '--quiet ' if $opt{quiet};
-+	$lame_opts		= '-f';
-+	$lame_opts		.= ' --quiet ' if $opt{quiet};
- 	$vlc			= $opt{vlc} || 'cvlc';
- 	$vlc_opts		= '-vv';
- 	$id3v2			= $opt{id3v2} || 'id3v2';
-@@ -562,11 +617,11 @@
- 		exit 1;
- 	}
- 
--	# Disable rtmp mode if rtmpdump does not exist
--	if ( $opt{rtmp} && ! exists_in_path($rtmpdump)) {
--		logger "\nERROR: Required program $rtmpdump does not exist (see http://linuxcentre.net/getiplayer/installation and http://linuxcentre.net/getiplayer/download), falling back to iphone mode\n";
--		delete $opt{rtmp};
--	}
-+	# Backward compatability options - to be removed eventually
-+	$opt{vmode} = 'rtmp' if $opt{rtmp};
-+	$opt{vmode} = 'n95_wifi' if $opt{n95};
-+	$opt{amode} = 'realaudio' if $opt{realaudio};
-+	$opt{amode} = 'iphone' if $opt{mp3audio};
- 
- 	# Web proxy
- 	$proxy_url = $opt{proxy} || $ENV{HTTP_PROXY} || $ENV{http_proxy} || '';
-@@ -585,8 +640,21 @@
- 		}
- 	}
- 
--	# Get arbitrary pid
-+	# Get prog by arbitrary pid (then exit)
- 	if ( $opt{pid} ) {
-+
-+		# Temporary hack to get 'ITV Catch-up' downloads specified as --pid itv:<pid>
-+		$type{itv} = 1 if $opt{pid} =~ m{^itv:(.+?)$};
-+		if ( $type{itv} ) {
-+			exit 1 if ( ! $opt{streaminfo} ) && check_download_history( $opt{pid} );
-+			# Remove leading itv: tag (backwards compat)
-+			$opt{pid} =~ s/^itv:(.+?)$/$1/ig;
-+			# Force prog type to itv
-+			$prog{$opt{pid}}{type} = 'itv';
-+			download_programme( $opt{pid} );
-+			exit 0;
-+		}
-+
- 		# Remove any url parts from the pid
- 		$opt{pid} =~ s/^.*(b0[a-z,0-9]{6}).*$/$1/g;
- 		# Retry loop
-@@ -594,21 +662,29 @@
- 		my $retries = 3;
- 		my $retcode;
- 		exit 1 if ( ! $opt{streaminfo} ) && check_download_history( $opt{pid} );
--		while ( $count < $retries && ($retcode = download_programme( $opt{pid} )) eq 'retry' ) {
--			logger "WARNING: Retrying download for PID $opt{pid}\n";
--			$count++;
-+		for ($count = 1; $count <= $retries; $count++) {
-+			$retcode = download_programme( $opt{pid} );
-+			return 0 if $retcode eq 'skip';
-+			if ( $retcode eq 'retry' && $count < $retries ) {
-+				logger "WARNING: Retrying download for PID $opt{pid}\n";
-+			} else {
-+				$retcode = 1 if $retcode eq 'retry';
-+				last;
-+			}
- 		}
- 		# Add to history, tag and Run post download command if download was successful
- 		if ($retcode == 0) {
- 			add_to_download_history( $opt{pid} );
- 			tag_file( $opt{pid} );
- 			run_user_command( $opt{pid}, $opt{command} ) if $opt{command};
--		}	
-+		} elsif (! $opt{test}) {
-+			logger "ERROR: Failed to download PID $opt{pid}\n";
-+		}
- 		exit 0;
- 	}
- 
- 	# Get stream links from BBC iplayer site or from cache (also populates all hashes) specified in --type option
--	get_links( $_ ) for split /,/, $opt{type};
-+	get_links( $_ ) for keys %type;
- 
- 	# List elements (i.e. 'channel' 'categories') if required and exit
- 	if ( $opt{list} ) {
-@@ -616,18 +692,13 @@
- 		exit 0;
- 	}
- 
--	# Write HTML and XML files if required
--	create_html( sort {$a <=> $b} keys %index_pid ) if $opt{html};
--	create_xml( $opt{fxd}, sort {$a <=> $b} keys %index_pid ) if $opt{fxd};
--	create_xml( $opt{mythtv}, sort {$a <=> $b} keys %index_pid ) if $opt{mythtv};
--
- 	# Parse remaining args
- 	my @match_list;
- 	for ( @search_args ) {
- 		chomp();
--	
--		# If Numerical value < 30000
--		if ( /^[\d]+$/ && $_ < 30000) {
-+
-+		# If Numerical value < $max_index
-+		if ( /^[\d]+$/ && $_ <= $max_index) {
- 			push @match_list, $_;
- 	
- 		# If PID then find matching programmes with this PID
-@@ -649,24 +720,29 @@
- 	# Go get the cached data for other programme types if the index numbers require it
- 	my %require;
- 	for ( @match_list ) {
--		$require{tv} = 1 if $_ >= 1 && $_ < 10000 && ( ! $require{tv} ) && $opt{type} !~ /tv/;
--		$require{radio} = 1 if $_ >= 10000 && $_ < 20000 && ( ! $require{radio} ) && $opt{type} !~ /radio/;
--		$require{podcast} = 1 if $_ >= 20000 && $_ < 30000 && ( ! $require{podcast} ) && $opt{type} !~ /podcast/;
-+		for my $types ( @all_prog_types ) {
-+			$require{$types} = 1 if $_ >= $index_range{$types}{min} && $_ <= $index_range{$types}{max} && ( ! $require{$types} ) && ( ! $type{$types} );
-+		}
- 	}
-+
- 	# Get extra required programme caches
- 	logger "INFO: Additionally getting cached programme data for ".(join ', ', keys %require)."\n" if %require > 0;
- 	# Get stream links from BBC iplayer site or from cache (also populates all hashes)
- 	for (keys %require) {
- 		# Get $_ stream links
- 		get_links( $_ );
--		# Add new prog types to the type option
--		$opt{type} .= ",$_";
-+		# Add new prog types to the type list
-+		$type{$_} = 1;
- 	}
--
- 	# Display list for download
- 	logger "Matches:\n" if @match_list;
- 	@match_list = list_progs( @match_list );
- 
-+	# Write HTML and XML files if required (with search options applied)
-+	create_html( @match_list ) if $opt{html};
-+	create_xml( $opt{fxd}, @match_list ) if $opt{fxd};
-+	create_xml( $opt{mythtv}, @match_list ) if $opt{mythtv};
-+
- 	# Do the downloads based on list of index numbers if required
- 	if ( $opt{get} || $opt{stdout} ) {
- 		for (@match_list) {
-@@ -681,16 +757,27 @@
- 				logger "ERROR: No PID for index $_ (try using --type option ?)\n";
- 				next;
- 			}
--			while ( $count < $retries && $pid && ($retcode = download_programme( $pid )) eq 'retry' ) {
--				logger "WARNING: Retrying download for '$prog{$pid}{name} - $prog{$pid}{episode}'\n";
--				$count++;
-+			for ($count = 1; $count <= $retries; $count++) {
-+				$retcode = download_programme( $pid );
-+				last if $retcode eq 'skip';
-+				if ( $retcode eq 'retry' && $count < $retries ) {
-+					logger "WARNING: Retrying download for '$prog{$pid}{name} - $prog{$pid}{episode}'\n";
-+				} else {
-+					$retcode = 1 if $retcode eq 'retry';
-+					last;
-+				}
- 			}
- 			# Add to history, tag file, and run post download command if download was successful
--			if ($retcode eq '0') {
-+			if ($retcode == 0) {
- 				add_to_download_history( $pid );
- 				tag_file( $pid );
- 				run_user_command( $pid, $opt{command} ) if $opt{command};
- 				pvr_report( $pid ) if $opt{pvr};
-+			# Next match if 'skip' was returned
-+			} elsif ( $retcode eq 'skip' ) {
-+				last;
-+			} elsif (! $opt{test}) {
-+				logger "ERROR: Failed to download '$prog{$pid}{name} - $prog{$pid}{episode}'\n";
- 			}
- 		}
- 	}
-@@ -702,16 +789,11 @@
- 
- # Lists progs given an array of index numbers, also returns an array with non-existent entries removed
- sub list_progs {
--	my $ua;
-+	my $ua = create_ua('desktop');
- 	my @checked;
- 	my %names;
- 	# Setup user agent for a persistent connection to get programme metadata
- 	if ( $opt{info} ) {
--		$ua = LWP::UserAgent->new;
--		$ua->timeout([$lwp_request_timeout]);
--		$ua->proxy( ['http'] => $proxy_url );
--		$ua->agent( $user_agent{desktop} );
--		$ua->conn_cache(LWP::ConnCache->new());
- 		# Truncate array if were lisiting info and > $info_limit entries are requested - be nice to the beeb!
- 		if ( $#_ >= $info_limit ) {
- 			$#_ = $info_limit - 1;
-@@ -733,18 +815,7 @@
- 		push @checked, $_;
- 		if ( $opt{info} ) {
- 			my %metadata = get_pid_metadata( $ua, $pid );
--			logger "\nPid:\t\t$metadata{pid}\n";
--			logger "Index:\t\t$metadata{index}\n";
--			logger "Type:\t\t$metadata{type}\n";
--			logger "Duration:\t$metadata{duration}\n";
--			logger "Channel:\t$metadata{channel}\n";
--			logger "Available:\t$metadata{available}\n";
--			logger "Expires:\t$metadata{expiry}\n";
--			logger "Versions:\t$metadata{versions}\n";
--			logger "Guidance:\t$metadata{guidance}\n";
--			logger "Categories:\t$metadata{categories}\n";
--			logger "Description:\t$metadata{desc}\n";
--			logger "Player:\t\t$metadata{player}\n";
-+			display_metadata( \%metadata, qw/ pid index type duration channel available expiry versions guidance categories desc player / );
- 		}
- 	}
- 	logger "\n";
-@@ -758,8 +829,9 @@
- # Display a line containing programme info (using long, terse, and type options)
- sub list_prog_entry {
- 	my ( $pid, $prefix, $tree ) = ( @_ );
--	my $type = '';
--	$type = "$prog{$pid}{type}, " if $opt{type} !~ /^(tv|radio|podcast)$/i;
-+	my $prog_type = '';
-+	# Show the type field if >1 type has been specified
-+	$prog_type = "$prog{$pid}{type}, " if keys %type > 1;
- 	my $name;
- 	# If tree view
- 	if ( $opt{tree} ) {
-@@ -768,20 +840,21 @@
- 	} else {
- 		$name = "$prog{$pid}{name} - ";
- 	}
--	# Remove some info depending on type
-+	# Remove some info depending on prog_type
- 	my $optional;
- 	$optional = ", '$prog{$pid}{channel}', $prog{$pid}{categories}, $prog{$pid}{versions}" if $prog{$pid}{type} eq 'tv';
-+	$optional = ", '$prog{$pid}{channel}'" if $prog{$pid}{type} eq 'itv';
- 	$optional = ", '$prog{$pid}{channel}', $prog{$pid}{categories}" if $prog{$pid}{type} eq 'radio';
- 	$optional = ", '$prog{$pid}{available}', '$prog{$pid}{channel}', $prog{$pid}{categories}" if $prog{$pid}{type} eq 'podcast';
--	logger "\n${type}$prog{$pid}{name}\n" if $opt{tree} && ! $tree;
-+	logger "\n${prog_type}$prog{$pid}{name}\n" if $opt{tree} && ! $tree;
- 	# Display based on output options
- 	if ( $opt{long} ) {
- 		my @time = gmtime( time() - $prog{$pid}{timeadded} );
--		logger "${prefix}$prog{$pid}{index}:\t${type}${name}$prog{$pid}{episode}${optional}, $time[7] days $time[2] hours ago - $prog{$pid}{desc}\n";
-+		logger "${prefix}$prog{$pid}{index}:\t${prog_type}${name}$prog{$pid}{episode}${optional}, $time[7] days $time[2] hours ago - $prog{$pid}{desc}\n";
- 	} elsif ( $opt{terse} ) {
--		logger "${prefix}$prog{$pid}{index}:\t${type}${name}$prog{$pid}{episode}\n";
-+		logger "${prefix}$prog{$pid}{index}:\t${prog_type}${name}$prog{$pid}{episode}\n";
- 	} else {
--		logger "${prefix}$prog{$pid}{index}:\t${type}${name}$prog{$pid}{episode}${optional}\n";
-+		logger "${prefix}$prog{$pid}{index}:\t${prog_type}${name}$prog{$pid}{episode}${optional}\n";
- 	}
- 	return 0;
- }
-@@ -795,6 +868,7 @@
- 	my $channel_regex = $opt{channel} || '.*';
- 	my $category_regex = $opt{category} || '.*';
- 	my $versions_regex = $opt{versions} || '.*';
-+	my $exclude_regex = $opt{exclude} || '^ROGUE$';
- 	my $channel_exclude_regex = $opt{excludechannel} || '^ROGUE$';
- 	my $category_exclude_regex = $opt{excludecategory} || '^ROGUE$';
- 	my $since = $opt{since} || 99999;
-@@ -808,6 +882,7 @@
- 		  && $prog{$pid}{categories} =~ /$category_regex/i
- 		  && $prog{$pid}{versions} =~ /$versions_regex/i
- 		  && $prog{$pid}{channel} !~ /$channel_exclude_regex/i
-+		  && $prog{$pid}{name} !~ /$exclude_regex/i
- 		  && $prog{$pid}{categories} !~ /$category_exclude_regex/i
- 		  && $prog{$pid}{timeadded} >= $now - ($since * 3600)
- 		) {
-@@ -828,25 +903,22 @@
- 			);
- 		}
- 	}
-+
- 	return sort {$a <=> $b} keys %download_hash;
- }
- 
- 
--# get_links_atom (%channels)
--sub get_links_atom {
--	my $type = shift;
-+# get_links_bbciplayer (%channels)
-+sub get_links_bbciplayer {
-+	my $prog_type = shift;
- 	my %channels = %{$_[0]};
- 
- 	my $xml;
- 	my $feed_data;
- 	my $res;
--	logger "INFO: Getting $type Index Feeds\n";
-+	logger "INFO: Getting $prog_type Index Feeds\n";
- 	# Setup User agent
--	my $ua = LWP::UserAgent->new;
--	$ua->timeout([$lwp_request_timeout]);
--	$ua->proxy( ['http'] => $proxy_url );
--	$ua->agent( $user_agent{desktop} );
--	$ua->conn_cache(LWP::ConnCache->new());
-+	my $ua = create_ua('desktop');
- 
- 	# Download index feed
- 	# Sort feeds so that category based feeds are done last - this makes sure that the channels get defined correctly if there are dups
-@@ -909,7 +981,7 @@
- 		# Discard first element == header
- 		shift @entries;
- 
--		my ( $name, $episode, $desc, $pid, $available, $channel, $duration, $thumbnail, $type, $versions );
-+		my ( $name, $episode, $desc, $pid, $available, $channel, $duration, $thumbnail, $prog_type, $versions );
- 		foreach my $entry (@entries) {
- 
- 			my $entry_flat = $entry;
-@@ -939,7 +1011,7 @@
- 			}
- 
- 			# Extract channel and type
--			($type, $channel) = (split /\|/, $channels{$_})[0,1];
-+			($prog_type, $channel) = (split /\|/, $channels{$_})[0,1];
- 
- 			logger "DEBUG: '$pid, $name - $episode, $channel'\n" if $opt{debug};
- 
-@@ -980,7 +1052,7 @@
- 				'thumbnail'	=> "${thumbnail_prefix}/${pid}_150_84.jpg",
- 				'channel'	=> $channel,
- 				'categories'	=> join(',', @category),
--				'type'		=> $type,
-+				'type'		=> $prog_type,
- 			};
- 		}
- 	}
-@@ -996,13 +1068,8 @@
- 
- 	# Add index field based on alphabetical sorting by prog name
- 	my %index;
--	$index{tv} = 1;
--	
--	# Start index counter at 10001 for radio progs
--	$index{radio} = 10001;
--
--	# Start index counter at 20001 for podcast progs
--	$index{podcast} = 20001;
-+	# Start index counter at 'min' for each prog type
-+	$index{$_} = $index_range{$_}{min} for @all_prog_types;
- 
- 	my @prog_pid;
- 
-@@ -1013,10 +1080,10 @@
- 	for (sort @prog_pid) {
- 		# Extract pid
- 		my $pid = (split /\|/)[1];
--		my $type = $prog{$pid}{type};
--		$index_pid{ $index{$type} } = $pid;
--		$prog{$pid}{index} = $index{$type};
--		$index{$type}++;
-+		my $prog_type = $prog{$pid}{type};
-+		$index_pid{ $index{$prog_type} } = $pid;
-+		$prog{$pid}{index} = $index{$prog_type};
-+		$index{$prog_type}++;
- 	}
- 	return 0;
- }
-@@ -1024,18 +1091,14 @@
- 
- 
- # Uses: $podcast_index_feed_url
--# get_podcast_links ()
--sub get_podcast_links {
-+# get_links_bbcpodcast ()
-+sub get_links_bbcpodcast {
- 
- 	my $xml;
- 	my $res;
- 	logger "INFO: Getting podcast Index Feeds\n";
- 	# Setup User agent
--	my $ua = LWP::UserAgent->new;
--	$ua->timeout([$lwp_request_timeout]);
--	$ua->proxy( ['http'] => $proxy_url );
--	$ua->agent( $user_agent{get_iplayer} );
--	$ua->conn_cache(LWP::ConnCache->new());
-+	my $ua = create_ua('get_iplayer');
- 	
- 	# Method
- 	# $podcast_index_feed_url (gets list of rss feeds for each podcast prog) =>
-@@ -1224,6 +1287,302 @@
- 
- 
- 
-+# Uses:
-+# get_links_itv ()
-+sub get_links_itv {
-+	my %channels = %{$_[0]};
-+	my $xml;
-+	my $res;
-+	my %series_pid;
-+	my %episode_pid;
-+	logger "INFO: Getting itv Index Feeds\n";
-+	# Setup User agent
-+	my $ua = create_ua('desktop');
-+
-+	# Method
-+	# http://www.itv.com/_data/xml/CatchUpData/CatchUp360/CatchUpMenu.xml (gets list of urls for each prog series) =>
-+	#  =>
-+	
-+	# Download index feed
-+	my $itv_index_shows_url = 'http://www.itv.com/ClassicTVshows/'; # $channel/default.html
-+	my $itv_index_feed_url = 'http://www.itv.com/_data/xml/CatchUpData/CatchUp360/CatchUpMenu.xml';
-+
-+	# Sort feeds so that pages are done last - this makes sure that the channels get defined correctly if there are dups
-+	my @channel_list;
-+	push @channel_list, grep !/\//, keys %channels;
-+	push @channel_list, grep  /\//, keys %channels;
-+	# ITV ClassicShows parsing
-+	for my $channel ( @channel_list ) {
-+		# <li class="first-child"><a href="http://www.itv.com/ClassicTVshows/comedy/ABitofaDo/default.html">A Bit of a Do</a><br></li>
-+		# <li><a href="http://www.itv.com/ClassicTVshows/familydrama/achristmascarol/default.html">A Christmas Carol</a><br></li>
-+		# Get page, search for relevent lines which contain series links and loop through each matching line
-+		for my $s_line ( grep /(<li><a\s+href=".+?"><img\s+src=".+?"\s+alt=".+?"><\/a><h4>|<li.*?><a href=".+?">.+?<\/a><br><\/li>)/, ( split /\n/, request_url_retry($ua, $itv_index_shows_url.${channel}.'/default.html', 3, '.', "WARNING: Failed to get itv ${channel} index from site\n") ) ) {
-+			my ($url, $name);
-+			# Extract series url + series description
-+			($url, $name) = ($1, $2) if $s_line =~ m{<li><a\s+href="\s*(.+?)\s*"><img\s+src=".+?"\s+alt="\s*(.+?)\s*"><\/a><h4>};
-+			($url, $name) = ($1, $2) if $s_line =~ m{<li.*?><a href="\s*(.+?)\s*">\s*(.+?)\s*<\/a><br><\/li>};
-+			chomp($url);
-+			chomp($name);
-+			next if ! ($url && $name);
-+			logger "DEBUG: Channel: '$channel' Series: '$name' URL: '$url'\n" if $opt{verbose};
-+
-+			# Get list of episodes for this series
-+			# e.g. <li class="first-child"><a title="Play" href="?vodcrid=crid://itv.com/993&amp;DF=0">Episode one</a><br>The Sun in a Bottle</li>
-+			#      <li><a title="Play" href="?vodcrid=crid://itv.com/994&amp;DF=0">Episode two</a><br>Castle Saburac</li>
-+			#      <li class="first-child"><a class="nsat" title="This programme contains strong language and violence       " href="?vodcrid=crid://itv.com/588&amp;G=10&amp;DF=0">Episode one</a><br>The Dead of Jericho</li>
-+			#
-+			# e.g. <li><a class="playVideo" title="Play" href="?vodcrid=crid://itv.com/1232&amp;DF=0"><img src="img/60x45/Crossroads-Rosemary-shoots-David-efeef7cd-8d41-416c-9e30-26ce1b3d625c.jpg" alt="Crossroads: Rosemary shoots David"><span>Play</span></a><h4>
-+			#      vodcrid=crid://itv.com/971&amp;DF=0"><img src="img/60x45/9d20fd47-5d4b-44f5-9188-856505de0d0f.jpg" alt="Emmerdale  2002 Louise kills Ray"
-+			#
-+			# e.g. <a class="playVideo" title="Play" href="?vodcrid=crid://itv.com/1854&amp;DF=1"><img src="img/157x104/140c456c-d8bd-49d5-90f8-f7cc6d86f132.jpg" alt="Soldier Soldier "><span>Play</span></a><h2>Soldier Soldier</h2>
-+			#
-+			for my $e_line ( grep /vodcrid=crid/, ( split /\n/, request_url_retry($ua, $url, 3, '.', "WARNING: Failed to get ${name} index from site\n") ) ) {
-+				my ($guidance, $pid, $episode, $thumbnail);
-+				logger "DEBUG: Match Line: $e_line\n" if $opt{debug};
-+				# Extract episode data
-+				($guidance, $pid, $episode)  = ($2, $3, $4) if $e_line =~ m{<li.*?><a\s+(class="nsat"\s+)?title="\s*(.+?)\s*"\s+href="\?vodcrid=crid://itv.com/(\d+?)&.+?>\s*(.+?)\s*<};
-+				($pid, $thumbnail, $episode) = ($1, $2, $3) if $e_line =~ m{vodcrid=crid://itv.com/(\d+?)&.+?><img\s+src="(.+?)"\s+alt="\s*(.+?)\s*"};
-+				next if ! ($pid && $episode);
-+				# Remove 'Play'
-+				$guidance =~ s/^Play$//ig;
-+				# Strip non-printables
-+				$guidance =~ s/[\s\x00\xc2\xa0]+$//ig;
-+				#$guidance =~ s|[^\w\s\-\!"£\$\\/%\^&\*\(\)\+=,\.\?':;@~\[\]]+||gi;
-+				#$guidance =~ s/(\s\s)+//g;
-+				logger "DEBUG: PID: '$pid' Episode: '$episode' Guidance: '$guidance'\n" if $opt{debug};
-+
-+				# Skip if this pid is a duplicate
-+				if ( defined $prog{$pid} ) {
-+					logger "WARNING: '$pid, $prog{$pid}{name} - $prog{$pid}{episode}, $prog{$pid}{channel}' already exists (this channel = $channel)\n" if $opt{verbose};
-+					# Merge data (hack)
-+					#$prog{$pid}{episode} .= ','.$episode;
-+					my $oldname = $prog{$pid}{name};
-+					$prog{$pid}{episode} = $episode if (! $prog{$pid}{episode}) || $prog{$pid}{episode} =~ /$oldname/i;
-+					$prog{$pid}{thumbnail} = $thumbnail if ! $prog{$pid}{thumbnail};
-+					$prog{$pid}{guidance} = $guidance if ! $prog{$pid}{guidance};
-+					next;
-+				}
-+
-+				# build data structure
-+				$prog{$pid} = {
-+					'name'		=> $name,
-+					'versions'	=> 'default',
-+					'episode'	=> $episode,
-+					'channel'	=> (split /\|/, $channels{$channel})[1],
-+					'guidance'	=> $guidance,
-+					'categories'	=> (split /\|/, $channels{$channel})[1],
-+					'type'		=> 'itv',
-+				};
-+			}
-+		}
-+	}
-+
-+	my $xmlindex = request_url_retry($ua, $itv_index_feed_url, 3, '.', "WARNING: Failed to get itv index from site\n");
-+	$xmlindex =~ s/[\n\r]//g;
-+
-+	# This gives a list of programme series (sometimes episodes)
-+	#    <ITVCatchUpProgramme>
-+	#      <ProgrammeId>50</ProgrammeId>
-+	#      <ProgrammeTitle>A CHRISTMAS CAROL</ProgrammeTitle>
-+	#      <ProgrammeMediaId>615915</ProgrammeMediaId>
-+	#      <ProgrammeMediaUrl>
-+	#      http://www.itv.com//img/150x113/A-Christmas-Carol-2f16d25a-de1d-4a3a-90cb-d47489eee98e.jpg</ProgrammeMediaUrl>
-+	#      <LastUpdated>2009-01-06T12:24:22.7419643+00:00</LastUpdated>
-+	#      <Url>
-+	#      http://www.itv.com/CatchUp/Video/default.html?ViewType=5&amp;Filter=32910</Url>
-+	#      <EpisodeCount>1</EpisodeCount>
-+	#      <VideoID>32910</VideoID>
-+	#      <DentonID>-1</DentonID>
-+	#      <DentonRating></DentonRating>
-+	#      <AdditionalContentUrl />
-+	#      <AdditionalContentUrlText />
-+	#    </ITVCatchUpProgramme>
-+
-+	for my $feedxml ( split /<ITVCatchUpProgramme>/, $xmlindex ) {
-+		# Extract feed data
-+		my ($episodecount, $viewtype, $videoid, $url);
-+		my @entries;
-+
-+		logger "\n\nDEBUG: XML: $feedxml\n"  if $opt{debug}; 
-+
-+		# <EpisodeCount>1</EpisodeCount>
-+		$episodecount = $1 if $feedxml =~ m{<EpisodeCount>\s*(\d+)\s*<\/EpisodeCount>};
-+
-+		# <Url>http://www.itv.com/CatchUp/Video/default.html?ViewType=5&amp;Filter=32910</Url>
-+		($viewtype, $videoid) = ($1, $2) if $feedxml =~ m{<Url>\s*.+?ViewType=(\d+).+?Filter=(\d+)\s*<\/Url>}i;
-+
-+		## <VideoID>32910</VideoID>
-+		#$videoid = $1 if $feedxml =~ m{<VideoID>\s*(\d+)\s*<\/VideoID>};
-+
-+		# Skip if there is no feed data for channel
-+		next if ($viewtype =~ /^0*$/ || $videoid =~ /^0*$/ );
-+
-+		logger "DEBUG: Got ViewType=$viewtype VideoId=$videoid EpisodeCount=$episodecount\n" if $opt{debug};
-+
-+		my $url = "http://www.itv.com/_app/Dynamic/CatchUpData.ashx?ViewType=${viewtype}&Filter=${videoid}";
-+
-+		# Add response from episode metadata url to list to be parsed if this is an episode link
-+		if ( $viewtype == 5 ) {
-+			next if $episode_pid{$videoid};
-+			$episode_pid{$videoid} = 1;
-+			# Get metadata pages for episode
-+
-+			my ( $name, $guidance, $channel, $episode, $desc, $pid, $available, $duration, $thumbnail );
-+
-+			$pid = $videoid;
-+			$channel = 'ITV Catch-up';
-+
-+			# Skip if this pid is a duplicate
-+			if ( defined $prog{$pid} ) {
-+				logger "WARNING: '$pid, $prog{$pid}{name} - $prog{$pid}{episode}, $prog{$pid}{channel}' already exists (this channel = $channel)\n" if $opt{verbose};
-+				next;
-+			}
-+
-+			$name = $1 if $feedxml =~ m{<ProgrammeTitle>\s*(.+?)\s*<\/ProgrammeTitle>};
-+			$guidance = $1 if $feedxml =~ m{<DentonRating>\s*(.+?)\s*<\/DentonRating>};
-+			$thumbnail = $1 if $feedxml =~ m{<ProgrammeMediaUrl>\s*(.+?)\s*<\/ProgrammeMediaUrl>};
-+			$episode = $pid;
-+			# Strip non-printable chars
-+			$guidance =~ s/[\s\x00\xc2\xa0]+$//ig;
-+
-+			# build data structure
-+			$prog{$pid} = {
-+				'name'		=> $name,
-+				'versions'	=> 'default',
-+				'episode'	=> $episode,
-+				'guidance'	=> $guidance,
-+				'desc'		=> $desc,
-+				'available'	=> $available,
-+				'duration'	=> $duration,
-+				'thumbnail'	=> $thumbnail,
-+				'channel'	=> $channel,
-+				'categories'	=> 'TV',
-+				'type'		=> 'itv',
-+			};
-+
-+
-+
-+
-+
-+		# Get next episode list and parse
-+		#     <div class="listItem highlight contain">
-+		#      <div class="floatLeft"><a href="http://www.itv.com/CatchUp/Video/default.html?ViewType=5&amp;Filter=33383"><img src="http://www.itv.com//img/157x88/P7-67e0b86f-b335-4f6b-8db
-+		#      <div class="content">
-+		#        <h3><a href="http://www.itv.com/CatchUp/Video/default.html?ViewType=5&amp;Filter=33383">Emmerdale</a></h3>
-+		#        <p class="date">Mon 05 Jan 2009</p>
-+		#        <p class="progDesc">Donna is stunned to learn Marlon has pointed the finger at Ross. Aaron defaces Tom King's grave.</p>
-+		#        <ul class="progDetails">
-+		#          <li>
-+		#                          Duration: 30 min
-+		#          </li>
-+		#          <li class="days">
-+		#            Expires in
-+		#                        <strong>29</strong>
-+		#                                        days
-+		#                                </li>
-+		#        </ul>
-+		#      </div>
-+		#    </div>
-+		#    <div class="listItem contain">
-+		#      <div class="floatLeft"><a href="http://www.itv.com/CatchUp/Video/default.html?ViewType=5&amp;Filter=33245"><img src="http://www.itv.com//img/157x88/Marlon-Dingle-742c50b3-3b
-+		#      <div class="content">
-+		#        <h3><a href="http://www.itv.com/CatchUp/Video/default.html?ViewType=5&amp;Filter=33245">Emmerdale</a></h3>
-+		#        <p class="date">Fri 02 Jan 2009</p>
-+		#        <p class="progDesc">Marlon gets his revenge on Ross. The King brothers struggle to restart their business without Matthew. Scarlett is fed up with Victoria getting all Daz
-+		#        <ul class="progDetails">
-+		#          <li>
-+		#                          Duration: 30 min
-+		#          </li>
-+		#          <li class="days">
-+		#            Expires in
-+		#                        <strong>26</strong>
-+		#                                        days
-+		#                                </li>
-+		#        </ul>
-+		#      </div>
-+		#    </div>
-+		# 
-+		} elsif ( $viewtype == 1 ) {
-+			# Make sure we don't duplicate parsing a series
-+			next if $series_pid{$videoid};
-+			$series_pid{$videoid} = 1;
-+
-+			# Get metadata pages for each series
-+			logger "DEBUG: Getting series metadata $url\n" if $opt{debug};
-+			$xml = request_url_retry($ua, $url, 2, '.', "WARNING: Failed to get itv series data for ${videoid} from itv site\n") if $opt{verbose};
-+			$xml = request_url_retry($ua, $url, 2, '.', '') if ! $opt{verbose};
-+
-+			# skip if no data
-+			next if ! $xml;
-+
-+			decode_entities($xml);
-+			# Flatten entry
-+			$xml =~ s/[\n\r]//g;
-+
-+			# Extract Filter (pids) from this list
-+			# e.g. <h3><a href="http://www.itv.com/CatchUp/Video/default.html?ViewType=5&amp;Filter=32042">Emmerdale</a></h3>
-+			my @videoids = (split /<h3><a href=.+?Filter=/, $xml);
-+
-+			# Get episode data for each videoid
-+			$viewtype = 5;
-+
-+			my @episode_data = split/<h3><a href=.+?Filter=/, $xml;
-+			# Ignore first entry
-+			shift @episode_data;
-+			logger "INFO: Got ".($#episode_data+1)." programmes\n" if $opt{verbose};
-+
-+			for my $xml (@episode_data) {
-+				$videoid = $1 if $xml =~ m{^(\d+?)".+$}i;
-+
-+				# Make sure we don't duplicate parsing an episode
-+				next if $episode_pid{$videoid};
-+				$episode_pid{$videoid} = 1;
-+
-+				my ( $name, $guidance, $channel, $episode, $desc, $pid, $available, $duration, $thumbnail );
-+	
-+				$pid = $videoid;
-+				$channel = 'ITV Catch-up';
-+	
-+				# Skip if this pid is a duplicate
-+				if ( defined $prog{$pid} ) {
-+					logger "WARNING: '$pid, $prog{$pid}{name} - $prog{$pid}{episode}, $prog{$pid}{channel}' already exists (this channel = $channel)\n" if $opt{verbose};
-+					next;
-+				}
-+				$name = $1 if $feedxml =~ m{<ProgrammeTitle>\s*(.+?)\s*<\/ProgrammeTitle>};
-+				$available = $1 if $xml =~ m{<p\s+class="date">(.+?)<\/p>}i;
-+				$episode = $available;
-+				$duration = $1 if $xml =~ m{<li>Duration:\s*(.+?)\s*<\/li>}i;
-+				$desc = $1 if $xml =~ m{<p\s+class="progDesc">(.+?)\s*<\/p>};
-+				$guidance = $1 if $feedxml =~ m{<DentonRating>\s*(.+?)\s*<\/DentonRating>};
-+				$thumbnail = $1 if $feedxml =~ m{<ProgrammeMediaUrl>\s*(.+?)\s*<\/ProgrammeMediaUrl>};
-+				$guidance =~ s/[\s\x00\xc2\xa0]+$//ig;
-+
-+				logger "DEBUG: name='$name' episode='$episode' pid=$pid available='$available' \n" if $opt{debug};	
-+	
-+				# build data structure
-+				$prog{$pid} = {
-+					'name'		=> $name,
-+					'versions'	=> 'default',
-+					'episode'	=> $episode,
-+					'guidance'	=> $guidance,
-+					'desc'		=> $desc,
-+					'available'	=> $available,
-+					'duration'	=> $duration,
-+					'thumbnail'	=> $thumbnail,
-+					'channel'	=> $channel,
-+					'categories'	=> 'TV',
-+					'type'		=> 'itv',
-+				};
-+			}
-+		}	
-+
-+	}
-+	logger "\n";
-+	return 0;
-+}
-+
-+
-+
- # Feed info:
- #	# Also see http://derivadow.com/2008/07/18/interesting-bbc-data-to-hack-with/
- #	# All podcasts menu (iphone)
-@@ -1261,14 +1620,14 @@
- #	http://www.bbc.co.uk/cbbc/programmes/genres/childrens/player
- #	http://www.bbc.co.uk/programmes/genres/childrens/schedules/upcoming.ics
- #
--# get_links( <radio|tv|podcast> )
-+# get_links( <prog_type> )
- sub get_links {
- 	my @cache;
- 	my $now = time();
--	my $type = shift;
-+	my $prog_type = shift;
- 
- 	# Open cache file (need to verify we can even read this)
--	if ( open(CACHE, "< $cachefile{$type}") ) {
-+	if ( open(CACHE, "< $cachefile{$prog_type}") ) {
- 		# Get file contents less any comments
- 		@cache = grep !/^[\#\s]/, <CACHE>;
- 		close (CACHE);
-@@ -1281,47 +1640,40 @@
- 		for (@cache) {
- 			# Populate %prog from cache
- 			chomp();
--			my ($index, $type, $name, $pid, $available, $episode, $versions, $duration, $desc, $channel, $categories, $thumbnail, $timeadded) = split /\|/;
--			# Create data structure with prog data
--			$prog_old{$pid} = {
--				'index'		=> $index,
--				'name'		=> $name,
--				'episode'	=> $episode,
--				'desc'		=> $desc,
--				'available'	=> $available,
--				'duration'	=> $duration,
--				'versions'	=> $versions,
--				'channel'	=> $channel,
--				'categories'	=> $categories,
--				'thumbnail'	=> $thumbnail,
--				'type'		=> $type,
--				'timeadded'	=> $timeadded,
--			};
--			$index_pid_old{$index}	= $pid;
-+			# Get cache line
-+			my @record = split /\|/;
-+			my %record_entries;
-+			# Update fields in %prog hash for $pid
-+			$record_entries{$_} = shift @record for @cache_format;
-+			$prog_old{ $record_entries{pid} } = \%record_entries;
-+			$index_pid_old{ $record_entries{index} }  = $record_entries{pid};
- 		}
- 	}
- 
- 	# if a cache file doesn't exist/corrupted, flush option is specified or original file is older than $cache_sec then download new data
--	if ( (! @cache) || (! -f $cachefile{$type}) || $opt{flush} || ($now >= ( stat($cachefile{$type})->mtime + $cache_secs )) ) {
-+	if ( (! @cache) || (! -f $cachefile{$prog_type}) || $opt{flush} || ($now >= ( stat($cachefile{$prog_type})->mtime + $cache_secs )) ) {
- 
--		# Podcast only
--		get_podcast_links() if $type eq 'podcast';
-+		# BBC Podcast only
-+		get_links_bbcpodcast() if $prog_type eq 'podcast';
- 
--		# Radio and TV
--		get_links_atom( $type, \%{$channels{$type}} ) if $type =~ /(tv|radio)/;
-+		# ITV only
-+		get_links_itv( \%{$channels{$prog_type}} ) if $prog_type eq 'itv';
-+
-+		# BBC Radio and TV
-+		get_links_bbciplayer( $prog_type, \%{$channels{$prog_type}} ) if $prog_type =~ /^(tv|radio)$/;
- 
- 		# Sort indexes
- 		sort_indexes();
- 		
- 		# Open cache file for writing
--		unlink $cachefile{$type};
-+		unlink $cachefile{$prog_type};
- 		my $now = time();
--		if ( open(CACHE, "> $cachefile{$type}") ) {
--			print CACHE "#Index|Type|Name|Pid|Available|Episode|Versions|Duration|Desc|Channel|Categories|Thumbnail|TimeAdded\n";
-+		if ( open(CACHE, "> $cachefile{$prog_type}") ) {
-+			print CACHE "#".(join '|', @cache_format)."\n";
- 			for (sort {$a <=> $b} keys %index_pid) {
- 				my $pid = $index_pid{$_};
- 				# Only write entries for correct prog type
--				if ($prog{$pid}{type} eq $type) {
-+				if ($prog{$pid}{type} eq $prog_type) {
- 					# Merge old and new data to retain timestamps
- 					# if the entry was in old cache then retain timestamp from old entry
- 					if ( $prog_old{$pid}{timeadded} ) {
-@@ -1332,12 +1684,17 @@
- 						list_prog_entry( $pid, 'Added: ' );
- 					}
- 					# write to cache file
--					print CACHE "$_|$prog{$pid}{type}|$prog{$pid}{name}|$pid|$prog{$pid}{available}|$prog{$pid}{episode}|$prog{$pid}{versions}|$prog{$pid}{duration}|$prog{$pid}{desc}|$prog{$pid}{channel}|$prog{$pid}{categories}|$prog{$pid}{thumbnail}|$prog{$pid}{timeadded}\n";
-+					$prog{$pid}{pid} = $pid;
-+					# Write each field into cache line
-+					for my $field (@cache_format) {
-+						print CACHE $prog{$pid}{$field}.'|';
-+					}
-+					print CACHE "\n";
- 				}
- 			}
- 			close (CACHE);
- 		} else {
--			logger "WARNING: Couldn't open cache file '$cachefile{$type}' for writing\n";
-+			logger "WARNING: Couldn't open cache file '$cachefile{$prog_type}' for writing\n";
- 		}
- 
- 
-@@ -1354,172 +1711,434 @@
- # Usage: download_programme (<pid>)
- sub download_programme {
- 	my $pid = shift;
-+	my %streamdata;
-+	my %version_pids;
-+	my $return;
- 
- 	# Setup user-agent
--	# Switch off automatic redirects
--	my $ua = LWP::UserAgent->new( requests_redirectable => [] );
--	# Setup user agent
--	$ua->timeout([$lwp_request_timeout]);
--	$ua->proxy( ['http'] => $proxy_url );
--	$ua->cookie_jar( HTTP::Cookies->new( file => $cookiejar, autosave => 1, ignore_discard => 1 ) );
-+	my $ua = create_ua('desktop');
- 
--	my $dir = $download_dir{ $prog{$pid}{type} };
--	$prog{$pid}{ext} = 'mov';
-+	# download depending on the prog type
-+	logger "INFO: Attempting to Download $prog{$pid}{type}: $prog{$pid}{name} - $prog{$pid}{episode}\n";
- 
--	# If were a podcast...
-+	# ITV TV
-+	if ( $prog{$pid}{type} eq 'itv' ) {
-+		# stream data
-+		# Display media stream data if required
-+		if ( $opt{streaminfo} ) {
-+			display_stream_info( $pid, undef, 'all' );
-+			$opt{quiet} = 1;
-+			return 'skip';
-+		}
-+		return download_programme_itv( $ua, $pid );
-+	}
-+
-+	# BBC Podcasts
- 	if ( $prog{$pid}{type} eq 'podcast' ) {
--		# Determine the correct filename and extension for this download
--		my $filename_orig = $pid;
--		$prog{$pid}{ext} = $pid;
--		$filename_orig =~ s|^.+/(.+?)\.\w+$|$1|g;
--		$prog{$pid}{ext} =~ s|^.*\.(\w+)$|$1|g;
--		$prog{$pid}{fileprefix} = generate_download_filename_prefix($pid, $dir, $opt{fileprefix} || "<longname> - <episode> $filename_orig");
--		$prog{$pid}{dir} = $dir;
--		logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                  \n";
--		my $file_done = "${dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
--		my $file = "${dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
--		$prog{$pid}{filename} = $file_done;
--		if ( -f $file_done ) {
--			logger "WARNING: File $file_done already exists\n\n";
--			return 1;
-+		# stream data not available
-+		return 'skip' if $opt{streaminfo};
-+		return download_programme_podcast( $ua, $pid );
-+	}
-+
-+	# For BBC Radio/TV we might have a pid with no prog_type - determine here first
-+	( $prog{$pid}{type}, $prog{$pid}{longname}, %version_pids ) = get_version_pids( $ua, $pid );
-+
-+	# BBC TV
-+	if ( $prog{$pid}{type} eq 'tv' ) {
-+
-+		# Deal with BBC TV fallback modes
-+		# Valid modes are iphone,rtmp,flashhigh,flashnormal,flashwii,n95_wifi
-+		$opt{vmode} = 'flashhigh,flashnormal' if $opt{vmode} eq 'rtmp' || $opt{vmode} eq 'flash';
-+		# Defaults
-+		if ( $opt{vmode} eq 'auto' || ! $opt{vmode} ) {
-+			if ( ! exists_in_path($rtmpdump) ) {
-+				$opt{vmode} = 'iphone';	
-+			} else {
-+				$opt{vmode} = 'iphone,flashhigh,flashnormal';
-+			}
- 		}
-+		# Expand the modes into a loop
-+		logger "INFO: $opt{vmode} modes will be tried\n";
-+		for my $mode ( split /,/, $opt{vmode} ) {
-+			chomp( $mode );
-+			logger "INFO: Attempting to download using $mode mode\n";
-+			$return = download_programme_tv( $ua, $pid, $mode, \%version_pids );
-+			logger "DEBUG: Download using $mode mode return code: '$return'\n" if $opt{debug};
- 
--		# Skip from here if we are only testing downloads
--		return 1 if $opt{test};
-+			# Give up trying alternative download methods
-+			return 2 if $return eq 'abort';
- 
--		# Create symlink filename if required
--		my $file_symlink;
--		if ( $opt{symlink} ) {
--			# Substitute the fields for the pid
--			$file_symlink = substitute_fields( $pid, $opt{symlink} );
-+			# Return to retry loop if successful or retry requested 
-+			return 'retry' if $return eq 'retry';
-+
-+			# Return to retry loop and do nothing 
-+			return 'skip' if $return eq 'skip';
-+
-+			# Return 0 if successful 
-+			return 0 if ! $return;
-+
-+			# Return failed if there is no 'next'
-+			return 1 if $return ne 'next';
- 		}
--		
--		return download_podcast_stream( $ua, $pid, $file, $file_done, $file_symlink );
- 	}
- 
--	logger "INFO: Attempting to Download: $prog{$pid}{name} - $prog{$pid}{episode}\n";
-+	# BBC Radio
-+	if ( $prog{$pid}{type} eq 'radio' ) {
-+		# This will always be the pid version for radio
-+		$prog{$pid}{version} = 'default';
-+		# Display media stream data if required
-+		if ( $opt{streaminfo} ) {
-+			display_stream_info( $pid, $version_pids{default}, 'all' );
-+			$opt{quiet} = 1;
-+			return 'skip';
-+		}
-+
-+		# Deal with radio fallback modes
-+		# Valid modes are mp3|iphone,flash|rtmp,real|ra
-+		# Defaults
-+		$opt{amode} = 'iphone,flash,real' if $opt{amode} eq 'auto' || ! $opt{amode};
-+
-+		# Expand the modes into a loop
-+		logger "INFO: $opt{amode} modes will be tried\n";
-+		for my $mode ( split /,/, $opt{amode} ) {
-+			chomp( $mode );
-+			logger "INFO: Attempting to download using $mode mode\n";
-+			# RealAudio
-+			if ( $mode =~ /^(real|ra)/ ) {
-+				$return = download_programme_radio_realaudio( $ua, $pid, \%version_pids );
-+
-+			# FlashAudio
-+			} elsif ( $mode =~ /^(flash|rtmp)/ ) {
-+				$return = download_programme_radio_flashaudio( $ua, $pid, $mode, \%version_pids );
-+
-+			# iPhone
-+			} elsif ( $mode =~ /^(iphone|mp3)/ ) {
-+				$return = download_programme_radio_iphone( $ua, $pid, \%version_pids );
-+			}
-+			logger "DEBUG: Download using $mode mode return code: '$return'\n" if $opt{debug};
- 
--	# Get version => pid hash
--	my ( $type, $title, %version_pids ) = get_version_pids( $ua, $pid );
-+			# Give up trying alternative download methods
-+			return 2 if $return eq 'abort';
- 
--	# Extract Long Name, e.g.: iplayer.episode.setTitle("DIY SOS: Series 16: Swansea");
--	$prog{$pid}{longname} = $title;
-+			# Not going to allow retries here until rtmpdump/flashaudio exits correctly - so just just skip to next mode for now
-+			$return = 'next' if $return eq 'retry';
-+			## Return to retry loop if successful or retry requested 
-+			#return 'retry' if $return eq 'retry';
- 
--	# Strip off the episode name
--	$prog{$pid}{longname} =~ s/^(.+):.*?$/$1/g;
-+			# Return to retry loop and do nothing 
-+			return 'skip' if $return eq 'skip';
- 
--	# Detect if this content is for radio
--	my $usemp3 = 0;
--	if ( $type eq 'radio' ) {
-+			# Return 0 if successful 
-+			return 0 if ! $return;
- 
--		# Display media stream data if required
--		if ( $opt{streaminfo} ) {
--			get_media_stream_data( $pid, $version_pids{'default'}, 'all' );
--			return 1;
-+			# Return failed if there is no 'next'
-+			return 1 if $return ne 'next';
- 		}
-+	}
- 
--		# Type is definitely radio
--		$prog{$pid}{type} = 'radio';
--		$dir = $download_dir{ $prog{$pid}{type} };
--
--		# Check for mp3 stream  - unless realaudio option is specified
--		if ( ! $opt{realaudio} ) {
--			# Check for iphone mp3 radio stream
--			if ( get_media_stream_data( $pid, $version_pids{default}, 'iphone' ) ) {
--				$usemp3 = 1;
--				$prog{$pid}{ext} = 'mp3';
--				logger "INFO: MP3 stream media is available\n" if $opt{verbose};
--
--			# if mp3audio option is specified do not fallback to realaudio
--			} elsif ( $opt{mp3audio} ) {
--				logger "ERROR: No MP3 stream media is available - not falling back to RealAudio\n";
--				return 1;
-+	# If we get here then we have failed
-+	return 1;
-+}
- 
--			# if not then force realaudio option as fallback
--			} else {
--				$opt{realaudio} = 1;
--				logger "INFO: No MP3 stream media is available - falling back to RealAudio\n" if $opt{verbose};
--			}
--		}
- 
--		# Use realplayer stream
--		if ( $opt{realaudio} ) {
- 
--			# Check dependancies for radio programme transcoding / streaming
--			# Check if we need 'tee'
--			if ( (! exists_in_path($tee)) && $opt{stdout} && (! $opt{nowrite}) ) {
--				logger "\nERROR: $tee does not exist in path, skipping\n";
--				return 20;
--			}
--			# Check if we have mplayer and lame
--			if ( (! $opt{wav}) && (! $opt{raw}) && (! exists_in_path($lame)) ) {
--				logger "\nWARNING: Required $lame does not exist, falling back to wav mode\n";
--				$opt{wav} = 1;
--			}		
--			if (! exists_in_path($mplayer)) {
--				logger "\nERROR: Required $mplayer does not exist, skipping\n";
--				return 20;
--			}
-+sub download_programme_itv {
-+	my ( $ua, $pid ) = ( @_ );
-+	my %streamdata;
-+
-+	# Check for mplayer (required)
-+	if (! exists_in_path($mplayer)) {
-+		logger "\nERROR: Required $mplayer does not exist, skipping\n";
-+		return 21;
-+	}
- 
--			my $url_2 = get_media_stream_data( $pid, $version_pids{default}, 'realaudio' );
-+	$prog{$pid}{dir} = $download_dir{ $prog{$pid}{type} };
-+	$prog{$pid}{pid} = $pid;
-+	$prog{$pid}{ext} = 'mp4';
-+	$prog{$pid}{ext} = 'asf' if $opt{raw};
- 	
--			logger "INFO: Version = $prog{$pid}{version}\n" if $opt{verbose};
--			logger "INFO: Stage 2 URL = $url_2\n" if $opt{verbose};
-+	my @url_list = %{get_media_stream_data( $pid, undef, 'itv')}->{streamurl};
- 
--			# Report error if no versions are available
--			if ( ! $url_2 ) {
--				logger "ERROR: No Stage 2 URL\n" if $opt{verbose};
--				return 15;
--			}
-+	# Get and set more meta data - Set the %prog values from metadata if they aren't already set
-+	my %metadata = get_pid_metadata($ua, $pid);
-+	for ( qw/ name episode available duration thumbnail desc guidance / ) {
-+		$prog{$pid}{$_} = $metadata{$_} if ! $prog{$pid}{$_};
-+	}
- 
--			# Determine the correct filenames for this download
--			$prog{$pid}{ext} = 'mp3';
--			$prog{$pid}{ext} = 'ra'  if $opt{raw};
--			$prog{$pid}{ext} = 'wav' if $opt{wav};
--			$prog{$pid}{fileprefix} = generate_download_filename_prefix( $pid, ${dir}, $opt{fileprefix} || "<longname> - <episode> <pid>" );
--			logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                 \n";
--			$prog{$pid}{dir} = $dir;
--			my $file_done = "${dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
--			my $file = "${dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
--			$prog{$pid}{filename} = $file_done;
--			if ( -f $file_done ) {
--				logger "WARNING: File $file_done already exists\n\n";
--				return 1;
--			}
-+	$prog{$pid}{fileprefix} = generate_download_filename_prefix( $pid, $prog{$pid}{dir}, $opt{fileprefix} || "<name> <pid>" );
-+	logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                 \n";
-+	# Create a subdir if there are multiple parts
-+	if ($#url_list > 0) {
-+		$prog{$pid}{dir} .= "/$prog{$pid}{fileprefix}";
-+		logger "INFO: Creating subdirectory $prog{$pid}{dir} for programme\n" if $opt{verbose};
-+		mkpath $prog{$pid}{dir} if ! -d $prog{$pid}{dir};
-+	}
-+	my $file_done = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
-+	my $file = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
-+	$prog{$pid}{filename} = $file_done;
- 
--			# Skip from here if we are only testing downloads
--			return 1 if $opt{test};
-+	# Display metadata
-+	display_metadata( $prog{$pid}, qw/ pid index name duration available expiry desc / );
- 
--			# Create symlink filename if required
--			my $file_symlink;
--			if ( $opt{symlink} ) {
--				# Substitute the fields for the pid
--				$file_symlink = substitute_fields( $pid, $opt{symlink} );
--			}
-+	# Skip from here if we are only testing downloads
-+	return 1 if $opt{test};
- 
--			# Do the audio download
--			return download_rtsp_stream( $ua, $url_2, $file, $file_done, $file_symlink, $pid );
--		}
-+	return download_stream_mms_video( $ua, (join '|', @url_list), $file, $file_done, $pid );
-+}	
-+
-+
-+
-+sub download_programme_podcast {
-+	my ( $ua, $pid ) = ( @_ );
-+	my %streamdata;
-+
-+	$prog{$pid}{dir} = $download_dir{ $prog{$pid}{type} };
-+
-+	# Determine the correct filename and extension for this download
-+	my $filename_orig = $pid;
-+	$prog{$pid}{ext} = $pid;
-+	$filename_orig =~ s|^.+/(.+?)\.\w+$|$1|g;
-+	$prog{$pid}{ext} =~ s|^.*\.(\w+)$|$1|g;
-+	$prog{$pid}{fileprefix} = generate_download_filename_prefix($pid, $prog{$pid}{dir}, $opt{fileprefix} || "<longname> - <episode> $filename_orig");
-+	logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                  \n";
-+	my $file_done = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
-+	my $file = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
-+	$prog{$pid}{filename} = $file_done;
-+	if ( -f $file_done && stat($file_done)->size > $min_download_size ) {
-+		logger "WARNING: File $file_done already exists\n\n";
-+		return 1;
-+	}
-+
-+	# Skip from here if we are only testing downloads
-+	return 1 if $opt{test};
-+
-+	# Create symlink filename if required
-+	my $file_symlink;
-+	if ( $opt{symlink} ) {
-+		# Substitute the fields for the pid
-+		$file_symlink = substitute_fields( $pid, $opt{symlink} );
-+	}
-+
-+	return download_stream_podcast( $ua, $pid, $file, $file_done, $file_symlink );
-+}
-+
-+
-+
-+sub download_programme_radio_realaudio {
-+	my $ua = shift; 
-+	my $pid = shift;
-+	my %version_pids = %{@_[0]};
-+	my %streamdata;
-+
-+	# Check dependancies for radio programme transcoding / streaming
-+	# Check if we need 'tee'
-+	if ( (! exists_in_path($tee)) && $opt{stdout} && (! $opt{nowrite}) ) {
-+		logger "\nERROR: $tee does not exist in path, skipping\n";
-+		return 'abort';
-+	}
-+	if (! exists_in_path($mplayer)) {
-+		logger "\nWARNING: Required $mplayer does not exist\n";
-+		return 'next';
-+	}
-+	# Check if we have mplayer and lame
-+	if ( (! $opt{wav}) && (! $opt{raw}) && (! exists_in_path($lame)) ) {
-+		logger "\nWARNING: Required $lame does not exist, will save file in wav format\n";
-+		$opt{wav} = 1;
-+	}
-+
-+	$prog{$pid}{dir} = $download_dir{ $prog{$pid}{type} };
-+	$prog{$pid}{ext} = 'mp3';
-+	$prog{$pid}{ext} = 'ra'  if $opt{raw};
-+	$prog{$pid}{ext} = 'wav' if $opt{wav};
- 
-+	my $url_2 = %{get_media_stream_data( $pid, $version_pids{default}, 'realaudio')}->{streamurl};
-+		
-+	# Report error if no versions are available
-+	if ( ! $url_2 ) {
-+		logger "WARNING: RealAudio version not available\n";
-+		return 'next';
- 	} else {
--		# Type is definitely tv
--		$prog{$pid}{type} = 'tv';
--		$dir = $download_dir{ $prog{$pid}{type} };
-+		logger "INFO: Stage 2 URL = $url_2\n" if $opt{verbose};
-+	}
-+
-+	# Determine the correct filenames for this download
-+	$prog{$pid}{fileprefix} = generate_download_filename_prefix( $pid, $prog{$pid}{dir}, $opt{fileprefix} || "<longname> - <episode> <pid>" );
-+	logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                 \n";
-+	my $file_done = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
-+	my $file = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
-+	$prog{$pid}{filename} = $file_done;
-+	if ( -f $file_done ) {
-+		logger "WARNING: File $file_done already exists\n\n";
-+		return 'abort';
- 	}
- 
-+	# Skip from here if we are only testing downloads
-+	return 'abort' if $opt{test};
- 
--	# iPhone mp3/h.264 stream downloading...
-+	# Create symlink filename if required
-+	my $file_symlink;
-+	if ( $opt{symlink} ) {
-+		# Substitute the fields for the pid
-+		$file_symlink = substitute_fields( $pid, $opt{symlink} );
-+	}
- 
--	# Check if we have vlc - if not use iPhone mode
--	if ( $opt{n95} && (! exists_in_path($vlc)) ) {
--		logger "\nWARNING: Required $vlc does not exist, falling back to iPhone mode\n";
--		$opt{n95} = 0;
--	}		
-+	# Do the audio download
-+	return download_stream_rtsp( $ua, $url_2, $file, $file_done, $file_symlink, $pid );
-+}
- 
- 
-+	
-+sub download_programme_radio_iphone {
-+	my $ua = shift; 
-+	my $pid = shift;
-+	my %version_pids = %{@_[0]};
-+	my %streamdata;
-+	my $url_2;
-+
-+	$prog{$pid}{dir} = $download_dir{ $prog{$pid}{type} };
-+	$prog{$pid}{ext} = 'mp3';
-+
-+	my $url_2 = %{get_media_stream_data( $pid, $version_pids{ $prog{$pid}{version} }, 'iphone')}->{streamurl};
-+
-+	# Report error if no versions are available
-+	if ( ! $url_2 ) {
-+		logger "WARNING: iPhone stream media not available\n";
-+		return 'next';
-+	} else {
-+		logger "INFO: Stage 2 URL = $url_2\n" if $opt{verbose};
-+	}
-+
-+	# Determine the correct filenames for this download
-+	$prog{$pid}{fileprefix} = generate_download_filename_prefix( $pid, $prog{$pid}{dir}, $opt{fileprefix} || "<longname> - <episode> <pid> <version>" );
-+	logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                 \n";
-+	my $file_done = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
-+	my $file = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
-+	$prog{$pid}{filename} = $file_done;
-+	if ( -f $file_done ) {
-+		logger "WARNING: File $file_done already exists\n\n";
-+		return 'abort';
-+	}
-+
-+	# Skip from here if we are only testing downloads
-+	return 'abort' if $opt{test};
-+
-+	# Create symlink filename if required
-+	my $file_symlink;
-+	if ( $opt{symlink} ) {
-+		# Substitute the fields for the pid
-+		$file_symlink = substitute_fields( $pid, $opt{symlink} );
-+	}
-+
-+	my $return;
-+	# Disable proxy here if required
-+	$ua->proxy( ['http'] => undef ) if $opt{partialproxy};
-+	$return = download_stream_iphone( $ua, $url_2, $pid, $file, $file_done, $file_symlink, 0 );
-+	# Re-enable proxy here if required
-+	$ua->proxy( ['http'] => $proxy_url ) if $opt{partialproxy};
-+
-+	return $return;
-+}
-+
-+
-+
-+sub download_programme_radio_flashaudio {
-+	my $ua = shift; 
-+	my $pid = shift;
-+	my $mode = shift;
-+	my %version_pids = %{@_[0]};
-+	my %streamdata;
-+	my $url_2;
-+
-+	# Force raw mode if ffmpeg is not installed
-+	if ( ! exists_in_path($ffmpeg) ) {
-+		logger "\nWARNING: $ffmpeg does not exist - not converting flv file\n";
-+		$opt{raw} = 1;
-+	}
-+	# Disable rtmp modes if rtmpdump does not exist
-+	if ( ! exists_in_path($rtmpdump) ) {
-+		logger "\nERROR: Required program $rtmpdump does not exist (see http://linuxcentre.net/getiplayer/installation and http://linuxcentre.net/getiplayer/download)\n";
-+		return 'next';
-+	}
-+
-+	$prog{$pid}{dir} = $download_dir{ $prog{$pid}{type} };
-+	$prog{$pid}{ext} = 'mp3';
-+	$prog{$pid}{ext} = 'flv' if $opt{raw};
-+
-+	logger "INFO: Trying to get media stream metadata for flashaudio RTMP mode\n" if $opt{verbose};
-+	%streamdata = %{ get_media_stream_data( $pid, $version_pids{ $prog{$pid}{version} }, 'flashaudio') };
-+	$url_2 = $streamdata{streamurl};
-+	if ( ! $url_2 ) {
-+		logger "WARNING: No flashaudio version available\n";
-+		return 'next';
-+	}
-+
-+	# Determine the correct filenames for this download
-+	$prog{$pid}{fileprefix} = generate_download_filename_prefix( $pid, $prog{$pid}{dir}, $opt{fileprefix} || "<longname> - <episode> <pid> <version>" );
-+	logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                 \n";
-+	my $file_done = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
-+	my $file = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
-+	$prog{$pid}{filename} = $file_done;
-+	if ( -f $file_done ) {
-+		logger "WARNING: File $file_done already exists\n\n";
-+		return 'abort';
-+	}
-+
-+	# Skip from here if we are only testing downloads
-+	return 'abort' if $opt{test};
-+
-+	# Create symlink filename if required
-+	my $file_symlink;
-+	if ( $opt{symlink} ) {
-+		# Substitute the fields for the pid
-+		$file_symlink = substitute_fields( $pid, $opt{symlink} );
-+	}
-+
-+	# Do the RTMP flashaudio download
-+	return download_stream_rtmp( $ua, $streamdata{streamurl}, $pid, $mode, $streamdata{application}, $streamdata{tcurl}, $streamdata{authstring}, $streamdata{swfurl}, $file, $file_done, $file_symlink );
-+}
-+
-+
-+
-+# Usage: download_programme_tv (<pid>)
-+sub download_programme_tv {
-+	my $ua = shift; 
-+	my $pid = shift;
-+	my $mode = shift;
-+	my %version_pids = %{@_[0]};
-+	my %streamdata;
- 	my $url_2;
- 	my $got_url;
- 
-+	# Check if we have vlc - if not use iPhone mode
-+	if ( $opt{vmode} eq 'n95' && (! exists_in_path($vlc)) ) {
-+		logger "\nWARNING: Required $vlc does not exist\n";
-+		return 'next';
-+	}		
-+	# if rtmpdump does not exist
-+	if ( $mode =~ /^(rtmp|flash)/ && ! exists_in_path($rtmpdump)) {
-+		logger "WARNING: Required program $rtmpdump does not exist (see http://linuxcentre.net/getiplayer/installation and http://linuxcentre.net/getiplayer/download)\n";
-+		return 'next';
-+	}
-+	# Force raw mode if ffmpeg is not installed
-+	if ( $mode =~ /^(flash|rtmp)/ && ! exists_in_path($ffmpeg)) {
-+		logger "\nWARNING: $ffmpeg does not exist - not converting flv file\n";
-+		$opt{raw} = 1;
-+	}
-+
-+	$prog{$pid}{dir} = $download_dir{ $prog{$pid}{type} };
-+	$prog{$pid}{ext} = 'mov';
-+	# Lookup table to determine which ext to use for different download methods
-+	my %stream_ext = (
-+		iphone		=> 'mov',
-+		flashhigh 	=> 'mp4',
-+		flashnormal	=> 'avi',
-+		flashwii	=> 'avi',
-+		n95_wifi	=> '3gp',
-+		n95_3g		=> '3gp',
-+	);
-+	$prog{$pid}{ext} = $stream_ext{$mode} if not $opt{raw};
-+	$prog{$pid}{ext} = 'flv' if $mode =~ /^(flash|rtmp)/ && $opt{raw};
-+
- 	# Do this for each version tried in this order (if they appeared in the content)
- 	for my $version ( @version_search_list ) {
- 
-@@ -1528,52 +2147,41 @@
- 			logger "INFO: Checking existence of $version version\n";
- 			$prog{$pid}{version} = $version;
- 			logger "INFO: Version = $prog{$pid}{version}\n" if $opt{verbose};
--			if( ! $opt{rtmp} ) {
--				$url_2 = get_iphone_stream_download_url( $ua, $version_pids{$version} );
--			} else {
--				$url_2 = get_media_stream_data( $pid, $version_pids{ $prog{$pid}{version} }, 'flashhigh' );
--			}
--			$got_url = 1;
-+			# Try to get stream data
-+			%streamdata = %{ get_media_stream_data( $pid, $version_pids{ $prog{$pid}{version} }, $mode) };
-+			$url_2 = $streamdata{streamurl};
- 		}
- 		# Break out of loop if we have an actual URL
--		last if $got_url && $url_2;
--	}
--
--	# Report error if no versions are available
--	if ( ! $got_url ) {
--		logger "ERROR: No versions exist for download\n";
--		return 14;
-+		last if $url_2;
- 	}
- 
- 	# Display media stream data if required
- 	if ( $opt{streaminfo} ) {
--		get_media_stream_data( $pid, $version_pids{'default'}, 'all' );
--		return 1;
-+		display_stream_info( $pid, $version_pids{ $prog{$pid}{version} }, 'all' );
-+		$opt{quiet} = 1;
-+		return 'skip';
- 	}
- 
--	# Report error if failed to get URL for version
--	if ( $got_url && ! $url_2 ) {
--		logger "ERROR: No Stage 2 URL\n" if $opt{verbose};
--		# If mp3 audio stream does not exist force realaudio mode and retry
--		if ( $usemp3 && ! $opt{mp3audio}) {
--			$opt{realaudio} = 1;
--			return 'retry';
--		}
--		return 15;
-+	# Report error if no versions are available
-+	if ( ! $url_2 ) {
-+		logger "WARNING: No $mode versions available\n";
-+		return 'next';
- 	}
--	
-+
- 	# Determine the correct filenames for this download
--	$prog{$pid}{fileprefix} = generate_download_filename_prefix( $pid, $dir, $opt{fileprefix} || "<longname> - <episode> <pid> <version>" );
-+	$prog{$pid}{fileprefix} = generate_download_filename_prefix( $pid, $prog{$pid}{dir}, $opt{fileprefix} || "<longname> - <episode> <pid> <version>" );
- 	logger "\rINFO: File name prefix = $prog{$pid}{fileprefix}                 \n";
--	$prog{$pid}{dir} = $dir;
--	my $file_done = "${dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
--	my $file = "${dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
-+	my $file_done = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.$prog{$pid}{ext}";
-+	my $file = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.partial.$prog{$pid}{ext}";
- 	$prog{$pid}{filename} = $file_done;
- 	if ( -f $file_done ) {
--		logger "WARNING: File $file_done already exists\n\n";
--		return 1;
-+		logger "ERROR: File $file_done already exists\n\n";
-+		return 'abort';
- 	}
- 
-+	# Skip from here if we are only testing downloads
-+	return 'abort' if $opt{test};
-+
- 	# Create symlink filename if required
- 	my $file_symlink;
- 	if ( $opt{symlink} ) {
-@@ -1581,53 +2189,34 @@
- 		$file_symlink = substitute_fields( $pid, $opt{symlink} );
- 	}
- 
--	# Skip from here if we are only testing downloads
--	return 1 if $opt{test};
--
--	# Get subtitles if they exist and are required
-+	# Get subtitles if they exist and are required 
-+	# best to do this before d/l of file so that the subtitles can be enjoyed while download progresses
- 	my $subfile_done;
- 	my $subfile;
- 	if ( $opt{subtitles} ) {
--		$subfile_done = "${dir}/$prog{$pid}{fileprefix}.srt";
--		$subfile = "${dir}/$prog{$pid}{fileprefix}.partial.srt";
--		download_subtitles( $ua, $subfile, $version_pids{ $prog{$pid}{version} } );
-+		$subfile_done = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.srt";
-+		$subfile = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}.partial.srt";
-+		$ua->proxy( ['http'] => undef ) if $opt{partialproxy};
-+		download_stream_subtitles( $ua, $subfile, $version_pids{ $prog{$pid}{version} } );
-+		$ua->proxy( ['http'] => $proxy_url ) if $opt{partialproxy};
- 	}
- 
- 	my $return;
- 	# Do rtmp download
--	if ( $opt{rtmp} ) {
--		# Get player url
--		my %metadata = get_pid_metadata( $ua, $pid );
--		# get this redirected page and find out where it is redirected to
--		my ($ub, $request, $response, $prog_url);
--		$ub = new LWP::UserAgent;
--		$request = new HTTP::Request HEAD => $metadata{player};
--		$response = $ub->request($request);
--		$prog_url = $response->request->url;
--		$return = download_h264_rtmp_stream( $ua, $url_2, $prog_url, $file, $file_done, $file_symlink );
-+	if ( $mode =~ /^(rtmp|flash)/ ) {
-+		$return = download_stream_rtmp( $ua, $streamdata{streamurl}, $pid, $mode, $streamdata{application}, $streamdata{tcurl}, $streamdata{authstring}, $streamdata{swfurl}, $file, $file_done, $file_symlink );
- 
- 	# Do the N95 h.264 download
--	} elsif ( $opt{n95} ) {
--		my $url = get_media_stream_data( $pid, $version_pids{ $prog{$pid}{version} }, 'n95_wifi' );
--		$return = download_h264_low_stream( $ua, $url, $file, $file_done );
-+	} elsif ( $mode =~ /^n95/ ) {
-+		$return = download_stream_h264_low( $ua, $url_2, $file, $file_done, $pid, $mode );
- 
- 	# Do the iPhone h.264 download
--	} elsif ( $prog{$pid}{type} eq 'tv' ) {
--		# Disable proxy here if required
--		$ua->proxy( ['http'] => undef ) if $opt{partialproxy};
--		$return = download_iphone_stream( $ua, $url_2, $file, $file_done, $file_symlink, 1 );
--		# Re-enable proxy here if required
--		$ua->proxy( ['http'] => $proxy_url ) if $opt{partialproxy};
--
--	# Do the iPhone mp3 download
--	} elsif ( $prog{$pid}{type} eq 'radio' ) {
-+	} else {
- 		# Disable proxy here if required
- 		$ua->proxy( ['http'] => undef ) if $opt{partialproxy};
--		$return = download_iphone_stream( $ua, $url_2, $file, $file_done, $file_symlink, 0 );
-+		$return = download_stream_iphone( $ua, $url_2, $pid, $file, $file_done, $file_symlink, 1 );
- 		# Re-enable proxy here if required
- 		$ua->proxy( ['http'] => $proxy_url ) if $opt{partialproxy};
--		# If the iphone mp3 download fails then it's probably not ready yet so retry using realaudio
--		$opt{realaudio} = 1 if $return eq 'retry';
- 	}
- 	
- 	# Rename the subtitle file accordingly
-@@ -1647,13 +2236,12 @@
- 
- 
- # Download Subtitles, convert to srt(SubRip) format and apply time offset
--sub download_subtitles {
-+sub download_stream_subtitles {
- 	my ( $ua, $file, $verpid ) = @_;
- 	my $suburl;
- 	my $subs;
- 	logger "INFO: Getting Subtitle metadata for $verpid\n" if $opt{verbose};
--	$suburl = get_media_stream_data( undef, $verpid, 'subtitles' );
--
-+	$suburl = %{get_media_stream_data( undef, $verpid, 'subtitles')}->{streamurl};
- 	# Return if we have no url
- 	if (! $suburl) {
- 		logger "INFO: Subtitles not available\n";
-@@ -1793,12 +2381,12 @@
- 
- 	# Get title
- 	# <title>Amazon with Bruce Parry: Episode 1</title>
--	my ( $title, $type );
-+	my ( $title, $prog_type );
- 	$title = $1 if $xml =~ m{<title>\s*(.+?)\s*<\/title>};
- 
- 	# Get type
--	$type = 'tv' if grep /kind="programme"/, $xml;
--	$type = 'radio' if grep /kind="radioProgramme"/, $xml;
-+	$prog_type = 'tv' if grep /kind="programme"/, $xml;
-+	$prog_type = 'radio' if grep /kind="radioProgramme"/, $xml;
- 
- 	# Split into <item kind="programme"> sections
- 	for ( split /<item\s+kind="(radioProgramme|programme)"/, $xml ) {
-@@ -1812,310 +2400,389 @@
- 		$version_pids{$version} = $verpid;
- 		logger "INFO: Version: $version, VersionPid: $verpid\n" if $opt{verbose};  
- 	}
-+
-+	# Extract Long Name, e.g.: iplayer.episode.setTitle("DIY SOS: Series 16: Swansea"), Strip off the episode name
-+	$title =~ s/^(.+):.*?$/$1/g;
-+
- 	# Add to prog hash
- 	$prog{$pid}{versions} = join ',', keys %version_pids;
--	return ( $type, $title, %version_pids );
-+	return ( $prog_type, $title, %version_pids );
- }
- 
- 
- 
- # Gets media streams data for this version pid
--# $media = all|flashhigh|flashnormal|iphone|flashwii|n95_wifi|n95_3g|mobile|flashaudio|realaudio|wma|subtitles
-+# $media = all|itv|flashhigh|flashnormal|iphone|flashwii|n95_wifi|n95_3g|mobile|flashaudio|realaudio|wma|subtitles
- sub get_media_stream_data {
- 	my ( $pid, $verpid, $media ) = @_;
--	my %streams;
--	my $ua = LWP::UserAgent->new();
-+	my %data;
-+
- 	# Setup user agent with redirection enabled
--	$ua->timeout([$lwp_request_timeout]);
--	$ua->proxy( ['http'] => $proxy_url );
--	$ua->cookie_jar( HTTP::Cookies->new( file => $cookiejar, autosave => 1, ignore_discard => 1 ) );
-+	my $ua = create_ua('desktop');
- 	$opt{quiet} = 0 if $opt{streaminfo};
--	logger "INFO: Getting media stream metadata for $prog{$pid}{name} - $prog{$pid}{episode}, $verpid\n" if $pid;
--	my $xml1 = request_url_retry($ua, $media_stream_data_prefix.$verpid, 3, '', '');
--	logger "\n$xml1\n" if $opt{debug};
--	# flatten
--	$xml1 =~ s/\n/ /g;
- 
--	for my $xml ( split /<media/, $xml1 ) {
--		$xml = "<media".$xml;
-+	# ITV streams
-+	if ( $prog{$pid}{type} eq 'itv' ) {
-+		my $prog_type = 'itv';
-+		$data{$prog_type}{type} = 'ITV ASF Video stream';
-+		$opt{quiet} = 1 if $opt{streaminfo};
-+		$data{$prog_type}{streamurl} = join('|', get_stream_url_itv($ua, $pid) );
-+		$opt{quiet} = 0 if $opt{streaminfo};
-+
-+	# BBC streams
-+	} else {
-+		my $xml1 = request_url_retry($ua, $media_stream_data_prefix.$verpid, 3, '', '');
-+		logger "\n$xml1\n" if $opt{debug};
-+		# flatten
-+		$xml1 =~ s/\n/ /g;
-+		
-+		for my $xml ( split /<media/, $xml1 ) {
-+			$xml = "<media".$xml;
-+			my $prog_type;
-+			
-+			# h.264 high quality stream
-+			#	<media kind="video"
-+			#        width="640"
-+			#        height="360"
-+			#        type="video/mp4"
-+			#        encoding="h264"  >
-+			#        <connection
-+			#                priority="10"
-+			#                application="bbciplayertok"
-+			#                kind="level3"
-+			#                server="bbciplayertokfs.fplive.net"
-+			#                identifier="mp4:b000zxf4-H26490898078"
-+			#                authString="[REDACTED]"
-+			#        />
-+			# application: bbciplayertok
-+			# tcURL: rtmp://bbciplayertokfs.fplive.net:80/bbciplayertok
-+			if ( $media =~ /^(flashhigh|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/mp4".+?encoding="h264".+?application="(.+?)".+?kind="level3"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
-+				$prog_type = 'flashhigh';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{application}, $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{authstring} ) = ( $1, $2, $3, $4 );
-+				$data{$prog_type}{type} = 'Flash RTMP H.264 high quality stream';
-+				$data{$prog_type}{tcurl} = "rtmp://$data{$prog_type}{server}:80/$data{$prog_type}{application}";
-+				$data{$prog_type}{swfurl} = "http://www.bbc.co.uk/emp/9player.swf?revision=7276";
-+				$data{$prog_type}{streamurl} = "rtmp://$data{$prog_type}{server}:1935/ondemand?_fcs_vhost=$data{$prog_type}{server}&auth=$data{$prog_type}{authstring}&aifp=v001&slist=$data{$prog_type}{identifier}";
-+			}
-+			
-+			# h.264 normal quality stream
-+			#	<media kind="video"
-+			#        width="640"
-+			#        height="360"
-+			#        type="video/x-flv"
-+			#        encoding="vp6"  >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="akamai"
-+			#                server="cp41752.edgefcs.net"
-+			#                identifier="secure/b000zxf4-streaming90898078"
-+			#                authString="[REDACTED]"
-+			#        />
-+			#	</media>
-+			#
-+			# application (e.g.):            ondemand?_fcs_vhost=cp41752.edgefcs.net&auth=daEcia8aQaRardxdwb_dCbvc0cPbLavc2cL-bjw5rj-cCp-JnlDCnzn.MEqHpxF&aifp=v001&slist=secure/b000gy717streaming103693754
-+			# tcURL: rtmp://88.221.26.165:80/ondemand?_fcs_vhost=cp41752.edgefcs.net&auth=daEcia8aQaRardxdwb_dCbvc0cPbLavc.2cL-bjw5rj-cCp-JnlDCnznMEqHpxF&aifp=v001&slist=secure/b000gy717streaming103693754
-+			if ( $media =~ /^(flashnormal|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/x-flv".+?encoding="vp6".+?kind="akamai"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
-+				$prog_type = 'flashnormal';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{authstring} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{application} = "ondemand?_fcs_vhost=$data{$prog_type}{server}&auth=$data{$prog_type}{authstring}&aifp=v001&slist=$data{$prog_type}{identifier}";
-+				$data{$prog_type}{type} = 'Flash RTMP H.264 normal quality stream';
-+				$data{$prog_type}{tcurl} = "rtmp://$data{$prog_type}{server}:80/$data{$prog_type}{application}";
-+				$data{$prog_type}{swfurl} = "http://www.bbc.co.uk/emp/9player.swf?revision=7276";
-+				$data{$prog_type}{streamurl} = "rtmp://$data{$prog_type}{server}:1935/ondemand?_fcs_vhost=$data{$prog_type}{server}&auth=$data{$prog_type}{authstring}&aifp=v001&slist=$data{$prog_type}{identifier}";
-+			}
-+			
-+			# Wii h.264 standard quality stream
-+			#<media kind="video"
-+			#        width="512"
-+			#        height="288"
-+			#        type="video/x-flv"
-+			#        encoding="spark"  >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="akamai"
-+			#                server="cp41752.edgefcs.net"
-+			#                identifier="secure/5242138581547639062"
-+			#                authString="[REDACTED]"
-+			#        />
-+			#</media>
-+			# application (e.g.):               ondemand?_fcs_vhost=cp41752.edgefcs.net&auth=daEcpc6cYbhdIakdWduc6bJdPbydbazdmdp-bjxPBF-cCp-GptFAoDqJBnHvzC&aifp=v001&slist=secure/b000g884xstreaming101052333
-+			# tcURL: rtmp: //88.221.26.173:1935/ondemand?_fcs_vhost=cp41752.edgefcs.net&auth=daEcpc6cYbhdIakdWduc6bJdPbydbazdmdp-bjxPBF-cCp-GptFAoDqJBnHvzC&aifp=v001&slist=secure/b000g884xstreaming101052333
-+			# swfUrl: http://www.bbc.co.uk/emp/iplayer/7player.swf?revision=3897
-+			if ( $media =~ /^(flashwii|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/x-flv".+?encoding="spark".+?kind="akamai"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
-+				$prog_type = 'flashwii';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{authstring} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{application} = "ondemand?_fcs_vhost=$data{$prog_type}{server}&auth=$data{$prog_type}{authstring}&aifp=v001&slist=$data{$prog_type}{identifier}";
-+				$data{$prog_type}{type} = 'Flash RTMP H.264 Wii stream';
-+				$data{$prog_type}{tcurl} = "rtmp://$data{$prog_type}{server}:1935/$data{$prog_type}{application}";
-+				$data{$prog_type}{swfurl} = "http://www.bbc.co.uk/emp/iplayer/7player.swf?revision=3897";
-+				$data{$prog_type}{streamurl} = "rtmp://$data{$prog_type}{server}:1935/ondemand?_fcs_vhost=$data{$prog_type}{server}&auth=$data{$prog_type}{authstring}&aifp=v001&slist=$data{$prog_type}{identifier}";
-+			}
-+		
-+			# iPhone h.264/mp3 stream
-+			#<media kind="video"
-+			#        width="480"
-+			#        height="272"
-+			#        type="video/mp4"
-+			#        encoding="h264"  >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="sis"
-+			#                server="http://www.bbc.co.uk/mediaselector/3/auth/stream/"
-+			#                identifier="5242138581547639062"
-+			#                href="http://www.bbc.co.uk/mediaselector/3/auth/stream/5242138581547639062.mp4"
-+			#        />
-+			#</media>
-+			if ( $media =~ /^(iphone|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/mp4".+?encoding="h264".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
-+				$prog_type = 'iphone';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{streamurl} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{type} = 'iPhone stream';
-+			}
-+		
-+			# Nokia N95 h.264 low quality stream (WiFi)
-+			#<media kind="video"
-+			#        type="video/mpeg"
-+			#        encoding="h264"  >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="sis"
-+			#                server="http://www.bbc.co.uk/mediaselector/4/sdp/"
-+			#                identifier="b00108ld/iplayer_streaming_n95_wifi"
-+			#                href="http://www.bbc.co.uk/mediaselector/4/sdp/b00108ld/iplayer_streaming_n95_wifi"
-+			#        />
-+			#</media>
-+			if ( $media =~ /^(n95_wifi|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/mpeg".+?encoding="h264".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
-+				$prog_type = 'n95_wifi';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{href} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{type} = 'Nokia N95 h.264 low quality WiFi stream';
-+				$opt{quiet} = 1 if $opt{streaminfo};
-+				chomp( $data{$prog_type}{streamurl} = request_url_retry($ua, $data{$prog_type}{href}, 2, '', '') );
-+				$opt{quiet} = 0 if $opt{streaminfo};
-+			}
-+		
-+			# Nokia N95 h.264 low quality stream (3G)
-+			#<media kind="" 
-+			#        expires="2008-10-30T12:29:00+00:00"
-+			#        type="video/mpeg"                  
-+			#        encoding="h264"  >                 
-+			#        <connection                        
-+			#                priority="10"              
-+			#                kind="sis"                 
-+			#                server="http://www.bbc.co.uk/mediaselector/4/sdp/" 
-+			#                identifier="b009tzxx/iplayer_streaming_n95_3g"     
-+			#                href="http://www.bbc.co.uk/mediaselector/4/sdp/b009tzxx/iplayer_streaming_n95_3g" 
-+			#        />                                                                                        
-+			#</media>    
-+			if ( $media =~ /^(n95_3g|all)$/ && $xml =~ m{<media\s+kind="".+?type="video/mpeg".+?encoding="h264".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
-+				$prog_type = 'n95_3g';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{href} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{type} = 'Nokia N95 h.264 low quality 3G stream';
-+				$opt{quiet} = 1 if $opt{streaminfo};
-+				chomp( $data{$prog_type}{streamurl} = request_url_retry($ua, $data{$prog_type}{href}, 2, '', '') );
-+				$opt{quiet} = 0 if $opt{streaminfo};
-+			}
-+		
-+			# Mobile WMV DRM
-+			#<media kind="video"
-+			#        expires="2008-10-20T21:59:00+01:00"
-+			#        type="video/wmv"   >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="licence"
-+			#                server="http://iplayldsvip.iplayer.bbc.co.uk/WMLicenceIssuer/LicenceDelivery.asmx"
-+			#                identifier="0A1CA43B-98A8-43EA-B684-DA06672C0575"
-+			#                href="http://iplayldsvip.iplayer.bbc.co.uk/WMLicenceIssuer/LicenceDelivery.asmx/0A1CA43B-98A8-43EA-B684-DA06672C0575"
-+			#        />
-+			#<connection
-+			#                priority="10"
-+			#                kind="sis"
-+			#                server="http://directdl.iplayer.bbc.co.uk/windowsmedia/"
-+			#                identifier="AmazonwithBruceParry_Episode5_200810132100_mobile"
-+			#                href="http://directdl.iplayer.bbc.co.uk/windowsmedia/AmazonwithBruceParry_Episode5_200810132100_mobile.wmv"
-+			#        />
-+			#</media>
-+			if ( $media =~ /^(mobile|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/wmv".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
-+				$prog_type = 'mobile';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{streamurl} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{type} = 'Mobile WMV DRM stream';
-+			}
-+		
-+			# Audio rtmp mp3
-+			#<media kind="audio"
-+			#        type="audio/mpeg"
-+			#        encoding="mp3"  >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="akamai"
-+			#                server="cp48181.edgefcs.net"
-+			#                identifier="mp3:secure/radio1/RBN2_mashup_b00d67h9_2008_09_05_22_14_25"
-+			#                authString="[REDACTED]"
-+			#        />
-+			#</media>
-+			#app: ondemand?_fcs_vhost=cp48181.edgefcs.net&auth=daEasducLbidOancObacmc0amd6d7ana8c6-bjx.9v-cCp-JqlFHoEq.FBqGnxC&aifp=v001&slist=secure/radio1/RBN2_radio_1_-_wednesday_1000_b00g3xcj_2008_12_31_13_21_49
-+			#swfUrl: http://www.bbc.co.uk/emp/9player.swf?revision=7276
-+			#tcUrl: rtmp://92.122.210.173:1935/ondemand?_fcs_vhost=cp48181.edgefcs.net&auth=daEasducLbidOancObacmc0amd6d7ana8c6-bjx.9v-cCp-JqlFHoEqFBqGnxC&aifp=v001&slist=secure/radio1/RBN2_radio_1_-_wednesday_1.000_b00g3xcj_2008_12_31_13_21_49
-+			#pageUrl: http://www.bbc.co.uk/iplayer/episode/b00g3xp7/Annie_Mac_31_12_2008/
-+			if ( $media =~ /^(flashaudio|all)$/ && $xml =~ m{<media\s+kind="audio".+?type="audio/mpeg".+?encoding="mp3".+?kind="akamai"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
-+				$prog_type = 'flashaudio';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{authstring} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{streamurl} = "rtmp://$data{$prog_type}{server}:1935/ondemand?_fcs_vhost=$data{$prog_type}{server}&auth=$data{$prog_type}{authstring}&aifp=v001&slist=$data{$prog_type}{identifier}";
-+				# Remove offending mp3: at the start of the identifier (don't remove in stream url)
-+				$data{$prog_type}{identifier} =~ s/^mp3://;
-+				$data{$prog_type}{application} = "ondemand?_fcs_vhost=$data{$prog_type}{server}&auth=$data{$prog_type}{authstring}&aifp=v001&slist=$data{$prog_type}{identifier}";
-+				$data{$prog_type}{type} = 'RTMP MP3 stream';
-+				$data{$prog_type}{tcurl} = "rtmp://$data{$prog_type}{server}:1935/$data{$prog_type}{application}";
-+				$data{$prog_type}{swfurl} = "http://www.bbc.co.uk/emp/9player.swf?revision=7276";
-+			}
-+		
-+			# RealAudio stream
-+			#<media kind="audio"
-+			#       type="audio/real"
-+			#        encoding="real"  >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="sis"
-+			#                server="http://www.bbc.co.uk"
-+			#                identifier="/radio/aod/playlists/9h/76/d0/0b/2000_bbc_radio_one"
-+			#                href="http://www.bbc.co.uk/radio/aod/playlists/9h/76/d0/0b/2000_bbc_radio_one.ram"
-+			#        />
-+			#</media>
-+			# Realaudio for worldservice	
-+			#<media kind=""
-+			#type="audio/real"
-+			#encoding="real"  >
-+			#<connection
-+			#        priority="10"
-+			#        kind="edgesuite"
-+			#        server="http://http-ws.bbc.co.uk.edgesuite.net"
-+			#        identifier="/generatecssram.esi?file=/worldservice/css/nb/410060838.ra"
-+			#        href="http://http-ws.bbc.co.uk.edgesuite.net/generatecssram.esi?file=/worldservice/css/nb/410060838.ra"
-+			#/>
-+			#</media>
-+			#</mediaSelection>
-+			if ( $media =~ /^(realaudio|all)$/ && $xml =~ m{<media\s+kind="(audio|)".+?type="audio/real".+?encoding="real".+?kind="(sis|edgesuite)"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
-+				$prog_type = 'realaudio';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{href} ) = ( $3, $4, $5 );
-+				$data{$prog_type}{type} = 'RealAudio RTSP stream';
-+				$opt{quiet} = 1 if $opt{streaminfo};
-+				chomp( $data{$prog_type}{streamurl} = request_url_retry($ua, $data{$prog_type}{href}, 2, '', '') );
-+				$data{$prog_type}{streamurl} =~ s/[\s\n]//g;
-+				$opt{quiet} = 0 if $opt{streaminfo};
-+			}
-+		
-+			# Radio WMA (low quality)
-+			#<mediaSelection xmlns="http://bbc.co.uk/2008/mp/mediaselection">
-+			#<media kind=""
-+			#        type="audio/wma"
-+			#        encoding="wma"  >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="edgesuite"
-+			#                server="http://http-ws.bbc.co.uk.edgesuite.net"
-+			#                identifier="/generatecssasx.esi?file=/worldservice/css/nb/410060838"
-+			#                href="http://http-ws.bbc.co.uk.edgesuite.net/generatecssasx.esi?file=/worldservice/css/nb/410060838.wma"
-+			#        />
-+			#</media>
-+			if ( $media =~ /^(wma|all)$/ && $xml =~ m{<media\s+kind="(audio|)".+?type="audio/wma".+?encoding="wma".+?kind="(sis|edgesuite)"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
-+				$prog_type = 'wma';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{href} ) = ( $3, $4, $5 );
-+				$data{$prog_type}{type} = 'WMA MMS stream';
-+				$opt{quiet} = 1 if $opt{streaminfo};
-+				chomp( $data{$prog_type}{streamurl} = request_url_retry($ua, $data{$prog_type}{href}, 2, '', '') );
-+				$data{$prog_type}{streamurl} =~ s/[\s\n]//g;
-+				# HREF="mms://a1899.v394403.c39440.g.vm.akamaistream.net/7/1899/39440/1/bbcworldservice.download.akamai.com/39440//worldservice/css/nb/410060838.wma"
-+				$data{$prog_type}{streamurl} =~ s/^.*href=\"(.+?)\".*$/$1/gi;
-+				$opt{quiet} = 0 if $opt{streaminfo};
-+			}
-+		
-+			# Subtitles stream
-+			#<media kind="captions"
-+			#        type="application/ttaf+xml"   >
-+			#        <connection
-+			#                priority="10"
-+			#                kind="http"
-+			#                server="http://www.bbc.co.uk/iplayer/subtitles/"
-+			#                identifier="b0008dc8rstreaming89808204.xml"
-+			#                href="http://www.bbc.co.uk/iplayer/subtitles/b0008dc8rstreaming89808204.xml"
-+			#        />
-+			#</media>
-+			if ( $media =~ /^(subtitles|all)$/ && $xml =~ m{<media\s+kind="captions".+?type="application/ttaf\+xml".+?kind="http"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
-+				$prog_type = 'subtitles';
-+				logger "DEBUG: Processing $prog_type stream\n" if $opt{verbose};
-+				( $data{$prog_type}{server}, $data{$prog_type}{identifier}, $data{$prog_type}{streamurl} ) = ( $1, $2, $3 );
-+				$data{$prog_type}{type} = 'Subtitles stream';
-+			}	
-+		}
-+		# Do iphone redirect check regardless of an xml entry for iphone - sometimes the iphone streams exist regardless
-+		if ( my $streamurl = get_stream_url_iphone($ua, $verpid) ) {
-+			my $prog_type = 'iphone';
-+			$data{$prog_type}{type} = 'iPhone stream';
-+			# Get iphone redirect
-+			$data{$prog_type}{streamurl} = $streamurl;
-+		} else {
-+			logger "DEBUG: No iphone redirect stream\n" if $opt{verbose};
-+		}
-+
-+	}
-+	# Return a hash with media => url if 'all' is specified - otherwise just the specified url
-+	if ( $media eq 'all' ) {
-+		return %data;
-+	} else {
-+		# Make sure this hash exists before we pass it back...
-+		$data{$media}{exists} = 0 if not defined $data{$media};
-+		return $data{$media};
-+	}
-+}
-+
- 
--		my ($server, $authstring, $identifier, $href);
- 
--		# h.264 high quality stream
--		#	<media kind="video"
--		#        width="640"
--		#        height="360"
--		#        type="video/mp4"
--		#        encoding="h264"  >
--		#        <connection
--		#                priority="10"
--		#                application="bbciplayertok"
--		#                kind="level3"
--		#                server="bbciplayertokfs.fplive.net"
--		#                identifier="mp4:b000zxf4-H26490898078"
--		#                authString="[REDACTED]"
--		#        />
--		if ( $media =~ /^(flashhigh|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/mp4".+?encoding="h264".+?kind="level3"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
--			( $server, $identifier, $authstring ) = ( $1, $2, $3 );
--			logger "INFO: RTMP h.264 high quality stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  authstring=$authstring\n" if $opt{verbose};
--			$streams{'flashhigh'} = "rtmp://${server}:1935/ondemand?_fcs_vhost=${server}&auth=${authstring}&aifp=v001&slist=${identifier}";
--			logger "INFO: RTMP high quality stream URL: $streams{'flashhigh'}\n";
--		}
--
--		# h.264 normal quality stream
--		#	<media kind="video"
--		#        width="512"
--		#        height="288"
--		#        type="video/x-flv"
--		#        encoding="vp6"  >
--		#        <connection
--		#                priority="10"
--		#                kind="akamai"
--		#                server="cp41752.edgefcs.net"
--		#                identifier="secure/b000zxf4-streaming90898078"
--		#                authString="[REDACTED]"
--		#        />
--		#	</media>
--		#
--		if ( $media =~ /^(flashnormal|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/x-flv".+?encoding="vp6".+?kind="akamai"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
--			( $server, $identifier, $authstring ) = ( $1, $2, $3 );
--			logger "INFO: RTMP h.264 normal quality stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  authstring=$authstring\n" if $opt{verbose};
--			$streams{'flashnormal'} = "rtmp://${server}:1935/ondemand?_fcs_vhost=${server}&auth=${authstring}&aifp=v001&slist=${identifier}";
--			logger "INFO: RTMP normal quality stream URL: $streams{'flashnormal'}\n";
--		}
--	
--		# Wii h.264 standard quality stream
--		#<media kind="video"
--		#        width="512"
--		#        height="288"
--		#        type="video/x-flv"
--		#        encoding="spark"  >
--		#        <connection
--		#                priority="10"
--		#                kind="akamai"
--		#                server="cp41752.edgefcs.net"
--		#                identifier="secure/5242138581547639062"
--		#                authString="[REDACTED]"
--		#        />
--		#</media>
--		if ( $media =~ /^(flashwii|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/x-flv".+?encoding="spark".+?kind="akamai"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
--			( $server, $identifier, $authstring ) = ( $1, $2, $3 );
--			logger "INFO: RTMP Wii normal quality stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  authstring=$authstring\n" if $opt{verbose};
--			$streams{'flashwii'} = "rtmp://${server}:1935/ondemand?_fcs_vhost=${server}&auth=${authstring}&aifp=v001&slist=${identifier}";
--			logger "INFO: RTMP Wii normal quality stream URL: $streams{'flashwii'}\n";
--		}
--	
--		# iPhone h.264/mp3 stream
--		#<media kind="video"
--		#        width="480"
--		#        height="272"
--		#        type="video/mp4"
--		#        encoding="h264"  >
--		#        <connection
--		#                priority="10"
--		#                kind="sis"
--		#                server="http://www.bbc.co.uk/mediaselector/3/auth/stream/"
--		#                identifier="5242138581547639062"
--		#                href="http://www.bbc.co.uk/mediaselector/3/auth/stream/5242138581547639062.mp4"
--		#        />
--		#</media>
--		if ( $media =~ /^(iphone|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/mp4".+?encoding="h264".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
--			( $server, $identifier, $href ) = ( $1, $2, $3 );
--			logger "INFO: iPhone stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  href=$href\n" if $opt{verbose};
--			$streams{'iphone'} = "$href";
--			logger "INFO: iPhone stream URL: $streams{'iphone'}\n";
--		}
--	
--		# Nokia N95 h.264 low quality stream (WiFi)
--		#<media kind="video"
--		#        type="video/mpeg"
--		#        encoding="h264"  >
--		#        <connection
--		#                priority="10"
--		#                kind="sis"
--		#                server="http://www.bbc.co.uk/mediaselector/4/sdp/"
--		#                identifier="b00108ld/iplayer_streaming_n95_wifi"
--		#                href="http://www.bbc.co.uk/mediaselector/4/sdp/b00108ld/iplayer_streaming_n95_wifi"
--		#        />
--		#</media>
--		if ( $media =~ /^(n95_wifi|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/mpeg".+?encoding="h264".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
--			( $server, $identifier, $href ) = ( $1, $2, $3 );
--			$opt{quiet} = 1 if $opt{streaminfo};
--			chomp( my $rtsp = request_url_retry($ua, $href, 2, '', '') );
--			$opt{quiet} = 0 if $opt{streaminfo};
--			logger "INFO: Nokia N95 h.264 low quality WiFi stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  href=$href\n" if $opt{verbose};
--			$streams{'n95_wifi'} = "$rtsp";
--			logger "INFO: Nokia N95 h.264 low quality WiFi stream URL: $streams{'n95_wifi'}\n";
--		}
--	
--		# Nokia N95 h.264 low quality stream (3G)
--		#<media kind="" 
--		#        expires="2008-10-30T12:29:00+00:00"
--		#        type="video/mpeg"                  
--		#        encoding="h264"  >                 
--		#        <connection                        
--		#                priority="10"              
--		#                kind="sis"                 
--		#                server="http://www.bbc.co.uk/mediaselector/4/sdp/" 
--		#                identifier="b009tzxx/iplayer_streaming_n95_3g"     
--		#                href="http://www.bbc.co.uk/mediaselector/4/sdp/b009tzxx/iplayer_streaming_n95_3g" 
--		#        />                                                                                        
--		#</media>    
--		if ( $media =~ /^(n95_3g|all)$/ && $xml =~ m{<media\s+kind="".+?type="video/mpeg".+?encoding="h264".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
--			( $server, $identifier, $href ) = ( $1, $2, $3 );
--			$opt{quiet} = 1 if $opt{streaminfo};
--			chomp( my $rtsp = request_url_retry($ua, $href, 2, '', '') );
--			$opt{quiet} = 0 if $opt{streaminfo};
--			logger "INFO: Nokia N95 h.264 low quality 3G stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  href=$href\n" if $opt{verbose};
--			$streams{'n95_3g'} = "$rtsp";
--			logger "INFO: Nokia N95 h.264 low quality 3G stream URL: $streams{'n95_3g'}\n";
--		}
--	
--	
--	
--		# Mobile WMV DRM
--		#<media kind="video"
--		#        expires="2008-10-20T21:59:00+01:00"
--		#        type="video/wmv"   >
--		#        <connection
--		#                priority="10"
--		#                kind="licence"
--		#                server="http://iplayldsvip.iplayer.bbc.co.uk/WMLicenceIssuer/LicenceDelivery.asmx"
--		#                identifier="0A1CA43B-98A8-43EA-B684-DA06672C0575"
--		#                href="http://iplayldsvip.iplayer.bbc.co.uk/WMLicenceIssuer/LicenceDelivery.asmx/0A1CA43B-98A8-43EA-B684-DA06672C0575"
--		#        />
--		#<connection
--		#                priority="10"
--		#                kind="sis"
--		#                server="http://directdl.iplayer.bbc.co.uk/windowsmedia/"
--		#                identifier="AmazonwithBruceParry_Episode5_200810132100_mobile"
--		#                href="http://directdl.iplayer.bbc.co.uk/windowsmedia/AmazonwithBruceParry_Episode5_200810132100_mobile.wmv"
--		#        />
--		#</media>
--		if ( $media =~ /^(mobile|all)$/ && $xml =~ m{<media\s+kind="video".+?type="video/wmv".+?kind="sis"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
--			( $server, $identifier, $href ) = ( $1, $2, $3 );
--			logger "INFO: Mobile WMV DRM stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  href=$href\n" if $opt{verbose};
--			$streams{'mobile'} = "$href";
--			logger "INFO: Mobile WMV DRM stream URL: $streams{'mobile'}\n";
--		}
--	
--		# Audio rtmp mp3
--		#<media kind="audio"
--		#        type="audio/mpeg"
--		#        encoding="mp3"  >
--		#        <connection
--		#                priority="10"
--		#                kind="akamai"
--		#                server="cp48181.edgefcs.net"
--		#                identifier="mp3:secure/radio1/RBN2_mashup_b00d67h9_2008_09_05_22_14_25"
--		#                authString="[REDACTED]"
--		#        />
--		#</media>
--		if ( $media =~ /^(flashaudio|all)$/ && $xml =~ m{<media\s+kind="audio".+?type="audio/mpeg".+?encoding="mp3".+?kind="akamai"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?authString="(.+?)"} ) {
--			( $server, $identifier, $authstring ) = ( $1, $2, $3 );
--			# Remove offending mp3: at the start of the identifier
--			$identifier =~ s/^mp3://;
--			logger "INFO: RTMP MP3 stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  authstring=$authstring\n" if $opt{verbose};
--			$streams{'flashaudio'} = "rtmp://${server}:1935/ondemand?_fcs_vhost=${server}&auth=${authstring}&aifp=v001&slist=${identifier}";
--			logger "INFO: RTMP stream URL: $streams{'flashaudio'}\n";
--		}
--	
--		# RealAudio stream
--		#<media kind="audio"
--		#       type="audio/real"
--		#        encoding="real"  >
--		#        <connection
--		#                priority="10"
--		#                kind="sis"
--		#                server="http://www.bbc.co.uk"
--		#                identifier="/radio/aod/playlists/9h/76/d0/0b/2000_bbc_radio_one"
--		#                href="http://www.bbc.co.uk/radio/aod/playlists/9h/76/d0/0b/2000_bbc_radio_one.ram"
--		#        />
--		#</media>
--		# Realaudio for worldservice	
--		#<media kind=""
--		#type="audio/real"
--		#encoding="real"  >
--		#<connection
--		#        priority="10"
--		#        kind="edgesuite"
--		#        server="http://http-ws.bbc.co.uk.edgesuite.net"
--		#        identifier="/generatecssram.esi?file=/worldservice/css/nb/410060838.ra"
--		#        href="http://http-ws.bbc.co.uk.edgesuite.net/generatecssram.esi?file=/worldservice/css/nb/410060838.ra"
--		#/>
--		#</media>
--		#</mediaSelection>
--		if ( $media =~ /^(realaudio|all)$/ && $xml =~ m{<media\s+kind="(audio|)".+?type="audio/real".+?encoding="real".+?kind="(sis|edgesuite)"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
--			( $server, $identifier, $href ) = ( $3, $4, $5 );
--			$opt{quiet} = 1 if $opt{streaminfo};
--			chomp( my $rtsp = request_url_retry($ua, $href, 2, '', '') );
--			$rtsp =~ s/[\s\n]//g;
--			$opt{quiet} = 0 if $opt{streaminfo};
--			logger "INFO: RealAudio RTSP stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  href=$href\n" if $opt{verbose};
--			$streams{'realaudio'} = "$rtsp";
--			logger "INFO: RealAudio RTSP stream URL: $streams{'realaudio'}\n";
--		}
--	
--	
--		# Radio WMA (low quality)
--		#<mediaSelection xmlns="http://bbc.co.uk/2008/mp/mediaselection">
--		#<media kind=""
--		#        type="audio/wma"
--		#        encoding="wma"  >
--		#        <connection
--		#                priority="10"
--		#                kind="edgesuite"
--		#                server="http://http-ws.bbc.co.uk.edgesuite.net"
--		#                identifier="/generatecssasx.esi?file=/worldservice/css/nb/410060838"
--		#                href="http://http-ws.bbc.co.uk.edgesuite.net/generatecssasx.esi?file=/worldservice/css/nb/410060838.wma"
--		#        />
--		#</media>
--		if ( $media =~ /^(wma|all)$/ && $xml =~ m{<media\s+kind="(audio|)".+?type="audio/wma".+?encoding="wma".+?kind="(sis|edgesuite)"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
--			( $server, $identifier, $href ) = ( $3, $4, $5 );
--			$opt{quiet} = 1 if $opt{streaminfo};
--			chomp( my $mms = request_url_retry($ua, $href, 2, '', '') );
--			$mms =~ s/[\n]//g;
--			# HREF="mms://a1899.v394403.c39440.g.vm.akamaistream.net/7/1899/39440/1/bbcworldservice.download.akamai.com/39440//worldservice/css/nb/410060838.wma"
--			$mms =~ s/^.*href=\"(.+?)\".*$/$1/gi;
--			$opt{quiet} = 0 if $opt{streaminfo};
--			logger "INFO: WMA MMS stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  href=$href\n" if $opt{verbose};
--			$streams{'wma'} = "$mms";
--			logger "INFO: WMA MMS stream URL: $streams{'wma'}\n";
--		}
--	
--	
--		# Subtitles stream
--		#<media kind="captions"
--		#        type="application/ttaf+xml"   >
--		#        <connection
--		#                priority="10"
--		#                kind="http"
--		#                server="http://www.bbc.co.uk/iplayer/subtitles/"
--		#                identifier="b0008dc8rstreaming89808204.xml"
--		#                href="http://www.bbc.co.uk/iplayer/subtitles/b0008dc8rstreaming89808204.xml"
--		#        />
--		#</media>
--		if ( $media =~ /^(subtitles|all)$/ && $xml =~ m{<media\s+kind="captions".+?type="application/ttaf\+xml".+?kind="http"\s+server="(.+?)"\s+?identifier="(.+?)"\s+?href="(.+?)"} ) {
--			( $server, $identifier, $href ) = ( $1, $2, $3 );
--			logger "INFO: Subtitles stream:\nINFO:  server=$server\nINFO:  identifier=$identifier\nINFO:  href=$href\n" if $opt{verbose};
--			$streams{'subtitles'} = "$href";
--			logger "INFO: Subtitles stream URL: $streams{'subtitles'}\n";
-+sub display_stream_info {
-+	my ($pid, $verpid, $media) = (@_);
-+	logger "INFO: Getting media stream metadata for $prog{$pid}{name} - $prog{$pid}{episode}, $verpid\n" if $pid;
-+	my %data = get_media_stream_data( $pid, $verpid, $media);
-+	# Print out stream data
-+	for my $prog_type (sort keys %data) {
-+		logger "stream:     $prog_type\n";
-+		for my $entry ( sort keys %{ $data{$prog_type} } ) {
-+			logger sprintf("%-11s %s\n", $entry.':', $data{$prog_type}{$entry} );
- 		}
-+		logger "\n";
- 	}
--	logger "\n" if $opt{streaminfo};
--	$opt{quiet} = 1 if $opt{streaminfo};
-+	return 0;
-+}
- 
--	# Return a hash with media => url if 'all' is specified - otherwise just the specified url
--	return %streams if $media eq 'all';
--	return $streams{$media};
-+
-+
-+# Displays specified metadata from supplied hash
-+# Usage: display_metadata( <hashref>, <array of elements to display> )
-+sub display_metadata {
-+	my %data = %{$_[0]};
-+	shift;
-+	my @keys = @_;
-+	@keys = keys %data if $#_ < 0;
-+	logger "\n";
-+	for (@keys) {
-+		logger sprintf "%-15s %s\n", ucfirst($_).':', $data{$_} if $data{$_};
-+	}
-+	return 0;
- }
- 
- 
- 
- # Actually do the h.264/mp3 downloading
- # ( $ua, $pid, $url_2, $file, $file_done, '0|1 == rearrange moov' )
--sub download_iphone_stream {
--	my ( $ua, $url_2, $file, $file_done, $file_symlink, $rearrange ) = @_;
-+sub download_stream_iphone {
-+	my ( $ua, $url_2, $pid, $file, $file_done, $file_symlink, $rearrange ) = @_;
- 
- 	# Stage 3a: Download 1st byte to get exact file length
- 	logger "INFO: Stage 3 URL = $url_2\n" if $opt{verbose};
-@@ -2132,53 +2799,44 @@
- 	my $req = HTTP::Request->new ('GET', $url_2, $h);
- 	my $res = $ua->request($req);
- 	# e.g. Content-Range: bytes 0-1/181338136 (return if no content length returned)
--	my $file_len = $res->header("Content-Range");
--	if ( ! $file_len ) {
--		logger "ERROR: No Content-Range was obtained\n" if $opt{verbose};
-+	my $download_len = $res->header("Content-Range");
-+	if ( ! $download_len ) {
-+		#logger "ERROR: No Content-Range was obtained\n" if $opt{verbose};
-+		logger "WARNING: iphone version not available\n";
- 		return 'retry'
- 	}
--	$file_len =~ s|^bytes 0-1/(\d+).*$|$1|;
--	logger "INFO: Download File Length $file_len\n" if $opt{verbose};
-+	$download_len =~ s|^bytes 0-1/(\d+).*$|$1|;
-+	logger "INFO: Download File Length $download_len\n" if $opt{verbose};
- 
- 	# Only do this if we're rearranging QT streams
- 	my $mdat_start = 0;
--	my $moov_start = $file_len + 1;
-+	# default to this if we are not rearranging (tells the download chunk loop where to stop - i.e. EOF instead of end of mdat atom)
-+	my $moov_start = $download_len + 1;
- 	my $header;
- 	if ($rearrange) {
- 		# Get ftyp+wide header etc
- 		$mdat_start = 0x1c;
- 		my $buffer = download_block(undef, $url_2, $ua, 0, $mdat_start + 4);
- 		# Get bytes upto (but not including) mdat atom start -> $header
--		$header = download_block(undef, $url_2, $ua, 0, $mdat_start - 1, $file_len);
--
-+		$header = substr($buffer, 0, $mdat_start);
-+		
- 		# Detemine moov start
--		# Get mdat_end_offset_chars from downloaded block
--		my $mdat_end_offset_chars = substr($buffer, $mdat_start, 4);
--		my $mdat_end_offset = bytestring_to_int($mdat_end_offset_chars);
--		logger "DEBUG: mdat_end_offset = ".get_hex($mdat_end_offset_chars)." = $mdat_end_offset\n" if $opt{debug};
--		logger "DEBUG: mdat_end_offset (decimal) = $mdat_end_offset\n" if $opt{debug};
-+		# Get mdat_length_chars from downloaded block
-+		my $mdat_length_chars = substr($buffer, $mdat_start, 4);
-+		my $mdat_length = bytestring_to_int($mdat_length_chars);
-+		logger "DEBUG: mdat_length = ".get_hex($mdat_length_chars)." = $mdat_length\n" if $opt{debug};
-+		logger "DEBUG: mdat_length (decimal) = $mdat_length\n" if $opt{debug};
- 		# The MOOV box starts one byte after MDAT box ends
--		$moov_start = $mdat_start + $mdat_end_offset;
--
--
--		## scan 2nd level atoms in moov atom until we get stco atom(s)
--		# We can skip first 8 bytes (moov atom header)
--		#my $i = 8;
--		#while( $i < $moov_length - 4 ) {
--		#  my $atom_len = bytestring_to_int( substr($moovdata, $i, 4) );
--		#  my $atom_name = substr($moovdata, $i+4, 4);
--		#  logger "Parsing atom: $atom_name, length: $atom_len\n";
--		#  # Increment $i by atom_len to get next atom
--		#  $i += $atom_len;
--		#}
-+		$moov_start = $mdat_start + $mdat_length;
- 	}
- 
- 	# If we have partial content and wish to stream, resume the download & spawn off STDOUT from existing file start 
- 	# Sanity check - we cannot support downloading of partial content if we're streaming also. 
- 	if ( $opt{stdout} && (! $opt{nowrite}) && -f $file ) {
- 		logger "WARNING: Partially downloaded file exists, streaming will start from the beginning of the programme\n";
--		# Don't do usual streaming code
--		$opt{stdout} = 0;
-+		# Don't do usual streaming code - also force all messages to go to stderr
-+		delete $opt{stdout};
-+		$opt{stderr} = 1;
- 		$childpid = fork();
- 		if (! $childpid) {
- 			# Child starts here
-@@ -2205,15 +2863,15 @@
- 	my $fh = open_file_append($file);
- 
- 	# If the partial file already exists, then resume from the correct mdat/download offset
--	my $restart_offset = $mdat_start;
-+	my $restart_offset = 0;
- 	my $moovdata;
- 	my $moov_length = 0;
- 
- 	if ($rearrange) {
- 		# if cookie fails then trigger a retry after deleting cookiejar
--		# Determine moov atom length so we can work out if the partially downloaded file has the moov atom in it already
-+		# Determine orginal moov atom length so we can work out if the partially downloaded file has the moov atom in it already
- 		$moov_length = bytestring_to_int( download_block( undef, $url_2, $ua, $moov_start, $moov_start+3 ) );
--		logger "INFO: moov atom length = $moov_length                          \n" if $opt{verbose};
-+		logger "INFO: original moov atom length = $moov_length                          \n" if $opt{verbose};
- 		# Sanity check this moov length - chances are that were being served up a duff file if this is > 10% of the file size or < 64k
- 		if ( $moov_length > (${moov_start}/9.0) || $moov_length < 65536 ) {
- 			logger "WARNING: Bad file download, deleting cookie                 \n";
-@@ -2222,33 +2880,73 @@
- 			unlink $file;
- 			return 'retry';
- 		}
--	}
--
--	# If we have a too-small-sized file and not stdout and not no-write then this is a partial download
--	if (-f $file && (! $opt{stdout}) && (! $opt{nowrite}) && stat($file)->size > ($moov_length+$mdat_start) ) {
--		# Calculate new start offset (considering that we've put moov first in file)
--		$restart_offset = stat($file)->size - $moov_length;
--		logger "INFO: Resuming download from $restart_offset                        \n";
--	}
- 
--	if ($rearrange) {
-+		# we still need an accurate moovlength for the already downloaded moov atom for resume restart_offset.....
- 		# If we have no existing file, a file which doesn't yet even have the moov atom, or using stdout (or no-write option)
--		if ( $opt{stdout} || $opt{nowrite} || stat($file)->size < ($moov_length+$mdat_start) ) {
-+		# (allow extra 1k on moov_length for metadata when testing)
-+		if ( $opt{stdout} || $opt{nowrite} || stat($file)->size < ($moov_length+$mdat_start+1024) ) {
- 			# get moov chunk into memory
--			$moovdata = download_block( undef, $url_2, $ua, $moov_start, (${file_len}-1) );
-+			$moovdata = download_block( undef, $url_2, $ua, $moov_start, (${download_len}-1) );
-+
-+			# Create new udta atom with child atoms for metadata
-+			my $udta_new = create_qt_atom('udta',
-+				create_qt_atom( chr(0xa9).'nam', $prog{$pid}{name}.' - '.$prog{$pid}{episode}, 'string' ).
-+				create_qt_atom( chr(0xa9).'alb', $prog{$pid}{name}, 'string' ).
-+				create_qt_atom( chr(0xa9).'trk', $prog{$pid}{episode}, 'string' ).
-+				create_qt_atom( chr(0xa9).'aut', $prog{$pid}{channel}, 'string' ).
-+				create_qt_atom( chr(0xa9).'ART', $prog{$pid}{channel}, 'string' ).
-+				create_qt_atom( chr(0xa9).'des', $prog{$pid}{desc}, 'string' ).
-+				create_qt_atom( chr(0xa9).'cmt', 'Downloaded with get_iplayer', 'string' ).
-+				create_qt_atom( chr(0xa9).'req', 'QuickTime 6.0 or greater', 'string' ).
-+				create_qt_atom( chr(0xa9).'day', (localtime())[5] + 1900, 'string' )
-+			);
-+			# Insert new udta atom over the old one and get the new $moov_length (and update moov atom size field)
-+			replace_moov_udta_atom ( $udta_new, $moovdata );
-+
- 			# Process the moov data so that we can relocate it (change the chunk offsets that are absolute)
-+			# Also update moov+_length to be accurate after metadata is added etc
- 			$moov_length = relocate_moov_chunk_offsets( $moovdata );
--			# write moov atom to file next (yes - were rearranging the file - moov+header+mdat - not header+mdat+moov)
--			logger "INFO: Appending moov+ftype+wide atoms to $file\n" if $opt{verbose};
--			# Write moov atom
--			print $fh $moovdata if ! $opt{nowrite};
--			print STDOUT $moovdata if $opt{stdout};
-+			logger "INFO: New moov atom length = $moov_length                          \n" if $opt{verbose};
-+			# write moov atom to file next (yes - were rearranging the file - header+moov+mdat - not header+mdat+moov)
-+			logger "INFO: Appending ftype+wide+moov atoms to $file\n" if $opt{verbose};
- 			# Write header atoms (ftyp, wide)
- 			print $fh $header if ! $opt{nowrite};
- 			print STDOUT $header if $opt{stdout};
-+			# Write moov atom
-+			print $fh $moovdata if ! $opt{nowrite};
-+			print STDOUT $moovdata if $opt{stdout};
-+			# If were not resuming we want to only start the download chunk loop from mdat_start 
-+			$restart_offset = $mdat_start;
-+		}
-+
-+		# Get accurate moov_length from file (unless stdout or nowrite options are specified)
-+		# Assume header+moov+mdat atom layout
-+		if ( (! $opt{stdout}) && (! $opt{nowrite}) && stat($file)->size > ($moov_length+$mdat_start) ) {
-+				logger "INFO: Getting moov atom length from partially downloaded file $file\n" if $opt{verbose};
-+				if ( ! open( MOOVDATA, "< $file" ) ) {
-+					logger "ERROR: Cannot Read partially downloaded file\n";
-+					return 4;
-+				}
-+				my $data;
-+				seek(MOOVDATA, $mdat_start, 0);
-+				if ( read(MOOVDATA, $data, 4, 0) != 4 ) {
-+					logger "ERROR: Cannot Read moov atom length from partially downloaded file\n";
-+					return 4;
-+				}
-+				close MOOVDATA;
-+				# Get moov atom size from file
-+				$moov_length = bytestring_to_int( substr($data, 0, 4) );
-+				logger "INFO: moov atom length (from partially downloaded file) = $moov_length                          \n" if $opt{verbose};
- 		}
- 	}
- 
-+	# If we have a too-small-sized file (greater than moov_length+mdat_start) and not stdout and not no-write then this is a partial download
-+	if (-f $file && (! $opt{stdout}) && (! $opt{nowrite}) && stat($file)->size > ($moov_length+$mdat_start) ) {
-+		# Calculate new start offset (considering that we've put moov first in file)
-+		$restart_offset = stat($file)->size - $moov_length;
-+		logger "INFO: Resuming download from $restart_offset                        \n";
-+	}
-+
- 	# Create symlink if required
- 	if ( $opt{symlink} ) {
- 		# remove old symlink
-@@ -2273,16 +2971,15 @@
- 			$e = $s + $chunk_size - 1;
- 		}
- 		# Get block from URL and append to $file
--		if ( download_block($file, $url_2, $ua, $s, $e, $file_len, $fh ) ) {
-+		if ( download_block($file, $url_2, $ua, $s, $e, $download_len, $fh ) ) {
- 			logger "ERROR: Could not download block $s - $e from $file\n\n";
--			return 9;
-+			return 'retry';
- 		}
- 	}
- 
- 	# end marker
- 	my $end_time = time();
- 
--	# Should now be able to concatenate header.block + mdat.block + moov.block to get movie!
- 	# Calculate average speed, duration and total bytes downloaded
- 	logger sprintf("INFO: Downloaded %.2fMB in %s at %5.0fkbps to %s\n", 
- 		($moov_start - 1 - $restart_offset) / (1024.0 * 1024.0),
-@@ -2292,57 +2989,217 @@
- 
- 	# Moving file into place as complete (if not stdout)
- 	move($file, $file_done) if ! $opt{stdout};
-+
-+	# Re-symlink file
-+	if ( $opt{symlink} ) {
-+		# remove old symlink
-+		unlink $file_symlink if -l $file_symlink;
-+		symlink $file_done, $file_symlink;
-+		logger "INFO: Created symlink from '$file_symlink' -> '$file_done'\n" if $opt{verbose};
-+	}
-+	$prog{$pid}{mode} = 'iphone';
- 	return 0;
- }
- 
- 
- 
--sub download_h264_rtmp_stream {
--        my ( $ua, $url_2, $prog_url, $file, $file_done, $file_symlink ) = @_;
--        my $file_flv = $file; # .'.flv';
-+# Actually do the RTMP stream downloading
-+sub download_stream_rtmp {
-+	my ( $ua, $url_2, $pid, $mode, $application, $tcurl, $authstring, $swfurl, $file, $file_done, $file_symlink ) = @_;
-+	my $file_tmp;
-+	my $cmd;
-+	
-+	if ( $opt{raw} ) {
-+		$file_tmp = $file;
-+	} else {
-+		$file_tmp = $file.'.flv'
-+	}
- 
--	logger "INFO: url: $url_2, prog_url: $prog_url, file: $file, file_done: $file_done\n" if $opt{verbose};
-+	# Remove failed file download (below a certain size) - hack to get around rtmpdump not returning correct exit code
-+	if ( -f $file_tmp && stat($file_tmp)->size < $min_download_size ) {
-+		unlink( $file_tmp );
-+	}
-+		
-+	logger "INFO: RTMP_URL: $url_2, tcUrl: $tcurl, application: $application, authString: $authstring, swfUrl: $swfurl, file: $file, file_done: $file_done\n" if $opt{verbose};
- 
- 	# Create symlink if required
- 	if ( $opt{symlink} ) {
- 		# remove old symlink
- 		unlink $file_symlink if -l $file_symlink;
--		symlink $file_flv, $file_symlink;
--		logger "INFO: Created symlink from '$file_symlink' -> '$file_flv'\n" if $opt{verbose};
-+		symlink $file_tmp, $file_symlink;
-+		logger "INFO: Created symlink from '$file_symlink' -> '$file_tmp'\n" if $opt{verbose};
- 	}
-+	$cmd = "$rtmpdump --resume --rtmp \"$url_2\" --auth \"$authstring\" --swfUrl \"$swfurl\" --tcUrl \"$tcurl\" --app \"$application\" -o \"$file_tmp\" >&2";
-+	logger "\n\nINFO: Command: $cmd\n" if $opt{verbose};
-+	my $return = system($cmd);
-+	# Hack to get around rtmpdump prentending to fail on successful flash downloads
-+	if ( (! -f $file_tmp) || ($return && -f $file_tmp && stat($file_tmp)->size < $min_download_size) ) {
-+		logger "\n\nINFO: Command: $cmd\n" if $opt{verbose};
-+		logger "\nWARNING: Failed to download file $file_tmp via RTMP\n";
-+		unlink $file_tmp;
-+		return 'next';
-+	}
-+	
-+	# Retain raw flv format if required
-+	if ( $opt{raw} ) {
-+		move($file_tmp, $file_done) if ! $opt{stdout};
-+		return 0;
- 
--	my $cmd = "$rtmpdump --rtmp \"$url_2\" --pageUrl \"$prog_url\" --swfUrl \"http://www.bbc.co.uk/emp/9player.swf?revision=6928_7030\" --tcUrl \"rtmp://bbciplayertokfs.fplive.net:80/bbciplayertok\" --app \"bbciplayertok\" -o \"$file_flv\" >&2";
--	#my $cmd2 = "$ffmpeg -i \"$file_flv\" -vcodec copy -acodec copy -f mp4 -y \"$file\" >&2";
--	#my $cmd2 = "$mencoder -oac copy -ovc copy -o \"$file\" \"$file_flv\" >&2";
-+	# Convert flv to mp3 for flash audio
-+	} elsif ( $mode eq 'flashaudio' ) {
-+		# We could do id3 tagging here but id3v2 does this later anyway
-+		$cmd = "$ffmpeg -i \"$file_tmp\" -vn -acodec copy -y \"$file\" >&2";
- 
--	# logger "\n\nINFO: Command1: $cmd\nINFO: Command2: $cmd2\n\n" if $opt{verbose};
--	if ( system($cmd) ) {
--		logger "\nWARNING: Failed to download file $file via RTMP\n";
--		return 1;
-+	# Convert video flv to mp4/avi if required
-+	} else {
-+		$cmd = "$ffmpeg $ffmpeg_opts -i \"$file_tmp\" -vcodec copy -acodec copy -f $prog{$pid}{ext} -y \"$file\" >&2";
-+	}
-+
-+	logger "\n\nINFO: Command: $cmd\n\n" if $opt{verbose};
-+	# Run flv conversion and delete source file on success
-+	if ( (! system($cmd)) && -f $file && stat($file)->size > $min_download_size ) {
-+			unlink( $file_tmp );
-+
-+	# If the ffmpeg conversion failed, remove the failed-converted file attempt - move the file as done anyway
-+	} else {
-+		logger "WARNING: flv conversion failed - retaining flv file\n";
-+		unlink $file;
-+		$file = $file_tmp;
-+		$file_done = $file_tmp;
-+	}
-+	# Moving file into place as complete (if not stdout)
-+	move($file, $file_done) if ! $opt{stdout};
-+	
-+	# Re-symlink file
-+	if ( $opt{symlink} ) {
-+		# remove old symlink
-+		unlink $file_symlink if -l $file_symlink;
-+		symlink $file_done, $file_symlink;
-+		logger "INFO: Created symlink from '$file_symlink' -> '$file_done'\n" if $opt{verbose};
-+	}
-+
-+	logger "INFO: Downloaded $file_done\n";
-+	$prog{$pid}{mode} = $mode;
-+	return 0;
-+}
-+
-+
-+
-+# Actually do the MMS video stream downloading
-+sub download_stream_mms_video {
-+	my ( $ua, $urls, $file, $file_done, $pid ) = @_;
-+	my $file_tmp;
-+	my $cmd;
-+	my $null;
-+	my @url_list = split /\|/, $urls;
-+	my @file_tmp_list;
-+	my %threadpid;
-+		
-+	logger "INFO: MMS_URLs: ".(join ', ', @file_tmp_list).", file: $file, file_done: $file_done\n" if $opt{verbose};
-+
-+	# Start marker
-+	my $start_time = time();
-+	# Download each mms url (multi-threaded to download in parallel)
-+	my $file_part_prefix = "$prog{$pid}{dir}/$prog{$pid}{fileprefix}_part";
-+	for ( my $count = 0; $count <= $#url_list; $count++ ) {
-+
-+		# Create temp download filename
-+		$file_tmp = $file_part_prefix.($count+1).".asf";
-+		$file_tmp_list[$count] = $file_tmp;
-+		$null = " 2>/dev/null " if (! $opt{verbose}) && (! $opt{debug});
-+		$cmd = "$mplayer -dumpstream \"$url_list[$count]\" -dumpfile \"$file_tmp\" $null >&2 </dev/null";
-+		logger "\n\nINFO: Command: $cmd\n" if $opt{verbose};
-+
-+		my $childpid = fork();
-+		if (! $childpid) {
-+			# Child starts here
-+			logger "INFO: Downloading file $file_tmp\n";
-+			if ( system($cmd) ) {
-+				logger "\nWARNING: Failed to download file $file_tmp via MMS\n";
-+				exit 1;
-+			}
-+			logger "INFO: Download thread has completed for file $file_tmp\n";
-+			exit 0;
-+		}
-+		# Create a hash of process_id => 'count'
-+		$threadpid{$childpid} = $count;
-+	}	
-+	# Wait for all threads to complete
-+	$| = 1;
-+	# Autoreap zombies
-+	$SIG{CHLD}='IGNORE';
-+	my $done = 0;
-+	while (keys %threadpid) {
-+		my @sizes;
-+		my $total_size = 0;
-+		my $total_size_new = 0;
-+		my $format = "Threads: ";
-+		sleep 1;
-+		#logger "DEBUG: ProcessIDs: ".(join ',', keys %threadpid)."\n";
-+		for my $procid (sort keys %threadpid) {
-+			my $size = 0;
-+			# Is this child still alive?
-+			if ( kill 0 => $procid ) {
-+				logger "DEBUG Thread $threadpid{$procid} still alive ($file_tmp_list[$threadpid{$procid}])\n" if $opt{debug};
-+				# Build the status string
-+				$format .= "%d) %.3fMB   ";
-+				$size = stat($file_tmp_list[$threadpid{$procid}])->size if -f $file_tmp_list[$threadpid{$procid}];
-+				push @sizes, $threadpid{$procid}+1, $size/(1024.0*1024.0);
-+				$total_size_new += $size;
-+			} else {
-+				$size = stat($file_tmp_list[$threadpid{$procid}])->size if -f $file_tmp_list[$threadpid{$procid}];
-+				# end marker
-+				my $end_time = time();
-+				# Calculate average speed, duration and total bytes downloaded
-+				logger sprintf("INFO: Thread #%d Downloaded %.2fMB in %s at %5.0fkbps to %s\n", 
-+					($threadpid{$procid}+1),
-+					$size / (1024.0 * 1024.0),
-+					sprintf("%02d:%02d:%02d", ( gmtime($end_time - $start_time))[2,1,0] ), 
-+					$size / ($end_time - $start_time) / 1024.0 * 8.0,
-+					$file_tmp_list[$threadpid{$procid}] );
-+				# Remove from thread test list
-+				delete $threadpid{$procid};
-+			}
-+		}
-+		$format .= " downloaded (%.0fkbps)        \r";
-+		logger sprintf $format, @sizes, ($total_size_new - $total_size) / (time() - $start_time) / 1024.0 * 8.0;
- 	}
--	# Only convert to mp4 if we have mencoder in path
--	# Disable rtmp mode if rtmpdump does not exist
--	if ( ! exists_in_path($ffmpeg)) {
--		logger "\nWARNING: $ffmpeg does not exist - not converting flv file to mp4\n";
--	#} else {
--		# Run flv conversion and delete source file on success
--		#if ( ! system($cmd2) ) {
--		#	unlink( $file_flv );
--		#} else {
--		#	logger "ERROR: flv to mp4 conversion failed\n";
--		#	return 2;
--		#}
--		# Moving file into place as complete (if not stdout)
--		#move($file, $file_done) if ! $opt{stdout};
-+	logger "INFO: All download threads completed\n";	
-+	# Unset autoreap
-+	delete $SIG{CHLD};
-+	# Retain raw format if required
-+	if ( $opt{raw} ) {
-+		return 0;
- 	}
-+
-+#	# Convert video asf to mp4 if required - need to find a suitable converter...
-+#	} else {
-+#		# Create part of cmd that specifies each partial file
-+#		my $filestring;
-+#		$filestring .= " -i \"$_\" " for (@file_tmp_list);
-+#		$cmd = "$ffmpeg $ffmpeg_opts $filestring -vcodec copy -acodec copy -f $prog{$pid}{ext} -y \"$file\" >&2";
-+#	}
-+#
-+#	logger "\n\nINFO: Command: $cmd\n\n" if $opt{verbose};
-+#	# Run asf conversion and delete source file on success
-+#	if ( ! system($cmd) ) {
-+#		unlink( @file_tmp_list );
-+#	} else {
-+#		logger "ERROR: asf conversion failed - retaining files ".(join ', ', @file_tmp_list)."\n";
-+#		return 2;
-+#	}
-+#	# Moving file into place as complete (if not stdout)
-+#	move($file, $file_done) if ! $opt{stdout};
-+
-+	$prog{$pid}{mode} = 'itv';
- 	return 0;
- }
- 
- 
- 
- # Actually do the N95 h.264 downloading
--sub download_h264_low_stream {
--	my ( $ua, $url_2, $file, $file_done ) = @_;
-+sub download_stream_h264_low {
-+	my ( $ua, $url_2, $file, $file_done, $pid, $mode ) = @_;
- 
- 	# Change filename extension
- 	$file =~ s/mov$/mpg/gi;
-@@ -2353,7 +3210,7 @@
- 		logger "INFO: Downloading Low Quality H.264 stream\n";
- 		my $cmd = "$vlc $vlc_opts --sout file/ts:${file} $url_2 1>&2";
- 		if ( system($cmd) ) {
--			return 2;
-+			return 'next';
- 		}
- 
- 	# to STDOUT
-@@ -2361,19 +3218,21 @@
- 		logger "INFO: Streaming Low Quality H.264 stream to stdout\n";
- 		my $cmd = "$vlc $vlc_opts --sout file/ts:- $url_2 1>&2";
- 		if ( system($cmd) ) {
--			return 2;
-+			return 'next';
- 		}	
- 	}
- 	logger "INFO: Downloaded $file_done\n";
- 	# Moving file into place as complete (if not stdout)
- 	move($file, $file_done) if ! $opt{stdout};
-+
-+	$prog{$pid}{mode} = $mode;
- 	return 0;
- }
- 
- 
- 
- # Actually do the rtsp downloading
--sub download_rtsp_stream {
-+sub download_stream_rtsp {
- 	my ( $ua, $url, $file, $file_done, $file_symlink, $pid ) = @_;
- 	my $childpid;
- 
-@@ -2389,7 +3248,7 @@
- 	# Create ID3 tagging options for lame (escape " for shell)
- 	my ( $id3_name, $id3_episode, $id3_desc, $id3_channel ) = ( $prog{$pid}{name}, $prog{$pid}{episode}, $prog{$pid}{desc}, $prog{$pid}{channel} );
- 	$id3_name =~ s|"|\"|g for ($id3_name, $id3_episode, $id3_desc, $id3_channel);
--	$lame_opts .= "--ignore-tag-errors --ty ".( (localtime())[5] + 1900 )." --tl \"$id3_name\" --tt \"$id3_episode\" --ta \"$id3_channel\" --tc \"$id3_desc\" ";
-+	$lame_opts .= " --ignore-tag-errors --ty ".( (localtime())[5] + 1900 )." --tl \"$id3_name\" --tt \"$id3_episode\" --ta \"$id3_channel\" --tc \"$id3_desc\" ";
- 
- 	# Use post-download transcoding using lame if namedpipes are not supported (i.e. ActivePerl/Windows)
- 	# (Fallback if no namedpipe support and raw/wav not specified)
-@@ -2402,14 +3261,14 @@
- 		logger "INFO: Downloading wav format (followed by transcoding)\n";
- 		$cmd = "$mplayer $mplayer_opts -cache 128 -bandwidth $bandwidth -vc null -vo null -ao pcm:waveheader:fast:file=\"${file}.wav\" \"$url\" 1>&2";
- 		if ( system($cmd) ) {
--			return 2;
-+			return 'next';
- 		}
- 		# Transcode
- 		logger "INFO: Transcoding ${file}.wav\n";
- 		$cmd = "$lame $lame_opts \"${file}.wav\" \"${file}.mp3\" 1>&2";
- 		logger "DEGUG: Running $cmd\n" if $opt{debug};
--		if ( system($cmd) ) {
--			return 2;
-+		if ( system($cmd) || (-f "${file}.wav" && stat("${file}.wav")->size < $min_download_size) ) {
-+			return 'next';
- 		}
- 		unlink "${file}.wav";
- 		move "${file}.mp3", $file_done;
-@@ -2425,7 +3284,7 @@
- 		my $cmd = "$mplayer $mplayer_opts -cache 128 -bandwidth $bandwidth -vc null -vo null -ao pcm:waveheader:fast:file=\"$file\" \"$url\" 1>&2";
- 		logger "DEGUG: Running $cmd\n" if $opt{debug};
- 		if ( system($cmd) ) {
--			return 2;
-+			return 'next';
- 		}
- 		# Move file to done state
- 		move $file, $file_done if ! $opt{nowrite};
-@@ -2438,7 +3297,7 @@
- 		my $cmd = "$mplayer $mplayer_opts -cache 128 -bandwidth $bandwidth -dumpstream -dumpfile \"$file\" \"$url\" 1>&2";
- 		logger "DEGUG: Running $cmd\n" if $opt{debug};
- 		if ( system($cmd) ) {
--			return 2;
-+			return 'next';
- 		}
- 		# Move file to done state
- 		move $file, $file_done if ! $opt{nowrite};
-@@ -2498,7 +3357,7 @@
- 			if ( system($cmd) ) {
- 				# If we fail then kill off child processes
- 				kill 9, $childpid;
--				return 2;
-+				return 'next';
- 			}
- 		# WAV / mp3 mode
- 		} else {
-@@ -2506,7 +3365,7 @@
- 			if ( system($cmd) ) {
- 				# If we fail then kill off child processes
- 				kill 9, $childpid;
--				return 2;
-+				return 'next';
- 			}
- 		}
- 		# Wait for child processes to prevent zombies
-@@ -2522,13 +3381,14 @@
- 		logger "INFO: Created symlink from '$file_symlink' -> '$file_done'\n" if $opt{verbose};
- 	}
- 
-+	$prog{$pid}{mode} = 'realaudio';
- 	return 0;
- }
- 
- 
- 
- # Actually do the podcast downloading
--sub download_podcast_stream {
-+sub download_stream_podcast {
- 	my ( $ua, $url_2, $file, $file_done, $file_symlink ) = @_;
- 	my $start_time = time();
- 
-@@ -2548,7 +3408,7 @@
- 
- 	if ( download_block($file, $url_2, $ua, $start, undef, undef, $fh) != 0 ) {
- 		logger "ERROR: Download failed\n";
--		return 22;
-+		return 'next';
- 	} else {
- 		# end marker
- 		my $end_time = time();
-@@ -2569,111 +3429,98 @@
- 			logger "INFO: Created symlink from '$file_symlink' -> '$file_done'\n" if $opt{verbose};
- 		}
- 	}
-+
-+	$prog{$url_2}{mode} = 'podcast';
- 	return 0;
- }
- 
- 
- 
- # Get streaming iphone URL
--sub get_iphone_stream_download_url {
--		my $ua = shift;
--		my $pid = shift;
--
--		# Create url with appended 6 digit random number
--		my $url_1 = ${iphone_download_prefix}.'/'.${pid}.'?'.(sprintf "%06.0f", 1000000*rand(0)).'%20';
--		logger "INFO: media stream download URL = $url_1\n" if $opt{verbose};
--		
--		# Stage 2: e.g. "Location: http://download.iplayer.bbc.co.uk/iplayer_streaming_http_mp4/121285241910131406.mp4?token=iVXexp1yQt4jalB2Hkl%2BMqI25nz2WKiSsqD7LzRmowrwXGe%2Bq94k8KPsm7pI8kDkLslodvHySUyU%0ApM76%2BxEGtoQTF20ZdFjuqo1%2B3b7Qmb2StOGniozptrHEVQl%2FYebFKVNINg%3D%3D%0A"
--		logger "\rGetting iplayer download URL         " if ! $opt{verbose};
--		my $h = new HTTP::Headers(
--			'User-Agent'	=> $user_agent{coremedia},
--			'Accept'	=> '*/*',
--			'Range'		=> 'bytes=0-1',
--		);
--		my $req = HTTP::Request->new ('GET', $url_1, $h);
--		# send request
--		my $res = $ua->request($req);
--		# Get resulting Location header (i.e. redirect URL)
--		my $url_2 = $res->header("location");
--		if ( ! $res->is_redirect ) {
--			logger "ERROR: Failed to get redirect from iplayer site\n\n";
--			return '';
--		}
--		# Extract redirection Location URL
--		$url_2 =~ s/^Location: (.*)$/$1/g;
--		# If we get a Redirection containing statuscode=404 then this prog is not yet ready
--		if ( $url_2 =~ /statuscode=404/ ) {
--			logger "\rERROR: Programme is not yet ready for download\n";
--			return '';
--		}
--
--		return $url_2;
--}
--
--
-+sub get_stream_url_iphone {
-+	my $ua = shift;
-+	my $pid = shift;
- 
--# Get streaming audio URL (Real => rtsp)
--#<media kind="audio"
--#        type="audio/real"
--#        encoding="real"  >
--#        <connection
--#                priority="10"
--#                kind="sis"
--#                server="http://www.bbc.co.uk"
--#                identifier="/radio/aod/playlists/gs/5d/c0/0b/0900_bbc_radio_two"
--#                href="http://www.bbc.co.uk/radio/aod/playlists/gs/5d/c0/0b/0900_bbc_radio_two.ram"
--#        />
--#</media>
--# OR
--#<media kind=""
--#        type="audio/real"
--#        encoding="real"  >
--#        <connection
--#                priority="10"
--#                kind="edgesuite"
--#                server="http://http-ws.bbc.co.uk.edgesuite.net"
--#                identifier="/generatecssram.esi?file=/worldservice/css/nb/410591221152760.ra"
--#                href="http://http-ws.bbc.co.uk.edgesuite.net/generatecssram.esi?file=/worldservice/css/nb/410591221152760.ra"
--#        />
--#</media>
--#
--sub get_audio_stream_download_url {
--		my $ua = shift;
--		my $url_1 = shift;
--		my $url_2;
-+	# Create url with appended 6 digit random number
-+	my $url_1 = ${iphone_download_prefix}.'/'.${pid}.'?'.(sprintf "%06.0f", 1000000*rand(0)).'%20';
-+	logger "INFO: media stream download URL = $url_1\n" if $opt{verbose};
- 		
--		logger "\rGetting iplayer download URL         " if ! $opt{verbose};
--		my $h = new HTTP::Headers(
--			'User-Agent'	=> $user_agent{coremedia},
--			'Accept'	=> '*/*',
--			'Range'		=> 'bytes=0-',
--		);
--		my $req = HTTP::Request->new ('GET', $url_1, $h);
--		# send request
--		my $res = $ua->request($req);
--		# Get resulting content 
--		my $content = $res->content;
--		# Flatten
--		$content =~ s/\n/ /g;
--		if ( ! $res->is_success ) {
--			logger "ERROR: Failed to get audio url from iplayer site\n\n";
--			return '';
--		}
--		# If we get a Redirection containing statuscode=404 then this prog is not yet ready
--		if ( $content =~ /statuscode=404/ ) {
--			logger "\rERROR: Programme is not yet ready for download\n";
--			return '';
--		}
--		# extract ram URL
--		$url_2 = $2 if $content =~ m{<media kind="(|audio)"\s*type="audio/real".*href="(.+?)"\s*};
--
--		# If we cannot see 'encoding="real"...' then we don't have real audio transcoded format then skip
--		if ( ! $url_2 ) {
--			logger "\rERROR: Programme is not yet ready for download in RealAudio format\n";
--			return '';
--		}
--
--		return $url_2;
-+	# Stage 2: e.g. "Location: http://download.iplayer.bbc.co.uk/iplayer_streaming_http_mp4/121285241910131406.mp4?token=iVXexp1yQt4jalB2Hkl%2BMqI25nz2WKiSsqD7LzRmowrwXGe%2Bq94k8KPsm7pI8kDkLslodvHySUyU%0ApM76%2BxEGtoQTF20ZdFjuqo1%2B3b7Qmb2StOGniozptrHEVQl%2FYebFKVNINg%3D%3D%0A"
-+	logger "\rGetting iplayer download URL         " if (! $opt{verbose}) && ! $opt{streaminfo};
-+	my $h = new HTTP::Headers(
-+		'User-Agent'	=> $user_agent{coremedia},
-+		'Accept'	=> '*/*',
-+		'Range'		=> 'bytes=0-1',
-+	);
-+	my $req = HTTP::Request->new ('GET', $url_1, $h);
-+	# send request (use simple_request here because that will not allow redirects)
-+	my $res = $ua->simple_request($req);
-+	# Get resulting Location header (i.e. redirect URL)
-+	my $url_2 = $res->header("location");
-+	if ( ! $res->is_redirect ) {
-+		logger "ERROR: Failed to get redirect from iplayer site\n\n";
-+		return '';
-+	}
-+	# Extract redirection Location URL
-+	$url_2 =~ s/^Location: (.*)$/$1/g;
-+	# If we get a Redirection containing statuscode=404 then this prog is not yet ready
-+	if ( $url_2 =~ /statuscode=404/ ) {
-+		logger "\rERROR: Programme is not yet ready for download\n" if $opt{verbose};
-+		return '';
-+	}
-+
-+	return $url_2;
-+}
-+
-+
-+
-+sub get_stream_url_itv {
-+	my ( $ua, $pid ) = ( @_ );
-+
-+	my ( $response, $url_1, $url_2, $url_3, $url_4 );
-+	my $part;
-+	my $duration;
-+	my $filename;
-+	my @url_list;
-+
-+	# construct stage 1 request url
-+	$url_1 = 'http://www.itv.com/_app/video/GetMediaItem.ashx?vodcrid=crid://itv.com/'.$pid.'&bitrate=384&adparams=SITE=ITV/AREA=CATCHUP.VIDEO/SEG=CATCHUP.VIDEO%20HTTP/1.1';
-+
-+	# Extract '<LicencePlaylist>(.+?) HTTP/1.1</LicencePlaylist>'
-+	logger "INFO: ITV Video Stage 1 URL: $url_1\n" if $opt{verbose};
-+	$response = request_url_retry($ua, $url_1, 2, '', '');
-+	logger "DEBUG: Response data: $response\n" if $opt{debug};
-+	$url_2 = $1 if $response =~ m{<LicencePlaylist>(.+?) HTTP/1.1</LicencePlaylist>};
-+	# replace '&amp;' with '&' and append '%20HTTP/1.1'
-+	$url_2 =~ s/&amp;/&/g;
-+	$url_2 .= '%20HTTP/1.1';
-+	logger "INFO: ITV Video Stage 2 URL: $url_2\n" if $opt{verbose};
-+	$response = request_url_retry($ua, $url_2, 2, '', '');
-+	logger "DEBUG: Response data: $response\n" if $opt{debug};
-+
-+	# Extract hrefs and names. There are multiple entries for parts of prog (due to ads):
-+	# e.g. <asx><Title>Doctor Zhivago</Title><EntryRef href="HTTP://SAM.ITV.COM/XTSERVER/ACC_RANDOM=1231194223/SITE=ITV/AREA=CATCHUP.VIDEO/SEG=CATCHUP.VIDEO HTTP/1.1/SOURCE=CATCH.UP/GENRE=DRAMA/PROGNAME=DOCTOR.ZHIVAGO/PROGID=33105/SERIES=DOCTOR.ZHIVAGO/EPNUM=/EPTITLE=/BREAKNUM=0/ADPOS=1/PAGEID=01231194223/DENTON=0/CUSTOMRATING=/TOTDUR=90/PREDUR=0/POSDUR=905/GENERIC=6e0536bf-7883-4aaa-9230-94ecc4aea403/AAMSZ=VIDEO" /><EntryRef href="HTTP://SAM.ITV.COM/XTSERVER/ACC_RANDOM=1231194223/SITE=ITV/AREA=CATCHUP.VIDEO/SEG=CATCHUP.VIDEOHTTP/1.1/SOURCE=CATCH.UP/GENRE=DRAMA/PROGNAME=DOCTOR.ZHIVAGO/PROGID=33105/SERIES=DOCTOR.ZHIVAGO/EPNUM=/EPTITLE=/BREAKNUM=0/ADPOS=LAST/PAGEID=01231194223/DENTON=0/CUSTOMRATING=/TOTDUR=90/PREDUR=0/POSDUR=905/GENERIC=6e0536bf-7883-4aaa-9230-94ecc4aea403/AAMSZ=VIDEO" />
-+	$prog{$pid}{name} = $1 if $response =~ m{<Title>(.+?)<\/Title>};
-+	for my $entry (split /<Entry><ref\s+href=/, $response) {
-+		logger "DEBUG: Entry data: $entry\n" if $opt{debug};
-+		$entry .= '<Entry><ref href='.$entry;
-+
-+		( $url_3, $part, $filename, $duration ) = ( $1, $2, $3, $4 ) if $entry =~ m{<Entry><ref\s+href="(.+?)"\s+\/><param\s+value="true"\s+name="Prebuffer"\s+\/>\s*<PARAM\s+NAME="PrgPartNumber"\s+VALUE="(.+?)"\s*\/><PARAM\s+NAME="FileName"\s+VALUE="(.+?)"\s*\/><PARAM\s+NAME="PrgLength"\s+VALUE="(.+?)"\s*\/>};
-+		next if not $url_3;
-+		# Replace '&amp;' with '&' in url
-+		$url_3 =~ s/&amp;/&/g;
-+		logger "INFO: ITV Video Name: $part\n";
-+
-+		logger "INFO: ITV Video Stage 3 URL: $url_3\n" if $opt{verbose};
-+		$entry = request_url_retry($ua, $url_3, 2, '', '');
-+		logger "DEBUG: Response data: $entry\n" if $opt{debug};
-+
-+		# Extract mms (replace 'http' with 'mms') url: e.g.: Ref1=http://itvbrdbnd.wmod.llnwd.net/a1379/o21/ucontent/2007/6/22/1549_384_1_2.wmv?MSWMExt=.asf
-+		chomp( $url_4 = 'mms'.$1 ) if $entry =~ m{Ref1=http(.+?)[\r\n]+};
-+		logger "INFO: ITV Video URL: $url_4\n" if $opt{verbose};
-+		push @url_list, $url_4;
-+	}
-+	return @url_list;
- }
- 
- 
-@@ -2711,7 +3558,7 @@
- 	# Change all the chunk offsets in moov->stco atoms and add moov_length to them all
- 	# get moov atom length
- 	my $moov_length = bytestring_to_int( substr($moovdata, 0, 4) );
--	# Use index() to seatch for a string within a string
-+	# Use index() to search for a string within a string
- 	my $i = -1;
- 	while (($i = index($moovdata, 'stco', $i)) > -1) {
- 
-@@ -2725,10 +3572,11 @@
- 			#logger "chunk_offset @ $i, $j = '".get_hex( substr($moovdata, $j, 4) )."',	$chunk_offset + $moov_length = ";
- 			$chunk_offset += $moov_length;
- 			# write back bytes into $moovdata
--			substr($moovdata, $j+0, 1) = chr( ($chunk_offset >> 24) & 0xFF );
--			substr($moovdata, $j+1, 1) = chr( ($chunk_offset >> 16) & 0xFF );
--			substr($moovdata, $j+2, 1) = chr( ($chunk_offset >>  8) & 0xFF );
--			substr($moovdata, $j+3, 1) = chr( ($chunk_offset >>  0) & 0xFF );
-+			#substr($moovdata, $j+0, 1) = chr( ($chunk_offset >> 24) & 0xFF );
-+			#substr($moovdata, $j+1, 1) = chr( ($chunk_offset >> 16) & 0xFF );
-+			#substr($moovdata, $j+2, 1) = chr( ($chunk_offset >>  8) & 0xFF );
-+			#substr($moovdata, $j+3, 1) = chr( ($chunk_offset >>  0) & 0xFF );
-+			write_msb_value_at_offset( $moovdata, $j, $chunk_offset );
- 			#$chunk_offset = bytestring_to_int( substr($moovdata, $j, 4) );
- 			#logger "$chunk_offset\n";
- 		}
-@@ -2743,6 +3591,86 @@
- 
- 
- 
-+# Replace the moov->udta atom with a new user-supplied one and update the moov atom size
-+# Usage: replace_moov_udta_atom ( $udta_new, $moovdata )
-+sub replace_moov_udta_atom {
-+	my $udta_new = $_[0];
-+	my $moovdata = $_[1];
-+
-+	# get moov atom length
-+	my $moov_length = bytestring_to_int( substr($moovdata, 0, 4) );
-+
-+	# Find the original udta atom start 
-+	# Use index() to search for a string within a string ($i will point at the beginning of the atom)
-+	my $i = index($moovdata, 'udta', -1) - 4;
-+
-+	# determine length of atom (4 bytes preceding the name)
-+	my $udta_len = bytestring_to_int( substr($moovdata, $i, 4) );
-+	logger "INFO: Found udta atom at moov atom offset: $i length $udta_len\n" if $opt{verbose};
-+
-+	# Save the data before the udta atom
-+	my $moovdata_before_udta = substr($moovdata, 0, $i);
-+
-+	# Save the remainder portion of data after the udta atom for later
-+	my $moovdata_after_udta = substr($moovdata, $i, $moovdata - $i + $udta_len);
-+
-+	# Old udta atom should we need it
-+	### my $udta_old = substr($moovdata, $i, $udta_len);
-+
-+	# Create new moov atom
-+	$moovdata = $moovdata_before_udta.$udta_new.$moovdata_after_udta;
-+	
-+	# Recalculate the moov size and insert into moovdata
-+	write_msb_value_at_offset( $moovdata, 0, length($moovdata) );
-+	
-+	# Write $moovdata back to calling string
-+	$_[1] = $moovdata;
-+
-+	return 0;
-+}
-+
-+
-+
-+# Write the msb 4 byte $value starting at $offset into the passed string
-+# Usage: write_msb_value($string, $offset, $value)
-+sub write_msb_value_at_offset {
-+	my $offset = $_[1];
-+	my $value = $_[2];
-+	substr($_[0], $offset+0, 1) = chr( ($value >> 24) & 0xFF );
-+	substr($_[0], $offset+1, 1) = chr( ($value >> 16) & 0xFF );
-+	substr($_[0], $offset+2, 1) = chr( ($value >>  8) & 0xFF );
-+	substr($_[0], $offset+3, 1) = chr( ($value >>  0) & 0xFF );
-+	return 0;
-+}
-+
-+
-+
-+# Returns a string containing an QT atom
-+# Usage: create_qt_atom(<atome name>, <atom data>, ['string'])
-+sub create_qt_atom {
-+	my ($name, $data, $prog_type) = (@_);
-+	if (length($name) != 4) {
-+		logger "ERROR: Inavlid QT atom name length '$name'\n";
-+		exit 1;
-+	}
-+	# prepend string length if this is a string type
-+	if ( $prog_type eq 'string' ) {
-+		my $value = length($data);
-+		$data = '1111'.$data;
-+		# overwrite '1111' with total atom length in 2-byte MSB + 0x0 0x0
-+		substr($data, 0, 1) = chr( ($value >> 8) & 0xFF );
-+		substr($data, 1, 1) = chr( ($value >> 0) & 0xFF );
-+		substr($data, 2, 1) = chr(0);
-+		substr($data, 3, 1) = chr(0);
-+	}
-+	my $atom = '0000'.$name.$data;
-+	# overwrite '0000' with total atom length in MSB
-+	write_msb_value_at_offset( $atom, 0, length($name.$data) + 4 );
-+	return $atom;
-+}
-+
-+
-+
- # Usage download_block($file, $url_2, $ua, $start, $end, $file_len, $fh);
- #  ensure filehandle $fh is open in append mode
- # or, $content = download_block(undef, $url_2, $ua, $start, $end, $file_len);
-@@ -2811,7 +3739,7 @@
- 			$rate = sprintf("%5.0fkbps", (8.0 / 1024.0) * $rate_bps);
- 			$time = sprintf("%02d:%02d:%02d", ( gmtime( ($file_len - $size) / $rate_bps ) )[2,1,0] );
- 		}
--		printf STDERR "%8.2fMB / %.2fMB %s %5.1f%%, %s remaining         \r", 
-+		logger sprintf "%8.2fMB / %.2fMB %s %5.1f%%, %s remaining         \r", 
- 			$size / 1024.0 / 1024.0, 
- 			$file_len / 1024.0 / 1024.0,
- 			$rate,
-@@ -2851,7 +3779,7 @@
- 				$time = sprintf("%02d:%02d:%02d", ( gmtime( ($file_len - $size) / $rate_bps ) )[2,1,0] );
- 			}
- 			# time remaining
--			printf STDERR "%8.2fMB / %.2fMB %s %5.1f%%, %s remaining         \r", 
-+			logger sprintf "%8.2fMB / %.2fMB %s %5.1f%%, %s remaining         \r", 
- 				$size / 1024.0 / 1024.0,
- 				$file_len / 1024.0 / 1024.0,
- 				$rate,
-@@ -2865,7 +3793,7 @@
- 			} else {
- 				$rate = sprintf("%5.0fkbps", (8.0 / 1024.0) * $size / ($timecalled - $now) );
- 			}
--			printf STDERR "%8.2fMB %s         \r", $size / 1024.0 / 1024.0, $rate;
-+			logger sprintf "%8.2fMB %s         \r", $size / 1024.0 / 1024.0, $rate;
- 		}
- 	};
- 
-@@ -2901,6 +3829,19 @@
- 
- 
- 
-+sub create_ua {
-+	my $agent = shift;
-+	my $ua = LWP::UserAgent->new;
-+	$ua->timeout([$lwp_request_timeout]);
-+	$ua->proxy( ['http'] => $proxy_url );
-+	$ua->agent( $user_agent{$agent} );
-+	$ua->conn_cache(LWP::ConnCache->new());
-+	$ua->cookie_jar( HTTP::Cookies->new( file => $cookiejar, autosave => 1, ignore_discard => 1 ) );
-+	return $ua;
-+};	
-+
-+
-+
- # Converts a string of chars to it's HEX representation
- sub get_hex {
-         my $buf = shift || '';
-@@ -2985,11 +3926,7 @@
- sub update_script {
- 	# Get version URL
- 	my $script_file = $0;
--	my $ua = LWP::UserAgent->new;
--	$ua->timeout([$lwp_request_timeout]);
--	$ua->proxy( ['http'] => $proxy_url );
--	$ua->agent( $user_agent{update} );
--	$ua->conn_cache(LWP::ConnCache->new());
-+	my $ua = create_ua('update');
- 	logger "INFO: Current version is $version\n";
- 	logger "INFO: Checking for latest version from linuxcentre.net\n";
- 	my $res = $ua->request( HTTP::Request->new( GET => $version_url ) );
-@@ -3070,10 +4007,8 @@
- 						<video><url id=\"p1\">${pid}.mov<playlist/></url></video>
- 						<info><description>${desc}</description></info>
- 					</movie>\n" if $opt{fxd};
--					my $newtitle = ${title} ;
--					$newtitle =~ s/\&//g ;
- 					print XML "<Stream>
--						<Name>\"$newtitle\"</Name>
-+						<Name>\"${title}\"</Name>
- 						<url>${pid}.mov</url>
- 						<Subtitle></Subtitle>
- 						<Synopsis>${desc}</Synopsis>
-@@ -3294,6 +4229,7 @@
- 	my $pid = shift;
- 	my $metadata;
- 	my $entry3;
-+	my ($name, $episode, $duration, $available, $channel, $expiry, $longdesc, $versions, $guidance, $prog_type, $categories, $player, $thumbnail);
- 
- 	# This URL works for all prog types:
- 	# http://www.bbc.co.uk/iplayer/playlist/${pid}
-@@ -3307,97 +4243,162 @@
- 	# This URL works for tv/radio prog types:
- 	# $prog_feed_url = http://feeds.bbc.co.uk/iplayer/episode/$pid
- 
--	if ( $prog{$pid}{type} =~ /(tv|radio)/i ) {
-+	if ( $prog{$pid}{type} =~ /^(tv|radio)$/i ) {
- 		$entry3 = request_url_retry($ua, $prog_feed_url.$pid, 3, '', '');
- 		decode_entities($entry3);
- 		logger "DEBUG: $prog_feed_url.$pid:\n$entry3\n\n" if $opt{debug};
- 		# Flatten
- 		$entry3 =~ s|\n| |g;
--	}
- 
--	# Entry3 format
--	#<?xml version="1.0" encoding="utf-8"?>                                      
--	#<?xml-stylesheet href="http://www.bbc.co.uk/iplayer/style/rss.css" type="text/css"?>
--	#<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:media="http://search.yahoo.com/mrss/" xml:lang="en-GB">
--	#  <title>BBC iPlayer - Episode Detail: Edith Bowman: 22/09/2008</title>                                                                          
--	#  <subtitle>Sara Cox sits in for Edith with another Cryptic Randomizer.</subtitle>
--	#  <updated>2008-09-29T10:59:45Z</updated>
--	#  <id>tag:feeds.bbc.co.uk,2008:/iplayer/feed/episode/b00djtfh</id>
--	#  <link rel="related" href="http://www.bbc.co.uk/iplayer" type="text/html" />
--	#  <link rel="self" href="http://feeds.bbc.co.uk/iplayer/episode/b00djtfh" type="application/atom+xml" />
--	#  <author>
--	#    <name>BBC</name>
--	#    <uri>http://www.bbc.co.uk</uri>
--	#  </author>
--	#  <entry>
--	#    <title type="text">Edith Bowman: 22/09/2008</title>
--	#    <id>tag:feeds.bbc.co.uk,2008:PIPS:b00djtfh</id>
--	#    <updated>2008-09-15T01:28:36Z</updated>
--	#    <summary>Sara Cox sits in for Edith with another Cryptic Randomizer.</summary>
--	#    <content type="html">
--	#      &lt;p&gt;
--	#        &lt;a href=&quot;http://www.bbc.co.uk/iplayer/episode/b00djtfh?src=a_syn30&quot;&gt;
--	#          &lt;img src=&quot;http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_150_84.jpg&quot; alt=&quot;Edith Bowman: 22/09/2008&quot; /&gt;
--	#        &lt;/a&gt;
--	#      &lt;/p&gt;
--	#      &lt;p&gt;
--	#        Sara Cox sits in for Edith with movie reviews and great new music, plus another Cryptic Randomizer.
--	#      &lt;/p&gt;
--	#    </content>
--	#    <link rel="alternate" href="http://www.bbc.co.uk/iplayer/episode/b00djtfh?src=a_syn31" type="text/html" title="Edith Bowman: 22/09/2008">
--	#      <media:content medium="audio" duration="10800">
--	#        <media:title>Edith Bowman: 22/09/2008</media:title>
--	#        <media:description>Sara Cox sits in for Edith with movie reviews and great new music, plus another Cryptic Randomizer.</media:description>
--	#        <media:player url="http://www.bbc.co.uk/iplayer/episode/b00djtfh?src=a_syn31" />
--	#        <media:category scheme="urn:bbc:metadata:cs:iPlayerUXCategoriesCS" label="Entertainment">9100099</media:category>
--	#        <media:category scheme="urn:bbc:metadata:cs:iPlayerUXCategoriesCS" label="Music">9100006</media:category>
--	#        <media:category scheme="urn:bbc:metadata:cs:iPlayerUXCategoriesCS" label="Pop &amp; Chart">9200069</media:category>
--	#        <media:credit role="Production Department" scheme="urn:ebu">BBC Radio 1</media:credit>
--	#        <media:credit role="Publishing Company" scheme="urn:ebu">BBC Radio 1</media:credit>
--	#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_86_48.jpg" width="86" height="48" />
--	#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_150_84.jpg" width="150" height="84" />
--	#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_178_100.jpg" width="178" height="100" />
--	#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_512_288.jpg" width="512" height="288" />
--	#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_528_297.jpg" width="528" height="297" />
--	#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_640_360.jpg" width="640" height="360" />
--	#        <dcterms:valid>
--	#          start=2008-09-22T15:44:20Z;
--	#          end=2008-09-29T15:02:00Z;
--	#          scheme=W3C-DTF
--	#        </dcterms:valid>
--	#      </media:content>
--	#    </link>
--	#    <link rel="self" href="http://feeds.bbc.co.uk/iplayer/episode/b00djtfh?format=atom" type="application/atom+xml" title="22/09/2008" />
--	#    <link rel="related" href="http://www.bbc.co.uk/programmes/b006wks4/microsite" type="text/html" title="Edith Bowman" />
--	#    <link rel="parent" href="http://feeds.bbc.co.uk/iplayer/programme_set/b006wks4" type="application/atom+xml" title="Edith Bowman" />
--	#  </entry>
--	#</feed>
--
--	my ($duration, $available, $channel, $expiry, $longdesc, $versions, $guidance, $type, $categories, $player, $thumbnail);
--
--	$expiry = $1 if $entry3 =~ m{<dcterms:valid>\s*start=.+?;\s*end=(.*?);};
--	$available = $1 if $entry3 =~ m{<dcterms:valid>\s*start=(.+?);\s*end=.*?;};
--	$duration = $1 if $entry3 =~ m{duration=\"(\d+?)\"};
--	$type = $1 if $entry3 =~ m{medium=\"(\w+?)\"};
--	$longdesc = $1 if $entry3 =~ m{<media:description>\s*(.*?)\s*<\/media:description>};
--	$guidance = $1 if $entry3 =~ m{<media:rating scheme="urn:simple">(.+?)<\/media:rating>};
--	$player = $1 if $entry3 =~ m{<media:player\s*url=\"(.*?)\"\s*\/>};
--	$thumbnail = $1 if $entry3 =~ m{<media:thumbnail url="([^"]+?)"\s+width="150"\s+height="84"\s*/>};
--	
--	my @cats;
--	for (split /<media:category scheme=\".+?\"/, $entry3) {
--		push @cats, $1 if m{\s*label="(.+?)">\d+<\/media:category>};
--	}
--	$categories = join ',', @cats;
-+		# Entry3 format
-+		#<?xml version="1.0" encoding="utf-8"?>                                      
-+		#<?xml-stylesheet href="http://www.bbc.co.uk/iplayer/style/rss.css" type="text/css"?>
-+		#<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:media="http://search.yahoo.com/mrss/" xml:lang="en-GB">
-+		#  <title>BBC iPlayer - Episode Detail: Edith Bowman: 22/09/2008</title>                                                                          
-+		#  <subtitle>Sara Cox sits in for Edith with another Cryptic Randomizer.</subtitle>
-+		#  <updated>2008-09-29T10:59:45Z</updated>
-+		#  <id>tag:feeds.bbc.co.uk,2008:/iplayer/feed/episode/b00djtfh</id>
-+		#  <link rel="related" href="http://www.bbc.co.uk/iplayer" type="text/html" />
-+		#  <link rel="self" href="http://feeds.bbc.co.uk/iplayer/episode/b00djtfh" type="application/atom+xml" />
-+		#  <author>
-+		#    <name>BBC</name>
-+		#    <uri>http://www.bbc.co.uk</uri>
-+		#  </author>
-+		#  <entry>
-+		#    <title type="text">Edith Bowman: 22/09/2008</title>
-+		#    <id>tag:feeds.bbc.co.uk,2008:PIPS:b00djtfh</id>
-+		#    <updated>2008-09-15T01:28:36Z</updated>
-+		#    <summary>Sara Cox sits in for Edith with another Cryptic Randomizer.</summary>
-+		#    <content type="html">
-+		#      &lt;p&gt;
-+		#        &lt;a href=&quot;http://www.bbc.co.uk/iplayer/episode/b00djtfh?src=a_syn30&quot;&gt;
-+		#          &lt;img src=&quot;http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_150_84.jpg&quot; alt=&quot;Edith Bowman: 22/09/2008&quot; /&gt;
-+		#        &lt;/a&gt;
-+		#      &lt;/p&gt;
-+		#      &lt;p&gt;
-+		#        Sara Cox sits in for Edith with movie reviews and great new music, plus another Cryptic Randomizer.
-+		#      &lt;/p&gt;
-+		#    </content>
-+		#    <link rel="alternate" href="http://www.bbc.co.uk/iplayer/episode/b00djtfh?src=a_syn31" type="text/html" title="Edith Bowman: 22/09/2008">
-+		#      <media:content medium="audio" duration="10800">
-+		#        <media:title>Edith Bowman: 22/09/2008</media:title>
-+		#        <media:description>Sara Cox sits in for Edith with movie reviews and great new music, plus another Cryptic Randomizer.</media:description>
-+		#        <media:player url="http://www.bbc.co.uk/iplayer/episode/b00djtfh?src=a_syn31" />
-+		#        <media:category scheme="urn:bbc:metadata:cs:iPlayerUXCategoriesCS" label="Entertainment">9100099</media:category>
-+		#        <media:category scheme="urn:bbc:metadata:cs:iPlayerUXCategoriesCS" label="Music">9100006</media:category>
-+		#        <media:category scheme="urn:bbc:metadata:cs:iPlayerUXCategoriesCS" label="Pop &amp; Chart">9200069</media:category>
-+		#        <media:credit role="Production Department" scheme="urn:ebu">BBC Radio 1</media:credit>
-+		#        <media:credit role="Publishing Company" scheme="urn:ebu">BBC Radio 1</media:credit>
-+		#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_86_48.jpg" width="86" height="48" />
-+		#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_150_84.jpg" width="150" height="84" />
-+		#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_178_100.jpg" width="178" height="100" />
-+		#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_512_288.jpg" width="512" height="288" />
-+		#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_528_297.jpg" width="528" height="297" />
-+		#        <media:thumbnail url="http://www.bbc.co.uk/iplayer/images/episode/b00djtfh_640_360.jpg" width="640" height="360" />
-+		#        <dcterms:valid>
-+		#          start=2008-09-22T15:44:20Z;
-+		#          end=2008-09-29T15:02:00Z;
-+		#          scheme=W3C-DTF
-+		#        </dcterms:valid>
-+		#      </media:content>
-+		#    </link>
-+		#    <link rel="self" href="http://feeds.bbc.co.uk/iplayer/episode/b00djtfh?format=atom" type="application/atom+xml" title="22/09/2008" />
-+		#    <link rel="related" href="http://www.bbc.co.uk/programmes/b006wks4/microsite" type="text/html" title="Edith Bowman" />
-+		#    <link rel="parent" href="http://feeds.bbc.co.uk/iplayer/programme_set/b006wks4" type="application/atom+xml" title="Edith Bowman" />
-+		#  </entry>
-+		#</feed>
-+			
-+		$expiry = $1 if $entry3 =~ m{<dcterms:valid>\s*start=.+?;\s*end=(.*?);};
-+		$available = $1 if $entry3 =~ m{<dcterms:valid>\s*start=(.+?);\s*end=.*?;};
-+		$duration = $1 if $entry3 =~ m{duration=\"(\d+?)\"};
-+		$prog_type = $1 if $entry3 =~ m{medium=\"(\w+?)\"};
-+		$longdesc = $1 if $entry3 =~ m{<media:description>\s*(.*?)\s*<\/media:description>};
-+		$guidance = $1 if $entry3 =~ m{<media:rating scheme="urn:simple">(.+?)<\/media:rating>};
-+		$player = $1 if $entry3 =~ m{<media:player\s*url=\"(.*?)\"\s*\/>};
-+		$thumbnail = $1 if $entry3 =~ m{<media:thumbnail url="([^"]+?)"\s+width="150"\s+height="84"\s*/>};
-+	
-+		my @cats;
-+		for (split /<media:category scheme=\".+?\"/, $entry3) {
-+			push @cats, $1 if m{\s*label="(.+?)">\d+<\/media:category>};
-+		}
-+		$categories = join ',', @cats;
-+
-+		# populate version pid metadata 
-+		get_version_pids($ua, $pid);
-+
-+	# ITV Catch-Up metadata
-+	} elsif ( $prog{$pid}{type} eq 'itv' ) {
-+		my $prog_metadata_url_itv = 'http://www.itv.com/_app/Dynamic/CatchUpData.ashx?ViewType=5&Filter='; # +<pid>
-+		$entry3 = request_url_retry($ua, "${prog_metadata_url_itv}${pid}", 3, '', '');
-+		decode_entities($entry3);
-+		logger "DEBUG: ${prog_metadata_url_itv}${pid}:\n$entry3\n\n" if $opt{debug};
-+		# Flatten
-+		$entry3 =~ s|[\r\n]||g;
-+
-+		#div class="itvCatchUpPlayerPanel" xmlns:ms="urn:schemas-microsoft-com:xslt">
-+		#  <div class="cu-sponsor"><a href="http://sam.itv.com/accipiter/adclick/CID=000040d70000000000000000/acc_random=1/SITE=CLICKTRACK/AREAITVCATCHUP.VIDEO=CLICKTRACK..FREEVIEW.SPONSORBUTTON.OCT08/AAMSZ=120X60/pageid=1" title="ITV Player in assocation with Freeview"><img src="/_app/img/catchup/catchup_video_freeview2.jpg" alt="ITV Player is sponsored by Freeview"></a></div>
-+		#  <h2>Doctor Zhivago</h2>
-+		#  <p>Part 1 of 3. Dramatisation of the epic novel by Boris Pasternak. Growing up in Moscow with his uncle, aunt and cousin Tonya, Yury is captivated by a stunning young girl called ...</p>
-+		#  <p class="timings"><span class="date">Mon 29 Dec 2008</span><br /><br /><span>
-+		#
-+		#        Duration: 1hr 30 min |
-+		#                                Expires in
-+		#                                <strong>22</strong>
-+		#                                                days
-+		#                                        </span></p>
-+		#  <p><a href="http://www.itv.com/CatchUp/Programmes/default.html?ViewType=1&amp;Filter=2352">3 Episodes Available
-+		#        </a><br></br></p>
-+		#  <p class="channelLogo"><img src="/_app/img/logos/itv3-black.gif" alt="ITV 4"></p>
-+		#  <div id="cu-2-0-VideoID">33105</div>
-+		#  <div id="cu-2-0-DentonId">17</div>
-+		#  <div id="cu-2-0-ItemMediaUrl">http://www.itv.com//img/480x272/Doctor-Zhivago-c47828f8-a1af-4cd2-b5a2-40c18eb7e63c.jpg</div>
-+		#</div><script language="javascript" type="text/javascript" xmlns:ms="urn:schemas-microsoft-com:xslt">
-+		#                        SetCatchUpModuleID(0);
-+		#                </script>
-+		#
- 
--	# populate version pid metadata 
--	get_version_pids($ua, $pid);
-+		#<div class="itvCatchUpPlayerPanel" xmlns:ms="urn:schemas-microsoft-com:xslt">
-+		#  <div class="cu-sponsor"><a href="http://sam.itv.com/accipiter/adclick/CID=000040d70000000000000000/acc_random=1/SITE=CLICKTRACK/AREAITVCATCHUP.VIDEO=CLICKTRACK..FREEVIEW.SPONSORBUTTON.OCT08/AAMSZ=120X60/pageid=1" title="ITV Player in assocation with Freeview"><img src="/_app/img/catchup/catchup_video_freeview2.jpg" alt="ITV Player is sponsored by Freeview"></a></div>
-+		#  <h2>Affinity</h2>
-+		#  <p>Victorian period drama with a murderous, pyschological twist.</p>
-+		#  <p class="timings"><span class="date">Sun 28 Dec 2008</span><br /><br /><span>
-+		#
-+		#        Duration: 2hr 00 min |
-+		#                                Expires in
-+		#                                <strong>21</strong>
-+		#                                                days
-+		#                                        </span></p>
-+		#  <p class="channelLogo"><img src="/_app/img/logos/itv1-black.gif" alt="ITV 2"></p>
-+		#  <div class="guidance">
-+		#    <div><strong>ITV Video Guidance</strong><p>This programme contains strong language and scenes of a sexual nature                                                                                                                           </p>
-+		#    </div>
-+		#  </div>
-+		#  <div id="cu-2-0-VideoID">33076</div>
-+		#  <div id="cu-2-0-DentonId">11</div>
-+		#  <div id="cu-2-0-ItemMediaUrl">http://www.itv.com//img/480x272/Affinity-9624033b-6e05-4784-85f7-114be0559b24.jpg</div>
-+		#</div><script language="javascript" type="text/javascript" xmlns:ms="urn:schemas-microsoft-com:xslt">
-+		#                        SetCatchUpModuleID(0);
-+		#                </script>
-+		#
-+
-+		#$expiry = $1 if $entry3 =~ m{<dcterms:valid>\s*start=.+?;\s*end=(.*?);};
-+		$available = $1 if $entry3 =~ m{<p\s+class="timings">\s*<span\s+class="date">(.+?)<\/span>};
-+		$duration = $1 if $entry3 =~ m{Duration:\s*(.+?)\s+\|};
-+		#$prog_type = $1 if $entry3 =~ m{medium=\"(\w+?)\"};
-+		$longdesc = $1 if $entry3 =~ m{<p>(.+?)<\/p>}i;
-+		$guidance = $1 if $entry3 =~ m{ITV Video Guidance<\/strong><p>\s*(.+?)[\W\s]*<\/p>};
-+		#$player = $1 if $entry3 =~ m{<media:player\s*url=\"(.*?)\"\s*\/>};
-+		$thumbnail = $1 if $entry3 =~ m{<div id="cu-2-0-ItemMediaUrl">(.+?)</div>};
-+		$name = $1 if $entry3 =~ m{<h2>(.+?)</h2>};
-+	}
- 
- 	# Fill in from cache if not got from metadata
- 	my %metadata;
- 	$metadata{pid}		= $pid;
- 	$metadata{index}	= $prog{$pid}{index};
--	$metadata{type}		= $type || $prog{$pid}{type};
-+	$metadata{name}		= $name || $prog{$pid}{name};
-+	$metadata{episode}	= $episode || $prog{$pid}{episode};
-+	$metadata{type}		= $prog_type || $prog{$pid}{type};
- 	$metadata{duration}	= $duration || $prog{$pid}{duration};
- 	$metadata{channel}	= $channel || $prog{$pid}{channel};
- 	$metadata{available}	= $available || $prog{$pid}{available};
-@@ -3492,7 +4493,7 @@
- 		logger "WARNING: Cannot write or append to $historyfile\n\n";
- 		return 1;
- 	}
--	print HIST "$pid|$prog{$pid}{name}|$prog{$pid}{episode}|$prog{$pid}{type}|".time()."\n";
-+	print HIST "$pid|$prog{$pid}{name}|$prog{$pid}{episode}|$prog{$pid}{type}|".time()."|$prog{$pid}{mode}\n";
- 	close HIST;
- 	return 0;
- }
-@@ -3555,7 +4556,10 @@
- # Add id3 tag to MP3 files if required
- sub tag_file {
- 	my $pid = shift;
-+
- 	if ( $prog{$pid}{ext} eq 'mp3' ) {
-+		# Return if file does not exist
-+		return if ! -f $prog{$pid}{filename};
- 		# Create ID3 tagging options for external tagger program (escape " for shell)
- 		my ( $id3_name, $id3_episode, $id3_desc, $id3_channel ) = ( $prog{$pid}{name}, $prog{$pid}{episode}, $prog{$pid}{desc}, $prog{$pid}{channel} );
- 		$id3_name =~ s|"|\"|g for ($id3_name, $id3_episode, $id3_desc, $id3_channel);
-@@ -3580,9 +4584,16 @@
- sub list_unique_element_counts {
- 	my $element_name = shift;
- 	my %elements;
--	logger "INFO: $opt{type} $element_name List:\n" if $opt{verbose};
-+	logger "INFO: ".(join ',', keys %type)." $element_name List:\n" if $opt{verbose};
- 	for my $pid (keys %prog) {
--		for my $element ( split /,/, $prog{$pid}{$element_name} ) {
-+		my @element;
-+		# Need to separate the categories
-+		if ($element_name eq 'categories') {
-+			@element = split /,/, $prog{$pid}{$element_name};
-+		} else {
-+			@element[0] = $prog{$pid}{$element_name};
-+		}
-+		for my $element (@element) {
- 			$elements{ $element }++;
- 		}
- 	}
-@@ -3659,6 +4670,7 @@
- 
- 
- 
-+
- # Save the options on the cmdline as a PVR search with the specified name
- sub pvr_add {
- 	my $name = shift;
-@@ -3670,7 +4682,7 @@
- 		return 1;
- 	}
- 	# Parse valid options and create array (ignore options from the options files that have not been overriden on the cmdline)
--	for (grep /^(long|output.*|proxy|subdir|whitespace|versions|type|(exclude)?category|(exclude)?channel|command|realaudio|mp3audio|wav|raw|bandwidth|subtitles|suboffset|since|versionlist|verbose)$/, sort {$a <=> $b} keys %opt_cmdline) {
-+	for (grep /^(amode|vmode|long|output.*|proxy|subdir|whitespace|versions|type|(exclude)?category|(exclude)?channel|command|realaudio|mp3audio|wav|raw|bandwidth|subtitles|suboffset|since|versionlist|verbose)$/, sort {lc $a cmp lc $b} keys %opt_cmdline) {
- 		if ( defined $opt_cmdline{$_} ) {
- 				push @options, "$_ $opt_cmdline{$_}";
- 				logger "DEBUG: Adding option $_ = $opt_cmdline{$_}\n" if $opt{debug};
-@@ -3715,7 +4727,7 @@
- 	pvr_load_list();
- 	# Print out list
- 	logger "All PVR Searches:\n\n";
--	for my $name ( sort {$a <=> $b} keys %pvrsearches ) {
-+	for my $name ( sort {lc $a cmp lc $b} keys %pvrsearches ) {
- 		# Report whether disabled
- 		if ( $pvrsearches{$name}{disable} ) {
- 			logger "(Disabled) PVR Search '$name':\n";
-diff -ruaN mythvodka.orig/scripts/gethulu.pl mythvodka/scripts/gethulu.pl
---- mythvodka.orig/scripts/gethulu.pl	2009-01-06 19:26:30.000000000 +0000
-+++ mythvodka/scripts/gethulu.pl	2009-02-12 07:27:44.000000000 +0000
-@@ -123,7 +123,8 @@
-       if($ephtml =~ m/thumbnail_url: "(.+?)"/)  { $epimg=$1 } ;
- 
-       print MYTHMENU "<Stream>\n";
--      print MYTHMENU "<Name>$eptitle</Name>\n";
-+      print MYTHMENU "<Name>$title-$eptitle</Name>\n";
-+      #print MYTHMENU "<Name>$eptitle</Name>\n";
-       print MYTHMENU "<Url>http://www.hulu.com/watch/$epid</Url>\n";
-       print MYTHMENU "<Subtitle>$season - $epno</Subtitle>\n";
-       print MYTHMENU "<Synopsis>$epdate - $epdesc</Synopsis>\n";
-diff -ruaN mythvodka.orig/scripts/hulu mythvodka/scripts/hulu
---- mythvodka.orig/scripts/hulu	2009-01-04 15:25:24.000000000 +0000
-+++ mythvodka/scripts/hulu	2009-02-12 07:27:44.000000000 +0000
-@@ -22,6 +22,7 @@
- html=get_HTML(cid)
- cidSoup=BeautifulStoneSoup(html)
- pid=cidSoup.findAll('pid')[0].contents[0]
-+logfile="/var/log/mythtv/hulu_quality.log"
- 
- smilURL = "http://releasegeo.hulu.com/content.select?pid=" + pid + "&mbr=true&format=smil"
- print smilURL
-@@ -34,18 +35,58 @@
- #label streams
- i=0
- quality=0
-+qual_medium=-1; qual_high=-1; qual_h264=-1; command2="echo hulu done."
-+os.system("rm -f "+logfile+".0")
-+os.system("mv -f "+logfile+" "+logfile+".0")
-+f=open(logfile,'w')
-+os.system("chmod a+rw "+logfile)
-+print >>f, "Debug debug"
-+print >>f, "hulu ",url, " ", fileout
-+#
-+# Find the various quality choices that are available
-+#
- for stream in video:
--    if "480K" in stream['src'] or "480k" in stream['src']:
-+    print >>f, stream
-+    if "H264" in stream['src'] or "h264" in stream['src'] or "h264" in stream['profile'] or "H264" in stream['profile']:
-+        streams.append(['H264',stream['src']])
-+	qual_h264=i
-+	print >>f, "DebugQual h264", i
-+	print >>f, ""
-+    elif "480K" in stream['src'] or "480k" in stream['src']:
-         streams.append(['Flash (480k)',stream['src']])
-+	qual_medium=i
-+	print >>f, "DebugQual medium", i
-+	print >>f, ""
-     elif "700K" in stream['src'] or "700k" in stream['src']:
-         streams.append(['Flash (700k)',stream['src']])
- 	quality=i
--    elif "H264" in stream['src'] or "h264" in stream['src']:
--        streams.append(['H264',stream['src']])
-+	qual_high=i
-+	print >>f, "DebugQual high", i
-+	print >>f, ""
-+    elif "medium" in stream['profile'] or "Medium" in stream['profile']:
-+	streams.append(['Flash (Medium)',stream['src']])
-+	if qual_medium==-1: qual_medium=i
-+        print >>f, "DebugQual Medium", i, qual_medium
-+        print >>f, ""
-+    elif "high" in stream['profile'] or "High" in stream['profile']:
-+        streams.append(['Flash (High)',stream['src']])
-+	if qual_high==-1: qual_high=i
-+	print >>f, "DebugQual High", i, qual_high
-+	print >>f, ""
-     else:
-         streams.append(['unkown quality: '+stream['src'].split('/')[-1],stream['src']])
-+	print >>f, "DebugQual Unknown", i
-+	print >>f, ""
-     i=i+1
- 
-+if qual_high>-1: 
-+    quality=qual_high
-+elif qual_medium>-1:
-+    quality=qual_medium
-+
-+print >>f, "DebugQualVars: h264, high, medium, selected=",qual_h264,qual_high,qual_medium,quality
-+
-+
- if quality!=-1:
-     print "stream url"
- #generate random code
-@@ -104,4 +145,9 @@
-     command=command.replace(';','\\;')
- 
-     print command
--    os.system(command)
-+    print >>f,"Command is ",command
-+    print >>f,"command2 is ",command2
-+    f.close()
-+    os.system(command + "; " + command2)
-+else:
-+    f.close()
-diff -ruaN mythvodka.orig/scripts/mythvodka_player.sh mythvodka/scripts/mythvodka_player.sh
---- mythvodka.orig/scripts/mythvodka_player.sh	1970-01-01 00:00:00.000000000 +0000
-+++ mythvodka/scripts/mythvodka_player.sh	2009-02-12 07:27:44.000000000 +0000
-@@ -0,0 +1,38 @@
-+#! /bin/bash
-+#
-+log=/var/log/mythtv/mythvodka_player.log
-+player_list="/usr/local/bin/mplayer_h264 /usr/local/bin/mplayer \
-+             /usr/bin/mplayer /bin/mplayer"
-+#
-+player_list="/usr/local/bin/mplayer /usr/bin/mplayer /bin/mplayer"
-+f="$1"
-+shift
-+rm -f $log
-+echo "Request to play $f on `date`" >> $log
-+player=""
-+for player in $player_list; do
-+  if [ -x "$player" ]; then
-+    echo "Found player $player" >> $log
-+    break
-+  fi
-+done
-+if [ ! -x $player ]; then
-+  echo "ERROR -- not able to find mplayer on your system. " >> $log
-+  echo "I searched the following list" >> $log
-+  echo "  $player_list" >> $log
-+  exit 1
-+fi
-+for pass in 1 2 4 8 10; do
-+  size="0"
-+  if [ -e $f ]; then
-+    size=$( du --apparent-size -sD "$f" | awk '{ print $1 }' )
-+    if [ $size -gt 1500 ]; then
-+      break
-+    fi
-+  fi
-+  echo "Pass $pass, filesize is $size kbytes, sleep $pass seconds" >> $log
-+  sleep $pass
-+done
-+size=$( du --apparent-size -sD "$f" | awk '{ print $1 }' )
-+echo "Reached $size kb on pass $pass `date`" >> $log
-+$player -fs -vo xv $f
diff --git a/abs/extra/mythvodka/mythvodka.install b/abs/extra/mythvodka/mythvodka.install
deleted file mode 100644
index 4a9827e..0000000
--- a/abs/extra/mythvodka/mythvodka.install
+++ /dev/null
@@ -1,47 +0,0 @@
-# arg 1:  the new package version
-post_install() {
-  mv /usr/share/mythtv/is.xml /tmp
-  grep -v -e /mythmenu /tmp/is.xml > /tmp/is.xml.tmp
-  echo "<!--#MythVodka-->" >> /tmp/is.xml.tmp
-  echo "   <button>" >> /tmp/is.xml.tmp
-  echo "     <type>STREAM</type>" >> /tmp/is.xml.tmp
-  echo "     <text>Myth Vodka</text>" >> /tmp/is.xml.tmp
-  echo "     <action>PLUGIN mythvodka</action>" >> /tmp/is.xml.tmp 
-  echo "     <depends>mythvodka</depends>" >> /tmp/is.xml.tmp 
-  echo "   </button>" >> /tmp/is.xml.tmp
-  echo "<!--#MythVodka-->" >> /tmp/is.xml.tmp
-  echo "" >> /tmp/is.xml.tmp
-  echo "</mythmenu>" >> /tmp/is.xml.tmp
-  mv /tmp/is.xml.tmp /usr/share/mythtv/is.xml
-
-  mv /usr/share/mythtv/media_settings.xml /tmp
-  grep -v -e /mythmenu /tmp/media_settings.xml > /tmp/ms.xml.tmp
-  echo "<!--#MythVodka-->" >> /tmp/ms.xml.tmp
-  echo "   <button>" >> /tmp/ms.xml.tmp
-  echo "     <type>SETTINGS MYTHVODKA</type>" >> /tmp/ms.xml.tmp
-  echo "     <text>MythVodka Settings</text>" >> /tmp/ms.xml.tmp
-  echo "     <action>CONFIGPLUGIN mythvodka</action>" >> /tmp/ms.xml.tmp 
-  echo "     <depends>mythvodka</depends>" >> /tmp/ms.xml.tmp 
-  echo "   </button>" >> /tmp/ms.xml.tmp
-  echo "<!--#MythVodka-->" >> /tmp/ms.xml.tmp
-  echo "" >> /tmp/ms.xml.tmp
-  echo "</mythmenu>" >> /tmp/ms.xml.tmp
-  mv /tmp/ms.xml.tmp /usr/share/mythtv/media_settings.xml
-}
-# arg 1:  the new package version
-# arg 2:  the old package version
-post_upgrade() {
-	/bin/true
-}
-
-# arg 1:  the old package version
-post_remove() {
-	mv /usr/share/mythtv/is.xml /tmp/is.xml.tmp
-	sed -e '/\#MythVodka/,/\#MythVodka/d' < /tmp/is.xml.tmp > /usr/share/mythtv/is.xml
-	mv /usr/share/mythtv/media_settings.xml /tmp/ms.xml.tmp
-	sed -e '/\#MythVodka/,/\#MythVodka/d' < /tmp/ms.xml.tmp > /usr/share/mythtv/media_settings.xml
-}
-
-op=$1
-shift
-$op $*
-- 
cgit v0.12

