Overview

Request 5513 (accepted)

get_iplayer 3.29

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

get_iplayer.changes Changed
x
 
1
@@ -1,4 +1,12 @@
2
 -------------------------------------------------------------------
3
+Tue Feb  8 10:40:09 UTC 2022 - Andrei Dziahel <develop7@develop7.info>
4
+
5
+- get_iplayer 3.29
6
+  
7
+  See https://github.com/get-iplayer/get_iplayer/wiki/release320to329#release329
8
+  for upstream release notes
9
+
10
+-------------------------------------------------------------------
11
 Mon Feb  7 18:56:44 UTC 2022 - Andrei Dziahel <develop7@develop7.info>
12
 
13
 - get_iplayer v3.28
14
get_iplayer.spec Changed
10
 
1
@@ -6,7 +6,7 @@
2
 #
3
 
4
 Name:           get_iplayer
5
-Version:        3.28
6
+Version:        3.29
7
 Release:        0
8
 Summary:        Downloads H.264 BBC IPlayer TV, Radio, and Podcast Programs
9
 License:        GPL-3.0-only
10
get_iplayer-3.28.tar.gz/.github/ISSUE_TEMPLATE/bug_report.md Deleted
37
 
1
@@ -1,35 +0,0 @@
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.29.tar.gz/.github/ISSUE_TEMPLATE/bug_report.yaml Added
88
 
1
@@ -0,0 +1,86 @@
2
+name: Bug Report
3
+description: File a bug report
4
+body:
5
+- type: markdown
6
+  attributes:
7
+    value: |
8
+      ## Read First
9
+      * Do not request help with using get_iplayer. User support will not be provided.
10
+      * Do not request new features for get_iplayer. Feature requests will not be accepted.
11
+      * All bug reports will automatically be closed and locked upon receipt.
12
+      * If your report identifies a reproducible bug in get_iplayer, it will be re-opened until a fix is released.
13
+      * You will receive no communication from the developers, so provide all the information required.  
14
+- type: checkboxes
15
+  attributes:
16
+    label: Do not file a bug report if you are using get_iplayer outside the UK. If you do, your report will be ignored.
17
+    options:
18
+    - label: I am not using get_iplayer outside the UK
19
+      required: true
20
+- type: checkboxes
21
+  attributes:
22
+    label: Do not file a bug report if you are using get_iplayer with a VPN or proxy from any location, including the UK. If you do, your report will be ignored.
23
+    options:
24
+    - label: I am not using get_iplayer with a VPN or proxy from any location, including the UK
25
+      required: true
26
+- type: checkboxes
27
+  attributes:
28
+    label: Search the repository (search field at top left) to see if a report already exists for the bug in the issue tracker. Do not create a duplicate report. Duplicate reports will be ignored.
29
+    description: See - **[Issue Tracker](https://github.com/get-iplayer/get_iplayer/issues)**
30
+    options:
31
+    - label: I have searched the repository and found no existing reports of the bug in the issue tracker
32
+      required: true
33
+- type: checkboxes
34
+  attributes:
35
+    label: Review recent open and closed entries in the issue tracker to see if a report already exists for the bug. Do not create a duplicate report. Duplicate reports will be ignored.
36
+    description: See - [Open Issues](https://github.com/get-iplayer/get_iplayer/issues?q=is%3Aopen+is%3Aissue), [Closed Issues](https://github.com/get-iplayer/get_iplayer/issues?q=is%3Aclosed+is%3Aissue)
37
+    options:
38
+    - label: I have reviewed recent open and closed entries in the issue tracker and found no existing reports of the bug
39
+      required: true
40
+- type: checkboxes
41
+  attributes:
42
+    label: Ensure that you are using get_iplayer 3.29 or higher. If not, your report will be ignored.
43
+    description: Check version with **`get_iplayer -V` or see the bottom of the Web PVR search page**
44
+    options:
45
+    - label: I am using get_iplayer 3.29 or higher
46
+      required: true
47
+- type: input
48
+  attributes:
49
+    label: Identify the operating system and version where get_iplayer demonstrates the bug
50
+    description: Examples - Ubuntu 20.04, Fedora 34, Arch, OpenBSD 6.8, macOS 10.14, macOS Monterey (M1), Windows 10
51
+  validations:
52
+    required: true
53
+- type: textarea
54
+  attributes:
55
+    label: Provide a clear and concise description of the bug. Do not paste get_iplayer output or screenshots into the field below. If you do, your report will be ignored.
56
+  validations:
57
+    required: true
58
+- type: input
59
+  attributes:
60
+    label: Provide the PID or URL of the programme you are attempting to download, if applicable. Provide the PID or URL for only one programme.    
61
+  validations:
62
+    required: false
63
+- type: textarea
64
+  attributes:
65
+    label: Provide the complete get_iplayer command line that demonstrates the bug. Do not truncate or excerpt the command. If you do, your report will be ignored. If you are using the Web PVR, list the steps necessary to reproduce the bug, in as much detail as possible.
66
+  validations:
67
+    required: true
68
+- type: markdown
69
+  attributes:
70
+    value: |
71
+      ## Create a verbose log file for the bug, e.g., "log.txt" using the `--verbose` option:
72
+      ```bash
73
+      get_iplayer [your options here] --verbose > log.txt 2>&1
74
+      ```
75
+      ### Do not truncate or excerpt the log file. If you do, your report will be ignored. If you are using the Web PVR, copy output from both your web browser and the Web PVR console window and paste it into a plain text file. Do not omit the console window output showing the get_iplayer command(s) invoked by the Web PVR. If you do, your report will be ignored. To minimise the amount of output in the console window, quit and restart the Web PVR, then immediately execute the command that demonstrates the bug.
76
+      ### Do not submit screenshots instead of a log file. If you do, your report will be ignored.
77
+- type: textarea
78
+  attributes:
79
+    label: Drag the log file into the field below to create an attachment. The log file must be added as an attachment. Do not paste its contents into the field below. If you do, your report will be ignored. You may enter a URL linking to your log file on a pastebin site. If the bug prevents get_iplayer from running, enter "N/A" in the field below. If you enter any other text in the field below, your report will be ignored.
80
+  validations:
81
+    required: true
82
+- type: input
83
+  attributes:
84
+    label: If you are using the Web PVR, provide your web browser name and version. This information typically can be found from the application menu via Chrome/Firefox/Safari->About... (macOS) or Help->About... (Linux/Windows)
85
+    description: Examples - Chrome 83.0.4103, Edge 83.0.478.56, Firefox 78.0.1, Safari 13.1.1
86
+  validations:
87
+    required: false
88
get_iplayer-3.29.tar.gz/.github/PULL_REQUEST_TEMPLATE.md Added
13
 
1
@@ -0,0 +1,11 @@
2
+### Read first
3
+
4
+- Fixes for reproducible bugs are welcome.
5
+- Do not submit new features. New features will not be merged.
6
+- Do not submit enhancements. Enhancements will not be merged.
7
+- Do not submit changes to existing behaviour. Changes to existing behaviour will not be merged.
8
+- All pull requests will automatically be closed and locked upon receipt.
9
+- If your pull request fixes a reproducible bug, it will be re-opened until it is merged.
10
+- You will receive no communication from the developers, so ensure your pull request is complete.
11
+
12
+#### Delete this line and all text above before submitting your pull request.
13
get_iplayer-3.29.tar.gz/.github/workflows/auto-close-lock-pr-action.yml Added
31
 
1
@@ -0,0 +1,29 @@
2
+on:
3
+  pull_request:
4
+    types:
5
+      - opened
6
+jobs:
7
+  auto-close-lock-pr-action_job:
8
+    runs-on: ubuntu-latest
9
+    name: auto-close-lock-pr-action_job
10
+    steps:
11
+      - name: auto-close-lock-pr-action_close-step
12
+        id: auto-close-lock-pr-action_close-step
13
+        uses: maxkomarychev/octions/octions/issues/update@master
14
+        with:
15
+          token: ${{ secrets.GITHUB_TOKEN }}
16
+          issue_number: ${{ github.event.number }}
17
+          state: closed
18
+      - name: auto-close-lock-pr-action_lock-step
19
+        id: auto-close-lock-pr-action_lock-step
20
+        uses: maxkomarychev/octions/octions/issues/lock@master
21
+        with:
22
+          token: ${{ secrets.GITHUB_TOKEN }}
23
+          issue_number: ${{ github.event.number }}
24
+      - name: auto-close-lock-pr-action_label-step
25
+        id: auto-close-lock-pr-action_label-step
26
+        uses: maxkomarychev/octions/octions/issues/add-labels@master
27
+        with:
28
+          token: ${{ secrets.GITHUB_TOKEN }}
29
+          issue_number: ${{ github.event.number }}
30
+          labels: invalid
31
get_iplayer-3.28.tar.gz/Makefile -> get_iplayer-3.29.tar.gz/Makefile Changed
18
 
1
@@ -9,13 +9,14 @@
2
    @git checkout master
3
    @sed -i.bak -e 's/^\(my $$version = \).*/\1$(VERSION);/' get_iplayer
4
    @sed -i.bak -e 's/^\(my $$VERSION = \).*/\1$(VERSION);/' get_iplayer.cgi
5
-   @rm -f get_iplayer.bak get_iplayer.cgi.bak
6
+   @sed -i.bak -e 's/\(get_iplayer \)[0-9.]\{1,\}\( or higher\)/\1$(VERSION)\2/g' .github/ISSUE_TEMPLATE/bug_report.yaml
7
+   @rm -f get_iplayer.bak get_iplayer.cgi.bak .github/ISSUE_TEMPLATE/bug_report.yaml.bak
8
    @./get_iplayer --nocopyright --manpage get_iplayer.1
9
    @git diff --exit-code get_iplayer.1 > /dev/null || \
10
        sed -i.bak -e 's/\(\.TH GET_IPLAYER "1" "\)[^"]*"/\1$(shell date +"%B %Y")\"/' get_iplayer get_iplayer.1
11
    @rm -f get_iplayer.bak get_iplayer.1.bak
12
    @git log --format='%aN' | sort -u > CONTRIBUTORS; git add CONTRIBUTORS
13
-   @git commit -m "Release $(VERSION)" get_iplayer get_iplayer.cgi get_iplayer.1 CONTRIBUTORS
14
+   @git commit -m "Release $(VERSION)" get_iplayer get_iplayer.cgi get_iplayer.1 CONTRIBUTORS .github/ISSUE_TEMPLATE/bug_report.yaml
15
    @git tag v$(VERSION)
16
 
17
 tarball:
18
get_iplayer-3.28.tar.gz/README.md -> get_iplayer-3.29.tar.gz/README.md Changed
59
 
1
@@ -4,7 +4,7 @@
2
 
3
 * Downloads TV and radio programmes from BBC iPlayer/BBC Sounds
4
 * Allows multiple programmes to be downloaded using a single command
5
-* Indexing of most available iPlayer/Sounds catch-up programmes from previous 30 days (not BBC Three, Red Button, iPlayer Exclusive, or Podcast-only)
6
+* Indexing of most available iPlayer/Sounds catch-up programmes from previous 30 days (not Red Button, iPlayer Exclusive, or Podcast-only)
7
 * Caching of programme index with automatic updating
8
 * Regex search on programme name
9
 * Regex search on programme description and episode title
10
@@ -81,17 +81,17 @@
11
 
12
    *(The `$` regular expression metacharacter matches "Radio 4" only at the end of the channel name, thus avoiding matches against "Radio 4 Extra")*
13
 
14
-* Record TV programme number 208 (index from search results) in HD, with SD fallback if HD not available:
15
+* Record TV programme number 208 (index from search results) in HD, with fallback to lower quality if not available:
16
 
17
-   `get_iplayer --get 208` [default is to download best available (max 1280x720)]
18
+   `get_iplayer --get 208` [default setting]
19
 
20
-   OR
21
-
22
-   `get_iplayer --get 208 --tvmode=best`
23
+   or
24
+   
25
+   `get_iplayer --get 208 --tv-quality=hd,sd,web,mobile` [explicit setting]
26
 
27
-* Record TV programme number 208 with lower resolution (max 704x396):
28
+* Record TV programme number 208 in lower resolution only (704x396@50):
29
 
30
-   `get_iplayer --get 208 --tvmode=good`
31
+   `get_iplayer --get 208 --tv-quality=web`
32
 
33
 * Record TV programme number 208 and download subtitles in SubRip (SRT) format:
34
 
35
@@ -112,17 +112,18 @@
36
 * Record a radio programme using its Sounds URL:
37
 
38
     `get_iplayer https://www.bbc.co.uk/sounds/play/b07gcv34`
39
-* Record a radio programme using the PID (b07gcv34) from its Sounds URL in highest quality (320k), with fallback to lower quality if not available:
40
 
41
-   `get_iplayer --pid=b07gcv34` [default is to download best available]
42
+* Record a radio programme using the PID (b07gcv34) from its Sounds URL in high quality (320k), with fallback to lower quality if not available (default setting):
43
+
44
+   `get_iplayer --pid=b07gcv34` [default setting]
45
 
46
    OR
47
 
48
-   `get_iplayer --pid=b07gcv34 --radiomode=best`
49
+   `get_iplayer --pid=b07gcv34 --radio-quality=high,std,med,low` [explicit setting]
50
 
51
-* Record a radio programme using the PID (b07gcv34) from its Sounds URL with lower bit rate (96k):
52
+* Record a radio programme using the PID (b07gcv34) from its Sounds URL with lower bit rate only (96k):
53
 
54
-   `get_iplayer --pid=b07gcv34 --radiomode=good`
55
+   `get_iplayer --pid=b07gcv34 --radio-quality=med`
56
 
57
 * Record multiple radio programmes (using PIDs from Sounds URLs):
58
 
59
get_iplayer-3.28.tar.gz/get_iplayer -> get_iplayer-3.29.tar.gz/get_iplayer Changed
1227
 
1
@@ -24,7 +24,7 @@
2
 #
3
 #
4
 package main;
5
-my $version = 3.28;
6
+my $version = 3.29;
7
 my $version_text;
8
 $version_text = sprintf("v%.2f", $version) unless $version_text;
9
 #
10
@@ -83,17 +83,18 @@
11
 my $opt_format = {
12
    # Recording
13
    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."],
14
-   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."],
15
-   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."],
16
+   audioonly       => [ 1, "audioonly|audio-only!", 'Recording', '--audio-only', "Only download audio stream for TV programme. Produces .m4a file. Implies --force."],
17
+   downloadabortonfail => [ 1, "downloadabortonfail||download-abort-onfail|download-abort-onfail!", 'Recording', '--download-abort-onfail', "Exit immediately if any stream to download. Use to avoid repeated failed download attempts if connection is dropped or access is blocked."],
18
+   excludeformat   => [ 1, "excludeformat|exclude-format=s", 'Recording', '--exclude-format <format>,<format>,...', "Comma-separated list of media stream formats to ignore when recording. Valid values: hls,dash."],
19
    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."],
20
    force       => [ 1, "force|force-download!", 'Recording', '--force', "Ignore programme history (unsets --hide option also)."],
21
-   fps25       => [ 1, "fps25!", 'Recording', '--fps25', "Use only 25fps streams for TV programmes (HD video not available)."],
22
    get     => [ 2, "get|record|g!", 'Recording', '--get, -g', "Start recording matching programmes. Search terms required."],
23
+   includeformat   => [ 1, "includeformat|include-format=s", 'Recording', '--include-format <format>,<format>,...', "Comma-separated list of media stream to use when recording. Overrides --exclude-format. Valid values: hls,dash"],
24
    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."],
25
    hash        => [ 1, "hash!", 'Recording', '--hash', "Show recording progress as hashes"],
26
    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."],
27
    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."],
28
-   modes       => [ 0, "modes=s", 'Recording', '--modes <mode>,<mode>,...', "Recording modes.  See --tvmode and --radiomode (with --long-help) for available modes and defaults.  Shortcuts: tvbest,tvbetter,tvgood,tvworst,radiobest,radiobetter,radiogood,radioworst (default=default for programme type)."],
29
+   modes       => [ 0, "modes|quality=s", 'Recording', '--quality <quality>,<quality>,...', "TV and radio recording quality preference.  See --tv-quality and --radio-quality for available values and defaults. Default: default for programme type."],
30
    nomergeversions => [ 1, "nomergeversions|no-merge-versions!", 'Recording', '--no-merge-versions', "Do not merge programme versions with same name and duration."],
31
    noproxy => [ 1, "noproxy|no-proxy!", 'Recording', '--no-proxy', "Ignore --proxy setting in preferences and/or http_proxy environment variable."],
32
    overwrite   => [ 1, "overwrite|over-write!", 'Recording', '--overwrite', "Overwrite recordings if they already exist"],
33
@@ -170,7 +171,7 @@
34
    cacherebuild    => [ 1, "rebuildcache|rebuild-cache|cacherebuild|cache-rebuild!", 'Config', '--cache-rebuild', "Rebuild cache with full 30-day programme index. Use --refresh-limit to restrict cache window."],
35
    expiry      => [ 1, "expiry|e=n", 'Config', '--expiry, -e <secs>', "Cache expiry in seconds (default 4hrs)"],
36
    limitmatches    => [ 1, "limitmatches|limit-matches=n", 'Config', '--limit-matches <number>', "Limits the number of matching results for any search (and for every PVR search)"],
37
-   nopurge     => [ 1, "no-purge|nopurge!", 'Config', '--nopurge', "Don't show warning about programmes recorded over 30 days ago"],
38
+   nopurge     => [ 1, "no-purge|nopurge!", 'Hidden', '--nopurge', "Don't show warning about programmes recorded over 30 days ago"],
39
    prefsadd    => [ 0, "addprefs|add-prefs|prefsadd|prefs-add!", 'Config', '--prefs-add', "Add/Change specified saved user or preset options"],
40
    prefsdel    => [ 0, "del-prefs|delprefs|prefsdel|prefs-del!", 'Config', '--prefs-del', "Remove specified saved user or preset options"],
41
    prefsclear  => [ 0, "clear-prefs|clearprefs|prefsclear|prefs-clear!", 'Config', '--prefs-clear', "Remove *ALL* saved user or preset options"],
42
@@ -234,10 +235,9 @@
43
    encodinglocalefs    => [ 1, "encodinglocalefs|encoding-locale-fs=s", 'Misc', '--encoding-locale-fs <name>', "Character encoding used to encode file and directory names.  Encoding name must be known to Perl Encode module.  Default (only if auto-detect fails): Linux/Unix/OSX = UTF-8, Windows = cp1252"],
44
    indexmaxconn    => [ 1, "indexmaxconn|index-maxconn=n", 'Misc', '--index-maxconn <number>', "Maximum number of connections to use for concurrent programme indexing.  Default: 5 Min: 1 Max: 10"],
45
    noindexconcurrent   => [ 1, "noindexconcurrent|no-index-concurrent!", 'Deprecated', '--no-index-concurrent', "Do not use concurrent indexing to update programme cache.  Cache updates will be very slow."],
46
-   purgefiles  => [ 1, "purgefiles|purge-files!", 'Misc', '--purge-files', "Delete downloaded programmes more than 30 days old"],
47
    releasecheck    => [ 1, "releasecheck|release-check!", 'Misc', '--release-check', "Forces check for new release if used on command line. Checks for new release weekly if saved in preferences."],
48
    throttle    => [ 1, "bw|throttle=f", 'Misc', '--throttle <Mb/s>', "Bandwidth limit (in Mb/s) for media file download. Default: unlimited. Synonym: --bw"],
49
-   trimhistory => [ 1, "trimhistory|trim-history=s", 'Misc', '--trim-history <# days to retain>', "Remove download history entries older than number of days specified in option value.  Cannot specify 0 - use 'all' to completely delete download history"],
50
+   trimhistory => [ 1, "trimhistory|trim-history=s", 'Hidden', '--trim-history <# days to retain>', "Remove download history entries older than number of days specified in option value.  Cannot specify 0 - use 'all' to completely delete download history"],
51
 
52
 };
53
 
54
@@ -388,6 +388,47 @@
55
 # Parse the cmdline using the opt_format hash
56
 Options->usage( 0 ) if not $opt_cmdline->parse();
57
 
58
+# check obsolete options on command ilne
59
+my %nono_remap = (
60
+   "mode" => "quality",
61
+   "modes" => "quality",
62
+   "tvmode" => "tv-quality",
63
+   "radiomode" => "radio-quality",
64
+   "fps25" => "tv-lower-bitrate",
65
+);
66
+my $nono_regex = "(" . join("|", keys %nono_remap) . ")";
67
+my @nono_args = map { $_ =~ s/\-//g; $_ =~ s/=.*$//; $_;} grep(/--${nono_regex}/, @argv_save);
68
+my $nono_found;
69
+for my $nono_arg ( @nono_args ) {
70
+   $nono_found = 1;
71
+   logger "WARNING: --$nono_arg is deprecated and will be removed in a future release. Use --$nono_remap{$nono_arg}.\n";
72
+   # logger "ERROR: --$nono_arg is no longer supported. Use --$nono_remap{$nono_arg}.\n";
73
+}
74
+# exit 1 if $nono_found;
75
+
76
+# check invalid quality settings on command ilne
77
+my $regex_quality = {
78
+   tvmode => qr/(fhd|hd|sd|web|mobile|1080p?|720p?|540p?|396p?|288p?|default)/,
79
+   radiomode => qr/(high|std|med|low|320k?|128k?|96k?|48k?|default)/
80
+};
81
+$regex_quality->{modes} = "($regex_quality->{tvmode}|$regex_quality->{radiomode})";
82
+my $bad_quality;
83
+for my $qp ( "", "tv", "radio" ) {
84
+   my $qs = $qp ? "" : "s";
85
+   my $cmd_quality = "${qp}quality";
86
+   my $opt_quality = "${qp}mode${qs}";
87
+   my @bad_quality;
88
+   if ( $opt_cmdline->{$opt_quality} ) {
89
+       @bad_quality = grep(!/^$regex_quality->{$opt_quality}$/, split(/,/, $opt_cmdline->{$opt_quality}));
90
+       if ( @bad_quality ) {
91
+           $bad_quality = 1;
92
+           logger "WARNING: Invalid values in --${cmd_quality}/--${opt_quality}: '" . join(",", @bad_quality) . "'. This will be a fatal error in a future release.\n";
93
+           # logger "ERROR: Invalid values in --${cmd_quality}/--${opt_quality}: '" . join(",", @bad_quality) . "'\n";
94
+       }
95
+   }
96
+}
97
+# exit 1 if $bad_quality;
98
+
99
 # process --start and --stop if necessary
100
 foreach ('start', 'stop') {
101
    if ($opt_cmdline->{$_} && $opt_cmdline->{$_} =~ /(\d\d):(\d\d)(:(\d\d))?/) {
102
@@ -416,9 +457,7 @@
103
    # Sanitize preset file name
104
    my $presetname = StringUtils::sanitize_path( $opt_cmdline->{preset}, 0, 1 );
105
    $optfile_preset = File::Spec->catfile($presets_dir, $presetname);
106
-   logger "INFO: Using user options preset '${presetname}'\n";
107
 }
108
-logger "DEBUG: User preset options file: $optfile_preset\n" if defined $optfile_preset && $opt->{debug};
109
 
110
 # Parse options if we're not saving/adding/deleting options (system-wide options are overridden by personal options)
111
 if ( ! ( $opt_pre->{prefsadd} || $opt_pre->{prefsdel} || $opt_pre->{prefsclear} ) ) {
112
@@ -561,7 +600,6 @@
113
    }
114
    elsif ( $search_args[0] =~ m{^bbc-ipd:/*download/(\w+)/\w+/(\w+)/} ) {
115
        $opt->{pid} = $1;
116
-       $opt->{modes} ||= "best" if $2 eq "hd";
117
    }
118
 }
119
 
120
@@ -592,16 +630,8 @@
121
 
122
 release_check();
123
 my $retcode = 0;
124
-# Trim history
125
-if ( defined($opt->{trimhistory}) ) {
126
-   my $hist = History->new();
127
-   $hist->trim();
128
-# purge files
129
-} elsif ( $opt->{purgefiles} ) {
130
-   my $hist = History->new();
131
-   purge_downloaded_files( $hist, 30 );
132
 # mark downloaded
133
-} elsif ( $opt->{markdownloaded} ) {
134
+if ( $opt->{markdownloaded} ) {
135
    if ( ! $opt->{pid} && $no_search_args ) {
136
        main::logger "ERROR: Search term(s) or --pid or --url required with --mark-downloaded\n";
137
        exit 1;
138
@@ -702,7 +732,6 @@
139
    my $hist = History->new();
140
    my @pids = split( /,/, $opt->{pid} );
141
    $retcode = download_pid_matches( $hist, find_pid_matches( $hist, @pids ) );
142
-   purge_warning( $hist, 30 );
143
 
144
 # Show history
145
 } elsif ( $opt->{history} ) {
146
@@ -717,7 +746,6 @@
147
    }
148
    my $hist = History->new();
149
    $retcode = download_matches( $hist, find_matches( $hist, @search_args ) );
150
-   purge_warning( $hist, 30 );
151
 }
152
 exit $retcode;
153
 
154
@@ -1949,67 +1977,6 @@
155
 }
156
 
157
 # Generic
158
-# Checks history for files that are over 30 days old and asks user if they should be deleted
159
-# "$prog->{pid}|$prog->{name}|$prog->{episode}|$prog->{type}|".time()."|$prog->{mode}|$prog->{filename}\n";
160
-sub purge_downloaded_files {
161
-   my $hist = shift;
162
-   my @delete;
163
-   my @proglist;
164
-   my $days = shift;
165
-
166
-   for my $pid ( $hist->get_pids() ) {
167
-       my $record = $hist->get_record( $pid );
168
-       if ( $record->{timeadded} < (time() - $days*86400) && $record->{filename} && -f $record->{filename} ) {
169
-           # Calculate the seconds difference between epoch_now and epoch_datestring and convert back into array_time
170
-           my @t = gmtime( time() - $record->{timeadded} );
171
-           push @proglist, "$record->{name} - $record->{episode}, Recorded: $t[7] days $t[2] hours ago";
172
-           push @delete, $record->{filename};
173
-       }
174
-   }
175
-
176
-   if ( @delete ) {
177
-       main::logger "\nThese programmes are over 30 days old and should be deleted:\n";
178
-       main::logger "-----------------------------------\n";
179
-       main::logger join "\n", @proglist;
180
-       main::logger "\n-----------------------------------\n";
181
-       main::logger "Do you wish to delete them now (Yes/No) ?\n";
182
-       my $answer = <STDIN>;
183
-       if ($answer =~ /^yes$/i ) {
184
-           for ( @delete ) {
185
-               main::logger "INFO: Deleting $_\n";
186
-               unlink $_;
187
-           }
188
-           main::logger "Programmes deleted\n";
189
-       } else {
190
-           main::logger "No Programmes deleted\n";
191
-       }
192
-   }
193
-
194
-   return 0;
195
-}
196
-
197
-sub purge_warning {
198
-   my $hist = shift;
199
-   my $days = shift;
200
-   my $overdue;
201
-   return 0 if $opt->{nopurge} || $opt->{nowrite};
202
-   for my $pid ( $hist->get_pids() ) {
203
-       my $record = $hist->get_record( $pid );
204
-       if ( $record->{timeadded} < (time() - $days*86400) && $record->{filename} && -f $record->{filename} ) {
205
-           $overdue = 1;
206
-           last;
207
-       }
208
-   }
209
-   if ( $overdue ) {
210
-       print STDOUT "WARNING: You have programmes over 30 days old that should be deleted.\n";
211
-       print STDOUT "WARNING: Find them with 'get_iplayer --history --before=720 \".*\"'\n";
212
-       print STDOUT "WARNING: or use the 'Recordings' tab in the Web PVR Manager.\n";
213
-       print STDOUT "WARNING: Use 'get_iplayer --purge-files' to delete all programmes over 30 days old.\n";
214
-       print STDOUT "WARNING: Use 'get_iplayer --prefs-add --no-purge' to suppress this warning.\n";
215
-   }
216
-   return 0;
217
-}
218
-
219
 # Returns url decoded string
220
 sub url_decode {
221
    my $str = shift;
222
@@ -2567,7 +2534,7 @@
223
        'This applies even if the base option name already begins with "no-", e.g., --no-no-tag or --no-no-artwork',
224
    );
225
    push @man,
226
-       '.TH GET_IPLAYER "1" "December 2021" "Phil Lewis" "get_iplayer Manual"',
227
+       '.TH GET_IPLAYER "1" "February 2022" "Phil Lewis" "get_iplayer Manual"',
228
        '.SH NAME', 'get_iplayer - Stream Recording tool and PVR for BBC iPlayer and BBC Sounds',
229
        '.SH SYNOPSIS',
230
        '\fBget_iplayer\fR [<options>] [<regex|index> ...]',
231
@@ -2715,7 +2682,7 @@
232
 
233
 # specify regex of options that cannot be saved
234
 sub excludeopts {
235
-   return '^(cache|profiledir|encoding|silent|help|debug|get|pvr|prefs|preset|warranty|conditions|dumpoptions|comment|purge|markdownloaded)';
236
+   return '^(cache|profiledir|encoding|silent|help|debug|get|pvr|prefs|preset|warranty|conditions|dumpoptions|comment|markdownloaded)';
237
 }
238
 
239
 # List all available presets in the specified dir
240
@@ -3042,55 +3009,6 @@
241
    $History::optref = shift;
242
 }
243
 
244
-sub trim {
245
-   my $oldhistoryfile = "$historyfile.old";
246
-   my $newhistoryfile = "$historyfile.new";
247
-   if ( $opt->{trimhistory} =~ /^all$/i ) {
248
-       if ( ! copy($historyfile, $oldhistoryfile) ) {
249
-           die "ERROR: Cannot copy $historyfile to $oldhistoryfile: $!\n";
250
-       }
251
-       if ( ! unlink($historyfile) ) {
252
-           die "ERROR: Cannot delete $historyfile: $! \n";
253
-       }
254
-       main::logger "INFO: Deleted all entries from download history\n";
255
-       return;
256
-   }
257
-   if ( $opt->{trimhistory} !~ /^\d+$/ ) {
258
-       die "ERROR: --trim-history option must have a positive integer value, or use 'all' to completely delete download history.\n";
259
-   }
260
-   if ( $opt->{trimhistory} =~ /^0+$/ ) {
261
-       die "ERROR: Cannot specify 0 for --trim-history option.  Use 'all' to completely delete download history.\n";
262
-   }
263
-   if ( ! open(HIST, "< $historyfile") ) {
264
-       die "ERROR: Cannot read from $historyfile\n";
265
-   }
266
-   if ( ! open(NEWHIST, "> $newhistoryfile") ) {
267
-       die "ERROR: Cannot write to $newhistoryfile\n";
268
-   }
269
-   my $trim_limit = time() - ($opt->{trimhistory} * 86400);
270
-   my $deleted_count = 0;
271
-   while (<HIST>) {
272
-       chomp();
273
-       next if /^[\#\s]/;
274
-       my @record = split /\|/;
275
-       my $timeadded = $record[4];
276
-       if ( $timeadded >= $trim_limit ) {
277
-           print NEWHIST "$_\n";
278
-       } else {
279
-           $deleted_count++;
280
-       }
281
-   }
282
-   close HIST;
283
-   close NEWHIST;
284
-   if ( ! copy($historyfile, $oldhistoryfile) ) {
285
-       die "ERROR: Cannot copy $historyfile to $oldhistoryfile: $!\n";
286
-   }
287
-   if ( ! move($newhistoryfile, $historyfile) ) {
288
-       die "ERROR: Cannot move $newhistoryfile to $historyfile: $!\n";
289
-   }
290
-   main::logger "INFO: Deleted $deleted_count entries from download history\n";
291
-}
292
-
293
 # Uses global @history_format
294
 # Adds prog to history file (with a timestamp) so that it is not rerecorded after deletion
295
 sub add {
296
@@ -3571,15 +3489,16 @@
297
            # skip these
298
        # If hash then list keys
299
        } elsif ( ref$data{$_} eq 'HASH' ) {
300
+           next if ( $_ eq "modes" || $_ eq "modesizes") && ! $opt->{verbose};
301
            for my $key ( sort keys %{$data{$_}} ) {
302
                main::logger sprintf "%-16s ", $_.':';
303
                if ( ref$data{$_}->{$key} ne 'HASH' ) {
304
-                   if ( $_ eq "modes" || $_ eq "modesizes" )   {
305
+                   if ( $_ eq "modes" || $_ eq "modesizes" ||  $_ eq "qualities" || $_ eq "qualitysizes" ) {
306
                        my %seen = ();
307
-                       my @vals = sort Programme::cmp_modes grep { not $seen{$_}++ } map { $_ =~ s/([a-z])\d+/$1/; $_; } split(",", $data{$_}->{$key});
308
+                       my @vals = sort Programme::cmp_modes grep { not $seen{$_}++ } map { $_ =~ s/([a-z])\d+/$1/; $_; } split(/,/, $data{$_}->{$key});
309
                        my $val = join(",", @vals);
310
                        main::logger "$key: $val";
311
-                       main::logger " [estimated sizes]" if $_ eq "modesizes";
312
+                       main::logger " [estimated sizes]" if $_ eq "modesizes" ||  $_ eq "qualitysizes";
313
                    } else {
314
                        main::logger "$key: $data{$_}->{$key}";
315
                    }
316
@@ -3717,25 +3636,23 @@
317
 sub cmp_modes($$) {
318
    my ($x, $y) = @_;
319
    my %ranks = (
320
-       'hd(\d+)?' => 1000,
321
-       '[^x]sd(\d+)?' => 2000,
322
-       'xsd(\d+)?' => 3000,
323
-       '[^vx]high(\d+)?' => 4000,
324
-       'xhigh(\d+)?' => 5000,
325
-       '[^x]std(\d+)?' => 6000,
326
-       'xstd(\d+)?' => 7000,
327
-       'med(\d+)?' => 8000,
328
-       'low(\d+)?' => 9000,
329
-       'subtitles(\d+)?' => 10000,
330
+       'fhd(\d+)?' => 1000,
331
+       '(\b|[^f])hd(\d+)?' => 2000,
332
+       '(\b|[^x])sd(\d+)?' => 3000,
333
+       'xsd(\d+)?' => 4000,
334
+       '(\b|[^x])web(\d+)?' => 5000,
335
+       'xweb(\d+)?' => 6000,
336
+       'mobile(\d+)?' => 7000,
337
+       'high(\d+)?' => 8000,
338
+       'std(\d+)?' => 9000,
339
+       'med(\d+)?' => 10000,
340
+       'low(\d+)?' => 11000,
341
+       'subtitles(\d+)?' => 12000,
342
    );
343
    my %ranks2 = (
344
-       '^haf' => 10,
345
-       '^hla' => 20,
346
-       '^hvf' => 30,
347
-       '^hls' => 40,
348
-       '^daf' => 50,
349
-       '^dvf' => 60,
350
-       '^subtitle' => 70,
351
+       '^hls' => 10,
352
+       '^dash' => 20,
353
+       '^subtitle' => 30,
354
    );
355
    my ($rank_x, $rank_y);
356
    for my $k ( keys %ranks ) {
357
@@ -3807,10 +3724,6 @@
358
        main::logger "WARNING: A UK TV licence is required to access BBC iPlayer TV content legally\n";
359
    }
360
 
361
-   # Get all possible (or user overridden) modes for this prog recording
362
-   my $modelist = $prog->modelist();
363
-   main::logger "INFO: Mode list: $modelist\n" if $opt->{verbose};
364
-
365
    ######## version loop #######
366
    # Do this for each version tried in this order (if they appeared in the content)
367
    for my $version ( @version_search_list ) {
368
@@ -3822,6 +3735,7 @@
369
                main::logger "INFO: Regenerate filename for version change: $prog->{version} -> $version\n" if ( $prog->{version} && $opt->{verbose} );
370
            }
371
            $prog->{version} = $version;
372
+           $prog->{verpid} = $prog->{verpids}->{$version};
373
            main::logger "INFO: Found version: '$prog->{version}'\n" if $opt->{verbose};
374
 
375
            # Try to get stream data for this version if not already populated
376
@@ -3829,6 +3743,10 @@
377
                $prog->{streams}->{$version} = $prog->get_stream_data( $prog->{verpids}->{$version}, undef, $version );
378
            }
379
 
380
+           # Get all possible (or user overridden) modes for this prog version
381
+           my $modelist = $prog->modelist();
382
+           main::logger "INFO: Mode list for version '$prog->{version}': $modelist\n" if $opt->{verbose};
383
+
384
            ########## mode loop ########
385
            # record prog depending on the prog type
386
 
387
@@ -3836,7 +3754,7 @@
388
            my @modes;
389
            my @available_modes = sort keys %{ $prog->{streams}->{$version} };
390
            for my $modename ( split /,/, $modelist ) {
391
-               next if $opt->{audioonly} && $prog->{type} eq "tv" && $modename =~ /^hls/;
392
+               # next if $opt->{audioonly} && $prog->{type} eq "tv" && $modename =~ /^hls/;
393
                # find all numbered modes starting with this modename
394
                push @modes, sort { $a cmp $b } grep /^$modename(\d+)?$/, @available_modes;
395
            }
396
@@ -3848,20 +3766,21 @@
397
                my %available_modes_short;
398
                # Strip the number from the end of the mode name and make a unique array
399
                for my $modename ( @available_modes ) {
400
-                   next if $opt->{audioonly} && $prog->{type} eq "tv" && $modename =~ /^hls/;
401
+                   # next if $opt->{audioonly} && $prog->{type} eq "tv" && $modename =~ /^hls/;
402
                    next if $modename =~ /subtitle/;
403
                    $modename =~ s/\d+$//g;
404
                    $available_modes_short{$modename}++;
405
                }
406
-               my $msg = "No supported modes";
407
+               my $msg = "No supported recording quality";
408
                if ( $opt->{$prog->{type}."mode"} || $opt->{modes} ) {
409
-                   $msg = "No specified modes";
410
+                   $msg = "No specified recording quality";
411
                }
412
+               my $available_qualities = $prog->qualities_from_modes( join( ",", sort Programme::cmp_modes @available_modes ) );
413
                main::logger "INFO: $msg ".($modelist ? "($modelist) " : "")."available for this programme with version '$version'\n";
414
-               if ( keys %available_modes_short ) {
415
-                   main::logger "INFO: Available modes: ".(join ',', sort Programme::cmp_modes keys %available_modes_short)."\n";
416
+               if ( $available_qualities ) {
417
+                   main::logger "INFO: Available qualities: $available_qualities\n"
418
                } else {
419
-                   main::logger "INFO: No other modes are available\n";
420
+                   main::logger "INFO: No other recording quality is available\n";
421
                    main::logger "INFO: The programme may no longer be available - check the iPlayer or Sounds site\n";
422
                    main::logger "INFO: The programme may only be available in an unsupported format (e.g., Flash) - check the iPlayer or Sounds site\n";
423
                    main::logger "INFO: If you use a VPN/VPS/Smart DNS/web proxy, it may have been blocked\n";
424
@@ -3881,6 +3800,7 @@
425
                $prog->{mode} = $mode;
426
                # Keep short mode name for substitutions
427
                $prog->{modeshort} = $modeshort;
428
+               $prog->{quality} = $prog->qualities_from_modes($mode);
429
 
430
                # try the recording for this mode (rtn==0 -> success, rtn==1 -> next mode, rtn==2 -> next prog)
431
                $retcode = mode_ver_download_retry_loop( $prog, $hist, $ua, $mode, $version, $prog->{verpids}->{$version} );
432
@@ -3992,9 +3912,9 @@
433
            $prog->{streams}->{$version} = $prog->get_stream_data( $version_pid, undef, $version );
434
            if ( keys %{ $prog->{streams}->{$version} } == 0 ) {
435
                main::logger "WARNING: No streams available for '$version' version ($prog->{verpids}->{$version}) - skipping (retry)\n";
436
-               if ( $prog->{geoblocked} ) {
437
+               if ( $prog->{geoblocked}->{$version} ) {
438
                    main::logger "WARNING: The BBC blocked access to this programme because it determined that you are outside the UK. (retry)\n";
439
-               } elsif ( $prog->{unavailable} ) {
440
+               } elsif ( $prog->{unavailable}->{$version} ) {
441
                    main::logger "WARNING: The BBC lists this programme as unavailable - check the iPlayer or Sounds site (retry)\n";
442
                }
443
                return 2;
444
@@ -4054,18 +3974,10 @@
445
    $template->{generic} .= '<program_meta_data xmlns="http://linuxcentre.net/xmlstuff/get_iplayer" revision="1">'."\n";
446
    my $version = $prog->{version} || 'unknown';
447
    for my $key ( sort keys %{$prog} ) {
448
+       next if $key eq "versions";
449
        my $subst = "[$key]";
450
        my $value = $prog->{$key};
451
-       if ( ref$value eq 'HASH' ) {
452
-           if ( ref$value->{$version} ne 'HASH' ) {
453
-               # abbreviate mode lists
454
-               if ( $key eq "modes" || $key eq "modesizes" )   {
455
-                   my %seen = ();
456
-                   my @vals = sort Programme::cmp_modes grep { not $seen{$_}++ } map { $_ =~ s/([a-z])\d+/$1/; $_; } split(",", $value->{$version});
457
-                   $subst = join(",", @vals);
458
-               }
459
-           }
460
-       }
461
+       next if ( ref$value eq 'HASH' );
462
        $template->{generic} .= "\t<$key>$subst</$key>\n";
463
    }
464
    $template->{generic} .= "</program_meta_data>\n";
465
@@ -4113,22 +4025,9 @@
466
    $self->{runtime} = int($self->{duration} / 60);
467
    my $jom = {};
468
    for my $key ( sort keys %{$self} ) {
469
+       next if $key eq "versions";
470
        my $value = $self->{$key};
471
-       # Get version specific value if this key is a hash
472
-       if ( ref$value eq 'HASH' ) {
473
-           if ( ref$value->{$version} ne 'HASH' ) {
474
-               # abbreviate mode lists
475
-               if ( $key eq "modes" || $key eq "modesizes" )   {
476
-                   my %seen = ();
477
-                   my @vals = sort Programme::cmp_modes grep { not $seen{$_}++ } map { $_ =~ s/([a-z])\d+/$1/; $_; } split(",", $value->{$version});
478
-                   $value = join(",", @vals);
479
-               } else {
480
-                   $value = $value->{$version};
481
-               }
482
-           } else {
483
-               next;
484
-           }
485
-       }
486
+       next if ( ref$value eq 'HASH' );
487
        # Join array elements if value is ARRAY type
488
        if ( ref$value eq 'ARRAY' ) {
489
            $value = join ',', @{ $value };
490
@@ -4310,11 +4209,11 @@
491
    $prog->{ext} = 'EXT' if ! $prog->{ext};
492
    # output files with --raw
493
    if ( $opt->{raw} && $mode ) {
494
-       if ( $mode =~ /(haf|hvf|hls)/ ) {
495
+       if ( $mode =~ /^hls/ ) {
496
            $prog->{ext} = "ts";
497
-       } elsif ( $mode =~ /daf/ ) {
498
+       } elsif ( $mode =~ /^dash/ && $prog->{type} eq "radio" ) {
499
            $prog->{ext} = "raw.m4a";
500
-       } elsif ( $mode =~ /dvf/ ) {
501
+       } elsif ( $mode =~ /^dash/ && $prog->{type} eq "tv" ) {
502
            $prog->{rawaudio} = main::encode_fs(File::Spec->catfile($prog->{dir}, "$prog->{fileprefix}.raw.m4a"));
503
            $prog->{rawvideo} = main::encode_fs(File::Spec->catfile($prog->{dir}, "$prog->{fileprefix}.raw.m4v"));
504
        }
505
@@ -5507,9 +5406,12 @@
506
 
507
    my $modes;
508
    my $mode_sizes;
509
+   my $qualities;
510
+   my $quality_sizes;
511
    for my $version ( sort keys %{ $prog->{verpids} } ) {
512
        my @version_modes = sort Programme::cmp_modes keys %{ $prog->{streams}->{$version} };
513
        $modes->{$version} = join ',', @version_modes;
514
+       $qualities->{$version} = $prog->qualities_from_modes($modes->{$version});
515
        # Estimate the file sizes for each mode
516
        my @sizes;
517
        for my $mode ( @version_modes ) {
518
@@ -5531,18 +5433,21 @@
519
            }
520
        }
521
        $mode_sizes->{$version} = join ',', sort Programme::cmp_modes @sizes;
522
+       $quality_sizes->{$version} = $prog->qualitysizes_from_modesizes($mode_sizes->{$version});
523
    }
524
 
525
    $prog->{versions} = $versions;
526
    $prog->{modes} = $modes;
527
    $prog->{modesizes} = $mode_sizes;
528
+   $prog->{qualities} = $qualities;
529
+   $prog->{qualitysizes} = $quality_sizes;
530
 
531
    # check at least one version available
532
    if ( keys %{ $prog->{verpids} } == 0 ) {
533
        main::logger "WARNING: No media streams found for requested programme versions and recording modes.\n";
534
-       if ( $prog->{geoblocked} ) {
535
+       if ( $prog->{geoblocked}->{$version} ) {
536
            main::logger "WARNING: The BBC blocked access to this programme because it determined that you are outside the UK.\n";
537
-       } elsif ( $prog->{unavailable} ) {
538
+       } elsif ( $prog->{unavailable}->{$version} ) {
539
            main::logger "WARNING: The BBC lists this programme as unavailable - check the iPlayer or Sounds site.\n";
540
        } else {
541
            main::logger "WARNING: The programme may no longer be available - check the iPlayer or Sounds site.\n";
542
@@ -6108,14 +6013,14 @@
543
    }
544
    $conn->{href} = $manifest_url;
545
    my $xml = main::request_url_retry( $ua, $conn->{href}, 3, undef, undef, 1, undef, 1 );
546
-   if ( ! $xml ) {
547
+   if ( $xml !~ /<\?xml.*?<MPD/si ) {
548
        main::logger "WARNING: No DASH manifest returned ($conn->{href})\n" if $opt->{verbose};
549
        return;
550
    }
551
    my $dom;
552
    eval { $dom = XML::LibXML->load_xml(string => $xml); };
553
    if ( $@ ) {
554
-       main::logger "ERROR: Failed to load DASH manifest:\n$@";
555
+       main::logger "ERROR: Failed to load DASH manifest:\n$@" if $opt->{verbose};
556
        return;
557
    }
558
    my $xpc = XML::LibXML::XPathContext->new($dom);
559
@@ -6370,7 +6275,6 @@
560
 # $media = undef|<modename>
561
 sub get_stream_data {
562
    my ( $prog, $verpid, $media, $version ) = @_;
563
-   my $modelist = $prog->modelist();
564
    my $data = {};
565
 
566
    main::logger "INFO: Getting stream data for version: '$version'\n" if $opt->{verbose};
567
@@ -6388,6 +6292,16 @@
568
        $exclude_regex = '_('.(join('|', @exclude_supplier)).')';
569
    }
570
 
571
+   # filter formats
572
+   my @exclude_format = split(/,/, $opt->{excludeformat});
573
+   if ( $opt->{includeformat} ) {
574
+       @exclude_format = grep { $opt->{includeformat} !~ /\b$_\b/ } @exclude_format;
575
+   }
576
+   my $exclude_format;
577
+   if ( @exclude_format ) {
578
+       $exclude_format = join(',', @exclude_format);
579
+   }
580
+
581
    # retrieve stream data
582
    my $ua = main::create_ua( 'desktop' );
583
    my $unblocked;
584
@@ -6398,9 +6312,8 @@
585
    my @medias;
586
    my @mediasets;
587
    my @ms_tf;
588
-   my $unknown_modes = $modelist !~ /(daf|dvf|haf|hla|hvf)/;
589
-   my $get_dash = $opt->{info} || $modelist =~ /(daf|dvf)/ || $unknown_modes;
590
-   my $get_hls = $opt->{info} || $modelist =~ /(haf|hla|hvf)/ || $unknown_modes;
591
+   my $get_dash = $opt->{info} || $exclude_format !~ /dash/;
592
+   my $get_hls = $opt->{info} ||  $exclude_format !~ /hls/;
593
    if ( $get_dash ) {
594
        push @ms_tf, "dash";
595
        push @mediasets, "iptv-all", "pc";
596
@@ -6483,12 +6396,12 @@
597
    }
598
 
599
    unless ( $unblocked ) {
600
-       $prog->{geoblocked} = 1 if $checked_geoblock;
601
+       $prog->{geoblocked}->{$version} = 1 if $checked_geoblock;
602
        return undef;
603
    }
604
 
605
    unless ( $isavailable ) {
606
-       $prog->{unavailable} = 1 if $checked_unavailable;
607
+       $prog->{unavailable}->{$version} = 1 if $checked_unavailable;
608
        return undef;
609
    }
610
 
611
@@ -6497,95 +6410,47 @@
612
 
613
        # Put verpid into mattribs
614
        $mattribs->{verpid} = $verpid;
615
-       $mattribs->{modelist} = $modelist;
616
 
617
-       if ( $mattribs->{service} =~ /hla/ ) {
618
-           if ( $mattribs->{kind} =~ 'audio' ) {
619
-               my $ext = "m4a";
620
-               if ( $mattribs->{bitrate} >= 192 ) {
621
-                   get_stream_data_cdn( $data, $mattribs, 'hlahigh', 'hls', $ext );
622
-               } elsif ( $mattribs->{bitrate} >= 120 ) {
623
-                   get_stream_data_cdn( $data, $mattribs, 'hlastd', 'hls', $ext );
624
-               } elsif ( $mattribs->{bitrate} >= 80 ) {
625
-                   get_stream_data_cdn( $data, $mattribs, 'hlamed', 'hls', $ext );
626
-               } else {
627
-                   get_stream_data_cdn( $data, $mattribs, 'hlalow', 'hls', $ext );
628
-               }
629
+       if ( $mattribs->{service} =~ /(daf|haf|hla)/ && $mattribs->{kind} =~ 'audio' ) {
630
+           my $stm = $mattribs->{service} =~ /daf/ ? "dash" : "hls";
631
+           my $ext = "m4a";
632
+           if ( $mattribs->{bitrate} >= 192 ) {
633
+               get_stream_data_cdn( $data, $mattribs, "${stm}high", $stm, $ext );
634
+           } elsif ( $mattribs->{bitrate} >= 120 ) {
635
+               get_stream_data_cdn( $data, $mattribs, "${stm}std", $stm, $ext );
636
+           } elsif ( $mattribs->{bitrate} >= 80 ) {
637
+               get_stream_data_cdn( $data, $mattribs, "${stm}med", $stm, $ext );
638
+           } else {
639
+               get_stream_data_cdn( $data, $mattribs, "${stm}low", $stm, $ext );
640
            }
641
 
642
-       } elsif ( $mattribs->{service} =~ /hvf/ ) {
643
-           if ( $mattribs->{kind} =~ 'video' ) {
644
-               my $ext = "mp4";
645
-               if ( $mattribs->{height} > 1000 ) {
646
-                   # full HD streams do not exist yet
647
-               } elsif ( $mattribs->{height} > 700 ) {
648
-                   get_stream_data_cdn( $data, $mattribs, "hvfhd", 'hls', $ext );
649
-               } elsif ( $mattribs->{height} > 500 ) {
650
-                   if ( $mattribs->{fps} > 25 ) {
651
-                       get_stream_data_cdn( $data, $mattribs, "hvfsd", 'hls', $ext );
652
+       } elsif ( $mattribs->{service} =~ /(dvf|hvf|hls)/ && $mattribs->{kind} =~ 'video' ) {
653
+           my $stm = $mattribs->{service} =~ /dvf/ ? "dash" : "hls";
654
+           my $ext = "mp4";
655
+           if ( $mattribs->{height} > 700 ) {
656
+               get_stream_data_cdn( $data, $mattribs, "${stm}hd", $stm, $ext );
657
+           } elsif ( $mattribs->{height} > 500 ) {
658
+               if ( $mattribs->{fps} > 25 ) {
659
+                   if ( $mattribs->{bitrate} >= 2500 ) {
660
+                       get_stream_data_cdn( $data, $mattribs, "${stm}sd", $stm, $ext );
661
                    } else {
662
-                       get_stream_data_cdn( $data, $mattribs, "hvfxsd", 'hls', $ext );
663
+                       get_stream_data_cdn( $data, $mattribs, "${stm}xsd", $stm, $ext );
664
                    }
665
-               } elsif ( $mattribs->{height} > 360 ) {
666
-                   if ( $mattribs->{fps} > 25 ) {
667
-                       get_stream_data_cdn( $data, $mattribs, "hvfhigh", 'hls', $ext );
668
-                   } else {
669
-                       get_stream_data_cdn( $data, $mattribs, "hvfxhigh", 'hls', $ext );
670
-                   }
671
-               } elsif ( $mattribs->{height} > 260  && $mattribs->{height} < 300 ) {
672
-                   get_stream_data_cdn( $data, $mattribs, "hvflow", 'hls', $ext );
673
-               }
674
-           }
675
-
676
-       } elsif ( $mattribs->{service} =~ /haf/ ) {
677
-           if ( $mattribs->{kind} =~ 'audio' ) {
678
-               my $ext = "m4a";
679
-               if ( $mattribs->{bitrate} >= 192 ) {
680
-                   get_stream_data_cdn( $data, $mattribs, 'hafhigh', 'hls', $ext );
681
-               } elsif ( $mattribs->{bitrate} >= 120 ) {
682
-                   get_stream_data_cdn( $data, $mattribs, 'hafstd', 'hls', $ext );
683
-               } elsif ( $mattribs->{bitrate} >= 80 ) {
684
-                   get_stream_data_cdn( $data, $mattribs, 'hafmed', 'hls', $ext );
685
                } else {
686
-                   get_stream_data_cdn( $data, $mattribs, 'haflow', 'hls', $ext );
687
+                   get_stream_data_cdn( $data, $mattribs, "${stm}xsd", $stm, $ext );
688
                }
689
-           }
690
-
691
-       } elsif ( $mattribs->{service} =~ /dvf/ ) {
692
-           if ( $mattribs->{kind} =~ 'video' ) {
693
-               my $ext = "mp4";
694
-               if ( $mattribs->{height} > 700 ) {
695
-                   get_stream_data_cdn( $data, $mattribs, "dvfhd", 'dash', $ext );
696
-               } elsif ( $mattribs->{height} > 500 ) {
697
-                   if ( $mattribs->{bitrate} > 2500 ) {
698
-                       get_stream_data_cdn( $data, $mattribs, "dvfsd", 'dash', $ext );
699
+           } elsif ( $mattribs->{height} > 350 ) {
700
+               if ( $mattribs->{fps} > 25 ) {
701
+                   if ( $mattribs->{bitrate} >= 1250 ) {
702
+                       get_stream_data_cdn( $data, $mattribs, "${stm}web", $stm, $ext );
703
                    } else {
704
-                       get_stream_data_cdn( $data, $mattribs, "dvfxsd", 'dash', $ext );
705
+                       get_stream_data_cdn( $data, $mattribs, "${stm}xweb", $stm, $ext );
706
                    }
707
-               } elsif ( $mattribs->{height} > 350 ) {
708
-                   if ( $mattribs->{bitrate} > 1500 ) {
709
-                       get_stream_data_cdn( $data, $mattribs, "dvfhigh", 'dash', $ext );
710
-                   } else {
711
-                       get_stream_data_cdn( $data, $mattribs, "dvfxhigh", 'dash', $ext );
712
-                   }
713
-               } elsif ( $mattribs->{height} > 250 ) {
714
-                   get_stream_data_cdn( $data, $mattribs, "dvflow", 'dash', $ext );
715
-               }
716
-           }
717
-
718
-       } elsif ( $mattribs->{service} =~ /daf/ ) {
719
-           if ( $mattribs->{kind} =~ 'audio' ) {
720
-               my $ext = "m4a";
721
-               # use DASH 320k stream as HLS 320k stream
722
-               if ( $mattribs->{bitrate} >= 192 ) {
723
-                   get_stream_data_cdn( $data, $mattribs, "dafhigh", 'dash', $ext );
724
-               } elsif ( $mattribs->{bitrate} >= 120 ) {
725
-                   get_stream_data_cdn( $data, $mattribs, "dafstd", 'dash', $ext );
726
-               } elsif ( $mattribs->{bitrate} >= 80 ) {
727
-                   get_stream_data_cdn( $data, $mattribs, "dafmed", 'dash', $ext );
728
                } else {
729
-                   get_stream_data_cdn( $data, $mattribs, "daflow", 'dash', $ext );
730
+                   get_stream_data_cdn( $data, $mattribs, "${stm}xweb", $stm, $ext );
731
                }
732
+           } elsif ( $mattribs->{height} > 250 ) {
733
+               get_stream_data_cdn( $data, $mattribs, "${stm}mobile", $stm, $ext );
734
            }
735
 
736
        # Subtitles modes
737
@@ -6619,6 +6484,37 @@
738
        }
739
    }
740
 
741
+   # generate FHD streams
742
+   for my $key (keys %{$data}) {
743
+       if ( $key =~ m/(hls|dash)hd/ ) {
744
+           my $xvi = 12000;
745
+           my $xvb = 8490;
746
+           my $xvw = 1920;
747
+           my $xvh = 1080;
748
+           my $xvr = 50;
749
+           my $stm2 = dclone($data->{$key});
750
+           (my $key2 = $key) =~ s/(hls|dash)hd/${1}fhd/;
751
+           $stm2->{streamurl} =~ s/video=\d+/video=${xvi}000/;
752
+           $stm2->{video_bitrate} = $xvb;
753
+           $stm2->{bitrate} = $stm2->{video_bitrate} + $stm2->{audio_bitrate};
754
+           $stm2->{type} =~ s/^(.*?gip_.vf_)\d+(.*?)\d+x\d+(.*?)\d+(fps.*?)\d+(kbps.*)$/$1${xvb}$2${xvw}x${xvh}$3${xvr}$4${xvb}$5/;
755
+           $stm2->{type} = sprintf("%12s %4s %4s %9s %5s %8s %7s %s", split(" ", $stm2->{type}));
756
+           if ( $key2 =~ /dashfhd/ ) {
757
+               $stm2->{size} = int($stm2->{audio_media}->{programme_duration} * $stm2->{bitrate} * 1000.0 / 8.0);
758
+               $stm2->{video_media}->{height} = $xvh;
759
+               $stm2->{video_media}->{width} = $xvw;
760
+               $stm2->{video_media}->{bitrate} = $xvb;
761
+               $stm2->{video_media}->{file_size} = int($stm2->{video_media}->{programme_duration} * $stm2->{video_media}->{bitrate} * 1000.0 / 8.0);
762
+               $stm2->{video_media}->{service} =~ s/(gip_dvf_)\d+/$1${xvb}/;
763
+               $stm2->{video_media}->{id} = "video=${xvi}000";
764
+           }
765
+           my $xvs = main::request_url_retry( $ua, $stm2->{streamurl}, 3, undef, undef, 1, undef, 1 );
766
+           if ( $xvs && $xvs !~ /<html/i ) {
767
+               $data->{$key2} = $stm2;
768
+           }
769
+       }
770
+   }
771
+
772
    # Report modes found
773
    if ( $opt->{verbose} ) {
774
        main::logger sprintf("INFO: Found mode %10s: %s\n", $_, $data->{$_}->{type}) for sort Programme::cmp_modes keys %{ $data };
775
@@ -6636,165 +6532,153 @@
776
 
777
 sub modelist {
778
    my $prog = shift;
779
+   my $regex_quality = qr/(fhd|hd|sd|web|mobile|high|std|med|low|default)/;
780
+   my $regex_alias = qr/(1080p?|720p?|540p?|396p?|288p?|320k?|128k?|96k?|48k?)/;
781
+   my $replace_alias = {
782
+       "1080p" => "fhd",
783
+       "720p" => "hd",
784
+       "540p" => "sd",
785
+       "396p" => "web",
786
+       "288p" => "mobile",
787
+       "320k" => "high",
788
+       "128k" => "std",
789
+        "96k" => "med",
790
+        "48k" => "low",
791
+       "1080" => "fhd",
792
+       "720" => "hd",
793
+       "540" => "sd",
794
+       "396" => "web",
795
+       "288" => "mobile",
796
+       "320" => "high",
797
+       "128" => "std",
798
+        "96" => "med",
799
+        "48" => "low",
800
+   };
801
+   my $tvlbr = $opt->{fps25};
802
    my $mlist = $opt->{$prog->{type}."mode"} || $opt->{modes};
803
-   # Defaults
804
-   if ( ! $mlist ) {
805
-       $mlist = 'default';
806
-   }
807
+   $mlist =~ s/\s+//g;
808
+   $mlist =~ s/,{2,}/,/g;
809
+   $mlist = lc($mlist);
810
    my $mlist_orig = $mlist;
811
    # backcompat
812
-   $mlist =~ s/(\b|[^t])vgood/$1better/g;
813
+   # prefixes first
814
+   $mlist =~ s/(flash|hls)aac//g;
815
+   $mlist =~ s/(flash|rtmp)//g;
816
+   $mlist =~ s/(dash|dvf|daf)//g;
817
+   $mlist =~ s/(hls|hvf|haf|hla)//g;
818
+   $mlist =~ s/(tv|radio)//g;
819
+   # then suffixes
820
+   $mlist =~ s/([^,\d]+)\d+/$1/g;
821
+   $mlist =~ s/vgood/better/g;
822
    $mlist =~ s/worse/good/g;
823
-   $mlist =~ s/hlsvhigh/hvfxsd/g;
824
-   $mlist =~ s/(hlsx?|hvf)std/hvfxhigh/g;
825
-   $mlist =~ s/(flash|hls)aac/radio/g;
826
-   $mlist =~ s/(flash|rtmp)/tv/g;
827
-   if ( $mlist ne $mlist_orig && ! $opt->{nowarnmoderemap} ) {
828
-       main::logger "WARNING: Invalid mode list '$mlist_orig' remapped to '$mlist'\n";
829
-       main::logger "WARNING: Please update your preferences\n";
830
-       $opt->{nowarnmoderemap} = 1;
831
+   $mlist =~ s/vhigh/sd/g;
832
+   $mlist =~ s/x(high|std)/xweb/g;
833
+   if ( $prog->{type} eq "tv" ) {
834
+       $mlist =~ s/high/web/g;
835
+       $mlist =~ s/low/mobile/g;
836
    }
837
-   # stream format aliases
838
+   # then expansions
839
    if ( $prog->{type} eq "tv" ) {
840
-       $mlist =~ s/dash/dvf/g;
841
-       $mlist =~ s/hls(?!hd)/hvf/g;
842
+       $mlist =~ s/best/hd,sd,web,mobile/g;
843
+       $mlist =~ s/better/sd,web,mobile/g;
844
+       $mlist =~ s/good/web,mobile/g;
845
+       $mlist =~ s/worst/mobile/g;
846
    } elsif ( $prog->{type} eq "radio" ) {
847
-       $mlist =~ s/dash/daf/g;
848
-       $mlist =~ s/hls(?!hd)/hlsaudio/g;
849
+       $mlist =~ s/best/high,std,med,low/g;
850
+       $mlist =~ s/better/std,med,low/g;
851
+       $mlist =~ s/good/med,low/g;
852
+       $mlist =~ s/worst/low/g;
853
    }
854
-   # Deal with fallback modes and expansions
855
-   # Generic aliases
856
-   $mlist = main::expand_list($mlist, 'default', "$prog->{type}default");
857
-   $mlist = main::expand_list($mlist, 'best', "$prog->{type}best");
858
-   $mlist = main::expand_list($mlist, 'better', "$prog->{type}better");
859
-   $mlist = main::expand_list($mlist, 'good', "$prog->{type}good");
860
-   $mlist = main::expand_list($mlist, 'worst', "$prog->{type}worst");
861
-   # single quality levels
862
-   if ( $prog->{type} eq "tv" ) {
863
-       $mlist = main::expand_list($mlist, 'hd', "$prog->{type}hd");
864
-       $mlist = main::expand_list($mlist, 'sd', "$prog->{type}sd");
865
+   $mlist = join( ",", grep( /^(${regex_quality}|${regex_alias})$/, split( /,/, $mlist ) ) );
866
+   if ( $mlist ne $mlist_orig && ! $opt->{nowarnmoderemap} ) {
867
+       main::logger "WARNING: Recording quality settings '$mlist_orig' corrected to '$mlist'\n";
868
+       main::logger "WARNING: Please update your preferences, preset, or PVR search\n";
869
+       $opt->{nowarnmoderemap} = 1;
870
    }
871
-   $mlist = main::expand_list($mlist, 'high', "$prog->{type}high");
872
-   if ( $prog->{type} eq "radio" ) {
873
-       $mlist = main::expand_list($mlist, 'std', "$prog->{type}std");
874
-       $mlist = main::expand_list($mlist, 'med', "$prog->{type}med");
875
-   }
876
-   $mlist = main::expand_list($mlist, 'low', "$prog->{type}low");
877
-   # DASH on-demand radio
878
-   if ( $prog->{type} eq "radio" && $mlist =~ /daf/ ) {
879
-       $mlist = main::expand_list($mlist, 'daf', 'dafdefault');
880
-       $mlist = main::expand_list($mlist, 'dafdefault', 'dafbest');
881
-       $mlist = main::expand_list($mlist, 'dafbest', 'dafhigh,dafbetter');
882
-       $mlist = main::expand_list($mlist, 'dafbetter', 'dafstd,dafgood');
883
-       $mlist = main::expand_list($mlist, 'dafgood', 'dafmed,dafworst');
884
-       $mlist = main::expand_list($mlist, 'dafworst', 'daflow');
885
-   }
886
-   # DASH on-demand tv
887
-   if ( $prog->{type} eq "tv" && $mlist =~ /dvf/ ) {
888
-       $mlist = main::expand_list($mlist, 'dvf', 'dvfdefault');
889
-       $mlist = main::expand_list($mlist, 'dvfdefault', 'dvfbest');
890
-       if ( $opt->{fps25} ) {
891
-           $mlist = main::expand_list($mlist, 'dvfbest', 'dvfbetter');
892
-           $mlist = main::expand_list($mlist, 'dvfbetter', 'dvfxsd,dvfgood');
893
-           $mlist = main::expand_list($mlist, 'dvfgood', 'dvfxhigh,dvfworst');
894
-       } else {
895
-           $mlist = main::expand_list($mlist, 'dvfbest', 'dvfhd,dvfbetter');
896
-           $mlist = main::expand_list($mlist, 'dvfbetter', 'dvfsd,dvfxsd,dvfgood');
897
-           $mlist = main::expand_list($mlist, 'dvfgood', 'dvfhigh,dvfxhigh,dvfworst');
898
-       }
899
-       $mlist = main::expand_list($mlist, 'dvfworst', 'dvflow');
900
-   }
901
-   # HLS Audio Factory on-demand radio
902
-   if ( $prog->{type} eq "radio" && $mlist =~ /haf/ ) {
903
-       $mlist = main::expand_list($mlist, 'haf', 'hafdefault');
904
-       $mlist = main::expand_list($mlist, 'hafdefault', 'hafbest');
905
-       $mlist = main::expand_list($mlist, 'hafbest', 'hafhigh,hafbetter');
906
-       $mlist = main::expand_list($mlist, 'hafbetter', 'hafstd,hafgood');
907
-       $mlist = main::expand_list($mlist, 'hafgood', 'hafmed,hafworst');
908
-       $mlist = main::expand_list($mlist, 'hafworst', 'haflow');
909
-   }
910
-   # HLS audio clips and archives
911
-   if ( $prog->{type} eq "radio" && $mlist =~ /hla/ ) {
912
-       $mlist = main::expand_list($mlist, 'hla', 'hladefault');
913
-       $mlist = main::expand_list($mlist, 'hladefault', 'hlabest');
914
-       $mlist = main::expand_list($mlist, 'hlabest', 'hlahigh,hlabetter');
915
-       $mlist = main::expand_list($mlist, 'hlabetter', 'hlastd,hlagood');
916
-       $mlist = main::expand_list($mlist, 'hlagood', 'hlamed,hlaworst');
917
-       $mlist = main::expand_list($mlist, 'hlaworst', 'hlalow');
918
-   }
919
-   # HLS Video Factory on-demand tv
920
-   if ( $prog->{type} eq "tv" && $mlist =~ /hvf/ ) {
921
-       $mlist = main::expand_list($mlist, 'hvf', 'hvfdefault');
922
-       $mlist = main::expand_list($mlist, 'hvfdefault', 'hvfbest');
923
-       if ( $opt->{fps25} ) {
924
-           $mlist = main::expand_list($mlist, 'hvfbest', 'hvfbetter');
925
-           $mlist = main::expand_list($mlist, 'hvfbetter', 'hvfxsd,hvfgood');
926
-           $mlist = main::expand_list($mlist, 'hvfgood', 'hvfxhigh,hvfworst');
927
-       } else {
928
-           $mlist = main::expand_list($mlist, 'hvfbest', 'hvfhd,hvfbetter');
929
-           $mlist = main::expand_list($mlist, 'hvfbetter', 'hvfsd,hvfxsd,hvfgood');
930
-           $mlist = main::expand_list($mlist, 'hvfgood', 'hvfhigh,hvfxhigh,hvfworst');
931
-       }
932
-       $mlist = main::expand_list($mlist, 'hvfworst', 'hvflow');
933
-   }
934
-   # HLS on-demand radio
935
-   if ( $prog->{type} eq "radio" && $mlist =~ /hlsaudio/ ) {
936
-       $mlist = main::expand_list($mlist, 'hlsaudio', 'hlsaudiodefault');
937
-       $mlist = main::expand_list($mlist, 'hlsaudiodefault', 'hlsaudiobest');
938
-       $mlist = main::expand_list($mlist, 'hlsaudiobest', 'hafhigh,hlahigh,hlsaudiobetter');
939
-       $mlist = main::expand_list($mlist, 'hlsaudiobetter', 'hafstd,hlastd,hlsaudiogood');
940
-       $mlist = main::expand_list($mlist, 'hlsaudiogood', 'hafmed,hlsmed,hlsaudioworst');
941
-       $mlist = main::expand_list($mlist, 'hlsaudioworst', 'haflow,hlalow');
942
-   }
943
-   # default on-demand radio
944
-   if ( $prog->{type} eq "radio" && $mlist =~ /radio/ ) {
945
-       $mlist = main::expand_list($mlist, 'radio', 'radiodefault');
946
-       $mlist = main::expand_list($mlist, 'radiodefault', 'radiobest');
947
-       $mlist = main::expand_list($mlist, 'radiobest', 'hafhigh,hlahigh,dafhigh,radiobetter');
948
-       $mlist = main::expand_list($mlist, 'radiobetter', 'hafstd,hlastd,dafstd,radiogood');
949
-       $mlist = main::expand_list($mlist, 'radiogood', 'hafmed,hlamed,dafmed,radioworst');
950
-       $mlist = main::expand_list($mlist, 'radioworst', 'haflow,hlalow,daflow');
951
-   }
952
-   # default on-demand tv
953
-   if ( $prog->{type} eq "tv" && $mlist =~ /tv/ ) {
954
-       $mlist = main::expand_list($mlist, 'tv', 'tvdefault');
955
-       $mlist = main::expand_list($mlist, 'tvdefault', 'tvbest');
956
-       if ( $opt->{fps25} ) {
957
-           $mlist = main::expand_list($mlist, 'tvbest', 'tvbetter');
958
-           $mlist = main::expand_list($mlist, 'tvbetter', 'hvfxsd,dvfxsd,tvgood');
959
-           $mlist = main::expand_list($mlist, 'tvgood', 'hvfxhigh,dvfxhigh,tvworst');
960
-       } else {
961
-           $mlist = main::expand_list($mlist, 'tvbest', 'hvfhd,dvfhd,tvbetter');
962
-           $mlist = main::expand_list($mlist, 'tvbetter', 'hvfsd,dvfsd,hvfxsd,dvfxsd,tvgood');
963
-           $mlist = main::expand_list($mlist, 'tvgood', 'hvfhigh,dvfhigh,hvfxhigh,dvfxhigh,tvworst');
964
-       }
965
-       $mlist = main::expand_list($mlist, 'tvworst', 'hvflow,dvflow');
966
-   }
967
-   # single quality level tv
968
-   if ( $prog->{type} eq "tv" && $mlist =~ /\btv(hd|sd|high|low)\b/ ) {
969
-       if ( $opt->{fps25} ) {
970
-           $mlist = main::expand_list($mlist, 'tvsd', 'hvfxsd,dvfxsd');
971
-           $mlist = main::expand_list($mlist, 'tvhigh', 'hvfxhigh,dvfxhigh');
972
-       } else {
973
-           $mlist = main::expand_list($mlist, 'tvhd', 'hvfhd,dvfhd');
974
-           $mlist = main::expand_list($mlist, 'tvsd', 'hvfsd,dvfsd,hvfxsd,dvfxsd');
975
-           $mlist = main::expand_list($mlist, 'tvhigh', 'hvfhigh,dvfhigh,hvfxhigh,dvfxhigh');
976
-       }
977
-       $mlist = main::expand_list($mlist, 'tvlow', 'hvflow,dvflow');
978
-   }
979
-   # single quality level radio
980
-   if ( $prog->{type} eq "radio" && $mlist =~ /\bradio(high|std|med|low)\b/ ) {
981
-       $mlist = main::expand_list($mlist, 'radiohigh', 'hafhigh,hlahigh,dafhigh');
982
-       $mlist = main::expand_list($mlist, 'radiostd', 'hafstd,hlastd,dafstd');
983
-       $mlist = main::expand_list($mlist, 'radiomed', 'hafmed,hlamed,dafmed');
984
-       $mlist = main::expand_list($mlist, 'radiolow', 'haflow,hlalow,daflow');
985
+   # Defaults
986
+   if ( ! $mlist ) {
987
+       $mlist = 'default';
988
+   }
989
+   if ( $prog->{type} eq "tv" ) {
990
+       if ( $mlist =~ /x(sd|web)/ ) {
991
+           $mlist =~ s/x(sd|web)/$1/g;
992
+           $tvlbr = 1;
993
+       }
994
+       if ( $opt->{audioonly} && $prog->{version} eq "audiodescribed" ) {
995
+           # for 128k audio
996
+           $mlist =~ s/default/hd,web,sd,mobile/g;
997
+       } else {
998
+           $mlist =~ s/default/hd,sd,web,mobile/g;
999
+       }
1000
+       # ensure valid mode for audiodescribed
1001
+       if ( $prog->{version} eq "audiodescribed" && $mlist !~ /(sd|web|mobile)/ ) {
1002
+           if ( $opt->{audioonly} ) {
1003
+               # for 128k audio
1004
+               $mlist .= ",web,sd,mobile";
1005
+           } else {
1006
+               $mlist .= ",sd,web,mobile";
1007
+           }
1008
+       }
1009
+   } elsif ( $prog->{type} eq "radio" ) {
1010
+           $mlist =~ s/default/high,std,med,low/g;
1011
    }
1012
+   $mlist =~ s/${regex_alias}/$replace_alias->{$1}/g;
1013
    # remove duplicates
1014
    my %seen;
1015
-   $mlist = join( ",", grep { my $seen = $seen{$_}; $seen{$_} = 1; !$seen } split( ",", $mlist ) );
1016
+   $mlist = join( ",", grep { my $seen = $seen{$_}; $seen{$_} = 1; !$seen } split( /,/, $mlist ) );
1017
+   # tv
1018
+   $mlist = main::expand_list($mlist, 'fhd', "dashfhd,hlsfhd");
1019
+   $mlist = main::expand_list($mlist, 'hd', "hlshd,dashhd");
1020
+   if ( $tvlbr ) {
1021
+       $mlist = main::expand_list($mlist, 'sd', "hlsxsd,dashxsd,hlssd,dashsd");
1022
+       $mlist = main::expand_list($mlist, 'web', "hlsxweb,dashxweb,hlsweb,dashweb");
1023
+   } else {
1024
+       $mlist = main::expand_list($mlist, 'sd', "hlssd,dashsd,hlsxsd,dashxsd");
1025
+       $mlist = main::expand_list($mlist, 'web', "hlsweb,dashweb,hlsxweb,dashxweb");
1026
+   }
1027
+   $mlist = main::expand_list($mlist, 'mobile', "hlsmobile,dashmobile");
1028
+   # radio
1029
+   $mlist = main::expand_list($mlist, 'high', "hlshigh,dashhigh");
1030
+   $mlist = main::expand_list($mlist, 'std', "hlsstd,dashstd");
1031
+   $mlist = main::expand_list($mlist, 'med', "hlsmed,dashmed");
1032
+   $mlist = main::expand_list($mlist, 'low', "hlslow,dashlow");
1033
    return $mlist;
1034
 }
1035
 
1036
+sub qualities_from_modes {
1037
+   my $prog = shift;
1038
+   my $modelist = shift;
1039
+   my $regex_quality = qr/(fhd|hd|sd|web|mobile|high|std|med|low)/;
1040
+   my @q1 = map { $_ =~ s/^(hls|dash)x?${regex_quality}.*?$/$2/; $_; } split( /,/, $modelist );
1041
+   my @q2 = grep(/^${regex_quality}$/, @q1);
1042
+   my %seen;
1043
+   my @q3 = grep { my $seen = $seen{$_}; $seen{$_} = 1; !$seen } @q2;
1044
+   return join(",", @q3);
1045
+}
1046
+
1047
+sub qualitysizes_from_modesizes {
1048
+   my $prog = shift;
1049
+   my $modesizes = shift;
1050
+   my $regex_quality = qr/(fhd|hd|sd|web|mobile|high|std|med|low)/;
1051
+   my %sizes;
1052
+   my %units;
1053
+   my @q1 = map {
1054
+       $_ =~ m/^(hls|dash)x?${regex_quality}.*?=(\d+)(.*?)$/;
1055
+       if ( $2 ) {
1056
+           if ( $3 > $sizes{$2} ) {
1057
+               $sizes{$2} = $3;
1058
+               $units{$2} = $4;
1059
+           }
1060
+       };
1061
+       $2;
1062
+   } split( /,/, $modesizes );
1063
+   my @q2 = grep(/^${regex_quality}$/, @q1);
1064
+   my @q3 = map { "$_=$sizes{$_}$units{$_}" } @q2;
1065
+   my %seen;
1066
+   my @q4 = grep { my $seen = $seen{$_}; $seen{$_} = 1; !$seen } @q3;
1067
+   return join(",", @q4);
1068
+}
1069
+
1070
 sub postproc {
1071
    my ( $prog, $audio_file, $video_file, $ua ) = @_;
1072
    my @cmd;
1073
@@ -6935,6 +6819,7 @@
1074
        'national' => {
1075
            'bbc_one'           => 'BBC One',
1076
            'bbc_two'           => 'BBC Two',
1077
+           'bbc_three'         => 'BBC Three',
1078
            'bbc_four'          => 'BBC Four',
1079
            'bbc_sport'     => 'BBC Sport',
1080
            'cbbc'              => 'CBBC',
1081
@@ -6959,6 +6844,7 @@
1082
            'p00fzl6g' => 'BBC News', # bbcnews/programmes/schedules
1083
            'p00fzl6n' => 'BBC One', # bbcone/programmes/schedules/hd
1084
            'p00fzl73' => 'BBC Parliament', # bbcparliament/programmes/schedules
1085
+           'p00fzl95' => 'BBC Three', # bbcthree/programmes/schedules
1086
            'p015pksy' => 'BBC Two', # bbctwo/programmes/schedules/hd
1087
            'p00fzl9r' => 'CBBC', # cbbc/programmes/schedules
1088
            'p00fzl9s' => 'CBeebies', # cbeebies/programmes/schedules
1089
@@ -7003,9 +6889,10 @@
1090
 # Class cmdline Options
1091
 sub opt_format {
1092
    return {
1093
-       tvmode      => [ 1, "tvmode|tv-mode|vmode=s", 'Recording', '--tvmode <mode>,<mode>,...', "TV recording modes (overrides --modes): dvfhd,dvfsd,dvfxsd,dvfhigh,dvfxhigh,dvflow,hvfhd,hvfsd,hvfxsd,hvfhigh,hvfxhigh,hvflow. Shortcuts: best,better,good,worst,dvf,hvf,dash,hls,hd,sd,high,low. 50fps streams (if available) preferred unless --fps25 specified (default=hvfhd,dvfhd,hvfsd,dvfsd,hvfxsd,dvfxsd,hvfhigh,dvfhigh,hvfxhigh,dvfxhigh,hvflow,dvflow)."],
1094
        commandtv   => [ 1, "commandtv|command-tv=s", 'Output', '--command-tv <command>', "User command to run after successful recording of TV programme. Use substitution parameters in command string (see docs for list). Overrides --command."],
1095
+       fps25       => [ 1, "fps25|tvlbr|tvlowerbitrate|tv-lower-bitrate!", 'Recording', '--tv-lower-bitrate', "Prefer 25fps (or lower-bitrate 50fps) streams for TV programmes if available."],
1096
        outputtv    => [ 1, "outputtv|output-tv=s", 'Output', '--output-tv <dir>', "Output directory for tv recordings (overrides --output)"],
1097
+       tvmode      => [ 0, "tvmode|tv-mode|vmode|tvquality|tv-quality|vquality=s", 'Recording', '--tv-quality <quality>,<quality>,...', "TV recording quality preference (overrides --quality): fhd,hd,sd,web,mobile,default (Aliases: 1080p,720p,540p,396p,288p). Comma-delimited list in descending order of preference. Default: hd,sd,web,mobile"],
1098
    };
1099
 }
1100
 
1101
@@ -7421,6 +7308,9 @@
1102
        decode_entities($name);
1103
        decode_entities($episode);
1104
        decode_entities($desc);
1105
+       $name =~ s/\|/-/g;
1106
+       $episode =~ s/\|/-/g;
1107
+       $desc =~ s/\|/-/g;
1108
        $prog->{$pid} = main::progclass($prog_type)->new(
1109
            'pid'       => $pid,
1110
            'name'      => $name,
1111
@@ -7546,6 +7436,9 @@
1112
        decode_entities($name);
1113
        decode_entities($episode);
1114
        decode_entities($desc);
1115
+       $name =~ s/\|/-/g;
1116
+       $episode =~ s/\|/-/g;
1117
+       $desc =~ s/\|/-/g;
1118
        $prog->{$pid} = main::progclass($prog_type)->new(
1119
            'pid'       => $pid,
1120
            'name'      => $name,
1121
@@ -7571,48 +7464,48 @@
1122
    if ( ! $opt->{raw} ) {
1123
        $prog->ffmpeg_init();
1124
        # require ffmpeg for HLS
1125
-       if ( $mode =~ /^(hls|hvf|haf)/ && ! $opt->{raw} && ! main::exists_in_path('ffmpeg') ) {
1126
+       if ( $mode =~ /^hls/ && ! $opt->{raw} && ! main::exists_in_path('ffmpeg') ) {
1127
            main::logger "WARNING: Required ffmpeg utility not found - not converting .ts file(s)\n";
1128
            $opt->{raw} = 1;
1129
        }
1130
        # cannot convert hvf with avconv or ffmpeg < 2.5
1131
-       if ( $mode =~ /^hvf/ && ! $opt->{raw} ) {
1132
+       if ( $mode =~ /^hls/ && $prog->{type} eq "tv" && ! $opt->{raw} ) {
1133
            if ( $opt->{myffmpegav} ) {
1134
-               main::logger "WARNING: avconv does not support conversion of hvf downloads to MP4 - not converting .ts file\n";
1135
+               main::logger "WARNING: avconv does not support conversion of HLS downloads to MP4 - not converting .ts file\n";
1136
                $opt->{raw} = 1;
1137
            } elsif ( $opt->{myffmpegxx} ) {
1138
-               main::logger "WARNING: Unable to determine ffmpeg version - MP4 conversion for hvf downloads may fail\n";
1139
+               main::logger "WARNING: Unable to determine ffmpeg version - MP4 conversion for HLS downloads may fail\n";
1140
            } elsif ( ! $opt->{myffmpeg25} ) {
1141
-               main::logger "WARNING: Your version of ffmpeg ($opt->{myffmpegversion}) does not support conversion of hvf downloads to MP4 - not converting .ts file\n";
1142
+               main::logger "WARNING: Your version of ffmpeg ($opt->{myffmpegversion}) does not support conversion of HLS downloads to MP4 - not converting .ts file\n";
1143
                $opt->{raw} = 1;
1144
            }
1145
            if ( $opt->{myffmpegav} || $opt->{myffmpegxx} || ! $opt->{myffmpeg25} ) {
1146
-               main::logger "WARNING: ffmpeg 2.5 or higher is required to convert hvf downloads to MP4\n";
1147
+               main::logger "WARNING: ffmpeg 2.5 or higher is required to convert HLS downloads to MP4\n";
1148
                main::logger "WARNING: Use --raw to bypass MP4 conversion and retain .ts file\n";
1149
                main::logger "WARNING: Use --ffmpeg-force to override checks and force MP4 conversion attempt\n";
1150
            }
1151
        }
1152
        # require ffmpeg for DASH
1153
-       if ( $mode =~ /^(daf|dvf)/ && ( ! $opt->{raw} || $opt->{mpegts} ) && ! main::exists_in_path('ffmpeg') ) {
1154
+       if ( $mode =~ /^dash/ && ( ! $opt->{raw} || $opt->{mpegts} ) && ! main::exists_in_path('ffmpeg') ) {
1155
            main::logger "WARNING: Required ffmpeg utility not found - not converting .m4a and .m4v files\n";
1156
            $opt->{raw} = 1;
1157
            delete $opt->{mpegts};
1158
        }
1159
        # cannot convert dvf with avconv or ffmpeg < 3.0
1160
-       if ( $mode =~ /^dvf/ && ( ! $opt->{raw} || $opt->{mpegts} ) ) {
1161
+       if ( $mode =~ /^dash/ && $prog->{type} eq "tv" && ( ! $opt->{raw} || $opt->{mpegts} ) ) {
1162
            if ( $opt->{myffmpegav} ) {
1163
-               main::logger "WARNING: avconv does not support conversion of dvf downloads to MPEG-TS/MP4 - not converting .m4a and .m4v files\n";
1164
+               main::logger "WARNING: avconv does not support conversion of MPEG-DASH downloads to MPEG-TS/MP4 - not converting .m4a and .m4v files\n";
1165
                $opt->{raw} = 1;
1166
                delete $opt->{mpegts};
1167
            } elsif ( $opt->{myffmpegxx} ) {
1168
-               main::logger "WARNING: Unable to determine ffmpeg version - MPEG-TS/MP4 conversion for dvf downloads may fail\n";
1169
+               main::logger "WARNING: Unable to determine ffmpeg version - MPEG-TS/MP4 conversion for MPEG-DASH downloads may fail\n";
1170
            } elsif ( ! $opt->{myffmpeg30} ) {
1171
-               main::logger "WARNING: Your version of ffmpeg ($opt->{myffmpegversion}) does not support conversion of dvf downloads to MPEG-TS/MP4 - not converting .m4a and .m4v files\n";
1172
+               main::logger "WARNING: Your version of ffmpeg ($opt->{myffmpegversion}) does not support conversion of MPEG-DASH downloads to MPEG-TS/MP4 - not converting .m4a and .m4v files\n";
1173
                $opt->{raw} = 1;
1174
                delete $opt->{mpegts};
1175
            }
1176
            if ( $opt->{myffmpegav} || $opt->{myffmpegxx} || ! $opt->{myffmpeg30} ) {
1177
-               main::logger "WARNING: ffmpeg 3.0 or higher is required to convert dvf downloads to MPEG-TS/MP4\n";
1178
+               main::logger "WARNING: ffmpeg 3.0 or higher is required to convert MPEG-DASH downloads to MPEG-TS/MP4\n";
1179
                main::logger "WARNING: Use --raw to bypass MPEG-TS/MP4 conversion and retain .m4a and .m4v files\n";
1180
                main::logger "WARNING: Use --ffmpeg-force to override checks and force MPEG-TS/MP4 conversion attempt\n";
1181
            }
1182
@@ -7646,6 +7539,7 @@
1183
    if ( ! $opt->{nowrite} ) {
1184
        # set mode
1185
        $prog->{mode} = $mode;
1186
+       $prog->{quality} = $prog->qualities_from_modes($mode);
1187
 
1188
        # Disable proxy here if required
1189
        main::proxy_disable($ua) if $opt->{partialproxy};
1190
@@ -8030,9 +7924,9 @@
1191
 # Class cmdline Options
1192
 sub opt_format {
1193
    return {
1194
-       radiomode   => [ 1, "radiomode|radio-mode|amode=s", 'Recording', '--radiomode <mode>,<mode>,...', "Radio recording modes (overrides --modes): dafhigh,dafstd,dafmed,daflow,hafhigh,hafstd,hafmed,haflow,hlahigh,hlastd,hlsmed,hlalow. Shortcuts: best,better,good,worst,haf,hla,daf,hls,dash,high,std,med,low (default=hafhigh,hlahigh,dafhigh,hafstd,hlastd,dafstd,hafmed,hlamed,dafmed,haflow,hlalow,daflow)."],
1195
        commandradio    => [ 1, "commandradio|command-radio=s", 'Output', '--command-radio <command>', "User command to run after successful recording of radio programme. Use substitution parameters in command string (see docs for list). Overrides --command."],
1196
        outputradio => [ 1, "outputradio|output-radio=s", 'Output', '--output-radio <dir>', "Output directory for radio recordings (overrides --output)"],
1197
+       radiomode   => [ 0, "radiomode|radio-mode|amode|radioquality|radio-quality|aquality=s", 'Recording', '--radio-quality <quality>,<quality>,...', "Radio recording quality preference (overrides --quality): high,std,med,low,default (Aliases: 320k,128k,96k,48k). Comma-delimited list in descending order of preference. Default: high,std,med,low."],
1198
    };
1199
 }
1200
 
1201
@@ -9079,6 +8973,8 @@
1202
        $opt->{info} = 0;
1203
        # Do the recording (force --get option)
1204
        $opt->{get} = 1;
1205
+       # reset for PVR search
1206
+       delete $opt->{nowarnmoderemap};
1207
 
1208
        my $failcount = 0;
1209
        if ( $pvr->{$name}->{pid} ) {
1210
@@ -9097,7 +8993,6 @@
1211
        }
1212
        $retcode += $failcount;
1213
    }
1214
-   main::purge_warning( $hist, 30 );
1215
    return $retcode;
1216
 }
1217
 
1218
@@ -9173,7 +9068,7 @@
1219
        return 1;
1220
    }
1221
    # Parse valid options and create array (ignore options from the options files that have not been overriden on the cmdline)
1222
-   for ( grep !/(^cache|profiledir|encoding.*|silent|webrequest|future|nocopyright|^test|metadataonly|subsonly|thumbonly|cuesheetonly|tracklistonly|creditsonly|tagonly|^get|refresh|^save|^prefs|help|expiry|tree|terse|streaminfo|listformat|^list|showoptions|hide|info|pvr.*|^purge|markdownloaded)$/, sort {lc $a cmp lc $b} keys %{$opt_cmdline} ) {
1223
+   for ( grep !/(^cache|profiledir|encoding.*|silent|webrequest|future|nocopyright|^test|metadataonly|subsonly|thumbonly|cuesheetonly|tracklistonly|creditsonly|tagonly|^get|refresh|^save|^prefs|help|expiry|tree|terse|streaminfo|listformat|^list|showoptions|hide|info|pvr.*|markdownloaded)$/, sort {lc $a cmp lc $b} keys %{$opt_cmdline} ) {
1224
        if ( defined $opt_cmdline->{$_} ) {
1225
                push @options, "$_ $opt_cmdline->{$_}";
1226
                main::logger "DEBUG: Adding option $_ = $opt_cmdline->{$_}\n" if $opt->{debug};
1227
get_iplayer-3.28.tar.gz/get_iplayer.1 -> get_iplayer-3.29.tar.gz/get_iplayer.1 Changed
118
 
1
@@ -1,4 +1,4 @@
2
-.TH GET_IPLAYER "1" "December 2021" "Phil Lewis" "get_iplayer Manual"
3
+.TH GET_IPLAYER "1" "February 2022" "Phil Lewis" "get_iplayer Manual"
4
 .SH NAME
5
 get_iplayer \- Stream Recording tool and PVR for BBC iPlayer and BBC Sounds
6
 .SH SYNOPSIS
7
@@ -168,10 +168,13 @@
8
 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.
9
 .TP
10
 \fB\-\-audio\-only
11
-Only download audio stream for TV programme. 'hls' recording modes are not supported and ignored. Produces .m4a file. Implies \-\-force.
12
+Only download audio stream for TV programme. Produces .m4a file. Implies \-\-force.
13
 .TP
14
-\fB\-\-download\-abortonfail
15
-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.
16
+\fB\-\-download\-abort\-onfail
17
+Exit immediately if any stream to download. Use to avoid repeated failed download attempts if connection is dropped or access is blocked.
18
+.TP
19
+\fB\-\-exclude\-format <format>,<format>,...
20
+Comma\-separated list of media stream formats to ignore when recording. Valid values: hls,dash.
21
 .TP
22
 \fB\-\-exclude\-supplier <supplier>,<supplier>,...
23
 Comma\-separated list of media stream suppliers (CDNs) to skip. Possible values: akamai,limelight,bidi,cloudfront. Synonym: \-\-exclude\-cdn.
24
@@ -179,15 +182,15 @@
25
 \fB\-\-force
26
 Ignore programme history (unsets \-\-hide option also).
27
 .TP
28
-\fB\-\-fps25
29
-Use only 25fps streams for TV programmes (HD video not available).
30
-.TP
31
 \fB\-\-get, \-g
32
 Start recording matching programmes. Search terms required.
33
 .TP
34
 \fB\-\-hash
35
 Show recording progress as hashes
36
 .TP
37
+\fB\-\-include\-format <format>,<format>,...
38
+Comma\-separated list of media stream to use when recording. Overrides \-\-exclude\-format. Valid values: hls,dash
39
+.TP
40
 \fB\-\-include\-supplier <supplier>,<supplier>,...
41
 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.
42
 .TP
43
@@ -197,9 +200,6 @@
44
 \fB\-\-mark\-downloaded
45
 Mark programmes in search results or specified with \-\-pid/\-\-url as downloaded by inserting records in download history.
46
 .TP
47
-\fB\-\-modes <mode>,<mode>,...
48
-Recording modes.  See \-\-tvmode and \-\-radiomode (with \-\-long\-help) for available modes and defaults.  Shortcuts: tvbest,tvbetter,tvgood,tvworst,radiobest,radiobetter,radiogood,radioworst (default=default for programme type).
49
-.TP
50
 \fB\-\-no\-merge\-versions
51
 Do not merge programme versions with same name and duration.
52
 .TP
53
@@ -236,8 +236,11 @@
54
 \fB\-\-proxy, \-p <url>
55
 Web proxy URL, e.g., http://username:password@server:port or http://server:port.  Value of http_proxy environment variable (if present) will be used unless \-\-proxy is specified. Used for both HTTP and HTTPS. Overridden by \-\-no\-proxy.
56
 .TP
57
-\fB\-\-radiomode <mode>,<mode>,...
58
-Radio recording modes (overrides \-\-modes): dafhigh,dafstd,dafmed,daflow,hafhigh,hafstd,hafmed,haflow,hlahigh,hlastd,hlsmed,hlalow. Shortcuts: best,better,good,worst,haf,hla,daf,hls,dash,high,std,med,low (default=hafhigh,hlahigh,dafhigh,hafstd,hlastd,dafstd,hafmed,hlamed,dafmed,haflow,hlalow,daflow).
59
+\fB\-\-quality <quality>,<quality>,...
60
+TV and radio recording quality preference.  See \-\-tv\-quality and \-\-radio\-quality for available values and defaults. Default: default for programme type.
61
+.TP
62
+\fB\-\-radio\-quality <quality>,<quality>,...
63
+Radio recording quality preference (overrides \-\-quality): high,std,med,low,default (Aliases: 320k,128k,96k,48k). Comma\-delimited list in descending order of preference. Default: high,std,med,low.
64
 .TP
65
 \fB\-\-start <secs|hh:mm:ss>
66
 Recording/streaming start offset (actual start may be several seconds earlier for HLS and DASH streams)
67
@@ -251,8 +254,11 @@
68
 \fB\-\-test, \-t
69
 Test only \- no recording (only shows search results with \-\-pvr and \-\-pid\-recursive)
70
 .TP
71
-\fB\-\-tvmode <mode>,<mode>,...
72
-TV recording modes (overrides \-\-modes): dvfhd,dvfsd,dvfxsd,dvfhigh,dvfxhigh,dvflow,hvfhd,hvfsd,hvfxsd,hvfhigh,hvfxhigh,hvflow. Shortcuts: best,better,good,worst,dvf,hvf,dash,hls,hd,sd,high,low. 50fps streams (if available) preferred unless \-\-fps25 specified (default=hvfhd,dvfhd,hvfsd,dvfsd,hvfxsd,dvfxsd,hvfhigh,dvfhigh,hvfxhigh,dvfxhigh,hvflow,dvflow).
73
+\fB\-\-tv\-lower\-bitrate
74
+Prefer 25fps (or lower\-bitrate 50fps) streams for TV programmes if available.
75
+.TP
76
+\fB\-\-tv\-quality <quality>,<quality>,...
77
+TV recording quality preference (overrides \-\-quality): fhd,hd,sd,web,mobile,default (Aliases: 1080p,720p,540p,396p,288p). Comma\-delimited list in descending order of preference. Default: hd,sd,web,mobile
78
 .TP
79
 \fB\-\-url <url>,<url>,...
80
 Record the PIDs contained in the specified iPlayer episode URLs. Alias for \-\-pid.
81
@@ -422,9 +428,6 @@
82
 \fB\-\-limit\-matches <number>
83
 Limits the number of matching results for any search (and for every PVR search)
84
 .TP
85
-\fB\-\-nopurge
86
-Don't show warning about programmes recorded over 30 days ago
87
-.TP
88
 \fB\-\-prefs\-add
89
 Add/Change specified saved user or preset options
90
 .TP
91
@@ -563,17 +566,11 @@
92
 \fB\-\-index\-maxconn <number>
93
 Maximum number of connections to use for concurrent programme indexing.  Default: 5 Min: 1 Max: 10
94
 .TP
95
-\fB\-\-purge\-files
96
-Delete downloaded programmes more than 30 days old
97
-.TP
98
 \fB\-\-release\-check
99
 Forces check for new release if used on command line. Checks for new release weekly if saved in preferences.
100
 .TP
101
 \fB\-\-throttle <Mb/s>
102
 Bandwidth limit (in Mb/s) for media file download. Default: unlimited. Synonym: \-\-bw
103
-.TP
104
-\fB\-\-trim\-history <# days to retain>
105
-Remove download history entries older than number of days specified in option value.  Cannot specify 0 \- use 'all' to completely delete download history
106
 .SS "Deprecated Options:"
107
 .TP
108
 \fB\-\-no\-index\-concurrent
109
@@ -583,7 +580,7 @@
110
 .PP
111
 This manual page was originally written by Jonathan Wiltshire <jmw@debian.org> for the Debian project (but may be used by others).
112
 .SH COPYRIGHT NOTICE
113
-get_iplayer v3.28, Copyright (C) 2008\-2010 Phil Lewis
114
+get_iplayer v3.29, Copyright (C) 2008\-2010 Phil Lewis
115
   This program comes with ABSOLUTELY NO WARRANTY; for details use \-\-warranty.
116
   This is free software, and you are welcome to redistribute it under certain
117
   conditions; use \-\-conditions for details.
118
get_iplayer-3.28.tar.gz/get_iplayer.cgi -> get_iplayer-3.29.tar.gz/get_iplayer.cgi Changed
32
 
1
@@ -24,7 +24,7 @@
2
 # License: GPLv3 (see LICENSE.txt)
3
 #
4
 
5
-my $VERSION = 3.28;
6
+my $VERSION = 3.29;
7
 my $VERSION_TEXT;
8
 $VERSION_TEXT = sprintf("v%.2f", $VERSION) unless $VERSION_TEXT;
9
 
10
@@ -3130,8 +3130,8 @@
11
    };
12
 
13
    $opt->{MODES} = {
14
-       title   => 'Recording Modes', # Title
15
-       tooltip => 'Comma separated list of recording modes which should be tried in order. Default is "best" for HD TV (if available, with fallback to SD TV). Set to "better" (without quotes) for best available SD TV.  Set to "good" (without quotes) for lower-quality SD TV.', # Tooltip
16
+       title   => 'Recording Quality', # Title
17
+       tooltip => 'Comma separated list of recording quality settings which should be tried in order', # Tooltip
18
        webvar  => 'MODES', # webvar
19
        optkey  => 'modes', # option
20
        type    => 'text', # type
21
@@ -3259,8 +3259,8 @@
22
    };
23
 
24
    $opt->{FPS25} = {
25
-       title   => 'Use only 25fps streams',
26
-       tooltip => "Use only 25fps media streams. HD video not available.",
27
+       title   => 'Prefer lower-bitrate TV streams',
28
+       tooltip => "Prefer lower-bitrate TV streams",
29
        webvar  => 'FPS25',
30
        optkey  => 'fps25',
31
        type    => 'radioboolean',
32
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 3.29


Andrei Dziahel's avatar

develop7 accepted request almost 3 years ago

self-accept