Overview

Request 5512 (accepted)

get_iplayer v3.28

Submit package home:develop7:branches:Extra / get_iplayer to package Extra / get_iplayer

get_iplayer.changes Changed
x
 
1
@@ -1,4 +1,47 @@
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
@@ -6,7 +6,7 @@
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
@@ -0,0 +1,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
@@ -0,0 +1,35 @@
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
@@ -0,0 +1,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
@@ -0,0 +1,29 @@
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,14 +2,13 @@
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
@@ -18,13 +17,6 @@
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
@@ -18,8 +18,8 @@
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
@@ -1,6 +1,6 @@
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
@@ -24,7 +24,7 @@
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
@@ -85,11 +85,11 @@
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
@@ -1867,7 +1867,7 @@
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
@@ -1887,25 +1887,22 @@
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
@@ -1914,7 +1911,7 @@
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
@@ -2570,8 +2567,8 @@
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
@@ -2583,7 +2580,7 @@
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
@@ -3160,10 +3157,12 @@
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
@@ -3575,8 +3574,15 @@
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
@@ -4046,7 +4052,22 @@
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
@@ -4091,12 +4112,19 @@
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
@@ -5592,7 +5620,7 @@
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
@@ -5638,11 +5666,12 @@
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
@@ -5691,7 +5720,10 @@
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
@@ -5746,7 +5778,7 @@
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
@@ -5837,7 +5869,7 @@
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
@@ -5949,7 +5981,7 @@
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
@@ -6075,7 +6107,7 @@
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
@@ -6344,6 +6376,7 @@
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
@@ -6352,7 +6385,7 @@
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
@@ -6567,6 +6600,25 @@
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
@@ -6780,7 +6832,7 @@
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
@@ -7200,13 +7252,26 @@
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
@@ -7215,12 +7280,20 @@
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
@@ -8222,8 +8295,8 @@
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
@@ -8681,6 +8754,22 @@
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
@@ -9326,7 +9415,6 @@
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
@@ -1,6 +1,6 @@
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
@@ -12,7 +12,7 @@
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
@@ -174,7 +174,7 @@
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
@@ -189,7 +189,7 @@
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
@@ -583,7 +583,7 @@
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
@@ -24,7 +24,7 @@
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
@@ -347,7 +347,7 @@
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
@@ -480,57 +480,52 @@
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
@@ -555,34 +550,25 @@
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
@@ -593,7 +579,7 @@
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
@@ -802,72 +788,41 @@
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
@@ -880,14 +835,8 @@
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
@@ -899,12 +848,9 @@
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
@@ -923,27 +869,15 @@
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
@@ -961,11 +895,6 @@
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
@@ -979,35 +908,15 @@
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
@@ -1018,137 +927,17 @@
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
@@ -1967,7 +1756,7 @@
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
@@ -1996,34 +1785,15 @@
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
@@ -2041,11 +1811,7 @@
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
@@ -2686,39 +2452,34 @@
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
@@ -2746,9 +2507,9 @@
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
@@ -3044,7 +2805,8 @@
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
@@ -3254,7 +3016,7 @@
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
@@ -3613,10 +3375,10 @@
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
@@ -3644,16 +3406,15 @@
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
@@ -4164,6 +3925,10 @@
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

Request History
Andrei Dziahel's avatar

develop7 created request about 3 years ago

get_iplayer v3.28


Olaf Hering's avatar

olh accepted request about 3 years ago