--- Begin Message ---
Package: release.debian.org
Severity: normal
User: [email protected]
Usertags: unblock
Hi,
Please unblock get-iplayer/2.87-2. Sorry that this is a little late up to
the starting gate.
get-iplayer is for browsing the BBC iPlayer archives with free software. It
consumes various feeds and can display schedules, download programmes and
stream live data.
A few weeks ago the BBC radically changed the way the feeds are produced,
rendering get-iplayer effectively useless. Upstream has made a number of
changes to suit, of which I've cherry picked the ones that restore basic
functionality, but left out nicities like thumbnail substitution. The
patches are unforunately invasive but necessary.
The bug fixed is severity:important.
Without an unblock, the alternative is to remove get-iplayer altogether. My
intention is to ship this working version in Jessie, and augment it with
the other missing features in backports later.
Debdiff attached.
changelog | 8
patches/cache-search.patch | 1030 ++++++++++++++++++++++++++++++++++++++++++
patches/data-feeds.patch | 221 +++++++++
patches/future-schedule.patch | 81 +++
patches/live-tv.patch | 18
patches/series | 4
6 files changed, 1362 insertions(+)
--
Jonathan Wiltshire [email protected]
Debian Developer http://people.debian.org/~jmw
4096R: 0xD3524C51 / 0A55 B7C5 1223 3942 86EC 74C3 5394 479D D352 4C51
diff -Nru get-iplayer-2.87/debian/changelog get-iplayer-2.87/debian/changelog
--- get-iplayer-2.87/debian/changelog 2014-10-20 20:39:26.000000000 +0100
+++ get-iplayer-2.87/debian/changelog 2014-12-04 23:22:09.000000000 +0000
@@ -1,3 +1,11 @@
+get-iplayer (2.87-2) unstable; urgency=medium
+
+ * Fix feed fetch, parse and search across all channels after invasive
+ changes by the BBC. All patches cherry-picked from upstream
+ (Closes: #767331)
+
+ -- Jonathan Wiltshire <[email protected]> Thu, 04 Dec 2014 23:21:16 +0000
+
get-iplayer (2.87-1) unstable; urgency=medium
* New upstream release (Closes: #743905, 623179)
diff -Nru get-iplayer-2.87/debian/patches/cache-search.patch
get-iplayer-2.87/debian/patches/cache-search.patch
--- get-iplayer-2.87/debian/patches/cache-search.patch 1970-01-01
01:00:00.000000000 +0100
+++ get-iplayer-2.87/debian/patches/cache-search.patch 2014-12-04
23:22:09.000000000 +0000
@@ -0,0 +1,1030 @@
+From: dinkypumpkin <[email protected]>
+Date: Thu, 30 Oct 2014 21:54:17 +0000
+Subject: Partial restoration of cache and search functions
+Origin:
http://git.infradead.org/get_iplayer.git/commit/8220a6bf04a83f49f75d4996b6222ef3fd5d9d8b
+
http://git.infradead.org/get_iplayer.git/commit/0c1e7ab3fb92656613dfe7811a31d559224957cc
+Last-Update: 2014-12-03
+
+--- get-iplayer-2.87.orig/get_iplayer
++++ get-iplayer-2.87/get_iplayer
+@@ -227,6 +227,12 @@
+ refreshinclude => [ 1, "refreshinclude|refresh-include=s", 'Config',
'--refresh-include <string>', "Include matched channel(s) when refreshing cache
(regex or comma separated values)"],
+ refreshexclude => [ 1,
"refreshexclude|refresh-exclude|ignorechannels=s", 'Config', '--refresh-exclude
<string>', "Exclude matched channel(s) when refreshing cache (regex or comma
separated values)"],
+ refreshfuture => [ 1, "refreshfuture|refresh-future!", 'Config',
'--refresh-future', "Obtain future programme schedule when refreshing cache
(between 7-14 days)"],
++ refreshfeeds => [ 1, "refreshfeeds|refresh-feeds=s", 'Config',
'--refresh-feeds <string>', "Alternate source for programme data. Valid
values: 'schedule'"],
++ refreshfeedsradio => [ 1,
"refreshfeedsradio|refresh-feeds-radio=s", 'Config', '--refresh-feeds-radio
<string>', "Alternate source for radio programme data. Valid values:
'schedule'"],
++ refreshfeedstv => [ 1, "refreshfeedstv|refresh-feeds-tv=s", 'Config',
'--refresh-feeds-tv <string>', "Alternate source for TV programme data. Valid
values: 'schedule'"],
++ refreshlimit => [ 1, "refreshlimit|refresh-limit=n", 'Config',
'--refresh-limit <integer>', "Number of days of programmes to cache. Only
applied with --refresh-feeds=schedule. Makes cache updates VERY slow. Default:
7 Min: 1 Max: 30"],
++ refreshlimitradio => [ 1,
"refreshlimitradio|refresh-limit-radio=n", 'Config', '--refresh-limit-radio
<integer>', "Number of days of radio programmes to cache. Only applied with
--refresh-feeds=schedule. Makes cache updates VERY slow. Default: 7 Min: 1 Max:
30"],
++ refreshlimittv => [ 1, "refreshlimittv|refresh-limit-tv=n", 'Config',
'--refresh-limit-tv <integer>', "Number of days of TV programmes to cache. Only
applied with --refresh-feeds=schedule. Makes cache updates VERY slow. Default:
7 Min: 1 Max: 30"],
+ skipdeleted => [ 1, "skipdeleted!", 'Config', "--skipdeleted",
"Skip the download of metadata/thumbs/subs if the media file no longer exists.
Use with --history & --metadataonly/subsonly/thumbonly."],
+ update => [ 2, "update|u!", 'Config', '--update, -u', "Update
get_iplayer if a newer one exists"],
+ webrequest => [ 1, "webrequest=s", 'Config', '--webrequest
<urlencoded string>', 'Specify all options as a urlencoded string of
"name=val&name=val&..."' ],
+@@ -6996,7 +7002,7 @@
+ use IO::Socket;
+ use LWP::ConnCache;
+ use LWP::UserAgent;
+-use POSIX qw(mkfifo);
++use POSIX qw(mkfifo strftime);
+ use strict;
+ use Time::Local;
+ use URI;
+@@ -7009,24 +7015,16 @@
+ sub index_max { return 9999 }
+ sub channels {
+ return {
+- 'bbcone' => 'BBC One',
+- 'bbctwo' => 'BBC Two',
+- 'bbcthree' => 'BBC Three',
+- 'bbcfour' => 'BBC Four',
+- 'bbcnews' => 'BBC News',
+- 'bbcnews24' => 'BBC News',
++ 'bbc_one' => 'BBC One',
++ 'bbc_two' => 'BBC Two',
++ 'bbc_three' => 'BBC Three',
++ 'bbc_four' => 'BBC Four',
+ 'cbbc' => 'CBBC',
+ 'cbeebies' => 'CBeebies',
+- 'parliament' => 'BBC Parliament',
+- 'bbcwebonly' => 'BBC Web Only',
+- 'bbchd' => 'BBC HD',
+- 'bbcalba' => 'BBC Alba',
+- 'categories/news/tv' => 'BBC News',
+- 'categories/sport/tv' => 'BBC Sport',
+- 'categories/signed' => 'Signed',
+- 'categories/audiodescribed' => 'Audio Described',
+- 'popular/tv' => 'Popular',
+- 'highlights/tv' => 'Highlights',
++ 'bbc_news24' => 'BBC News',
++ 'bbc_parliament' => 'BBC Parliament',
++ 'bbc_alba' => 'BBC Alba',
++ 'bbc_webonly' => 'BBC Web Only',
+ };
+ }
+
+@@ -7176,143 +7174,53 @@
+ }
+ }
+
+-
+-
+-# Usage: Programme::tv->get_links( \%prog, 'tv' );
+-# Uses: %{ channels() }, \%prog
+-sub get_links {
+- shift; # ignore obj ref
++sub get_links_aod {
++ my $self = shift;
+ my $prog = shift;
+ my $prog_type = shift;
++ return 1 if $prog_type ne "radio";
+ # Hack to get correct 'channels' method because this methods is being
shared with Programme::radio
+- my %channels = %{ main::progclass($prog_type)->channels_filtered(
main::progclass($prog_type)->channels() ) };
+- my $channel_feed_url = 'http://feeds.bbc.co.uk/iplayer'; #
/$channel/list
++ my %channels = %{ main::progclass($prog_type)->channels_filtered(
main::progclass($prog_type)->channels_aod() ) };
+ my $bbc_prog_page_prefix = 'http://www.bbc.co.uk/programmes'; # /$pid
+- my $thumbnail_prefix = 'http://www.bbc.co.uk/iplayer/images/episode';
+- my $xml;
+- my $feed_data;
+- my $res;
+- main::logger "INFO: Getting $prog_type Index Feeds\n";
+ # Setup User agent
+ my $ua = main::create_ua( 'desktop', 1 );
+-
+ # 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
+- my @channel_list;
+- push @channel_list, grep !/(categor|popular|highlights|bbchd)/, keys
%channels;
+- push @channel_list, grep /categor/, keys %channels;
+- push @channel_list, grep /popular/, keys %channels;
+- push @channel_list, grep /highlights/, keys %channels;
+- push @channel_list, grep /bbchd/, keys %channels;
+- for ( @channel_list ) {
+-
+- my $url = "${channel_feed_url}/$_/list/limit/400";
+- main::logger "DEBUG: Getting feed $url\n" if $opt->{verbose};
+- $xml = main::request_url_retry($ua, $url, 3, '.', "WARNING:
Failed to get programme index feed for $_ from iplayer site\n");
++ my @channel_list = keys %channels;
++ for my $channel_id ( @channel_list ) {
++ my $url =
"http://www.bbc.co.uk/radio/aod/availability/${channel_id}.xml";
++ main::logger "\nDEBUG: Getting feed $url\n" if $opt->{verbose};
++ my $xml = main::request_url_retry($ua, $url, 3, '.',
"\nWARNING: Failed to get programme index feed for $channels{$channel_id}\n");
+ decode_entities($xml);
+-
+- # Feed as of August 2008
+- # <entry>
+- # <title type="text">Bargain Hunt: Series 18:
Oswestry</title>
+- # <id>tag:feeds.bbc.co.uk,2008:PIPS:b0088jgs</id>
+- # <updated>2008-07-22T00:23:50Z</updated>
+- # <content type="html">
+- # <p>
+- # <a
href="http://www.bbc.co.uk/iplayer/episode/b0088jgs?src=a_syn30">
+- # <img
src="http://www.bbc.co.uk/iplayer/images/episode/b0088jgs_150_84.jpg"
alt="Bargain Hunt: Series 18: Oswestry" />
+- # </a>
+- # </p>
+- # <p>
+- # The teams are at an antiques fair in Oswestry
showground. Hosted by Tim Wonnacott.
+- # </p>
+- # </content>
+- # <category term="Factual" />
+- # <category term="Guidance" />
+- # <category term="TV" />
+- # <link rel="via"
href="http://www.bbc.co.uk/iplayer/episode/b0088jgs?src=a_syn30"
type="text/html" title="Bargain Hunt: Series 18: Oswestry" />
+- # </entry>
+- #
+-
+- ### New Feed
+- # <entry>
+- # <title type="text">House of Lords: 02/07/2008</title>
+- # <id>tag:bbc.co.uk,2008:PIPS:b00cd5p7</id>
+- # <updated>2008-06-24T00:15:11Z</updated>
+- # <content type="html">
+- # <p>
+- # <a
href="http://www.bbc.co.uk/iplayer/episode/b00cd5p7?src=a_syn30">
+- # <img
src="http://www.bbc.co.uk/iplayer/images/episode/b00cd5p7_150_84.jpg"
alt="House of Lords: 02/07/2008" />
+- # </a>
+- # </p>
+- # <p>
+- # House of Lords, including the third reading of the
Health and Social Care Bill. 1 July.
+- # </p>
+- # </content>
+- # <category term="Factual" scheme="urn:bbciplayer:category"
/>
+- # <link rel="via"
href="http://www.bbc.co.uk/iplayer/episode/b00cd5p7?src=a_syn30"
type="application/atom+xml" title="House of Lords: 02/07/2008">
+- # </link>
+- # </entry>
+-
+- ### Newer feed (Sept 2009)
+- # <entry>
+- # <title type="text">BBC Proms: 2009: Prom 65: Gustav Mahler
Jugend Orchester</title>
+- # <id>tag:feeds.bbc.co.uk,2008:PIPS:b00mgw03</id>
+- # <updated>2009-09-05T03:29:07Z</updated>
+- # <content type="html">
+- # <p>
+- # <a
href="http://www.bbc.co.uk/iplayer/episode/b00mgw03/BBC_Proms_2009_Prom_65_Gustav_Mahler_Jugend_Orchester/">
+- # <img
src="http://node1.bbcimg.co.uk/iplayer/images/episode/b00mgw03_150_84.jpg"
alt="BBC Proms: 2009: Prom 65: Gustav Mahler Jugend Orchester" />
+- # </a>
+- # </p>
+- # <p>
+- # The Gustav Mahler Youth Orchestra perform works by
Mahler, Richard Strauss and Ligeti.
+- # </p>
+- # </content>
+- # <category term="Music" />
+- # <category term="Classical" />
+- # <category term="TV" />
+- # <link rel="alternate"
href="http://www.bbc.co.uk/iplayer/episode/b00mgw03/BBC_Proms_2009_Prom_65_Gustav_Mahler_Jugend_Orchester/"
type="text/html" title="BBC Proms: 2009: Prom 65: Gustav Mahler Jugend
Orchester">
+- # <media:content>
+- # <media:thumbnail
url="http://node1.bbcimg.co.uk/iplayer/images/episode/b00mgw03_150_84.jpg"
width="150" height="84" />
+- # </media:content>
+- # </link>
+- # <link rel="self"
href="http://feeds.bbc.co.uk/iplayer/episode/b00mgw03"
type="application/atom+xml" title="Prom 65: Gustav Mahler Jugend Orchester" />
+- # <link rel="related"
href="http://www.bbc.co.uk/programmes/b007v097/microsite" type="text/html"
title="BBC Proms" />
+- # </entry>
+-
+-
+ # Parse XML
+-
+ # get list of entries within <entry> </entry> tags
+- my @entries = split /<entry>/, $xml;
++ my @entries = split /<entry/, $xml;
+ # Discard first element == header
+ shift @entries;
+-
+- main::logger "INFO: Got ".($#entries + 1)." programmes\n" if
$opt->{verbose};
++ main::logger "\nINFO: Got ".($#entries + 1)." programmes for
$channels{$channel_id}\n" if $opt->{verbose};
++ my $now = time();
+ foreach my $entry (@entries) {
+ my ( $title, $name, $episode, $episodetitle,
$nametitle, $episodenum, $seriesnum, $desc, $pid, $available, $channel,
$duration, $thumbnail, $version, $guidance );
+-
+- my $entry_flat = $entry;
+- $entry_flat =~ s/\n/ /g;
+-
+- # <id>tag:bbc.co.uk,2008:PIPS:b008pj3w</id>
+- $pid = $1 if $entry =~ m{<id>.*PIPS:(.+?)</id>};
+-
+- # <title type="text">Richard Hammond's Blast Lab:
Series Two: Episode 11</title>
+- # <title type="text">Skate Nation: Pro-Skate
Camp</title>
+- $title = $1 if $entry =~
m{<title\s*.*?>\s*(.*?)\s*</title>};
+-
++ my ($start, $available) = ($1, $2) if $entry =~
m{<availability\s+start="(.*?)"\s+end="(.*?)"};
++ next if ! ( $start || $available );
++ if ( $start ) {
++ my $xstart = Programme::get_time_string( $start
);
++ next if $xstart > $now;
++ }
++ if ( $available ) {
++ my $xavailable = Programme::get_time_string(
$available );
++ next if $xavailable < $now;
++ }
++ my $vpid = $1 if $entry =~ m{pid="(.+?)">};
++ $pid = $1 if $entry =~ m{<pid>(.+?)</pid>};
++ $duration = $1 if $entry =~ m{duration="(.*?)"};
++ $title = $1 if $entry =~ m{<title>(.*?)</title>};
+ # determine name and episode from title
+ ( $name, $episode ) =
Programme::bbciplayer::split_title( $title );
+-
+- # Get the title from the atom link refs only to
determine the longer episode name
+- $episodetitle = $1 if $entry =~
m{<link\s+rel="self"\s+href="http.+?/episode/.+?"\s+type="application/atom\+xml"\s+title="(.+?)"};
+- $nametitle = $1 if $entry =~
m{<link\s+rel="related"\s+href="http.+?/programmes/.+?"\s+type="text/html"\s+title="(.+?)"};
+-
++ $episodetitle = $episode;
++ $nametitle = $name;
+ # Extract the seriesnum
+ my $regex = 'Series\s+'.main::regex_numbers();
+ $seriesnum = main::convert_words_to_number( $1 ) if
"$name $episode" =~ m{$regex}i;
+-
+ # Extract the episode num
+ my $regex_1 = 'Episode\s+'.main::regex_numbers();
+ my $regex_2 = '^'.main::regex_numbers().'\.\s+';
+@@ -7323,79 +7231,20 @@
+ } elsif ( $episodetitle =~ m{$regex_2}i ) {
+ $episodenum = main::convert_words_to_number( $1
);
+ }
+-
+ # Re-insert the episode number if the episode text
doesn't have it
+ if ( $episodenum && $episodetitle =~ /^\d+\./ &&
$episode !~ /^(.+:\s+)?\d+\./ ) {
+ $episode =~ s/^(.+:\s+)?(.*)$/$1$episodenum.
$2/;
+ }
+-
+- #<p> House of Lords, including the third reading of
the Health and Social Care Bill. 1 July. </p> </content>
+- $desc = $1 if $entry =~
m{<p>\s*(.*?)\s*</p>\s*</content>};
+- $desc =~ s|[\n\r]| |g;
+- # Remove unwanted html tags
+- $desc =~ s!</?(br|b|i|p|strong)\s*/?>!!gi;
+-
+- # Parse the categories into hash
+- # <category term="Factual" />
+- my @category;
+- for my $line ( grep /<category/, (split /\n/, $entry) )
{
+- push @category, $1 if $line =~
m{<category\s+term="(.+?)"};
+- }
+- # strip commas - they confuse sorting and spliting later
+- s/,//g for @category;
+-
++ $desc = $1 if $entry =~ m{<synopsis>(.*?)</synopsis>};
+ # Extract channel
+- $channel = $channels{$_};
+- # Add HD as category
+- push @category, 'HD' if $channel eq 'BBC HD';
+-
++ $channel = $channels{$channel_id};
+ main::logger "DEBUG: '$pid, $name - $episode,
$channel'\n" if $opt->{debug};
+-
+ # Merge and Skip if this pid is a duplicate
+ if ( defined $prog->{$pid} ) {
+- main::logger "WARNING: '$pid,
$prog->{$pid}->{name} - $prog->{$pid}->{episode}, $prog->{$pid}->{channel}'
already exists (this channel = $channel)\n" if $opt->{verbose};
+- # Since we use the 'Signed' (or 'Audio
Described') channel to get sign zone/audio described data, merge the categories
from this entry to the existing entry
+- if ( $prog->{$pid}->{categories} ne join(',',
sort @category) ) {
+- my %cats;
+- $cats{$_} = 1 for ( @category, split
/,/, $prog->{$pid}->{categories} );
+- main::logger "INFO: Merged categories
for $pid from $prog->{$pid}->{categories} to ".join(',', sort keys %cats)."\n"
if $opt->{verbose};
+- $prog->{$pid}->{categories} = join(',',
sort keys %cats);
+- }
+-
+- # If this a popular or highlights programme
then add these tags to categories
+- my %cats;
+- $cats{$_} = 1 for ( @category, split /,/,
$prog->{$pid}->{categories} );
+- $cats{Popular} = 1 if $channel eq 'Popular';
+- $cats{Highlights} = 1 if $channel eq
'Highlights';
+- $prog->{$pid}->{categories} = join(',', sort
keys %cats);
+-
+- # If this is a dupicate pid and the channel is
now Signed then both versions are available
+- $version = 'signed' if $channel eq 'Signed';
+- $version = 'audiodescribed' if $channel eq
'Audio Described';
+- # Add version to versions for existing prog
+- $prog->{$pid}->{versions} = join ',',
main::make_array_unique_ordered( (split /,/, $prog->{$pid}->{versions}),
$version );
+ next;
+ }
+-
+- # Set guidance based on category
+- $guidance = 'Yes' if grep /guidance/i, @category;
+-
+- # Check for signed-only or audiodescribed-only version
from Channel
+- if ( $channel eq 'Signed' ) {
+- $version = 'signed';
+- } elsif ( $channel eq 'Audio Described' ) {
+- $version = 'audiodescribed';
+- } else {
+- $version = 'default';
+- }
+-
+- # Default to 150px width thumbnail;
+- my $thumbsize = $opt->{thumbsizecache} || 150;
+- my $thumbnail = $1 if $entry =~
m{<media:thumbnail.*?url="(.*?)"};
+- my $suffix =
Programme::bbciplayer->thumb_url_suffixes->{ $thumbsize };
+- if ( $thumbnail !~ /$suffix/ ) {
+- $thumbnail =~ s/_\d+_\d+\.jpg/$suffix/;
+- }
++ $version = 'default';
++ my @category;
+ # build data structure
+ $prog->{$pid} = main::progclass($prog_type)->new(
+ 'pid' => $pid,
+@@ -7407,203 +7256,408 @@
+ 'desc' => $desc,
+ 'guidance' => $guidance,
+ 'available' => 'Unknown',
+- 'duration' => 'Unknown',
++ 'duration' => $duration || 'Unknown',
+ 'thumbnail' => $thumbnail,
+ 'channel' => $channel,
+ 'categories' => join(',', sort @category),
+ 'type' => $prog_type,
+- 'web' =>
"${bbc_prog_page_prefix}/${pid}.html",
++ 'web' =>
"${bbc_prog_page_prefix}/${pid}",
+ );
+-
+ }
+ }
++}
+
+- # Get future schedules if required
+- # http://www.bbc.co.uk/cbbc/programmes/schedules/this_week.xml
+- # http://www.bbc.co.uk/cbbc/programmes/schedules/next_week.xml
+- if ( $opt->{refreshfuture} ) {
+- # Hack to get correct 'channels' method because this methods is
being shared with Programme::radio
+- my %channels = %{
main::progclass($prog_type)->channels_filtered(
main::progclass($prog_type)->channels_schedule() ) };
+- # Only get schedules for real channels
+- @channel_list = keys %channels;
+- for my $channel_id ( @channel_list ) {
+- my @schedule_feeds = (
+-
"http://www.bbc.co.uk/${channel_id}/this_week.xml",
+-
"http://www.bbc.co.uk/${channel_id}/next_week.xml",
+- );
+- for my $url ( @schedule_feeds ) {
+- main::logger "DEBUG: Getting feed $url\n" if
$opt->{verbose};
+- $xml = main::request_url_retry($ua, $url, 3,
'.', "WARNING: Failed to get programme schedule feed for $channel_id from
iplayer site\n");
+- decode_entities($xml);
+-
+- # <broadcast is_repeat="1" is_blanked="0">
+- # <pid>p00l44r8</pid>
+- # <start>2011-10-24T00:45:00+01:00</start>
+- # <end>2011-10-24T01:15:00+01:00</end>
+- # <duration>1800</duration>
+- # <programme type="episode">
+- # <pid>b016c73c</pid>
+- # <position>3</position>
+- # <title>Episode 3</title>
+- # <short_synopsis>With team captains Noel
Fielding and Phill Jupitus, and a surprise special guest host.</short_synopsis>
+- # <media_type>audio_video</media_type>
+- # <duration>2100</duration>
+- # <display_titles>
+- # <title>Never Mind the Buzzcocks</title>
+- # <subtitle>Series 25, Episode
3</subtitle>
+- # </display_titles>
+- #
<first_broadcast_date>2011-10-17T22:00:00+01:00</first_broadcast_date>
+- # <ownership>
+- # <service type="tv" id="bbc_two"
key="bbctwo">
+- # <title>BBC Two</title>
+- # </service>
+- # </ownership>
+- # <programme type="series">
+- # <pid>b015skhy</pid>
+- # <title>Series 25</title>
+- # <position>25</position>
+- #
<expected_child_count>12</expected_child_count>
+- #
<first_broadcast_date>2011-10-03T22:00:00+01:00</first_broadcast_date>
+- # <programme type="brand">
+- # <pid>b006v0dz</pid>
+- # <title>Never Mind the
Buzzcocks</title>
+- # <position />
+- # <expected_child_count />
+- #
<first_broadcast_date>2007-06-20T22:00:00+01:00</first_broadcast_date>
+- # <ownership>
+- # <service type="tv" id="bbc_two"
key="bbctwo">
+- # <title>BBC Two</title>
+- # </service>
+- # </ownership>
+- # </programme>
+- # </programme>
+- #
<available_until>2011-10-30T23:29:00Z</available_until>
+- #
<actual_start>2011-10-17T22:30:00+01:00</actual_start>
+- #
<is_available_mediaset_pc_sd>1</is_available_mediaset_pc_sd>
+- # <is_legacy_media>0</is_legacy_media>
+- # <media format="video">
+- # <expires>2011-10-30T23:29:00Z</expires>
+- # <availability>11 days left to
watch</availability>
+- # </media>
+- # </programme>
+- # </broadcast>
+-
+- # get list of entries within <broadcast>
</broadcast> tags
+- my @entries = split /<broadcast[^s]/, $xml;
+- # Discard first element == header
+- shift @entries;
+- main::logger "INFO: Got ".($#entries + 1)."
programmes\n" if $opt->{verbose};
+- my $now = time();
+- foreach my $entry (@entries) {
+- my ( $title, $channel, $name, $episode,
$episodetitle, $nametitle, $seriestitle, $episodenum, $seriesnum, $desc, $pid,
$available, $duration, $thumbnail, $version, $guidance );
+-
+- my $entry_flat = $entry;
+- $entry_flat =~ s/\n/ /g;
+-
+- $pid = $1 if $entry =~
m{<programme\s+type="episode">.*?<pid>\s*(.+?)\s*</pid>};
+-
+- $episode = $1 if $entry =~
m{<programme\s+type="episode">.*?<title>\s*(.*?)\s*</title>};
+- $nametitle = $1 if $entry =~
m{<programme\s+type="brand">.*?<title>\s*(.*?)\s*</title>.*?</programme>};
+- $seriestitle = $1 if $entry =~
m{<programme\s+type="series">.*?<title>\s*(.*?)\s*</title>.*?</programme>};
+-
+- # Set name
+- if ( $nametitle && $seriestitle ) {
+- $name = "$nametitle:
$seriestitle";
+- } elsif ( $seriestitle && ! $nametitle
) {
+- $name = $seriestitle;
+- # Fallback to episade name if the BBC
missed out both Series and Name
+- } elsif ( ( ! $seriestitle ) && !
$nametitle ) {
+- $name = $episode;
+- } else {
+- $name = $nametitle;
+- }
+-
+- # Extract the seriesnum
+- my $regex =
'Series\s+'.main::regex_numbers();
+- $seriesnum =
main::convert_words_to_number( $1 ) if $seriestitle =~ m{$regex}i;
+-
+- # Extract the episode num
+- my $regex_1 =
'Episode\s+'.main::regex_numbers();
+- my $regex_2 =
'^'.main::regex_numbers().'\.\s+';
+- if ( $episode =~ m{$regex_1}i ) {
+- $episodenum =
main::convert_words_to_number( $1 );
+- } elsif ( $episode =~ m{$regex_2}i ) {
+- $episodenum =
main::convert_words_to_number( $1 );
+- }
+
+- # extract desc
+- if ( $entry =~
m{<long_synopsis>\s*(.+?)\s*</long_synopsis>} ) {
+- $desc = $1;
+- } elsif ( $entry =~
m{<medium_synopsis>\s*(.+?)\s*</medium_synopsis>} ) {
+- $desc = $1;
+- } elsif ( $entry =~
m{<short_synopsis>\s*(.+?)\s*</short_synopsis>} ) {
+- $desc = $1;
+- };
+- # Remove unwanted html tags
+- $desc =~
s!</?(br|b|i|p|strong)\s*/?>!!gi;
+-
+- $duration = $1 if $entry =~
m{<duration>\s*(.+?)\s*</duration>};
+- $available = $1 if $entry =~
m{<start>\s*(.+?)\s*</start>};
+-
+- # Extract channel nice name
+- $channel = $channels{$channel_id};
+-
+- main::logger "DEBUG: '$pid, $name -
$episode, $channel'\n" if $opt->{debug};
+-
+- # Merge and Skip if this pid is a
duplicate
+- if ( defined $prog->{$pid} ) {
+- main::logger "WARNING: '$pid,
$prog->{$pid}->{name} - $prog->{$pid}->{episode}, $prog->{$pid}->{channel}'
already exists (this channel = $channel)\n" if $opt->{verbose};
+- # Update this info from
schedule (not available in the usual iplayer channels feeds)
+- $prog->{$pid}->{duration} =
$duration;
+- $prog->{$pid}->{episodenum} =
$episodenum if ! $prog->{$pid}->{episodenum};
+- $prog->{$pid}->{seriesnum} =
$seriesnum if ! $prog->{$pid}->{seriesnum};
+- # don't add this as some progs
are already available
+- #$prog->{$pid}->{available} =
$available;
+- next;
++sub get_links_ion {
++ my $self = shift;
++ my $prog = shift;
++ my $prog_type = shift;
++ # Hack to get correct 'channels' method because this methods is being
shared with Programme::radio
++ my %channels = %{ main::progclass($prog_type)->channels_filtered(
main::progclass($prog_type)->channels() ) };
++ my $bbc_prog_page_prefix = 'http://www.bbc.co.uk/programmes'; # /$pid
++ # Setup User agent
++ my $ua = main::create_ua( 'desktop', 1 );
++ # Download index feed
++ my @channel_list;
++ @channel_list = sort keys %channels;
++ for my $channel_id ( @channel_list ) {
++ my @ranges;
++ push @ranges, ('a-z', '0-9');
++ if ( $prog_type eq 'tv' ) {
++ push @ranges, ('signed_a-z', 'signed_0-9');
++ }
++ for my $range ( @ranges ) {
++ my $cond = $range;
++ my $op = "letters";
++ my $cat;
++ if ( $cond =~ /signed_/ ) {
++ $cond =~ s/signed_//;
++ $cat = "category/signed";
++ }
++ my $url =
"http://www.bbc.co.uk/iplayer/ion/atoz/format/xml/service_type/${prog_type}/masterbrand/$channel_id/$op/$cond/$cat";
++ main::logger "\nDEBUG: Getting feed $url\n" if
$opt->{verbose};
++ my $xml = main::request_url_retry($ua, $url, 3, '.',
"\nWARNING: Failed to get programme index feed for $channels{$channel_id} -
$cond $cat\n");
++ decode_entities($xml);
++ # Parse XML
++ # get list of entries within <entry> </entry> tags
++ my @entries = split /<episode>/, $xml;
++ # Discard first element == header
++ shift @entries;
++ main::logger "\nINFO: Got ".($#entries + 1)."
programmes for $channels{$channel_id} - $cond $cat\n" if $opt->{verbose};
++ foreach my $entry (@entries) {
++ my ( $title, $name, $episode, $episodetitle,
$nametitle, $episodenum, $seriesnum, $desc, $pid, $available, $channel,
$duration, $thumbnail, $version, $guidance );
++ $pid = $1 if $entry =~
m{</passionsite_title>.*?<id>(.+?)</id>}s;
++ $duration = $1 if $entry =~
m{<duration>(.*?)</duration>};
++ $title = $1 if $entry =~
m{<complete_title>(.*?)</complete_title>};
++ # determine name and episode from title
++ ( $name, $episode ) =
Programme::bbciplayer::split_title( $title );
++ $episodetitle = $1 if $entry =~
m{<short_synopsis>.*?<title>(.*?)</title>}s;
++ $nametitle = $name;
++ # Extract the seriesnum
++ my $regex = 'Series\s+'.main::regex_numbers();
++ $seriesnum = main::convert_words_to_number( $1
) if "$name $episode" =~ m{$regex}i;
++ # Extract the episode num
++ my $regex_1 =
'Episode\s+'.main::regex_numbers();
++ my $regex_2 = '^'.main::regex_numbers().'\.\s+';
++ if ( "$name $episode" =~ m{$regex_1}i ) {
++ $episodenum =
main::convert_words_to_number( $1 );
++ } elsif ( $episode =~ m{$regex_2}i ) {
++ $episodenum =
main::convert_words_to_number( $1 );
++ } elsif ( $episodetitle =~ m{$regex_2}i ) {
++ $episodenum =
main::convert_words_to_number( $1 );
++ }
++ # Re-insert the episode number if the episode
text doesn't have it
++ if ( $episodenum && $episodetitle =~ /^\d+\./
&& $episode !~ /^(.+:\s+)?\d+\./ ) {
++ $episode =~
s/^(.+:\s+)?(.*)$/$1$episodenum. $2/;
++ }
++ $desc = $1 if $entry =~
m{<short_synopsis>(.*?)</short_synopsis>};
++ my @category;
++ my @lines = split /<category>/, $entry;
++ shift @lines;
++ for my $line ( @lines ) {
++ push @category, $1 if $line =~
m{<title>(.*?)</title>};
++ }
++ # strip commas - they confuse sorting and
spliting later
++ s/,//g for @category;
++ # Extract channel
++ $channel = $1 if $entry =~
m{<masterbrand_title>(.*?)</masterbrand_title>};
++ main::logger "DEBUG: '$pid, $name - $episode,
$channel'\n" if $opt->{debug};
++ # Merge and Skip if this pid is a duplicate
++ if ( defined $prog->{$pid} ) {
++ main::logger "WARNING: '$pid,
$prog->{$pid}->{name} - $prog->{$pid}->{episode}, $prog->{$pid}->{channel}'
already exists (this channel = $channel)\n" if $opt->{verbose};
++ # Since we use the 'Signed' (or 'Audio
Described') channel to get sign zone/audio described data, merge the categories
from this entry to the existing entry
++ if ( $prog->{$pid}->{categories} ne
join(',', sort @category) ) {
++ my %cats;
++ $cats{$_} = 1 for ( @category,
split /,/, $prog->{$pid}->{categories} );
++ main::logger "INFO: Merged
categories for $pid from $prog->{$pid}->{categories} to ".join(',', sort keys
%cats)."\n" if $opt->{verbose};
++ $prog->{$pid}->{categories} =
join(',', sort keys %cats);
+ }
+-
++ # If this is a duplicate pid and the
channel is now Signed then both versions are available
++ $version = 'signed' if grep /Sign
Zone/, @category;
++ $version = 'audiodescribed' if grep
/Audio Described/, @category;
++ # Add version to versions for existing
prog
++ $prog->{$pid}->{versions} = join ',',
main::make_array_unique_ordered( (split /,/, $prog->{$pid}->{versions}),
$version );
++ next;
++ }
++ $guidance = $1 if $entry =~
m{<has_guidance>(.*?)</has_guidance>};
++ if ( $guidance ) {
++ $guidance = "Yes";
++ } else {
++ $guidance = undef;
++ }
++ # Check for signed-only or audiodescribed-only
version from category
++ if ( grep /Sign Zone/, @category ) {
++ $version = 'signed';
++ } elsif ( grep /Audio Described/, @category ) {
++ $version = 'audiodescribed';
++ } else {
+ $version = 'default';
+-
+- # Default to 150px width thumbnail;
+- my $thumbsize = $opt->{thumbsizecache}
|| 150;
+- my $thumbnail = $1 if $entry =~
m{<media:thumbnail.*?url="(.*?)"};
+- if ( $thumbnail ) {
+- my $suffix =
Programme::bbciplayer->thumb_url_suffixes->{ $thumbsize };
+- if ( $thumbnail !~ /$suffix/ ) {
+- $thumbnail =~
s/_\d+_\d+\.jpg/$suffix/;
+- }
+- }
+-
+- # Don't create this prog instance if
the availablity is in the past
+- # this prevents programmes which never
appear in iPlayer from being indexed
+- next if Programme::get_time_string(
$available ) < $now;
+-
+- # build data structure
+- $prog->{$pid} =
main::progclass($prog_type)->new(
+- 'pid' => $pid,
+- 'name' => $name,
+- 'versions' => $version,
+- 'episode' => $episode,
+- 'seriesnum' => $seriesnum,
+- 'episodenum' => $episodenum,
+- 'desc' => $desc,
+- 'available' => $available,
+- 'duration' => $duration,
+- 'thumbnail' => $thumbnail,
+- 'channel' => $channel,
+- 'type' => $prog_type,
+- 'web' =>
"${bbc_prog_page_prefix}/${pid}.html",
+- );
+ }
+- }
++ # Default to 150px width thumbnail;
++ my $thumbsize = $opt->{thumbsizecache} || 150;
++ my $image_template_url = $1 if $entry =~
m{<image_template_url>(.*?)</image_template_url>};
++ my $recipe =
Programme::bbciplayer->thumb_url_recipes->{ $thumbsize };
++ my $thumbnail = $image_template_url;
++ $thumbnail =~ s/\$recipe/$recipe/;
++ # build data structure
++ $prog->{$pid} =
main::progclass($prog_type)->new(
++ 'pid' => $pid,
++ 'name' => $name,
++ 'versions' => $version,
++ 'episode' => $episode,
++ 'seriesnum' => $seriesnum,
++ 'episodenum' => $episodenum,
++ 'desc' => $desc,
++ 'guidance' => $guidance,
++ 'available' => 'Unknown',
++ 'duration' => $duration ||
'Unknown',
++ 'thumbnail' => $thumbnail,
++ 'channel' => $channel,
++ 'categories' => join(',', sort
@category),
++ 'type' => $prog_type,
++ 'web' =>
"${bbc_prog_page_prefix}/${pid}",
++ );
++ }
++ }
++ }
++}
+
++
++# Usage: Programme::tv->get_links( \%prog, 'tv' );
++# Uses: %{ channels() }, \%prog
++sub get_links {
++ my $self = shift; # ignore obj ref
++ my $prog = shift;
++ my $prog_type = shift;
++ my $feeds = lc($opt->{"refreshfeeds".${prog_type}} ||
$opt->{"refreshfeeds"});
++ main::logger "INFO: Getting $prog_type Index Feeds (this may take a few
minutes)\n";
++ if ( $feeds eq 'schedule' ) {
++ return $self->get_links_schedule($prog, $prog_type, 0);
++ } else {
++ if ( $prog_type eq 'radio' ) {
++ return $self->get_links_aod($prog, $prog_type);
++ }
++ elsif ( $prog_type eq 'tv' ) {
++ return $self->get_links_ion($prog, $prog_type);
+ }
+ }
++
++ if ( $opt->{refreshfuture} ) {
++ $self->get_links_schedule($prog, $prog_type, 1);
++ }
++
+ main::logger "\n";
+ return 0;
+ }
+
+
++# get cache info for programmes from schedule
++sub get_links_schedule {
++ my $self = shift;
++ my $prog = shift;
++ my $prog_type = shift;
++ my $future = shift;
++ my %channels = %{ main::progclass($prog_type)->channels_filtered(
main::progclass($prog_type)->channels_schedule() ) };
++ my @channel_list = sort keys %channels;
++ my @schedule_dates;
++ my $limit = 0;
++ my $limit_days = $opt->{"refreshlimit".${prog_type}} ||
$opt->{"refreshlimit"};
++ $limit_days = 30 if $limit_days > 30;
++ if ( $limit_days ) {
++ my $now = time();
++ $limit = $now - $limit_days * 86400;
++ my ($limit_weeks, $rem) = (int $limit_days / 7, $limit_days %
7);
++ $limit_weeks++ if $rem && $limit_weeks;
++ for (my $i = $limit_weeks; $i >= 0; $i -= 1) {
++ my $then = $now - ($i * 7) * 86400;
++ my $year = (gmtime($then))[5];
++ my $week = strftime( "%W", gmtime($then) );
++ push @schedule_dates, sprintf("%04d/w%02d", $year+1900,
++$week);
++ }
++ } else {
++ if ( $future ) {
++ @schedule_dates = ( "this_week", "next_week" );
++ } else {
++ @schedule_dates = ( "last_week", "this_week" );
++ }
++ }
++ for my $channel_id ( @channel_list ) {
++ for my $schedule_date ( @schedule_dates ) {
++ my $url =
"http://www.bbc.co.uk/${channel_id}/${schedule_date}.xml";
++ my $rc = $self->get_links_schedule_page($prog,
$prog_type, $channels{$channel_id}, $future, $url, $limit);
++ if ( $rc ) {
++ main::logger("\nWARNING: Failed to get
programme schedule feed for $channel_id from iplayer site\n");
++ }
++ }
++ }
++}
++
++# get cache info from schedule page
++sub get_links_schedule_page {
++ my $self = shift;
++ my $prog = shift;
++ my $prog_type = shift;
++ my $channel = shift;
++ my $future = shift;
++ my $url = shift;
++ my $limit = shift;
++ my $bbc_prog_page_prefix = 'http://www.bbc.co.uk/programmes'; # /$pid
++ my $ua = main::create_ua( 'desktop', 1 );
++ main::logger "DEBUG: Getting feed $url\n" if $opt->{debug};
++ my $xml = main::request_url_retry($ua, $url, 3, '.', "\nWARNING: Failed
to download programme schedule $url\n");
++ return 1 if ! $xml;
++ decode_entities($xml);
++
++ # <broadcast is_repeat="0" is_blanked="0">
++ # <pid>p0290kxs</pid>
++ # <start>2014-10-31T11:00:00Z</start>
++ # <end>2014-10-31T11:45:00Z</end>
++ # <duration>2700</duration>
++ # <programme type="episode">
++ # <pid>b04n8rx0</pid>
++ # <position>10</position>
++ # <title>Episode 10</title>
++ # <short_synopsis>Council officers deal with home owners
living on top of deadly waste.</short_synopsis>
++ # <media_type>audio_video</media_type>
++ # <duration>2700</duration>
++ # <image>
++ # <pid>p028r5jx</pid>
++ # </image>
++ # <display_titles>
++ # <title>Call the Council</title>
++ # <subtitle>Series 2, Episode 10</subtitle>
++ # </display_titles>
++ #
<first_broadcast_date>2014-10-31T11:00:00Z</first_broadcast_date>
++ # <ownership>
++ # <service type="tv" id="bbc_one" key="bbcone">
++ # <title>BBC One</title>
++ # </service>
++ # </ownership>
++ # <programme type="series">
++ # <pid>b04mlq1k</pid>
++ # <title>Series 2</title>
++ # <position>2</position>
++ # <image>
++ # <pid>p028r5jx</pid>
++ # </image>
++ # <expected_child_count>10</expected_child_count>
++ #
<first_broadcast_date>2014-10-20T11:00:00+01:00</first_broadcast_date>
++ # <ownership>
++ # <service type="tv" id="bbc_one"
key="bbcone">
++ # <title>BBC One</title>
++ # </service>
++ # </ownership>
++ # <programme type="brand">
++ # <pid>b04mlpdd</pid>
++ # <title>Call the Council</title>
++ # <position/>
++ # <image>
++ # <pid>p028r5jx</pid>
++ # </image>
++ # <expected_child_count/>
++ #
<first_broadcast_date>2014-05-19T11:30:00+01:00</first_broadcast_date>
++ # <ownership>
++ # <service type="tv" id="bbc_one"
key="bbcone">
++ # <title>BBC One</title>
++ # </service>
++ # </ownership>
++ # </programme>
++ # </programme>
++ # <available_until>2014-12-03T07:45:00Z</available_until>
++ # <actual_start>2014-10-31T11:45:00Z</actual_start>
++ #
<is_available_mediaset_pc_sd>1</is_available_mediaset_pc_sd>
++ # <is_legacy_media>0</is_legacy_media>
++ # <media format="video">
++ # <expires>2014-12-03T07:45:00Z</expires>
++ # <availability>1 month left to
watch</availability>
++ # </media>
++ # </programme>
++ # </broadcast>
++
++ # get list of entries within <broadcast> </broadcast> tags
++ my @entries = split /<broadcast[^s]/, $xml;
++ # Discard first element == header
++ shift @entries;
++ main::logger "\nINFO: Got ".($#entries + 1)." programmes for
$channel\n" if $opt->{verbose};
++ my $now = time();
++ foreach my $entry (@entries) {
++ my ( $title, $name, $episode, $episodetitle, $nametitle,
$seriestitle, $episodenum, $seriesnum, $desc, $pid, $available, $duration,
$thumbnail, $version, $guidance, $descshort, $start );
++ $start = $1 if $entry =~ m{<start>\s*(.+?)\s*</start>};
++ next if ! $start;
++ my $xstart = Programme::get_time_string( $start );
++ next if $future && $xstart < $now;
++ next if ! $future && $xstart >= $now;
++ next if ! $future && $limit && $xstart < $limit;
++ $available = $1 if $entry =~
m{<available_until>\s*(.+?)\s*</available_until>};
++ my $availability = $1 if $entry =~
m{<availability>.*?(Available).*?</availability>}i;
++ next if ! ( $available || $availability );
++ if ( $available ) {
++ my $xavailable = Programme::get_time_string( $available
);
++ next if $xavailable < $now;
++ }
++ $pid = $1 if $entry =~
m{<programme\s+type="episode">.*?<pid>\s*(.+?)\s*</pid>};
++ $episode = $1 if $entry =~
m{<programme\s+type="episode">.*?<title>\s*(.*?)\s*</title>};
++ $nametitle = $1 if $entry =~
m{<programme\s+type="brand">.*?<title>\s*(.*?)\s*</title>.*?</programme>};
++ $seriestitle = $1 if $entry =~
m{<programme\s+type="series">.*?<title>\s*(.*?)\s*</title>.*?</programme>};
++ # Set name
++ if ( $nametitle && $seriestitle ) {
++ $name = "$nametitle: $seriestitle";
++ } elsif ( $seriestitle && ! $nametitle ) {
++ $name = $seriestitle;
++ # Fallback to episode name if the BBC missed out both Series
and Name
++ } elsif ( ( ! $seriestitle ) && ! $nametitle ) {
++ $name = $episode;
++ } else {
++ $name = $nametitle;
++ }
++ # Extract the seriesnum
++ my $regex = 'Series\s+'.main::regex_numbers();
++ $seriesnum = main::convert_words_to_number( $1 ) if
$seriestitle =~ m{$regex}i;
++ my $series_position = $1 if $entry =~
m{<programme\s+type="series">.*?<position>\s*(.+?)\s*</position>};
++ $seriesnum ||= $series_position;
++ # Extract the episode num
++ my $regex_1 = 'Episode\s+'.main::regex_numbers();
++ my $regex_2 = '^'.main::regex_numbers().'\.\s+';
++ if ( $episode =~ m{$regex_1}i ) {
++ $episodenum = main::convert_words_to_number( $1 );
++ } elsif ( $episode =~ m{$regex_2}i ) {
++ $episodenum = main::convert_words_to_number( $1 );
++ }
++ my $episode_position = $1 if $entry =~
m{<programme\s+type="episode">.*?<position>\s*(.+?)\s*</position>};
++ $episodenum ||= $episode_position;
++ # extract desc
++ if ( $entry =~ m{<long_synopsis>\s*(.+?)\s*</long_synopsis>} ) {
++ $desc = $1;
++ } elsif ( $entry =~
m{<medium_synopsis>\s*(.+?)\s*</medium_synopsis>} ) {
++ $desc = $1;
++ } elsif ( $entry =~
m{<short_synopsis>\s*(.+?)\s*</short_synopsis>} ) {
++ $desc = $1;
++ };
++ # Remove unwanted html tags
++ $desc =~ s!</?(br|b|i|p|strong)\s*/?>!!gi;
++ $duration = $1 if $entry =~ m{<duration>\s*(.+?)\s*</duration>};
++ # Extract channel nice name
++ # $channel = $channels{$channel_id};
++ main::logger "DEBUG: '$pid, $name - $episode, $channel'\n" if
$opt->{debug};
++ # Merge and Skip if this pid is a duplicate
++ if ( defined $prog->{$pid} ) {
++ main::logger "WARNING: '$pid, $prog->{$pid}->{name} -
$prog->{$pid}->{episode}, $prog->{$pid}->{channel}' already exists (this
channel = $channel)\n" if $opt->{verbose};
++ # Update this info from schedule (not available in the
usual iplayer channels feeds)
++ $prog->{$pid}->{duration} = $duration;
++ $prog->{$pid}->{episodenum} = $episodenum if !
$prog->{$pid}->{episodenum};
++ $prog->{$pid}->{seriesnum} = $seriesnum if !
$prog->{$pid}->{seriesnum};
++ # don't add this as some progs are already available
++ #$prog->{$pid}->{available} = $available;
++ next;
++ }
++ $version = 'default';
++ # thumbnail options
++ #
http://ichef.bbci.co.uk/programmeimages/p01m1x5p/b04l8sml_640_360.jpg
++ # http://ichef.bbci.co.uk/images/ic/640x360/p01m1x5p.jpg
++ # Default to 150px width thumbnail;
++ my $thumbsize = $opt->{thumbsizecache} || 150;
++ my $image_pid = $1 if $entry =~ m{<image><pid>(.*?)</pid>}s;
++ my $suffix = Programme::bbciplayer->thumb_url_suffixes->{
$thumbsize };
++ my $thumbnail =
"http://ichef.bbci.co.uk/programmeimages/${image_pid}/${pid}${suffix}";
++ # build data structure
++ $prog->{$pid} = main::progclass($prog_type)->new(
++ 'pid' => $pid,
++ 'name' => $name,
++ 'versions' => $version,
++ 'episode' => $episode,
++ 'seriesnum' => $seriesnum,
++ 'episodenum' => $episodenum,
++ 'desc' => $desc,
++ 'available' => $start,
++ 'duration' => $duration,
++ 'thumbnail' => $thumbnail,
++ 'channel' => $channel,
++ 'type' => $prog_type,
++ 'web' => "${bbc_prog_page_prefix}/${pid}",
++ );
++ }
++}
++
+
+ # Usage: download (<prog>, <ua>, <mode>, <version>, <version_pid>)
+ sub download {
+@@ -7886,6 +7940,72 @@
+ # Class vars
+ sub index_min { return 10001 }
+ sub index_max { return 19999 };
++sub channels_aod {
++ return {
++ # national stations
++ '1xtra' => 'BBC Radio 1Xtra',
++ 'radio1' => 'BBC Radio 1',
++ 'radio2' => 'BBC Radio 2',
++ 'radio3' => 'BBC Radio 3',
++ 'radio4' => 'BBC Radio 4',
++ 'radio4extra' => 'BBC Radio 4 Extra',
++ 'fivelive' => 'BBC Radio 5 live',
++ 'sportsextra' => 'BBC 5 live sports extra',
++ '6music' => 'BBC 6 Music',
++ 'asiannetwork' => 'BBC Asian Network',
++ # nations
++ 'radiofoyle' => 'BBC Radio Foyle',
++ 'radioscotland' => 'BBC Radio Scotland',
++ 'alba' => 'BBC Radio Nan Gaidheal',
++ 'radioulster' => 'BBC Radio Ulster',
++ 'radiowales' => 'BBC Radio Wales',
++ 'radiocymru' => 'BBC Radio Cymru',
++ 'worldservice' => 'BBC World Service',
++ # local
++ 'bbc_radio_cumbria' => 'BBC Radio Cumbria',
++ 'bbc_radio_newcastle' => 'BBC Newcastle',
++ 'bbc_tees' => 'BBC Tees',
++ 'bbc_radio_lancashire' => 'BBC Radio
Lancashire',
++ 'bbc_radio_merseyside' => 'BBC Radio
Merseyside',
++ 'bbc_radio_manchester' => 'BBC Radio
Manchester',
++ 'bbc_radio_leeds' => 'BBC Radio Leeds',
++ 'bbc_radio_sheffield' => 'BBC Radio
Sheffield',
++ 'bbc_radio_york' => 'BBC Radio York',
++ 'bbc_radio_humberside' => 'BBC Radio
Humberside',
++ 'bbc_radio_lincolnshire' => 'BBC Radio
Lincolnshire',
++ 'bbc_radio_nottingham' => 'BBC Radio
Nottingham',
++ 'bbc_radio_leicester' => 'BBC Radio
Leicester',
++ 'bbc_radio_derby' => 'BBC Radio Derby',
++ 'bbc_radio_stoke' => 'BBC Radio Stoke',
++ 'bbc_radio_shropshire' => 'BBC Radio
Shropshire',
++ 'bbc_wm' => 'BBC WM 95.6',
++ 'bbc_radio_coventry_warwickshire' => 'BBC Coventry &
Warwickshire',
++ 'bbc_radio_hereford_worcester' => 'BBC Hereford &
Worcester',
++ 'bbc_radio_northampton' => 'BBC Radio
Northampton',
++ 'bbc_three_counties_radio' => 'BBC Three Counties
Radio',
++ 'bbc_radio_cambridge' => 'BBC Radio
Cambridgeshire',
++ 'bbc_radio_norfolk' => 'BBC Radio Norfolk',
++ 'bbc_radio_suffolk' => 'BBC Radio Suffolk',
++ 'bbc_radio_essex' => 'BBC Essex',
++ 'bbc_london' => 'BBC London 94.9',
++ 'bbc_radio_kent' => 'BBC Radio Kent',
++ 'bbc_radio_surrey' => 'BBC Surrey',
++ 'bbc_radio_sussex' => 'BBC Sussex',
++ 'bbc_radio_oxford' => 'BBC Radio Oxford',
++ 'bbc_radio_berkshire' => 'BBC Radio
Berkshire',
++ 'bbc_radio_solent' => 'BBC Radio Solent',
++ 'bbc_radio_gloucestershire' => 'BBC Radio
Gloucestershire',
++ 'bbc_radio_wiltshire' => 'BBC Wiltshire',
++ 'bbc_radio_bristol' => 'BBC Radio Bristol',
++ 'bbc_radio_somerset_sound' => 'BBC Somerset',
++ 'bbc_radio_devon' => 'BBC Radio Devon',
++ 'bbc_radio_cornwall' => 'BBC Radio Cornwall',
++ 'bbc_radio_guernsey' => 'BBC Radio Guernsey',
++ 'bbc_radio_jersey' => 'BBC Radio Jersey',
++ 'bbc_radio_jersey' => 'BBC Radio Jersey',
++ };
++}
++
+ sub channels {
+ return {
+ 'bbc_1xtra' => 'BBC Radio 1Xtra',
+@@ -7897,7 +8017,7 @@
+ 'bbc_radio_five_live' => 'BBC Radio 5 live',
+ 'bbc_radio_five_live_sports_extra' => 'BBC 5 live sports
extra',
+ 'bbc_6music' => 'BBC 6 Music',
+- 'bbc_7' => 'BBC 7',
++ #'bbc_7' => 'BBC 7',
+ 'bbc_asian_network' => 'BBC Asian Network',
+ 'bbc_radio_foyle' => 'BBC Radio Foyle',
+ 'bbc_radio_scotland' => 'BBC Radio Scotland',
+@@ -7946,8 +8066,6 @@
+ 'bbc_radio_cornwall' => 'BBC Radio Cornwall',
+ 'bbc_radio_guernsey' => 'BBC Radio Guernsey',
+ 'bbc_radio_jersey' => 'BBC Radio Jersey',
+- 'popular/radio' => 'Popular',
+- 'highlights/radio' => 'Highlights',
+ };
+ }
+
+--- get-iplayer-2.87.orig/get_iplayer.1
++++ get-iplayer-2.87/get_iplayer.1
+@@ -508,12 +508,30 @@
+ \fB\-\-refresh\-exclude <string>
+ Exclude matched channel(s) when refreshing cache (regex or comma separated
values)
+ .TP
++\fB\-\-refresh\-feeds <string>
++Alternate source for programme data. Valid values: 'schedule'
++.TP
++\fB\-\-refresh\-feeds\-radio <string>
++Alternate source for radio programme data. Valid values: 'schedule'
++.TP
++\fB\-\-refresh\-feeds\-tv <string>
++Alternate source for TV programme data. Valid values: 'schedule'
++.TP
+ \fB\-\-refresh\-future
+ Obtain future programme schedule when refreshing cache (between 7\-14 days)
+ .TP
+ \fB\-\-refresh\-include <string>
+ Include matched channel(s) when refreshing cache (regex or comma separated
values)
+ .TP
++\fB\-\-refresh\-limit <integer>
++Number of days of programmes to cache. Only applied with
\-\-refresh\-feeds=schedule. Makes cache updates VERY slow. Default: 7 Min: 1
Max: 30
++.TP
++\fB\-\-refresh\-limit\-radio <integer>
++Number of days of radio programmes to cache. Only applied with
\-\-refresh\-feeds=schedule. Makes cache updates VERY slow. Default: 7 Min: 1
Max: 30
++.TP
++\fB\-\-refresh\-limit\-tv <integer>
++Number of days of TV programmes to cache. Only applied with
\-\-refresh\-feeds=schedule. Makes cache updates VERY slow. Default: 7 Min: 1
Max: 30
++.TP
+ \fB\-\-skipdeleted
+ Skip the download of metadata/thumbs/subs if the media file no longer exists.
Use with \-\-history & \-\-metadataonly/subsonly/thumbonly.
+ .TP
diff -Nru get-iplayer-2.87/debian/patches/data-feeds.patch
get-iplayer-2.87/debian/patches/data-feeds.patch
--- get-iplayer-2.87/debian/patches/data-feeds.patch 1970-01-01
01:00:00.000000000 +0100
+++ get-iplayer-2.87/debian/patches/data-feeds.patch 2014-12-04
23:22:09.000000000 +0000
@@ -0,0 +1,221 @@
+From: dinkypumpkin <[email protected]>
+Date: Fri, 31 Oct 2014 12:40:29 +0000
+Subject: Fixes for metadata problems due to BBC removing data feeds
+Origin:
http://git.infradead.org/get_iplayer.git/commit/3b11bf9baffd66e17d18116eb546566f84ae7927
+Last-Update: 2014-12-03
+
+--- get-iplayer-2.87.orig/get_iplayer
++++ get-iplayer-2.87/get_iplayer
+@@ -5421,28 +5421,26 @@
+ # flatten
+ $xml =~ s/\n/ /g;
+
++ # set title here - broken in JSON playlists
++ $prog->{title} = decode_entities($1) if $xml =~
m{<title>\s*(.+?)\s*<\/title>};
++ $prog->{thumbnail} = $1 if $xml =~ m{<link rel="holding" href="(.*?)"};
++ $prog->{guidance} = $1 if $xml =~ m{<guidance.*?>(.*?)</guidance>};
++ $prog->{descshort} = $1 if $xml =~ m{<summary>(.*?)</summary>};
++ $prog->{type} = 'tv' if grep /kind="programme"/, $xml;
++ $prog->{type} = 'radio' if grep /kind="radioProgramme"/, $xml;
++
+ # Detect noItems or no programmes
+ if ( $xml =~ m{<noItems\s+reason="(\w+)"} || $xml !~
m{kind="(programme|radioProgramme)"} ) {
+- # set title here - broken in JSON playlists
+- $prog->{title} = decode_entities($1) if $xml =~
m{<title>\s*(.+?)\s*<\/title>};
+- my $rc_verpids = $prog->get_verpids_json( $ua );
+- if ( $rc_verpids ) {
+- $rc_verpids = $prog->get_verpids_html( $ua )
++ my $rc_json = $prog->get_verpids_json( $ua );
++ my $rc_html = 1;
++ if ( ! $prog->{type} || $prog->{type} eq 'tv' ) {
++ $rc_html = $prog->get_verpids_html( $ua );
+ }
+- return 0 if ! $rc_verpids;
+- main::logger "\rWARNING: No programmes are available for this
pid with version(s): ".($opt->{versionlist} ? $opt->{versionlist} :
'default').($prog->{versions} ? " (available versions: $prog->{versions})\n" :
"\n");
++ return 0 if ! $rc_json || ! $rc_html;
++ main::logger "\nWARNING: No programmes are available for this
pid with version(s): ".($opt->{versionlist} ? $opt->{versionlist} :
'default').($prog->{versions} ? " (available versions: $prog->{versions})\n" :
"\n");
+ return 1;
+ }
+
+- # Get title
+- # <title>Amazon with Bruce Parry: Episode 1</title>
+- my ( $title, $prog_type );
+- $title = $1 if $xml =~ m{<title>\s*(.+?)\s*<\/title>};
+-
+- # Get type
+- $prog_type = 'tv' if grep /kind="programme"/, $xml;
+- $prog_type = 'radio' if grep /kind="radioProgramme"/, $xml;
+-
+ # Split into <item kind="programme"> sections
+ my $prev_version = '';
+ for ( split /<item\s+kind="(radioProgramme|programme)"/, $xml ) {
+@@ -5530,7 +5528,6 @@
+
+ # Add to prog hash
+ $prog->{versions} = join ',', keys %{ $prog->{verpids} };
+- $prog->{title} = decode_entities($title);
+ return 0;
+ }
+
+@@ -5556,30 +5553,37 @@
+ return 1;
+ }
+ my ( $default, $versions ) = split /"allAvailableVersions"/, $json;
+- my $channel = $1 if $default =~ /"masterBrandName":"(.*?)"/;
+- $prog->{channel} = $channel if $channel;
+- my $descshort = $1 if $default =~ /"summary":"(.*?)"/;
+- $prog->{descshort} = $descshort if $descshort;
+- my $guidance = $2 if $default =~ /"guidance":(null|"(.*?)")/;
+- $prog->{guidance} = "Yes" if $guidance;
+- my $thumbnail = $1 if $default =~ /"holdingImageURL":"(.*?)"/;
+- $thumbnail =~ s/\\\//\//g;
+- my $thumbsize = $opt->{thumbsize} || $opt->{thumbsizecache} || 150;
+- my $recipe = Programme::bbciplayer->thumb_url_recipes->{ $thumbsize };
+- if ( ! $recipe ) {
+- main::logger "WARNING: Invalid thumbnail size: $thumbsize -
using default (JSON)\n";
+- $recipe = Programme::bbciplayer->thumb_url_recipes->{ 150 };
+- }
+- $thumbnail =~ s/\$recipe/$recipe/;
+- $prog->{thumbnail} = $thumbnail if $thumbnail;
+- if ( ! $prog->{title} ) {
++ unless ( $prog->{channel} ) {
++ $prog->{channel} = $1 if $default =~
/"masterBrandName":"(.*?)"/;
++ }
++ unless ( $prog->{descshort} ) {
++ $prog->{descshort} = $1 if $default =~ /"summary":"(.*?)"/;
++ }
++ unless ( $prog->{guidance} ) {
++ my $guidance = $2 if $default =~ /"guidance":(null|"(.*?)")/;
++ $prog->{guidance} = "Yes" if $guidance;
++ }
++ unless ( $prog->{thumbnail} ) {
++ my $thumbnail = $1 if $default =~ /"holdingImageURL":"(.*?)"/;
++ $thumbnail =~ s/\\\//\//g;
++ my $thumbsize = $opt->{thumbsize} || $opt->{thumbsizecache} ||
150;
++ my $recipe = Programme::bbciplayer->thumb_url_recipes->{
$thumbsize };
++ if ( ! $recipe ) {
++ main::logger "WARNING: Invalid thumbnail size:
$thumbsize - using default (JSON)\n";
++ $recipe = Programme::bbciplayer->thumb_url_recipes->{
150 };
++ }
++ $thumbnail =~ s/\$recipe/$recipe/;
++ $prog->{thumbnail} = $thumbnail if $thumbnail;
++ }
++ unless ( $prog->{title} ) {
+ my $title = $1 if $default =~ /"title":"(.*?)"/;
+ $title =~ s/\\\//\//g;
+ $prog->{title} = decode_entities($title) if $title;
+ }
+- my $prog_type = 'tv' if $default =~ /"kind":"video"/;
+- $prog_type = 'radio' if $default =~ /"kind":"audio"/;
+- $prog->{type} = $prog_type if $prog_type;
++ unless ( $prog->{type} ) {
++ $prog->{type} = 'tv' if $default =~ /"kind":"video"/;
++ $prog->{type} = 'radio' if $default =~ /"kind":"audio"/;
++ }
+ my $version_json = {
+ 'DubbedAudioDescribed' => 'audiodescribed',
+ 'Signed' => 'signed'
+@@ -5609,6 +5613,7 @@
+ }
+ unless ( $prog->{player} ) {
+ $prog->{player} = $episode_url if $episode_url;
++ last;
+ }
+ }
+ }
+@@ -5636,8 +5641,10 @@
+ main::logger "INFO: pid changed from $prog->{pid} to $pid
(HTML)\n" if $opt->{verbose};
+ $prog->{pid} = $pid;
+ }
++ my $version_list = $opt->{versionlist} || 'default';
+ my $version_map = { "default" => "", "audiodescribed" => "ad", "signed"
=> "sign"};
+ for my $version ( "default", "audiodescribed", "signed" ) {
++ next if $version_list !~ /$version/ ||
$prog->{verpids}->{$version};
+ my $url =
'http://www.bbc.co.uk/iplayer/episode/'.$pid."/$version_map->{$version}";
+ main::logger "INFO: iPlayer metadata URL (HTML) [$version] =
$url\n" if $opt->{verbose};
+ my $html = main::request_url_retry( $ua, $url, 3 );
+@@ -5653,12 +5660,10 @@
+ next;
+ }
+ unless ( $prog->{channel} ) {
+- my $channel = $1 if $config =~
/"masterBrandTitle":"(.*?)"/;
+- $prog->{channel} = $channel if $channel;
++ $prog->{channel} = $1 if $config =~
/"masterBrandTitle":"(.*?)"/;
+ }
+ unless ( $prog->{descshort} ) {
+- my $descshort = $1 if $config =~ /"summary":"(.*?)"/;
+- $prog->{descshort} = $descshort if $descshort;
++ $prog->{descshort} = $1 if $config =~
/"summary":"(.*?)"/;
+ }
+ unless ( $prog->{guidance} ) {
+ my $guidance = $2 if $config =~
/"guidance":(null|"(.*?)")/;
+@@ -5691,7 +5696,6 @@
+ $prog->{durations}->{$version} = $1 if $config =~
/"duration":(\d+)/;
+ }
+ $prog->{versions} = join ',', keys %{ $prog->{verpids} };
+- my $version_list = $opt->{versionlist} || 'default';
+ for ( split /,/, $version_list ) {
+ if ( $prog->{verpids}->{$_} ) {
+ my $episode_url;
+@@ -5702,6 +5706,7 @@
+ }
+ unless ( $prog->{player} ) {
+ $prog->{player} = $episode_url if $episode_url;
++ last;
+ }
+ }
+ }
+@@ -5806,7 +5811,8 @@
+ #</feed>
+
+ # Don't get metadata from this URL if the pid contains a full url
(problem: this still tries for BBC iPlayer live channels)
+- if ( $prog->{pid} !~ m{^http}i ) {
++ # skip this section since BBC killed feeds, but keep code for reference
++ if ( $prog->{pid} !~ m{^http}i && 0) {
+ $entry = main::request_url_retry($ua,
$prog_feed_url.$prog->{pid}, 3, '', '');
+ decode_entities($entry);
+ main::logger "DEBUG: $prog_feed_url.$prog->{pid}:\n$entry\n\n"
if $opt->{debug};
+@@ -5870,6 +5876,21 @@
+ }
+ }
+
++ # Get list of available modes for each version available
++ # populate version pid metadata if we don't have it already
++ if ( keys %{ $prog->{verpids} } == 0 ) {
++ if ( $prog->get_verpids( $ua ) ) {
++ main::logger "ERROR: Could not get version pid
metadata\n" if $opt->{verbose};
++ # Only return at this stage unless we want
metadata/tags only for various reasons
++ return 1 if ! ( $opt->{info} || $opt->{metadataonly} ||
$opt->{thumbonly} || $opt->{tagonly} )
++ }
++ }
++ # Re-split title if changed in get_verpids()
++ #if ( $prog->{title} && $prog->{title} ne $title ) {
++ # $title = $prog->{title};
++ # ( $name, $episode ) = Programme::bbciplayer::split_title(
$title );
++ #}
++ $versions = join ',', sort keys %{ $prog->{verpids} };
+
+ # Even more info...
+ #<?xml version="1.0" encoding="utf-8"?>
+@@ -5957,21 +5978,6 @@
+ $categories ||= "get_iplayer";
+ $category ||= "get_iplayer";
+
+- # Get list of available modes for each version available
+- # populate version pid metadata if we don't have it already
+- if ( keys %{ $prog->{verpids} } == 0 ) {
+- if ( $prog->get_verpids( $ua ) ) {
+- main::logger "ERROR: Could not get version pid
metadata\n" if $opt->{verbose};
+- # Only return at this stage unless we want
metadata/tags only for various reasons
+- return 1 if ! ( $opt->{info} || $opt->{metadataonly} ||
$opt->{thumbonly} || $opt->{tagonly} )
+- }
+- }
+- # Re-split title if changed in get_verpids()
+- if ( $prog->{title} && $prog->{title} ne $title ) {
+- $title = $prog->{title};
+- ( $name, $episode ) = Programme::bbciplayer::split_title(
$title );
+- }
+- $versions = join ',', sort keys %{ $prog->{verpids} };
+ my $modes;
+ my $mode_sizes;
+ my $first_broadcast;
diff -Nru get-iplayer-2.87/debian/patches/future-schedule.patch
get-iplayer-2.87/debian/patches/future-schedule.patch
--- get-iplayer-2.87/debian/patches/future-schedule.patch 1970-01-01
01:00:00.000000000 +0100
+++ get-iplayer-2.87/debian/patches/future-schedule.patch 2014-12-04
23:22:09.000000000 +0000
@@ -0,0 +1,81 @@
+From: dinkypumpkin <[email protected]>
+Date: Sun, 2 Nov 2014 21:24:12 +0000
+Subject: Restored future schedule refresh
+Origin:
http://git.infradead.org/get_iplayer.git/commitdiff/cad12b98c56d796c3e73210eba5f348b08385d3a?hp=9ddffb88f05dd15c6e9192cd8df04a71d82a6a67
+Last-Update: 2014-12-03
+
+--- get-iplayer-2.87.orig/get_iplayer
++++ get-iplayer-2.87/get_iplayer
+@@ -7410,15 +7410,15 @@
+ my $prog = shift;
+ my $prog_type = shift;
+ my $feeds = lc($opt->{"refreshfeeds".${prog_type}} ||
$opt->{"refreshfeeds"});
+- main::logger "INFO: Getting $prog_type Index Feeds (this may take a few
minutes)\n";
++ main::logger "\nINFO: Getting $prog_type Index Feeds (this may take a
few minutes)\n";
+ if ( $feeds eq 'schedule' ) {
+- return $self->get_links_schedule($prog, $prog_type, 0);
++ $self->get_links_schedule($prog, $prog_type, 0);
+ } else {
+ if ( $prog_type eq 'radio' ) {
+- return $self->get_links_aod($prog, $prog_type);
++ $self->get_links_aod($prog, $prog_type);
+ }
+ elsif ( $prog_type eq 'tv' ) {
+- return $self->get_links_ion($prog, $prog_type);
++ $self->get_links_ion($prog, $prog_type);
+ }
+ }
+
+@@ -7561,20 +7561,12 @@
+ main::logger "\nINFO: Got ".($#entries + 1)." programmes for
$channel\n" if $opt->{verbose};
+ my $now = time();
+ foreach my $entry (@entries) {
+- my ( $title, $name, $episode, $episodetitle, $nametitle,
$seriestitle, $episodenum, $seriesnum, $desc, $pid, $available, $duration,
$thumbnail, $version, $guidance, $descshort, $start );
+- $start = $1 if $entry =~ m{<start>\s*(.+?)\s*</start>};
+- next if ! $start;
+- my $xstart = Programme::get_time_string( $start );
+- next if $future && $xstart < $now;
+- next if ! $future && $xstart >= $now;
+- next if ! $future && $limit && $xstart < $limit;
+- $available = $1 if $entry =~
m{<available_until>\s*(.+?)\s*</available_until>};
+- my $availability = $1 if $entry =~
m{<availability>.*?(Available).*?</availability>}i;
+- next if ! ( $available || $availability );
+- if ( $available ) {
+- my $xavailable = Programme::get_time_string( $available
);
+- next if $xavailable < $now;
+- }
++ my ( $title, $name, $episode, $episodetitle, $nametitle,
$seriestitle, $episodenum, $seriesnum, $desc, $pid, $available, $duration,
$thumbnail, $version, $guidance, $descshort );
++ # Don't create this prog instance if the availablity is in the
past
++ # this prevents programmes which never appear in iPlayer from
being indexed
++ $available = $1 if $entry =~ m{<start>\s*(.+?)\s*</start>};
++ next if $future && Programme::get_time_string( $available ) <
$now;
++ next if ! $future && $limit && Programme::get_time_string(
$available ) < $limit;
+ $pid = $1 if $entry =~
m{<programme\s+type="episode">.*?<pid>\s*(.+?)\s*</pid>};
+ $episode = $1 if $entry =~
m{<programme\s+type="episode">.*?<title>\s*(.*?)\s*</title>};
+ $nametitle = $1 if $entry =~
m{<programme\s+type="brand">.*?<title>\s*(.*?)\s*</title>.*?</programme>};
+@@ -7639,6 +7631,7 @@
+ my $image_pid = $1 if $entry =~ m{<image><pid>(.*?)</pid>}s;
+ my $suffix = Programme::bbciplayer->thumb_url_suffixes->{
$thumbsize };
+ my $thumbnail =
"http://ichef.bbci.co.uk/programmeimages/${image_pid}/${pid}${suffix}";
++
+ # build data structure
+ $prog->{$pid} = main::progclass($prog_type)->new(
+ 'pid' => $pid,
+@@ -7648,7 +7641,7 @@
+ 'seriesnum' => $seriesnum,
+ 'episodenum' => $episodenum,
+ 'desc' => $desc,
+- 'available' => $start,
++ 'available' => $available,
+ 'duration' => $duration,
+ 'thumbnail' => $thumbnail,
+ 'channel' => $channel,
+@@ -7939,7 +7932,7 @@
+
+ # Class vars
+ sub index_min { return 10001 }
+-sub index_max { return 19999 };
++sub index_max { return 39999 };
+ sub channels_aod {
+ return {
+ # national stations
diff -Nru get-iplayer-2.87/debian/patches/live-tv.patch
get-iplayer-2.87/debian/patches/live-tv.patch
--- get-iplayer-2.87/debian/patches/live-tv.patch 1970-01-01
01:00:00.000000000 +0100
+++ get-iplayer-2.87/debian/patches/live-tv.patch 2014-12-04
23:22:09.000000000 +0000
@@ -0,0 +1,18 @@
+From: dinkypumpkin <[email protected]>
+Date: Sat, 25 Oct 2014 15:48:54 +0000 (+0100)
+Subject: Fixed live TV streaming
+Origin:
http://git.infradead.org/get_iplayer.git/commitdiff_plain/754b2007a18c75d4aca96d153c4df65606676c09?hp=b7e729ccdc7261d6270b26c054e79876decd6ecb
+Last-Update: 2014-12-03
+
+--- get-iplayer-2.87.orig/get_iplayer
++++ get-iplayer-2.87/get_iplayer
+@@ -5454,7 +5454,8 @@
+ if ( m{\s+simulcast="true"} ) {
+ $version = 'default';
+ # <item kind="programme" live="true" liverewind="true"
identifier="bbc_two_england" group="bbc_two_england" simulcast="true"
availability_class="liverewind">
+- $verpid =
"http://www.bbc.co.uk/emp/simulcast/".$2.".xml" if
m{\s+live="true"\s+(liverewind="true"\s+)?identifier="(.+?)"};
++ # $verpid =
"http://www.bbc.co.uk/emp/simulcast/".$2.".xml" if
m{\s+live="true"\s+(liverewind="true"\s+)?identifier="(.+?)"};
++ $verpid = $2 if
m{\s+live="true"\s+(liverewind="true"\s+)?identifier="(.+?)"};
+ main::logger "INFO: Using Live TV: $verpid\n" if
$opt->{verbose} && $verpid;
+
+ # Live/Non-live EMP tv/radio XML URL
diff -Nru get-iplayer-2.87/debian/patches/series
get-iplayer-2.87/debian/patches/series
--- get-iplayer-2.87/debian/patches/series 2014-10-20 20:39:26.000000000
+0100
+++ get-iplayer-2.87/debian/patches/series 2014-12-04 23:22:09.000000000
+0000
@@ -0,0 +1,4 @@
+live-tv.patch
+data-feeds.patch
+cache-search.patch
+future-schedule.patch
signature.asc
Description: Digital signature
--- End Message ---