Overview
Submit package home:develop7:branches:Extra / get_iplayer to package Extra / get_iplayer
get_iplayer.changes
Changed
x
1
2
-------------------------------------------------------------------
3
+Mon Feb 7 18:56:44 UTC 2022 - Andrei Dziahel <develop7@develop7.info>
4
+
5
+- get_iplayer v3.28
6
+
7
+ * Web PVR: Fixed wrapping of long lines in programme info page
8
+ * Fixed bug that caused some episodes to be skipped when using
9
+ `--pid-recursive` with certain CBeebies/CBBC programmes
10
+ * Added support for "cloudfront" CDN. You can now use
11
+ `--exclude-supplier="cloudfront"` if necessary.
12
+ * The `modes` and `modesizes` programme info fields are now shown
13
+ in an abbreviated form. Individual streams are no longer listed,
14
+ only available quality levels.
15
+ * The "vbidi" CDN is now excluded by default. It is inaccessible
16
+ to get_iplayer and generates useless warnings derived from 403 responses
17
+ to requests for HLS master playlists.
18
+
19
+- get_iplayer v3.27
20
+
21
+ * Removed deprecated `--tag-utf8` option
22
+ * For a programme downloaded multiple times, history search now returns
23
+ the most recent entry with an extant media file instead of the
24
+ oldest entry.
25
+ * Web PVR
26
+ + Programme info pages and help page now open in new window/tab
27
+ + Play* links now open in new window/tab
28
+ + Play* links are no longer displayed for deleted files
29
+ + Play Direct links should now work in Firefox, Chrome, Edge
30
+ (but not Safari) With Remote Streaming type = Auto
31
+ + Play Direct links are now only displayed where MP4/M4A files
32
+ (or MP3 files from obsolete versions of get_iplayer) are available
33
+ + Removed Quicktime, AVI streaming formats
34
+ + Added MPEG-TS, Matroska, AAC, Vorbis streaming formats
35
+ * Windows: Fixed incorrect documentation link in installer finish screen
36
+ * macOS: get_iplayer should work on Apple Silicon systems via Rosetta 2,
37
+ but this has not been verified. The developers do not have access
38
+ to an Apple Silicon system.
39
+ * get_iplayer 3.27 or higher is required with Mojolicious 9.0+. Earlier
40
+ releases of Mojolicious will continue to work with get_iplayer 3.27
41
+ or higher.
42
+
43
+- added download_sources source service
44
+
45
+-------------------------------------------------------------------
46
Sun Nov 29 10:36:39 UTC 2020 - Luigi Baldoni <aloisio@gmx.com>
47
48
- Update to version 3.26 (see
49
get_iplayer.spec
Changed
10
1
2
#
3
4
Name: get_iplayer
5
-Version: 3.26
6
+Version: 3.28
7
Release: 0
8
Summary: Downloads H.264 BBC IPlayer TV, Radio, and Podcast Programs
9
License: GPL-3.0-only
10
_service
Added
3
1
2
+<services><service name="download_files" mode="disabled" /></services>
3
get_iplayer-3.28.tar.gz/.github
Added
2
1
+(directory)
2
get_iplayer-3.28.tar.gz/.github/ISSUE_TEMPLATE
Added
2
1
+(directory)
2
get_iplayer-3.28.tar.gz/.github/ISSUE_TEMPLATE/bug_report.md
Added
37
1
2
+---
3
+name: Bug report
4
+about: Create a bug report
5
+title: ''
6
+labels: ''
7
+assignees: ''
8
+
9
+---
10
+### *Remove this line and all the text below before submitting your bug report*
11
+
12
+#### Read first
13
+
14
+- Do not request help with using get_iplayer. No user support will be provided.
15
+- Do not request new features. Feature requests will not be accepted.
16
+- All bug reports will automatically be closed and locked upon receipt.
17
+- If your report identifies a reproducible bug in get_iplayer, it will be re-opened until a fix is released.
18
+- You will receive no communication from the developers, so provide all the information required.
19
+
20
+#### What you need to provide
21
+
22
+- A clear and concise description of the bug.
23
+- The **complete get_iplayer command line** used.
24
+- The PID or URL of the programme you attempted to download, if applicable. **Only provide one programme**.
25
+- A complete verbose log. Add logs as attachments. Do not paste logs into your bug report. Create a verbose log [e.g., log.txt] with:
26
+
27
+ get_iplayer [your options here] --verbose > log.txt 2>&1
28
+
29
+- Screenshots, if the bug appears to be in the Web PVR Manager user interface.
30
+- OS and version [e.g. Windows 10 2004, macOS 10.15.5, Ubuntu 20.04.1]
31
+- Browser and version [e.g. Chrome 83.0.4103, Edge 83.0.478.56, Firefox 78.0.1, Safari 13.1.1]
32
+- get_iplayer version [e.g. 3.26, 3.26.0-MSWin32, 3.26.1-darwin] - use `get_iplayer -V`
33
+
34
+#### Documentation changes
35
+
36
+If you would like to contribute documentation changes, submit a bug report with your suggested changes and provide the full URL for the wiki page you wish to change. Direct editing of the wiki has been restricted to project developers due to attempted link hijacking by spambots.
37
get_iplayer-3.28.tar.gz/.github/ISSUE_TEMPLATE/config.yml
Added
3
1
2
+blank_issues_enabled: false
3
get_iplayer-3.28.tar.gz/.github/workflows
Added
2
1
+(directory)
2
get_iplayer-3.28.tar.gz/.github/workflows/auto-close-lock-issue-action.yml
Added
31
1
2
+on:
3
+ issues:
4
+ types:
5
+ - opened
6
+jobs:
7
+ auto-close-lock-issue-action_job:
8
+ runs-on: ubuntu-latest
9
+ name: auto-close-lock-issue-action_job
10
+ steps:
11
+ - name: auto-close-lock-issue-action_close-step
12
+ id: auto-close-lock-issue-action_close-step
13
+ uses: maxkomarychev/octions/octions/issues/update@master
14
+ with:
15
+ token: ${{ secrets.GITHUB_TOKEN }}
16
+ issue_number: ${{ github.event.issue.number }}
17
+ state: closed
18
+ - name: auto-close-lock-issue-action_lock-step
19
+ id: auto-close-lock-issue-action_lock-step
20
+ uses: maxkomarychev/octions/octions/issues/lock@master
21
+ with:
22
+ token: ${{ secrets.GITHUB_TOKEN }}
23
+ issue_number: ${{ github.event.issue.number }}
24
+ - name: auto-close-lock-issue-action_label-step
25
+ id: auto-close-lock-issue-action_label-step
26
+ uses: maxkomarychev/octions/octions/issues/add-labels@master
27
+ with:
28
+ token: ${{ secrets.GITHUB_TOKEN }}
29
+ issue_number: ${{ github.event.issue.number }}
30
+ labels: invalid
31
get_iplayer-3.26.tar.gz/Makefile -> get_iplayer-3.28.tar.gz/Makefile
Changed
32
1
2
@echo No need to make anything.
3
4
ifdef VERSION
5
-next_ver := $(shell echo $(VERSION) + 0.01 | bc)
6
release:
7
@git update-index --refresh --unmerged
8
@if git diff-index --name-only HEAD | grep ^ ; then \
9
echo Uncommitted changes in above files; exit 1; fi
10
@git checkout master
11
- @sed -i.bak -e 's/^\(my $$version = \).*/\1$(VERSION);/' -e 's/^\(my $$version_text\) = .*/\1;/' get_iplayer
12
- @sed -i.bak -e 's/^\(my $$VERSION = \).*/\1$(VERSION);/' -e 's/^\(my $$VERSION_TEXT\) = .*/\1;/' get_iplayer.cgi
13
+ @sed -i.bak -e 's/^\(my $$version = \).*/\1$(VERSION);/' get_iplayer
14
+ @sed -i.bak -e 's/^\(my $$VERSION = \).*/\1$(VERSION);/' get_iplayer.cgi
15
@rm -f get_iplayer.bak get_iplayer.cgi.bak
16
@./get_iplayer --nocopyright --manpage get_iplayer.1
17
@git diff --exit-code get_iplayer.1 > /dev/null || \
18
19
@git log --format='%aN' | sort -u > CONTRIBUTORS; git add CONTRIBUTORS
20
@git commit -m "Release $(VERSION)" get_iplayer get_iplayer.cgi get_iplayer.1 CONTRIBUTORS
21
@git tag v$(VERSION)
22
- @git checkout contribute
23
- @git merge master
24
- @sed -i.bak -e 's/^\(my $$version_text\);/\1 = "$(next_ver)-dev";/' get_iplayer
25
- @sed -i.bak -e 's/^\(my $$VERSION_TEXT\);/\1 = "$(next_ver)-dev";/' get_iplayer.cgi
26
- @rm -f get_iplayer.bak get_iplayer.cgi.bak
27
- @git commit -m "bump dev version" get_iplayer get_iplayer.cgi
28
- @git checkout master
29
30
tarball:
31
@git update-index --refresh --unmerged
32
get_iplayer-3.26.tar.gz/README.md -> get_iplayer-3.28.tar.gz/README.md
Changed
12
1
2
3
**NOTE:**
4
5
-- **get_iplayer can only search for programmes that were scheduled for broadcast on BBC linear services within the previous 30 days, even if some are available for more than 30 days on the iPlayer/Sounds sites. BBC Three programmes, red button programmes, iPlayer box sets, iPlayer exclusives, and BBC podcasts are not searchable. Old programmes that are still available after 30 days must be located on the iPlayer/Sounds sites and downloaded directly via PID or URL, but such use is not supported.**.
6
-- **get_iplayer does not support downloading news/sport videos, other embedded media, archive sites, special collections, educational material, programme clips or any content other than whole episodes of programmes broadcast on BBC linear services within the previous 30 days, plus episodes of BBC Three programmes posted within the same period. It may be possible to download other content such as red button programmes or iPlayer box sets directly via PID or URL, but such use is not supported. get_iplayer DOES NOT support live recording from BBC channels.**
7
+- **get_iplayer can only search for programmes that were scheduled for broadcast on BBC linear services within the previous 30 days, even if some are available for more than 30 days on the iPlayer/Sounds sites. BBC Three programmes, red button programmes, iPlayer box sets, web-only content, and BBC podcasts are not searchable. Old programmes that are still available after 30 days must be located on the iPlayer/Sounds sites and downloaded directly via PID or URL.**
8
+- **get_iplayer does not support downloading news/sport videos, other embedded media, archive sites, special collections, educational material, programme clips or any content other than whole episodes of programmes broadcast on BBC linear services within the previous 30 days, plus episodes of BBC Three programmes posted within the same period. It is often possible to download other content such as red button programmes or iPlayer box sets directly via PID or URL. get_iplayer DOES NOT support live recording from BBC channels.**
9
10
## Documentation
11
12
get_iplayer-3.26.tar.gz/get_iplayer -> get_iplayer-3.28.tar.gz/get_iplayer
Changed
406
1
2
#!/usr/bin/env perl
3
#
4
-# get_iplayer - Lists and records BBC iPlayer TV and radio programmes
5
+# get_iplayer - Lists and records BBC iPlayer TV and BBC Sounds radio programmes
6
#
7
# Copyright (C) 2008-2010 Phil Lewis
8
#
9
10
#
11
#
12
package main;
13
-my $version = 3.26;
14
+my $version = 3.28;
15
my $version_text;
16
$version_text = sprintf("v%.2f", $version) unless $version_text;
17
#
18
19
attempts => [ 1, "attempts=n", 'Recording', '--attempts <number>', "Number of attempts to make or resume a failed connection. --attempts is applied per-stream, per-mode. Many modes have two or more streams available."],
20
audioonly => [ 1, "audioonly|audio-only!", 'Recording', '--audio-only', "Only download audio stream for TV programme. 'hls' recording modes are not supported and ignored. Produces .m4a file. Implies --force."],
21
downloadabortonfail => [ 1, "downloadabortonfail|download-abortonfail!", 'Recording', '--download-abortonfail', "Exit immediately if stream for any recording mode fails to download. Use to avoid repeated failed download attempts if connection is dropped or access is blocked."],
22
- excludesupplier => [ 1, "excludecdn|exclude-cdn|excludesupplier|exclude-supplier=s", 'Recording', '--exclude-supplier <supplier>,<supplier>,...', "Comma-separated list of media stream suppliers (CDNs) to skip. Possible values: akamai,limelight,bidi. Synonym: --exclude-cdn."],
23
+ excludesupplier => [ 1, "excludecdn|exclude-cdn|excludesupplier|exclude-supplier=s", 'Recording', '--exclude-supplier <supplier>,<supplier>,...', "Comma-separated list of media stream suppliers (CDNs) to skip. Possible values: akamai,limelight,bidi,cloudfront. Synonym: --exclude-cdn."],
24
force => [ 1, "force|force-download!", 'Recording', '--force', "Ignore programme history (unsets --hide option also)."],
25
fps25 => [ 1, "fps25!", 'Recording', '--fps25', "Use only 25fps streams for TV programmes (HD video not available)."],
26
get => [ 2, "get|record|g!", 'Recording', '--get, -g', "Start recording matching programmes. Search terms required."],
27
- includesupplier => [ 1, "includecdn|include-cdn|includesupplier|include-supplier=s", 'Recording', '--include-supplier <supplier>,<supplier>,...', "Comma-separated list of media stream suppliers (CDNs) to use if not included by default or if previously excluded by --exclude-supplier. Possible values: akamai,limelight,bidi. Synonym: --include-cdn."],
28
+ includesupplier => [ 1, "includecdn|include-cdn|includesupplier|include-supplier=s", 'Recording', '--include-supplier <supplier>,<supplier>,...', "Comma-separated list of media stream suppliers (CDNs) to use if not included by default or if previously excluded by --exclude-supplier. Possible values: akamai,limelight,bidi,cloudfront. Synonym: --include-cdn."],
29
hash => [ 1, "hash!", 'Recording', '--hash', "Show recording progress as hashes"],
30
logprogress => [ 1, "log-progress|logprogress!", 'Recording', '--log-progress', "Force HLS/DASH download progress display to be captured when screen output is redirected to file. Progress display is normally omitted unless writing to terminal."],
31
markdownloaded => [ 1, "markdownloaded|mark-downloaded!", 'Recording', '--mark-downloaded', "Mark programmes in search results or specified with --pid/--url as downloaded by inserting records in download history."],
32
33
$OPTS{SendTE} = 0;
34
@LWP::Protocol::http::EXTRA_SOCK_OPTS = %OPTS;
35
36
- my ($ua, $url, $retries, $succeedmsg, $failmsg, $mustproxy, $fail_content, $ok404) = @_;
37
+ my ($ua, $url, $retries, $succeedmsg, $failmsg, $mustproxy, $fail_content, $ok4xx) = @_;
38
$failmsg ||= "Failed to download URL";
39
$fail_content ||= '';
40
my $res;
41
42
# Disable proxy unless mustproxy is flagged
43
main::proxy_disable($ua) if $opt->{partialproxy} && ! $mustproxy;
44
my $i;
45
+ my $is4xx;
46
for ($i = 1; $i <= $retries; $i++) {
47
logger "\nINFO: Downloading URL ($i/$retries): $url\n" if $opt->{verbose};
48
+ $is4xx = 0;
49
$res = $ua->request( HTTP::Request->new( GET => $url ) );
50
if ( ! $res->is_success ) {
51
- if ( $i < $retries ) {
52
- if ( $opt->{verbose} ) {
53
- logger "\nWARNING: $failmsg ($i/$retries): $url\n";
54
- logger "WARNING: Response: ${\$res->code()} ${\$res->message()}\n";
55
- }
56
- } else {
57
- if ( $opt->{verbose} || ! ( $res->code() == 404 && $ok404 ) ) {
58
- logger "\nERROR: $failmsg ($i/$retries): $url\n";
59
- logger "ERROR: Response: ${\$res->code()} ${\$res->message()}\n";
60
- if ( $res->code() == 403 ) {
61
- logger "ERROR: Access to this resource was blocked by the BBC\n";
62
- }
63
- logger "ERROR: Ignore this error if programme download is successful\n";
64
+ $is4xx = $res->code() == 403 || $res->code() == 404;
65
+ if ( $opt->{verbose} || ! ( $is4xx && $ok4xx ) ) {
66
+ logger "\nWARNING: $failmsg ($i/$retries): $url\n";
67
+ logger "WARNING: Response: ${\$res->code()} ${\$res->message()}\n";
68
+ if ( $res->code() == 403 ) {
69
+ logger "WARNING: Access to this resource was blocked by the BBC\n";
70
}
71
+ logger "WARNING: Ignore this warning if programme download is successful\n";
72
}
73
+ last if $is4xx;
74
} else {
75
logger $succeedmsg;
76
last;
77
78
# Re-enable proxy unless mustproxy is flagged
79
main::proxy_enable($ua) if $opt->{partialproxy} && ! $mustproxy;
80
# Return empty string if we failed and content not required
81
- if ( $i > $retries ) {
82
+ if ( ( $is4xx && ! $ok4xx ) || $i > $retries ) {
83
if ( wantarray ) {
84
return ($fail_content, $res);
85
} else {
86
87
'This applies even if the base option name already begins with "no-", e.g., --no-no-tag or --no-no-artwork',
88
);
89
push @man,
90
- '.TH GET_IPLAYER "1" "June 2020" "Phil Lewis" "get_iplayer Manual"',
91
- '.SH NAME', 'get_iplayer - Stream Recording tool and PVR for BBC iPlayer',
92
+ '.TH GET_IPLAYER "1" "December 2021" "Phil Lewis" "get_iplayer Manual"',
93
+ '.SH NAME', 'get_iplayer - Stream Recording tool and PVR for BBC iPlayer and BBC Sounds',
94
'.SH SYNOPSIS',
95
'\fBget_iplayer\fR [<options>] [<regex|index> ...]',
96
'.PP',
97
98
'.PP',
99
'\fBget_iplayer\fR \fB--refresh\fR [\fB--type\fR=<type> <options>]',
100
'.SH DESCRIPTION',
101
- '\fBget_iplayer\fR lists, searches and records BBC iPlayer TV and radio programmes.',
102
+ '\fBget_iplayer\fR lists, searches and records BBC iPlayer TV and BBC Sounds radio programmes.',
103
'.PP',
104
'\fBget_iplayer\fR has two modes: recording a complete programme for later playback, and as a Personal Video Recorder (PVR), subscribing to',
105
'search terms and recording programmes automatically.',
106
107
# Create new history entry
108
if ( defined $hist->{ $record_entries->{pid} } ) {
109
main::logger "WARNING: duplicate pid $record_entries->{pid} in history\n" if $opt->{debug};
110
- # Append filename and modes
111
- $hist->{ $record_entries->{pid} }->{mode} .= ','.$record_entries->{mode} if defined $record_entries->{mode};
112
- $hist->{ $record_entries->{pid} }->{filename} .= ','.$record_entries->{filename} if defined $record_entries->{filename};
113
- main::logger "DEBUG: Loaded and merged '$record_entries->{pid}' = '$record_entries->{name} - $record_entries->{episode}' from history\n" if $opt->{debug};
114
+ # Replace filename and mode with latest entry if file exists
115
+ if ( -f $record_entries->{filename} ) {
116
+ $hist->{ $record_entries->{pid} }->{mode} = $record_entries->{mode};
117
+ $hist->{ $record_entries->{pid} }->{filename} = $record_entries->{filename};
118
+ main::logger "DEBUG: Loaded and replaced '$record_entries->{pid}' = '$record_entries->{name} - $record_entries->{episode}' from history\n" if $opt->{debug};
119
+ }
120
} else {
121
# workaround empty names
122
#$record_entries->{name} = 'pid:'.$record_entries->{pid} if ! $record_entries->{name};
123
124
for my $key ( sort keys %{$data{$_}} ) {
125
main::logger sprintf "%-16s ", $_.':';
126
if ( ref$data{$_}->{$key} ne 'HASH' ) {
127
- main::logger "$key: $data{$_}->{$key}";
128
- main::logger " [estimated sizes only]" if $_ eq "modesizes";
129
+ if ( $_ eq "modes" || $_ eq "modesizes" ) {
130
+ my %seen = ();
131
+ my @vals = sort Programme::cmp_modes grep { not $seen{$_}++ } map { $_ =~ s/([a-z])\d+/$1/; $_; } split(",", $data{$_}->{$key});
132
+ my $val = join(",", @vals);
133
+ main::logger "$key: $val";
134
+ main::logger " [estimated sizes]" if $_ eq "modesizes";
135
+ } else {
136
+ main::logger "$key: $data{$_}->{$key}";
137
+ }
138
# This is the same as 'modes' list
139
#} else {
140
# main::logger "$key: ".(join ',', sort keys %{ $data{$_}->{$key} } );
141
142
$filename->{generic} = main::encode_fs(File::Spec->catfile($prog->{dir}, "$prog->{fileprefix}.xml"));
143
$template->{generic} = '<?xml version="1.0" encoding="UTF-8" ?>'."\n";
144
$template->{generic} .= '<program_meta_data xmlns="http://linuxcentre.net/xmlstuff/get_iplayer" revision="1">'."\n";
145
- $template->{generic} .= "\t<$_>[$_]</$_>\n" for ( sort keys %{$prog} );
146
+ my $version = $prog->{version} || 'unknown';
147
+ for my $key ( sort keys %{$prog} ) {
148
+ my $subst = "[$key]";
149
+ my $value = $prog->{$key};
150
+ if ( ref$value eq 'HASH' ) {
151
+ if ( ref$value->{$version} ne 'HASH' ) {
152
+ # abbreviate mode lists
153
+ if ( $key eq "modes" || $key eq "modesizes" ) {
154
+ my %seen = ();
155
+ my @vals = sort Programme::cmp_modes grep { not $seen{$_}++ } map { $_ =~ s/([a-z])\d+/$1/; $_; } split(",", $value->{$version});
156
+ $subst = join(",", @vals);
157
+ }
158
+ }
159
+ }
160
+ $template->{generic} .= "\t<$key>$subst</$key>\n";
161
+ }
162
$template->{generic} .= "</program_meta_data>\n";
163
# JSON template for all info (ignored)
164
$filename->{json} = main::encode_fs(File::Spec->catfile($prog->{dir}, "$prog->{fileprefix}.json"));
165
166
$self->{duration} = $self->{durations}->{$version} if $self->{durations}->{$version};
167
$self->{runtime} = int($self->{duration} / 60);
168
my $jom = {};
169
- for my $key ( keys %{$self} ) {
170
+ for my $key ( sort keys %{$self} ) {
171
my $value = $self->{$key};
172
# Get version specific value if this key is a hash
173
if ( ref$value eq 'HASH' ) {
174
if ( ref$value->{$version} ne 'HASH' ) {
175
- $value = $value->{$version};
176
+ # abbreviate mode lists
177
+ if ( $key eq "modes" || $key eq "modesizes" ) {
178
+ my %seen = ();
179
+ my @vals = sort Programme::cmp_modes grep { not $seen{$_}++ } map { $_ =~ s/([a-z])\d+/$1/; $_; } split(",", $value->{$version});
180
+ $value = join(",", @vals);
181
+ } else {
182
+ $value = $value->{$version};
183
+ }
184
} else {
185
next;
186
}
187
188
last unless $html;
189
my $dom = XML::LibXML->load_html(string => $html, recover => 1, suppress_errors => 1);
190
unless ( $channel ) {
191
- $channel = $dom->findvalue('//a[contains(@class,"br-masthead__masterbrand")]');
192
+ $channel = $dom->findvalue('//*[contains(@class,"br-masthead__masterbrand")]');
193
}
194
unless ( $title ) {
195
$title = $dom->findvalue('//div[contains(@class,"br-masthead__title")]/a');
196
197
$channel = undef;
198
my @urls = ( "https://www.bbc.co.uk/iplayer/episodes/$parent_pid" );
199
for my $url ( @urls ) {
200
+ my $curr_url = $url;
201
$curr_page = 1;
202
$max_page = 1;
203
$last_page = undef;
204
{ do {
205
- my $html = main::request_url_retry($ua, $url, 3, '', '');
206
+ my $html = main::request_url_retry($ua, $curr_url, 3, '', '');
207
last unless $html;
208
my $dom = XML::LibXML->load_html(string => $html, recover => 1, suppress_errors => 1);
209
if ( ! $check_series_nav ) {
210
211
$last_page =~ s/(^\s+|\s+$)//g;
212
$max_page = $last_page if $last_page > $max_page;
213
$curr_page++;
214
- $url = "https://www.bbc.co.uk/iplayer/episodes/$parent_pid?page=$curr_page";
215
+ $curr_url = $url;
216
+ $curr_url .= "&" if $curr_url =~ /\?/;
217
+ $curr_url .= "?" unless $curr_url =~ /\?/;
218
+ $curr_url = "${curr_url}page=$curr_page";
219
} while ( $curr_page <= $max_page ) };
220
}
221
}
222
223
return $eps;
224
}
225
226
-# Intelligently split name and episode from title string for BBC iPlayer metadata
227
+# Intelligently split name and episode from title string for BBC iPlayer/BBC Sounds metadata
228
sub split_title {
229
my $title = shift;
230
my ( $name, $episode );
231
232
my $mattribs = shift;
233
my $cattribs = shift;
234
235
- main::logger "New BBC iPlayer Stream Found:\n";
236
+ main::logger "New BBC iPlayer/BBC Sounds Stream Found:\n";
237
main::logger "MEDIA-ELEMENT:\n";
238
239
# list media attribs
240
241
}
242
}
243
$conn->{href} = $variant_url;
244
- my $data = main::request_url_retry( $ua, $conn->{href}, 3, undef, undef, 1 );
245
+ my $data = main::request_url_retry( $ua, $conn->{href}, 3, undef, undef, 1, undef, 1 );
246
if ( ! $data ) {
247
main::logger "WARNING: No HLS playlist returned ($conn->{href})\n" if $opt->{verbose};
248
return;
249
250
}
251
}
252
$conn->{href} = $manifest_url;
253
- my $xml = main::request_url_retry( $ua, $conn->{href}, 3, undef, undef, 1 );
254
+ my $xml = main::request_url_retry( $ua, $conn->{href}, 3, undef, undef, 1, undef, 1 );
255
if ( ! $xml ) {
256
main::logger "WARNING: No DASH manifest returned ($conn->{href})\n" if $opt->{verbose};
257
return;
258
259
main::logger "INFO: Getting stream data for version: '$version'\n" if $opt->{verbose};
260
# filter CDN suppliers
261
my @exclude_supplier = split(/,/, $opt->{excludesupplier});
262
+ push @exclude_supplier, 'vbidi';
263
if ( $opt->{includesupplier} ) {
264
@exclude_supplier = grep { $opt->{includesupplier} !~ /\b$_\b/ } @exclude_supplier;
265
}
266
267
}
268
my $exclude_regex = '^ROGUEVALUE$';
269
if ( @exclude_supplier ) {
270
- $exclude_regex = '('.(join('|', @exclude_supplier)).')';
271
+ $exclude_regex = '_('.(join('|', @exclude_supplier)).')';
272
}
273
274
# retrieve stream data
275
276
}
277
}
278
279
+ # keep max audio bitrate if more than one for given video resolution
280
+ my %seen = ();
281
+ my @modes = sort Programme::cmp_modes grep { not $seen{$_}++ } map { $_ =~ s/\d+$//; $_; } keys %$data;
282
+ for my $m ( @modes ) {
283
+ my $n = 0;
284
+ my $xbr;
285
+ while ( my $strm = $data->{$m . ++$n} ) {
286
+ if ( $strm->{audio_bitrate} > $xbr ) {
287
+ $xbr = $strm->{audio_bitrate};
288
+ }
289
+ }
290
+ $n = 0;
291
+ while ( my $strm = $data->{$m . ++$n} ) {
292
+ if ( $strm->{audio_bitrate} < $xbr ) {
293
+ delete $data->{$m . $n};
294
+ }
295
+ }
296
+ }
297
+
298
# Report modes found
299
if ( $opt->{verbose} ) {
300
main::logger sprintf("INFO: Found mode %10s: %s\n", $_, $data->{$_}->{type}) for sort Programme::cmp_modes keys %{ $data };
301
302
}
303
}
304
my @other_opts;
305
- if ( ! $opt->{ffmpegobsolete} && $opt->{notag} ) {
306
+ if ( ! $opt->{ffmpegobsolete} ) {
307
push @other_opts, ( '-movflags', 'faststart' );
308
}
309
310
311
}
312
}
313
};
314
-
315
- my $delay = Mojo::IOLoop->delay;
316
+ my $promise;
317
+ my $delay;
318
+ my $use_delay;
319
+ eval {
320
+ $promise = Mojo::Promise->new;
321
+ };
322
+ if ( $@ ) {
323
+ main::logger "DEBUG: Mojo::Promise not available, using Mojo::IOLoop->delay\n" if $opt->{verbose};
324
+ $delay = Mojo::IOLoop->delay;
325
+ $use_delay = 1;
326
+ }
327
+ my $count = 0;
328
my $fetch;
329
$fetch = sub {
330
return unless my $url = shift @$urls;
331
return if ( $rc_mojo && $opt->{refreshabortonerror} );
332
- my $end = $delay->begin;
333
+ my $end;
334
+ if ( $use_delay ) {
335
+ $end = $delay->begin;
336
+ }
337
$attempts{$url}++;
338
main::logger "\nINFO: Downloading $channels->{$url} schedule page ($attempts{$url}/$retries): $url\n" if $opt->{verbose};
339
$ua->get($url => sub {
340
341
$get_callback->($ua, $tx);
342
$fetch->();
343
}
344
- $end->();
345
+ if ( $use_delay ) {
346
+ $end->();
347
+ } else {
348
+ $promise->resolve if --$count == 0;
349
+ }
350
});
351
+ $count++;
352
};
353
-
354
$fetch->() for 1 .. $max_conn;
355
- $delay->wait;
356
+ if ( $use_delay ) {
357
+ $delay->wait;
358
+ } else {
359
+ $promise->wait;
360
+ }
361
undef $ua;
362
return 1 if $rc_mojo;
363
}
364
365
my $rate_percent;
366
my $eta_str;
367
my $prog_cdn;
368
- ($prog_cdn = "$streamdata{type} ak ll bi") =~ s/^.*akamai(?=.*\b(ak)\b).*$|^.*limelight(?=.*\b(ll)\b).*$|^.*bidi(?=.*\b(bi)\b).*$/$1$2$3/;
369
- $prog_cdn = "un" unless $prog_cdn =~ /^(ak|ll|bi)$/;
370
+ ($prog_cdn = "$streamdata{type} ak ll bi cf") =~ s/^.*akamai(?=.*\b(ak)\b).*$|^.*limelight(?=.*\b(ll)\b).*$|^.*bidi(?=.*\b(bi)\b).*$|^.*cloudfront(?=.*\b(cf)\b).*$/$1$2$3$4/;
371
+ $prog_cdn = "un" unless $prog_cdn =~ /^(ak|ll|bi|cf)$/;
372
373
# LWP download callback
374
my $callback = sub {
375
376
my ( $self, $ua, $url, $prog, $version, %streamdata ) = @_;
377
my $rc;
378
379
+ my $media_file = main::encode_fs(File::Spec->catfile($prog->{dir}, "$prog->{fileprefix}.dash.ts"));
380
+ my $media_type = $prog->{type} eq "tv" ? "video" : "audio";
381
+ if ( $opt->{overwrite} ) {
382
+ unlink $media_file;
383
+ } else {
384
+ if ( -f $media_file ) {
385
+ main::logger "INFO: Using existing DASH $media_type file: $media_file\n";
386
+ main::logger "INFO: Use --overwrite to re-download\n";
387
+ if ( $prog->{type} eq "tv" && ! $opt->{audioonly} ) {
388
+ return $prog->postproc(undef, $media_file, $ua);
389
+ } else {
390
+ return $prog->postproc($media_file, undef, $ua);
391
+ }
392
+ }
393
+ }
394
+
395
# audio files
396
my $audio_prefix = $prog->{fileprefix};
397
my $audio_tmp = main::encode_fs(File::Spec->catfile($prog->{dir}, "${audio_prefix}.audio.m4a"));
398
399
tag_podcast_radio => [ 1, "tagpodcastradio|tag-podcast-radio!", 'Tagging', '--tag-podcast-radio', "Tag only downloaded radio programmes as iTunes podcasts (incompatible with Music/Podcasts/TV apps on macOS 10.15 and higher)"],
400
tag_podcast_tv => [ 1, "tagpodcasttv|tag-podcast-tv!", 'Tagging', '--tag-podcast-tv', "Tag only downloaded tv programmes as iTunes podcasts (incompatible with Music/Podcasts/TV apps on macOS 10.15 and higher)"],
401
tag_tracklist => [ 1, "tagtracklist|tag-tracklist!", 'Tagging', '--tag-tracklist', "Add track list of music played in programme (if available) to lyrics field."],
402
- tag_utf8 => [ 1, "tagutf8|tag-utf8!", 'Ignored', '--tag-utf8', "Use UTF-8 encoding for non-ASCII characters in AtomicParsley parameter values (Linux/Unix/macOS only). Use only if auto-detect fails."],
403
};
404
}
405
406
get_iplayer-3.26.tar.gz/get_iplayer.1 -> get_iplayer-3.28.tar.gz/get_iplayer.1
Changed
46
1
2
-.TH GET_IPLAYER "1" "June 2020" "Phil Lewis" "get_iplayer Manual"
3
+.TH GET_IPLAYER "1" "December 2021" "Phil Lewis" "get_iplayer Manual"
4
.SH NAME
5
-get_iplayer \- Stream Recording tool and PVR for BBC iPlayer
6
+get_iplayer \- Stream Recording tool and PVR for BBC iPlayer and BBC Sounds
7
.SH SYNOPSIS
8
\fBget_iplayer\fR [<options>] [<regex|index> ...]
9
.PP
10
11
.PP
12
\fBget_iplayer\fR \fB\-\-refresh\fR [\fB\-\-type\fR=<type> <options>]
13
.SH DESCRIPTION
14
-\fBget_iplayer\fR lists, searches and records BBC iPlayer TV and radio programmes.
15
+\fBget_iplayer\fR lists, searches and records BBC iPlayer TV and BBC Sounds radio programmes.
16
.PP
17
\fBget_iplayer\fR has two modes: recording a complete programme for later playback, and as a Personal Video Recorder (PVR), subscribing to
18
search terms and recording programmes automatically.
19
20
Exit immediately if stream for any recording mode fails to download. Use to avoid repeated failed download attempts if connection is dropped or access is blocked.
21
.TP
22
\fB\-\-exclude\-supplier <supplier>,<supplier>,...
23
-Comma\-separated list of media stream suppliers (CDNs) to skip. Possible values: akamai,limelight,bidi. Synonym: \-\-exclude\-cdn.
24
+Comma\-separated list of media stream suppliers (CDNs) to skip. Possible values: akamai,limelight,bidi,cloudfront. Synonym: \-\-exclude\-cdn.
25
.TP
26
\fB\-\-force
27
Ignore programme history (unsets \-\-hide option also).
28
29
Show recording progress as hashes
30
.TP
31
\fB\-\-include\-supplier <supplier>,<supplier>,...
32
-Comma\-separated list of media stream suppliers (CDNs) to use if not included by default or if previously excluded by \-\-exclude\-supplier. Possible values: akamai,limelight,bidi. Synonym: \-\-include\-cdn.
33
+Comma\-separated list of media stream suppliers (CDNs) to use if not included by default or if previously excluded by \-\-exclude\-supplier. Possible values: akamai,limelight,bidi,cloudfront. Synonym: \-\-include\-cdn.
34
.TP
35
\fB\-\-log\-progress
36
Force HLS/DASH download progress display to be captured when screen output is redirected to file. Progress display is normally omitted unless writing to terminal.
37
38
.PP
39
This manual page was originally written by Jonathan Wiltshire <jmw@debian.org> for the Debian project (but may be used by others).
40
.SH COPYRIGHT NOTICE
41
-get_iplayer v3.26, Copyright (C) 2008\-2010 Phil Lewis
42
+get_iplayer v3.28, Copyright (C) 2008\-2010 Phil Lewis
43
This program comes with ABSOLUTELY NO WARRANTY; for details use \-\-warranty.
44
This is free software, and you are welcome to redistribute it under certain
45
conditions; use \-\-conditions for details.
46
get_iplayer-3.26.tar.gz/get_iplayer.cgi -> get_iplayer-3.28.tar.gz/get_iplayer.cgi
Changed
690
1
2
# License: GPLv3 (see LICENSE.txt)
3
#
4
5
-my $VERSION = 3.26;
6
+my $VERSION = 3.28;
7
my $VERSION_TEXT;
8
$VERSION_TEXT = sprintf("v%.2f", $VERSION) unless $VERSION_TEXT;
9
10
11
print $se "$data{_method}: $request{URL}\n";
12
13
# Is this the CGI or some other file request?
14
- if ( $request{URL} =~ /^\/?(iplayer|recordings_delete|playlist.*|genplaylist.*|opml|)\/?$/ ) {
15
+ if ( $request{URL} =~ /^\/?(recordings_delete|playlist.+|genplaylist.+|)\/?$/ ) {
16
# remove any vars that might affect the CGI
17
#%ENV = ();
18
@ARGV = ();
19
20
my $action = $cgi->param( 'ACTION' ) || $request_uri;
21
# Strip the leading '/' to get the action
22
$action =~ s|^\/||g;
23
- # rewrite short-form backwards compatible URIs
24
- # e.g. http://server/stream?args -> http://server/get_iplayer.cgi?ACTION=stream&args
25
26
- # Stream from get_iplayer STDOUT (optionally transcoding if required)
27
- if ( $action eq 'direct' ) {
28
+ # Stream from file (optionally transcoding if required)
29
+ if ( $action eq 'direct' || $action eq 'playdirect' ) {
30
binmode $fh, ':raw';
31
# get filename first
32
my $progtype = $cgi->param( 'PROGTYPES' );
33
my $pid = $cgi->param( 'PID' );
34
- # If the modes list f set to nothing
35
- #my $mode = $opt->{MODES}->{current} || $opt->{MODES}->{default};
36
my $mode = $cgi->param( 'MODES' );
37
my $filename = get_direct_filename( $pid, $mode, $progtype );
38
- # Use OUTTYPE for transcoding if required - get output ext
39
- # $cgi->param('STREAMTYPE') || $cgi->param('OUTTYPE') || 'flv' if $action eq 'playlistdirect';
40
my $ext = lc( $cgi->param('STREAMTYPE') || $cgi->param( 'OUTTYPE' ) );
41
- # Remove fileprefix
42
- $ext =~ s/^.*\.//g;
43
# get file source ext
44
my $src_ext = $filename;
45
$src_ext =~ s/^.*\.//g;
46
# Stream mime types
47
my %mimetypes = (
48
- wav => 'audio/x-wav',
49
+ aac => 'audio/aac',
50
+ adts => 'audio/aac',
51
flac => 'audio/x-flac',
52
- aac => 'audio/mpeg',
53
- m4a => 'audio/mpeg',
54
+ m4a => 'audio/mp4',
55
mp3 => 'audio/mpeg',
56
- rm => 'audio/x-pn-realaudio',
57
+ oga => 'audio/vorbis',
58
+ wav => 'audio/x-wav',
59
+ asf => 'video/x-ms-asf',
60
+ avi => 'video/avi',
61
+ flv => 'video/x-flv',
62
+ matroska => 'video/x-matroska',
63
+ mkv => 'video/x-matroska',
64
mov => 'video/quicktime',
65
mp4 => 'video/mp4',
66
- avi => 'video/x-flv',
67
- flv => 'video/x-flv',
68
- asf => 'video/x-ms-asf',
69
+ mpegts => 'video/MP2T',
70
+ rm => 'audio/x-pn-realaudio',
71
+ ts => 'video/MP2T',
72
);
73
74
- # default recipies
75
- # Disable transcoding if none is specified as OUTTYPE/STREAMTYPE
76
+ # default recipes
77
my $notranscode = 0;
78
+ # Disable transcoding if none is specified as OUTTYPE/STREAMTYPE
79
+ # Or if streaming MP4 via play direct
80
if ( $ext =~ /none/i ) {
81
- print $se "INFO: Transcoding disabled (OUTTYPE=none)\n";
82
- $ext = $src_ext;
83
- $notranscode = 1;
84
-
85
- # cannot stream mp4/avi so transcode to flv
86
- # Add types here which you want re-muxed into flv
87
- #if ( $src_ext =~ m{^(mp4|avi|mov|mp3|aac)$} && ! $ext ) {
88
- } elsif ( $src_ext =~ m{^(mp4|m4a|aac|avi|mov)$} && ! $ext ) {
89
+ print $se "INFO: Transcoding disabled (OUTTYPE=$ext)\n";
90
+ $ext = $src_ext;
91
+ $notranscode = 1;
92
+ # Else known types re-mux into flv unless play direct
93
+ } elsif ( $action ne 'playdirect' && ! $ext && $src_ext =~ m{^(m4a|mp4|mp3|aac|avi|mkv|mov|ts)$} ) {
94
$ext = 'flv';
95
-
96
- # Else Default to no transcoding
97
+ # Else default to no transcoding
98
} elsif ( ! $ext ) {
99
$ext = $src_ext;
100
}
101
102
}
103
104
# Get a playlist for a specified 'PROGTYPES'
105
- } elsif ( $action eq 'playlist' || $action eq 'playlistdirect' || $action eq 'playlistfiles' ) {
106
+ } elsif ( $action eq 'playlistdirect' || $action eq 'playlistfiles' ) {
107
# Output headers
108
my $headers = $cgi->header( -type => 'audio/x-mpegurl' );
109
+ # To save file
110
+ #my $headers = $cgi->header( -type => 'audio/x-mpegurl', -attachment => 'get_iplayer.m3u' );
111
112
# Send the headers to the browser
113
print $se "\r\nHEADERS:\n$headers\n"; #if $opt_cmdline->{debug};
114
print $fh $headers;
115
116
# determine output type
117
- my $outtype = $cgi->param('OUTTYPE') || 'flv';
118
- $outtype = $cgi->param('STREAMTYPE') || $cgi->param('OUTTYPE') || 'flv' if $action eq 'playlistdirect';
119
+ my $outtype = $cgi->param('OUTTYPE');
120
+ $outtype = $cgi->param('STREAMTYPE') || $cgi->param('OUTTYPE') if $action eq 'playlistdirect';
121
122
# ( host, outtype, modes, progtype, bitrate, search, searchfields, action )
123
print $fh create_playlist_m3u_single( $request_host, $outtype, $opt->{MODES}->{current}, $opt->{PROGTYPES}->{current} , $cgi->param('BITRATE') || '', $opt->{SEARCH}->{current}, $opt->{SEARCHFIELDS}->{current} || 'name', $opt->{VERSIONLIST}->{current}, $action );
124
125
- # Get a playlist for a specified 'PROGTYPES'
126
- } elsif ( $action eq 'opml' ) {
127
- # Output headers
128
- my $headers = $cgi->header( -type => 'text/xml' );
129
-
130
- # Send the headers to the browser
131
- print $se "\r\nHEADERS:\n$headers\n"; #if $opt_cmdline->{debug};
132
- print $fh $headers;
133
- # ( host, outtype, modes, type, bitrate )
134
- print $fh get_opml( $request_host, $cgi->param('OUTTYPE') || 'flv', $opt->{MODES}->{current}, $opt->{PROGTYPES}->{current} , $cgi->param('BITRATE') || '', $opt->{SEARCH}->{current}, $cgi->param('LIST') || '' );
135
-
136
# Get a playlist for a selected progs in form
137
- } elsif ( $action eq 'genplaylist' || $action eq 'genplaylistdirect' || $action eq 'genplaylistfile' ) {
138
+ } elsif ( $action eq 'genplaylistdirect' || $action eq 'genplaylistfile' ) {
139
# Output headers
140
my $headers = $cgi->header( -type => 'audio/x-mpegurl' );
141
# To save file
142
143
print $fh $headers;
144
145
# determine output type
146
- my $outtype = $cgi->param('OUTTYPE') || 'flv';
147
+ my $outtype = $cgi->param('OUTTYPE');
148
$outtype = $cgi->param('STREAMTYPE') || $cgi->param('OUTTYPE') if $action eq 'genplaylistdirect';
149
150
# ( host, outtype, modes, bitrate, action )
151
152
153
sub build_ffmpeg_args {
154
my ( $filename, $mimetype, $ext, $abitrate, $vsize, $vfr, $src_ext ) = ( @_ );
155
+ my @cmd;
156
+ my @cmd_vopts;
157
my @cmd_aopts;
158
- my $src_mimetype = $mimetype;
159
- # mime type override for audio->flv conversion
160
- if ( lc( $src_ext ) =~ m{^(aac|m4a|mp3)$} ) {
161
- $src_mimetype = 'audio/mpeg';
162
- }
163
-
164
if ( $abitrate =~ m{^\d+$} ) {
165
- if ( lc( $ext ) eq 'flv' ) {
166
- push @cmd_aopts, ( '-ar', '44100', '-ab', "${abitrate}k" );
167
- } else {
168
- push @cmd_aopts, ( '-ab', "${abitrate}k" );
169
- }
170
- } else {
171
- if ( lc( $ext ) eq 'flv' ) {
172
- push @cmd_aopts, ( '-ar', '44100' );
173
- }
174
- # cannot copy code if for example we have an aac stream output as WAV (e.g. squeezebox flashaac)
175
- #push @cmd_aopts, ( '-acodec', 'copy' );
176
+ push @cmd_aopts, ( '-ab', "${abitrate}k" );
177
+ }
178
+ if ( lc( $ext ) eq 'flv' ) {
179
+ push @cmd_aopts, ( '-ar', '44100' );
180
}
181
-
182
- my @cmd;
183
# If conversion is necessary
184
# Video
185
- if ( $src_mimetype =~ m{^video} ) {
186
- my @cmd_vopts;
187
-
188
+ if ( $mimetype =~ m{^video} && $filename !~ m{\.(aac|m4a|mp3)$} ) {
189
# Apply video size
190
push @cmd_vopts, ( '-s', "${vsize}" ) if $vsize =~ m{^\d+x\d+$};
191
-
192
# Apply video framerate - caveat - bitrate defaults to 200k if only vfr is set
193
- push @cmd_vopts, ( '-r', $vfr ) if $vfr =~ m{^\d$};
194
-
195
- # -sameq is bad
196
- ## Apply sameq if framerate only and no bitrate
197
- #push @cmd_vopts, '-sameq' if $vfr =~ m{^\d$} && $vsize !~ m{^\d+x\d+$};
198
-
199
+ push @cmd_vopts, ( '-r', $vfr ) if $vfr =~ m{^\d+$};
200
# Add in the codec if we are transcoding and not remuxing the stream
201
if ( @cmd_vopts ) {
202
push @cmd_vopts, ( '-vcodec', 'libx264' );
203
} else {
204
push @cmd_vopts, ( '-vcodec', 'copy' );
205
}
206
-
207
- @cmd = (
208
- $opt_cmdline->{ffmpeg},
209
- #'-f', $src_ext, # not required?
210
- '-i', $filename,
211
- @cmd_aopts,
212
- @cmd_vopts,
213
- '-f', $ext,
214
- '-',
215
- );
216
# Audio
217
} else {
218
- @cmd = (
219
- $opt_cmdline->{ffmpeg},
220
- #'-f', $src_ext, # not required?
221
- '-i', $filename,
222
- '-vn',
223
- @cmd_aopts,
224
- '-ac', 2,
225
- '-f', $ext,
226
- '-',
227
- );
228
+ push @cmd_vopts, ( '-vn' );
229
}
230
+ @cmd = (
231
+ $opt_cmdline->{ffmpeg},
232
+ '-i', $filename,
233
+ @cmd_vopts,
234
+ @cmd_aopts,
235
+ '-ac', 2,
236
+ '-f', $ext,
237
+ '-',
238
+ );
239
print $se "DEBUG: Command args: ".(join ' ', @cmd)."\n";
240
return @cmd;
241
}
242
243
$outtype =~ s/^.*\.//g;
244
245
my $searchterm = $search;
246
- # this is already a wildcard default regex...
247
- if ( $search eq '.*' ) {
248
- $searchterm = '.*';
249
- # if it's a URL then bypass regex stuff
250
- } elsif ( $search =~ m{^http} ) {
251
- $searchterm = $search;
252
# make search term regex friendly
253
- } else {
254
+ if ( $searchterm ne '.*' && $searchterm !~ m{^http} ) {
255
$searchterm =~ s|([\/\.\?\+\-\*\^\(\)\[\]\{\}])|\\$1|g;
256
}
257
258
259
'--nocopyright',
260
'--expiry=999999999',
261
'--webrequest',
262
- get_iplayer_webrequest_args( 'nopurge=1', "type=$type", 'listformat=ENTRY|<pid>|<name>|<episode>|<desc>|<filename>|<mode>', "fields=$searchfields", "search=$searchterm", "versionlist=$versionlist" ),
263
+ get_iplayer_webrequest_args( 'history=1', 'skipdeleted=1', 'nopurge=1', "type=$type", 'listformat=ENTRY|<pid>|<name>|<episode>|<desc>|<filename>|<mode>', "fields=$searchfields", "search=$searchterm", "versionlist=$versionlist" ),
264
);
265
- # Only add history search if the request is of this type or is a PlayFile from localfiles type
266
- if ( ( $request eq 'playlistfiles' || $request eq 'playlistdirect' ) && ! ( $search =~ m{^/} && $searchfields eq 'pid' ) ) {
267
- push @cmd, '--history', '--skipdeleted';
268
- }
269
+
270
my @out = get_cmd_output( @cmd );
271
272
push @playlist, "#EXTM3U\n";
273
274
# playlist with direct streaming for files through webserver
275
if ( $request eq 'playlistdirect' ) {
276
next if ! ( $pid && $type && $mode );
277
- $url = build_url_direct( $request_host, $type, $pid, $mode, basename( $filename ), $opt->{STREAMTYPE}->{current}, $opt->{HISTORY}->{current}, $opt->{BITRATE}->{current}, $opt->{VSIZE}->{current}, $opt->{VFR}->{current}, $opt->{VERSIONLIST}->{current} );
278
-
279
- # If pid is actually a filename then use it cos this is a local file type programme
280
- } elsif ( $request eq 'playlistfiles' && $pid =~ m{^/} ) {
281
- next if ! $pid;
282
- $url = search_absolute_path( $pid ) if $pid;
283
+ $url = build_url_direct( $request_host, $type, $pid, $mode, $outtype, $opt->{STREAMTYPE}->{current}, $opt->{HISTORY}->{current}, $opt->{BITRATE}->{current}, $opt->{VSIZE}->{current}, $opt->{VFR}->{current}, $opt->{VERSIONLIST}->{current} );
284
285
# playlist with local files
286
} elsif ( $request eq 'playlistfiles' ) {
287
next if ! $filename;
288
$url = search_absolute_path( $filename );
289
290
- # playlist of proxied urls for streaming online prog via web server
291
- } else {
292
- next if ! ( $type && $pid );
293
- my $suffix = "${pid}.${outtype}";
294
- $url = build_url_stream( $request_host, $type, $pid, $mode || $modes, $suffix, $opt->{STREAMTYPE}->{current}, $opt->{BITRATE}->{current}, $opt->{VSIZE}->{current}, $opt->{VFR}->{current}, $opt->{VERSIONLIST}->{current} );
295
}
296
297
- # Format required, e.g.
298
- ##EXTINF:-1,BBC Radio - BBC Radio One (High Quality Stream)
299
push @playlist, "#EXTINF:-1,$type - $channel - $name - $episode - $desc";
300
push @playlist, "$url\n";
301
302
303
304
my @record = ( $cgi->param( 'PROGSELECT' ) );
305
306
- # If a URL was specified by the User (assume auto mode list is OK):
307
- if ( $opt->{URL}->{current} =~ m{^https?://} ) {
308
- push @record, "$opt->{PROGTYPES}->{current}|$opt->{URL}->{current}|$opt->{URL}->{current}|-";
309
- }
310
-
311
# Create m3u from all selected 'TYPE|PID|NAME|EPISODE|MODE|CHANNEL' entries in the PVR
312
for (@record) {
313
my $url;
314
315
316
# playlist with local files
317
} elsif ( $request eq 'genplaylistfile' ) {
318
- # If pid is actually a filename then use it cos this is a local file type programme
319
- if ( $pid =~ m{^/} ) {
320
- my $filename = search_absolute_path( $pid );
321
- $url = $filename if $filename;
322
- } else {
323
- # Lookup filename (add it if defined - even if relative)
324
- # check for -f $filename if you want to exclude files that cannot be found
325
- my $filename = get_direct_filename( $pid, $mode, $type );
326
- $url = $filename if $filename;
327
- }
328
-
329
- # Uncomment this to make all playlists local for localfiles types
330
- # If pid is actually a filename then use it cos this is a local file type programme
331
- #} elsif ( $pid =~ m{^/} ) {
332
- # my $filename = search_absolute_path( $pid );
333
- # $url = $filename if $filename;
334
-
335
- # playlist of proxied urls for streaming online prog via web server
336
- } else {
337
- my $suffix = "${pid}.${outtype}";
338
- $url = build_url_stream( $request_host, $type, $pid, $mode || $opt->{MODES}->{current}, $suffix, $opt->{STREAMTYPE}->{current}, $opt->{BITRATE}->{current}, $opt->{VSIZE}->{current}, $opt->{VFR}->{current}, $opt->{VERSIONLIST}->{current} );
339
+ # Lookup filename (add it if defined - even if relative)
340
+ # check for -f $filename if you want to exclude files that cannot be found
341
+ my $filename = get_direct_filename( $pid, $mode, $type );
342
+ $url = $filename if -f $filename;
343
}
344
345
# Skip empty urls
346
next if ! $url;
347
348
- # Format required, e.g.
349
- ##EXTINF:-1,BBC Radio - BBC Radio One (High Quality Stream)
350
- #http://localhost:1935/stream?PID=liveradio:bbc_radio_one&MODES=flashaac&OUTTYPE=bbc_radio_one.wav
351
push @playlist, "#EXTINF:-1,$type - $channel - $name - $episode";
352
push @playlist, "$url\n";
353
354
355
356
357
358
-sub get_opml {
359
- my ( $request_host, $outtype, $modes, $type, $bitrate, $search, $list ) = ( @_ );
360
- my @playlist;
361
- $outtype =~ s/^.*\.//g;
362
-
363
- #<?xml version="1.0" encoding="UTF-8"?>
364
- #<opml version="1.1">
365
- # <head>
366
- # <title>Grateful Dead - 1995-07-09-Chicago, IL</title>
367
- # </head>
368
- # <body>
369
- # <outline URL="http://www.archive.org/.../gd1995-07-09d1t01_vbr.mp3" bitrate="200" source="Soundboard" text="Touch Of Grey" type="audio" />
370
- # <outline URL="http://www.archive.org/.../gd1995-07-09d1t02_vbr.mp3" bitrate="203" source="Soundboard" text="Little Red Rooster" type="audio" />
371
- # <outline URL="http://www.archive.org/.../gd1995-07-09d1t03_vbr.mp3" bitrate="194" source="Soundboard" text="Lazy River Road" type="audio" />
372
- # </body>
373
- #</opml>
374
-
375
- print $se "INFO: Getting playlist for type '$type' using modes '$modes', bitrate '$bitrate', search='$search' and list '$list'\n";
376
-
377
- # Header
378
- push @playlist, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<opml version=\"1.1\">";
379
-
380
- # Programmes
381
- if (! $list) {
382
-
383
- # Header
384
- push @playlist, "\t<head>\n\t\t\n\t</head>";
385
- push @playlist, "\t<body>";
386
-
387
- # Extract and rewrite into playlist format
388
- my @out = get_cmd_output(
389
- $opt_cmdline->{getiplayer},
390
- '--encoding-locale=UTF-8',
391
- '--encoding-console-out=UTF-8',
392
- '--nocopyright',
393
- '--expiry=999999999',
394
- '--webrequest',
395
- get_iplayer_webrequest_args( 'nopurge=1', "type=$type", 'listformat=<pid>|<name>|<episode>|<desc>', "search=$search" ),
396
- );
397
- for ( grep !/^(Added:|Matches|$)/, @out ) {
398
- chomp();
399
- # Strip unprinatble chars
400
- s/(.)/(ord($1) > 127) ? "" : $1/egs;
401
- my ($pid, $name, $episode, $desc) = (split /\|/)[0,1,2,3];
402
- next if ! ( $pid && $name );
403
- push @playlist, "\t\t<outline URL=\"".encode_entities( build_url_stream( $request_host, $type, $pid, $modes, $outtype ) )."\" bitrate=\"${bitrate}\" source=\"get_iplayer\" title=\"".encode_entities("$name - $episode - $desc")."\" text=\"".encode_entities("$name - $episode - $desc")."\" type=\"audio\" />";
404
- }
405
-
406
- # Top-level Menu
407
- } elsif ( lc($list) eq 'menu' ) {
408
- my %menu = (
409
- 'BBC iPlayer Radio Listen Again'=> "${request_host}?ACTION=opml&PROGTYPES=radio&LIST=channel",
410
- );
411
-
412
- # Header
413
- push @playlist, "\t<head title=\"GetIplayer\">\n\t\t\n\t</head>";
414
- push @playlist, "\t<body>";
415
- for my $item ( sort keys %menu ) {
416
- my $item_url = $menu{ $item };
417
- #http://localhost:1935/opml?PROGTYPES=<type>SEARCH=bbc+radio+1&MODES=${modes}&OUTTYPE=a.wav
418
- push @playlist, "\t\t<outline URL=\"".encode_entities( $item_url )."\" text=\"".encode_entities( "$item" )."\" />";
419
- }
420
-
421
- # Channels/Names etc
422
- } elsif ($list) {
423
-
424
- # Header
425
- push @playlist, "\t<head>\n\t\t\n\t</head>";
426
- push @playlist, "\t<body>";
427
-
428
- # Extract and rewrite into playlist format
429
- my @out = get_cmd_output(
430
- $opt_cmdline->{getiplayer},
431
- '--encoding-locale=UTF-8',
432
- '--encoding-console-out=UTF-8',
433
- '--nocopyright',
434
- '--expiry=999999999',
435
- '--webrequest',
436
- get_iplayer_webrequest_args( 'nopurge=1', "type=$type", "list=$list", "channel=$search" ),
437
- );
438
- for ( grep !/^(Added:|Matches|$)/, @out ) {
439
- my $suffix;
440
- chomp();
441
- # Strip unprinatble chars
442
- s/(.)/(ord($1) > 127) ? "" : $1/egs;
443
- next if ! m{^.+\(\d+\)$};
444
- my $item = $_;
445
- s/\s*\(\d+\)$//g;
446
- my $itemregex = '^'.$_.'$';
447
- # URL encode it
448
- $itemregex =~ s/([^A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg;
449
- # Stateful addition of search terms
450
- $suffix = '&LIST=name' if $list eq 'channel';
451
- # Format required, e.g.
452
- #http://localhost:1935/opml?PROGTYPES=<type>SEARCH=bbc+radio+1&MODES=${modes}&OUTTYPE=a.wav
453
- push @playlist, "\t\t<outline URL=\"".encode_entities("${request_host}?ACTION=opml&PROGTYPES=${type}&SEARCH=${itemregex}${suffix}&MODES=${modes}&OUTTYPE=a.wav")."\" text=\"".encode_entities("$item")."\" title=\"".encode_entities("$item")."\" type=\"playlist\" />";
454
- }
455
-
456
- }
457
-
458
- # Footer
459
- push @playlist, "\t</body>\n</opml>";
460
-
461
- return join ("\n", @playlist);
462
-}
463
-
464
-
465
-
466
### Playlist URL builders
467
sub build_url_direct {
468
- my ( $request_host, $progtypes, $pid, $modes, $outtype, $streamtype, $history, $bitrate, $vsize, $vfr, $versionlist ) = ( @_ );
469
+ my ( $request_host, $progtypes, $pid, $modes, $outtype, $streamtype, $history, $bitrate, $vsize, $vfr, $versionlist, $action ) = ( @_ );
470
# Sanity check
471
#print $se "DEBUG: building direct playback request using: PROGTYPES=${progtypes} PID=${pid} MODES=${modes} OUTTYPE=${outtype}\n";
472
# CGI::escape
473
$_ = CGI::escape($_) for ( $progtypes, $pid, $modes, $outtype, $streamtype, $history, $bitrate, $vsize );
474
#print $se "DEBUG: building direct playback request using: PROGTYPES=${progtypes} PID=${pid} MODES=${modes} OUTTYPE=${outtype} BITRATE=${bitrate} VSIZE=${vsize} VFR=${vfr}\n";
475
# Build URL
476
- return "${request_host}?ACTION=direct&PROGTYPES=${progtypes}&PID=${pid}&MODES=${modes}&HISTORY=${history}&OUTTYPE=${outtype}&STREAMTYPE=${streamtype}&BITRATE=${bitrate}&VSIZE=${vsize}&VFR=${vfr}&VERSIONLIST=${versionlist}";
477
-}
478
-
479
-
480
-# "${request_host}?ACTION=stream&PROGTYPES=${type}&PID=${pid}&MODES=${modes}&OUTTYPE=${suffix}";
481
-sub build_url_stream {
482
- my ( $request_host, $progtypes, $pid, $modes, $outtype, $streamtype, $bitrate, $vsize, $vfr, $versionlist ) = ( @_ );
483
- # Sanity check
484
- #print $se "DEBUG: building stream playback request using: PROGTYPES=${progtypes} PID=${pid} MODES=${modes} OUTTYPE=${outtype}\n";
485
- # CGI::escape
486
- $_ = CGI::escape($_) for ( $progtypes, $pid, $modes, $outtype, $streamtype, $bitrate, $vsize, $vfr );
487
- #print $se "DEBUG: building stream playback request using: PROGTYPES=${progtypes} PID=${pid} MODES=${modes} OUTTYPE=${outtype}\n";
488
- # Build URL
489
- return "${request_host}?ACTION=stream&PROGTYPES=${progtypes}&PID=${pid}&MODES=${modes}&OUTTYPE=${outtype}&STREAMTYPE=${streamtype}&BITRATE=${bitrate}&VSIZE=${vsize}&VFR=${vfr}&VERSIONLIST=${versionlist}";
490
+ $action ||= 'direct';
491
+ return "${request_host}?ACTION=$action&PROGTYPES=${progtypes}&PID=${pid}&MODES=${modes}&HISTORY=${history}&OUTTYPE=${outtype}&STREAMTYPE=${streamtype}&BITRATE=${bitrate}&VSIZE=${vsize}&VFR=${vfr}&VERSIONLIST=${versionlist}";
492
}
493
494
495
496
}
497
# Show thumb if one exists
498
$prog{$pid}->{thumbnail} ||= DEFAULT_THUMBNAIL;
499
- print $fh img( { -class=>'action', -src=>$prog{$pid}->{thumbnail} } ) if $prog{$pid}->{thumbnail};
500
+ print $fh img( { -height=>216, -class=>'action', -src=>$prog{$pid}->{thumbnail} } ) if $prog{$pid}->{thumbnail};
501
# Set optional output dir for pvr queue if set
502
my $outdir;
503
$outdir = '&OUTPUT='.CGI::escape("$opt->{OUTPUT}->{current}") if $opt->{OUTPUT}->{current};
504
505
# If the PID is a filename then filename is still searched using PID and TYPE
506
sub get_direct_filename {
507
my ( $pid, $mode, $type ) = ( @_ );
508
- my $out;
509
- my @html;
510
- my %prog;
511
- my $pidisfile;
512
my $history = 1;
513
514
print $se "DEBUG: Looking up filename for MODE=$mode TYPE=$type PID=$pid\n";
515
516
- # set this flag if required and unset history if pid is a file
517
- if ( -f $pid ) {
518
- print $se "DEBUG: PID is a valid filename\n";
519
- $pidisfile = 1;
520
- $history = 0;
521
- }
522
-
523
- # Skip if not defined or, if pid is a file and no type defined
524
- if ( $pidisfile && ! $type ) {
525
- print $se "ERROR: Cannot lookup filename for PID which is a filename if type is not set\n";
526
- return '';
527
- }
528
- if ( ( ! $pidisfile ) && ! ( $pid && $mode && $type ) ) {
529
+ if ( ! ( $pid && $mode && $type ) ) {
530
print $se "ERROR: Cannot lookup filename unless PID, MODE and TYPE are set\n";
531
return '';
532
}
533
534
- # make the pid regex friendly
535
- $pid =~ s|([\/\.\?\+\-\*\^\(\)\[\]\{\}])|\\$1|g;
536
-
537
# Get the 'filename' entry from --history --info for this pid
538
my @cmd = (
539
$opt_cmdline->{getiplayer},
540
541
# Extract the filename
542
my $match = ( grep /^filename:/, @cmdout )[0];
543
my $filename;
544
- if ( $pidisfile ) {
545
- $filename = $1 if $match =~ m{^filename: (\/.+?)\|<filename>\|<mode>\s*$};
546
- } else {
547
- $filename = $1 if $match =~ m{^filename: .+?\|\s*(.+?)\|$mode\s*$};
548
- }
549
+ $filename = $1 if $match =~ m{^filename: .+?\|\s*(.+?)\|$mode\s*$};
550
if ( $filename && $opt_cmdline->{encodinglocalefs} !~ /UTF-?8/i ) {
551
$filename = encode($opt_cmdline->{encodinglocalefs}, $filename, sub { '' });
552
}
553
554
}
555
556
# Format of PROGSELECT: TYPE|PID|NAME|EPISODE|MODE|CHANNEL
557
- push @row, td( {-class=>$search_class},
558
- checkbox(
559
- -class => $search_class,
560
- -name => 'PROGSELECT',
561
- -label => '',
562
- -value => "$prog{$pid}->{type}|$pid|$prog{$pid}->{name}|$prog{$pid}->{episode}|$prog{$pid}->{mode}|$prog{$pid}->{channel}",
563
- -checked => 0,
564
- -override => 1,
565
- )
566
- );
567
- # Record and stream links
568
+ if ( $opt->{HISTORY}->{current} && ! -f $prog{$pid}->{filename} ) {
569
+ push @row, td( {-class=>$search_class} );
570
+ } else {
571
+ push @row, td( {-class=>$search_class},
572
+ checkbox(
573
+ -class => $search_class,
574
+ -name => 'PROGSELECT',
575
+ -label => '',
576
+ -value => "$prog{$pid}->{type}|$pid|$prog{$pid}->{name}|$prog{$pid}->{episode}|$prog{$pid}->{mode}|$prog{$pid}->{channel}",
577
+ -checked => 0,
578
+ -override => 1,
579
+ )
580
+ );
581
+ }
582
+ # Record links
583
584
my $links;
585
- # 'Play'
586
- # Search mode with filename as pid
587
- if ( $pid =~ m{^/} ) {
588
- if ( -f $pid ) {
589
- # Play
590
- $links .= a( { -class=>$search_class, -title=>"Play from file on web server", -href=>build_url_playlist( '', 'playlist', 'pid', $pid, $opt->{MODES}->{current} || $default_modes, $prog{$pid}->{type}, basename( $pid ) , $opt->{STREAMTYPE}->{current}, $opt->{BITRATE}->{current}, $opt->{VSIZE}->{current}, $opt->{VFR}->{current}, $opt->{VERSIONLIST}->{current} ) }, 'Play' ).'<br />';
591
- # PlayFile
592
- $links .= a( { -id=>'nowrap', -class=>$search_class, -title=>"Play from local file", -href=>build_url_playlist( '', 'playlistfiles', 'pid', $pid, $prog{$pid}->{mode}, $prog{$pid}->{type}, undef, undef ) }, 'Play File' ).'<br />';
593
- # PlayDirect
594
- $links .= a( { -id=>'nowrap', -class=>$search_class, -title=>"Stream file into browser", -href=>build_url_direct( '', $prog{$pid}->{type}, $pid, $prog{$pid}->{mode}, $opt->{STREAMTYPE}->{current}, $opt->{STREAMTYPE}->{current}, $opt->{HISTORY}->{current}, $opt->{BITRATE}->{current}, $opt->{VSIZE}->{current}, $opt->{VFR}->{current}, $opt->{VERSIONLIST}->{current} ) }, 'Play Direct' ).'<br />';
595
- }
596
# History mode
597
- } elsif ( $opt->{HISTORY}->{current} ) {
598
- if ( $opt->{HIDEDELETED}->{current} || -f $prog{$pid}->{filename} ) {
599
+ if ( $opt->{HISTORY}->{current} ) {
600
+ if ( -f $prog{$pid}->{filename} ) {
601
# Play (Play Remote)
602
- $links .= a( { -id=>'nowrap', -class=>$search_class, -title=>"Play from file on web server", -href=>build_url_playlist( '', 'playlistdirect', 'pid', $pid, $prog{$pid}->{mode}, $prog{$pid}->{type}, 'flv', 'flv', $opt->{BITRATE}->{current}, $opt->{VSIZE}->{current}, $opt->{VFR}->{current}, $opt->{VERSIONLIST}->{current} ) }, 'Play' ).'<br />';
603
+ $links .= a( { -id=>'nowrap', -target=>'_blank', -class=>$search_class, -title=>"Stream from file on web server", -href=>build_url_playlist( '', 'playlistdirect', 'pid', $pid, $prog{$pid}->{mode}, $prog{$pid}->{type}, $opt->{STREAMTYPE}->{current}, $opt->{STREAMTYPE}->{current}, $opt->{BITRATE}->{current}, $opt->{VSIZE}->{current}, $opt->{VFR}->{current}, $opt->{VERSIONLIST}->{current} ) }, 'Play' ).'<br />';
604
# PlayFile
605
- $links .= a( { -id=>'nowrap', -class=>$search_class, -title=>"Play from local file", -href=>build_url_playlist( '', 'playlistfiles', 'pid', $pid, $prog{$pid}->{mode}, $prog{$pid}->{type}, undef ) }, 'Play File' ).'<br />';
606
+ $links .= a( { -id=>'nowrap', -target=>'_blank', -class=>$search_class, -title=>"Play from local file", -href=>build_url_playlist( '', 'playlistfiles', 'pid', $pid, $prog{$pid}->{mode}, $prog{$pid}->{type}, undef ) }, 'Play File' ).'<br />';
607
# PlayDirect - depends on browser support
608
- $links .= a( { -id=>'nowrap', -class=>$search_class, -title=>"Stream file into browser", -href=>build_url_direct( '', $prog{$pid}->{type}, $pid, $prog{$pid}->{mode}, $opt->{STREAMTYPE}->{current}, $opt->{STREAMTYPE}->{current}, $opt->{HISTORY}->{current}, $opt->{BITRATE}->{current}, $opt->{VSIZE}->{current}, $opt->{VFR}->{current}, $opt->{VERSIONLIST}->{current} ) }, 'Play Direct' ).'<br />';
609
+ if ( $prog{$pid}->{filename} =~ m{\.(m4a|mp4|mp3)$} ) {
610
+ $links .= a( { -id=>'nowrap', -target=>'_blank', -class=>$search_class, -title=>"Stream file into browser", -href=>build_url_direct( '', $prog{$pid}->{type}, $pid, $prog{$pid}->{mode}, $opt->{STREAMTYPE}->{current}, $opt->{STREAMTYPE}->{current}, $opt->{HISTORY}->{current}, $opt->{BITRATE}->{current}, $opt->{VSIZE}->{current}, $opt->{VFR}->{current}, $opt->{VERSIONLIST}->{current}, 'playdirect' ) }, 'Play Direct' ).'<br />';
611
+ }
612
}
613
# Search mode
614
} else {
615
616
if ( $prog{$pid}->{$_} !~ m{^https?://} ) {
617
$prog{$pid}->{$_} = DEFAULT_THUMBNAIL;
618
}
619
- push @row, td( {-class=>$search_class}, a( { -title=>"Open original web URL", -class=>$search_class, -href=>$prog{$pid}->{web}, -target => "_new" }, img( { -class=>$search_class, -height=>40, -src=>$prog{$pid}->{$_} } ) ) );
620
+ push @row, td( {-class=>$search_class}, a( { -title=>"Open original web URL", -class=>$search_class, -href=>$prog{$pid}->{web}, -target => "_blank" }, img( { -class=>$search_class, -height=>40, -src=>$prog{$pid}->{$_} } ) ) );
621
} elsif ( /^web$/ ) {
622
- push @row, td( {-class=>$search_class}, a( { -title=>"Open original web URL", -class=>$search_class, -href=>$prog{$pid}->{$_}, -target => "_new" }, 'Open URL' ) );
623
+ push @row, td( {-class=>$search_class}, a( { -title=>"Open original web URL", -class=>$search_class, -href=>$prog{$pid}->{$_}, -target => "_blank" }, 'Open URL' ) );
624
# Calculate the seconds difference between epoch_now and epoch_datestring and convert back into array_time
625
} elsif ( /^timeadded$/ ) {
626
my @t = gmtime( $time - $prog{$pid}->{$_} );
627
628
my ( $page, $pagesize, $count, $trailsize ) = ( @_ );
629
630
# How many pages
631
- my $pages = int( $count / $pagesize ) + 1;
632
+ my $pages = int( $count / $pagesize );
633
+ $pages++ if $count % $pagesize;
634
# If we request a page that is too high
635
$page = $pages if $page > $pages;
636
# Calc first and last programme numbers
637
638
li( { -class=>$class->{recordings} }, a( { -class=>'nav', -title=>'History search page', -onClick => "BackupFormVars(formheader); formheader.NEXTPAGE.value='search_history'; formheader.submit(); RestoreFormVars(formheader);" }, 'Recordings' ) ).
639
li( { -class=>$class->{pvrlist} }, a( { -class=>'nav', -title=>'List all saved PVR searches', -onClick => "BackupFormVars(formheader); formheader.NEXTPAGE.value='pvr_list'; formheader.submit(); RestoreFormVars(formheader);" }, 'PVR List' ) ).
640
li( { -class=>$class->{pvrrun} }, a( { -class=>'nav', -title=>'Run the PVR now - wait for the PVR to complete', -onClick => "BackupFormVars(formheader); formheader.NEXTPAGE.value='pvr_run'; formheader.target='_newtab_pvrrun'; formheader.submit(); RestoreFormVars(formheader); formheader.target='';" }, 'Run PVR' ) ).
641
- li( { -class=>'nav_tab' }, a( { -class=>'nav', -title=>'Show help and instructions', -href => "https://github.com/get-iplayer/get_iplayer/wiki/webpvr", -target => "_new" }, 'Help' ) )
642
+ li( { -class=>'nav_tab' }, a( { -class=>'nav', -title=>'Show help and instructions', -href => "https://github.com/get-iplayer/get_iplayer/wiki/webpvr", -target => "_newtab_help" }, 'Help' ) )
643
),
644
);
645
print $fh hidden( -name => 'AUTOPVRRUN', -value => $opt->{AUTOPVRRUN}->{current}, -override => 1 );
646
647
save => 1,
648
};
649
650
- my %vsize_labels = ( ''=>'Native', '1280x720'=>'1280x720', '832x468'=>'832x468', '640x360'=>'640x360', '512x288'=>'512x288', '480x272'=>'480x272', '320x176'=>'320x176', '176x96'=>'176x96' );
651
+ my %vsize_labels = ( ''=>'Native', '1280x720'=>'1280x720', '960x540'=>'960x540', '832x468'=>'832x468', '704x396'=>'704x396', '640x360'=>'640x360', '512x288'=>'512x288', '448x252'=>'448x252', '384x216'=>'384x216', '256x144'=>'256x144', '192x108'=>'192x108' );
652
$opt->{VSIZE} = {
653
title => 'Remote Streaming Video Size', # Title
654
- tooltip => "Video size '<width>x<height>' to transcode remotely played files - leave blank for native size", # Tooltip
655
+ tooltip => "Video size '<width>x<height>' to transcode remotely played files - specify 'Native' for native size", # Tooltip
656
webvar => 'VSIZE', # webvar
657
type => 'popup', # type
658
label => , \%vsize_labels, # labels
659
660
default => '',
661
save => 1,
662
};
663
-
664
- my %streamtype_labels = ( ''=>'Auto', 'none'=>'Disable Transcoding', 'flv'=>'Flash Video (flv)', 'mov'=>'Quicktime (mov)', 'asf'=>'Advanced Streaming Format (asf)', 'avi'=>'AVI', 'mp3'=>'MP3 (Audio Only)', 'aac'=>'AAC (Audio Only)', 'wav'=>'WAV (Audio Only)', 'flac'=>'FLAC (Audio Only)' );
665
+ my %streamtype_labels = ( ''=>'Auto', 'none'=>'Disable Transcoding', 'flv'=>'Flash Video (H.264/MP3)', 'mpegts'=>'MPEG Transport Stream (H.264/MP2)', 'matroska'=>'Matroska (H.264/Vorbis)', 'asf'=>'Advanced Systems Format (H.264/WMA)', 'mp3'=>'MP3 (Audio Only)', 'adts'=>'AAC (Audio Only)', 'oga'=>'Vorbis (Audio Only)', 'wav'=>'WAV (Audio Only)', 'flac'=>'FLAC (Audio Only)' );
666
$opt->{STREAMTYPE} = {
667
title => "Remote Streaming type", # Title
668
- tooltip => "Force the output to be this type when using 'Play Remote' for 'PlayDirect' streaming(e.g. flv, mov). Specify 'none' to disable transcoding/remuxing. Leave blank for auto-detection", # Tooltip
669
+ tooltip => "Force the output to be this type when using 'Play' streaming. Specify 'Native' to disable transcoding/remuxing.", # Tooltip
670
webvar => 'STREAMTYPE', # webvar
671
type => 'popup', # type
672
label => , \%streamtype_labels, # labels
673
default => '', # default
674
- value => [ '', 'none', 'flv', 'mov', 'asf', 'avi', 'mp3', 'aac', 'wav', 'flac' ], # values
675
+ value => [ '', 'none', 'flv', 'mpegts', 'matroska', 'asf', 'mp3', 'adts', 'oga', 'wav', 'flac' ], # values
676
onChange=> "form1.submit();",
677
save => 1,
678
};
679
680
padding: 4px 8px;
681
}
682
683
+ table.info > tbody > tr > td {
684
+ word-break: break-all
685
+ }
686
+
687
table.searchhead {
688
width: 100%;
689
}
690
Refresh
No build results available
Refresh
No rpmlint results available
Login required, please
login
or
signup
in order to comment