[cleanup] Misc cleanup

Closes #1942 #1976 #2020 #2058 #1984
This commit is contained in:
pukkandan 2021-12-23 07:12:26 +05:30
parent e0fd95737d
commit b69fd25c25
No known key found for this signature in database
GPG Key ID: 0F00D95A001F4698
30 changed files with 109 additions and 68 deletions

View File

@ -34,7 +34,7 @@ body:
label: Example URLs label: Example URLs
description: | description: |
Provide all kinds of example URLs for which support should be added Provide all kinds of example URLs for which support should be added
value: | placeholder: |
- Single video: https://www.youtube.com/watch?v=BaW_jenozKc - Single video: https://www.youtube.com/watch?v=BaW_jenozKc
- Single video: https://youtu.be/BaW_jenozKc - Single video: https://youtu.be/BaW_jenozKc
- Playlist: https://www.youtube.com/playlist?list=PL4lCao7KL_QFVb7Iudeipvc2BCavECqzc - Playlist: https://www.youtube.com/playlist?list=PL4lCao7KL_QFVb7Iudeipvc2BCavECqzc

View File

@ -1,6 +1,6 @@
name: Broken site support name: Broken site support
description: Report broken or misfunctioning site description: Report broken or misfunctioning site
labels: [triage, extractor-bug] labels: [triage, site-bug]
body: body:
- type: checkboxes - type: checkboxes
id: checklist id: checklist

View File

@ -1,5 +1,5 @@
name: Site feature request name: Site feature request
description: Request a new functionality for a site description: Request a new functionality for a supported site
labels: [triage, site-enhancement] labels: [triage, site-enhancement]
body: body:
- type: checkboxes - type: checkboxes
@ -47,3 +47,26 @@ body:
placeholder: WRITE DESCRIPTION HERE placeholder: WRITE DESCRIPTION HERE
validations: validations:
required: true required: true
- type: textarea
id: log
attributes:
label: Verbose log
description: |
Provide the complete verbose output of yt-dlp that demonstrates the need for the enhancement.
Add the `-Uv` flag to your command line you run yt-dlp with (`yt-dlp -Uv <your command line>`), copy the WHOLE output and insert it below.
It should look similar to this:
placeholder: |
[debug] Command-line config: ['-Uv', 'http://www.youtube.com/watch?v=BaW_jenozKc']
[debug] Portable config file: yt-dlp.conf
[debug] Portable config: ['-i']
[debug] Encodings: locale cp1252, fs utf-8, stdout utf-8, stderr utf-8, pref cp1252
[debug] yt-dlp version %(version)s (exe)
[debug] Python version 3.8.8 (CPython 64bit) - Windows-10-10.0.19041-SP0
[debug] exe versions: ffmpeg 3.0.1, ffprobe 3.0.1
[debug] Optional libraries: Cryptodome, keyring, mutagen, sqlite, websockets
[debug] Proxy map: {}
yt-dlp is up to date (%(version)s)
<more lines>
render: shell
validations:
required: true

View File

@ -1,4 +1,4 @@
name: Feature request request name: Feature request
description: Request a new functionality unrelated to any particular site or extractor description: Request a new functionality unrelated to any particular site or extractor
labels: [triage, enhancement] labels: [triage, enhancement]
body: body:

View File

@ -9,7 +9,7 @@ body:
description: | description: |
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp: Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
options: options:
- label: I'm asking a question and not reporting a bug/feature request - label: I'm asking a question and **not** reporting a bug/feature request
required: true required: true
- label: I've looked through the [README](https://github.com/yt-dlp/yt-dlp#readme) - label: I've looked through the [README](https://github.com/yt-dlp/yt-dlp#readme)
required: true required: true
@ -24,7 +24,8 @@ body:
description: | description: |
Ask your question in an arbitrary form. Ask your question in an arbitrary form.
Please make sure it's worded well enough to be understood, see [is-the-description-of-the-issue-itself-sufficient](https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient). Please make sure it's worded well enough to be understood, see [is-the-description-of-the-issue-itself-sufficient](https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient).
Provide any additional information and as much context and examples as possible Provide any additional information and as much context and examples as possible.
If your question contains "isn't working" or "can you add", this is most likely the wrong template
placeholder: WRITE QUESTION HERE placeholder: WRITE QUESTION HERE
validations: validations:
required: true required: true

27
.gitignore vendored
View File

@ -1,27 +1,32 @@
# Config # Config
*.conf *.conf
*.spec
cookies cookies
*cookies.txt *cookies.txt
.netrc .netrc
# Downloaded # Downloaded
*.3gp
*.annotations.xml *.annotations.xml
*.ape
*.aria2 *.aria2
*.avi
*.description *.description
*.desktop
*.dump *.dump
*.flac
*.flv
*.frag *.frag
*.frag.aria2
*.frag.urls *.frag.urls
*.info.json *.info.json
*.live_chat.json
*.part*
*.unknown_video
*.ytdl
.cache/
*.3gp
*.ape
*.avi
*.desktop
*.flac
*.flv
*.jpeg *.jpeg
*.jpg *.jpg
*.live_chat.json
*.m4a *.m4a
*.m4v *.m4v
*.mhtml *.mhtml
@ -31,23 +36,18 @@ cookies
*.mp4 *.mp4
*.ogg *.ogg
*.opus *.opus
*.part
*.part-*
*.png *.png
*.sbv *.sbv
*.srt *.srt
*.swf *.swf
*.swp *.swp
*.ttml *.ttml
*.unknown_video
*.url *.url
*.vtt *.vtt
*.wav *.wav
*.webloc *.webloc
*.webm *.webm
*.webp *.webp
*.ytdl
.cache/
# Allow config/media files in testdata # Allow config/media files in testdata
!test/** !test/**
@ -86,7 +86,6 @@ README.txt
*.1 *.1
*.bash-completion *.bash-completion
*.fish *.fish
*.exe
*.tar.gz *.tar.gz
*.zsh *.zsh
*.spec *.spec

View File

@ -227,6 +227,13 @@ ## Adding support for a new site
In any case, thank you very much for your contributions! In any case, thank you very much for your contributions!
**Tip:** To test extractors that require login information, create a file `test/local_parameters.json` and add `"usenetrc": true` or your username and password in it:
```json
{
"username": "your user name",
"password": "your password"
}
```
## yt-dlp coding conventions ## yt-dlp coding conventions

View File

@ -28,6 +28,7 @@ ## [coletdjnz](https://github.com/coletdjnz)
[![gh-sponsor](https://img.shields.io/badge/_-Sponsor-red.svg?logo=githubsponsors&labelColor=555555&style=for-the-badge)](https://github.com/sponsors/coletdjnz) [![gh-sponsor](https://img.shields.io/badge/_-Sponsor-red.svg?logo=githubsponsors&labelColor=555555&style=for-the-badge)](https://github.com/sponsors/coletdjnz)
* YouTube improvements including: age-gate bypass, private playlists, multiple-clients (to avoid throttling) and a lot of under-the-hood improvements * YouTube improvements including: age-gate bypass, private playlists, multiple-clients (to avoid throttling) and a lot of under-the-hood improvements
* Added support for downloading YoutubeWebArchive videos

View File

@ -13,10 +13,10 @@ pypi-files: AUTHORS Changelog.md LICENSE README.md README.txt supportedsites com
.PHONY: all clean install test tar pypi-files completions ot offlinetest codetest supportedsites .PHONY: all clean install test tar pypi-files completions ot offlinetest codetest supportedsites
clean-test: clean-test:
rm -rf *.3gp *.annotations.xml *.ape *.avi *.description *.dump *.flac *.flv *.frag *.frag.aria2 *.frag.urls \ rm -rf test/testdata/player-*.js tmp/ *.annotations.xml *.aria2 *.description *.dump *.frag \
*.info.json *.jpeg *.jpg *.live_chat.json *.m4a *.m4v *.mkv *.mp3 *.mp4 *.ogg *.opus *.part* *.png *.sbv *.srt \ *.frag.aria2 *.frag.urls *.info.json *.live_chat.json *.part* *.unknown_video *.ytdl \
*.swf *.swp *.ttml *.vtt *.wav *.webm *.webp *.mhtml *.mov *.unknown_video *.desktop *.url *.webloc *.ytdl \ *.3gp *.ape *.avi *.desktop *.flac *.flv *.jpeg *.jpg *.m4a *.m4v *.mhtml *.mkv *.mov *.mp3 \
test/testdata/player-*.js tmp/ *.mp4 *.ogg *.opus *.png *.sbv *.srt *.swf *.swp *.ttml *.url *.vtt *.wav *.webloc *.webm *.webp
clean-dist: clean-dist:
rm -rf yt-dlp.1.temp.md yt-dlp.1 README.txt MANIFEST build/ dist/ .coverage cover/ yt-dlp.tar.gz completions/ \ rm -rf yt-dlp.1.temp.md yt-dlp.1 README.txt MANIFEST build/ dist/ .coverage cover/ yt-dlp.tar.gz completions/ \
yt_dlp/extractor/lazy_extractors.py *.spec CONTRIBUTING.md.tmp yt-dlp yt-dlp.exe yt_dlp.egg-info/ AUTHORS .mailmap yt_dlp/extractor/lazy_extractors.py *.spec CONTRIBUTING.md.tmp yt-dlp yt-dlp.exe yt_dlp.egg-info/ AUTHORS .mailmap

View File

@ -71,7 +71,7 @@
# NEW FEATURES # NEW FEATURES
* Based on **youtube-dl 2021.06.06 [commit/379f52a](https://github.com/ytdl-org/youtube-dl/commit/379f52a4954013767219d25099cce9e0f9401961)** and **youtube-dlc 2020.11.11-3 [commit/98e248f](https://github.com/blackjack4494/yt-dlc/commit/98e248faa49e69d795abc60f7cdefcf91e2612aa)**: You get all the features and patches of [youtube-dlc](https://github.com/blackjack4494/yt-dlc) in addition to the latest [youtube-dl](https://github.com/ytdl-org/youtube-dl) * Based on **youtube-dl 2021.12.17 [commit/5014bd6](https://github.com/ytdl-org/youtube-dl/commit/5014bd67c22b421207b2650d4dc874b95b36dda1)** and **youtube-dlc 2020.11.11-3 [commit/f9401f2](https://github.com/blackjack4494/yt-dlc/commit/f9401f2a91987068139c5f757b12fc711d4c0cee)**: You get all the features and patches of [youtube-dlc](https://github.com/blackjack4494/yt-dlc) in addition to the latest [youtube-dl](https://github.com/ytdl-org/youtube-dl)
* **[SponsorBlock Integration](#sponsorblock-options)**: You can mark/remove sponsor sections in youtube videos by utilizing the [SponsorBlock](https://sponsor.ajay.app) API * **[SponsorBlock Integration](#sponsorblock-options)**: You can mark/remove sponsor sections in youtube videos by utilizing the [SponsorBlock](https://sponsor.ajay.app) API
@ -125,7 +125,7 @@ ### Differences in default behavior
Some of yt-dlp's default options are different from that of youtube-dl and youtube-dlc: Some of yt-dlp's default options are different from that of youtube-dl and youtube-dlc:
* The options `--auto-number` (`-A`), `--title` (`-t`) and `--literal` (`-l`), no longer work. See [removed options](#Removed) for details * The options `--auto-number` (`-A`), `--title` (`-t`) and `--literal` (`-l`), no longer work. See [removed options](#Removed) for details
* `avconv` is not supported as as an alternative to `ffmpeg` * `avconv` is not supported as an alternative to `ffmpeg`
* The default [output template](#output-template) is `%(title)s [%(id)s].%(ext)s`. There is no real reason for this change. This was changed before yt-dlp was ever made public and now there are no plans to change it back to `%(title)s-%(id)s.%(ext)s`. Instead, you may use `--compat-options filename` * The default [output template](#output-template) is `%(title)s [%(id)s].%(ext)s`. There is no real reason for this change. This was changed before yt-dlp was ever made public and now there are no plans to change it back to `%(title)s-%(id)s.%(ext)s`. Instead, you may use `--compat-options filename`
* The default [format sorting](#sorting-formats) is different from youtube-dl and prefers higher resolution and better codecs rather than higher bitrates. You can use the `--format-sort` option to change this to any order you prefer, or use `--compat-options format-sort` to use youtube-dl's sorting order * The default [format sorting](#sorting-formats) is different from youtube-dl and prefers higher resolution and better codecs rather than higher bitrates. You can use the `--format-sort` option to change this to any order you prefer, or use `--compat-options format-sort` to use youtube-dl's sorting order
* The default format selector is `bv*+ba/b`. This means that if a combined video + audio format that is better than the best video-only format is found, the former will be preferred. Use `-f bv+ba/b` or `--compat-options format-spec` to revert this * The default format selector is `bv*+ba/b`. This means that if a combined video + audio format that is better than the best video-only format is found, the former will be preferred. Use `-f bv+ba/b` or `--compat-options format-spec` to revert this
@ -172,7 +172,7 @@ ### Using the release binary
``` ```
``` ```
sudo aria2c https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp sudo aria2c https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp --dir /usr/local/bin -o yt-dlp
sudo chmod a+rx /usr/local/bin/yt-dlp sudo chmod a+rx /usr/local/bin/yt-dlp
``` ```
@ -251,7 +251,7 @@ ## DEPENDENCIES
While all the other dependencies are optional, `ffmpeg` and `ffprobe` are highly recommended While all the other dependencies are optional, `ffmpeg` and `ffprobe` are highly recommended
* [**ffmpeg** and **ffprobe**](https://www.ffmpeg.org) - Required for [merging separate video and audio files](#format-selection) as well as for various [post-processing](#post-processing-options) tasks. Licence [depends on the build](https://www.ffmpeg.org/legal.html) * [**ffmpeg** and **ffprobe**](https://www.ffmpeg.org) - Required for [merging separate video and audio files](#format-selection) as well as for various [post-processing](#post-processing-options) tasks. License [depends on the build](https://www.ffmpeg.org/legal.html)
* [**mutagen**](https://github.com/quodlibet/mutagen) - For embedding thumbnail in certain formats. Licensed under [GPLv2+](https://github.com/quodlibet/mutagen/blob/master/COPYING) * [**mutagen**](https://github.com/quodlibet/mutagen) - For embedding thumbnail in certain formats. Licensed under [GPLv2+](https://github.com/quodlibet/mutagen/blob/master/COPYING)
* [**pycryptodomex**](https://github.com/Legrandin/pycryptodome) - For decrypting AES-128 HLS streams and various other data. Licensed under [BSD2](https://github.com/Legrandin/pycryptodome/blob/master/LICENSE.rst) * [**pycryptodomex**](https://github.com/Legrandin/pycryptodome) - For decrypting AES-128 HLS streams and various other data. Licensed under [BSD2](https://github.com/Legrandin/pycryptodome/blob/master/LICENSE.rst)
* [**websockets**](https://github.com/aaugustin/websockets) - For downloading over websocket. Licensed under [BSD3](https://github.com/aaugustin/websockets/blob/main/LICENSE) * [**websockets**](https://github.com/aaugustin/websockets) - For downloading over websocket. Licensed under [BSD3](https://github.com/aaugustin/websockets/blob/main/LICENSE)

View File

@ -27,13 +27,13 @@
except Exception: except Exception:
GIT_HEAD = None GIT_HEAD = None
VERSION_FILE = f''' VERSION_FILE = f'''\
# Autogenerated by devscripts/update-version.py # Autogenerated by devscripts/update-version.py
__version__ = {VERSION!r} __version__ = {VERSION!r}
RELEASE_GIT_HEAD = {GIT_HEAD!r} RELEASE_GIT_HEAD = {GIT_HEAD!r}
'''.lstrip() '''
with open('yt_dlp/version.py', 'wt') as f: with open('yt_dlp/version.py', 'wt') as f:
f.write(VERSION_FILE) f.write(VERSION_FILE)

5
docs/Contributing.md Normal file
View File

@ -0,0 +1,5 @@
---
orphan: true
---
```{include} ../Contributing.md
```

View File

@ -780,8 +780,8 @@ def expect_same_infodict(out):
test('%(title5)+#U', 'a\u0301e\u0301i\u0301 A') test('%(title5)+#U', 'a\u0301e\u0301i\u0301 A')
test('%(height)D', '1K') test('%(height)D', '1K')
test('%(height)5.2D', ' 1.08K') test('%(height)5.2D', ' 1.08K')
test('%(title4).10F', ('foo \'bar\' ', 'foo \'bar\'#'))
test('%(title4)#F', 'foo_bar_test') test('%(title4)#F', 'foo_bar_test')
test('%(title4).10F', ('foo \'bar\' ', 'foo \'bar\'' + ('#' if compat_os_name == 'nt' else ' ')))
if compat_os_name == 'nt': if compat_os_name == 'nt':
test('%(title4)q', ('"foo \\"bar\\" test"', "'foo _'bar_' test'")) test('%(title4)q', ('"foo \\"bar\\" test"', "'foo _'bar_' test'"))
test('%(formats.:.id)#q', ('"id 1" "id 2" "id 3"', "'id 1' 'id 2' 'id 3'")) test('%(formats.:.id)#q', ('"id 1" "id 2" "id 3"', "'id 1' 'id 2' 'id 3'"))

View File

@ -82,6 +82,10 @@
'https://www.youtube.com/s/player/f1ca6900/player_ias.vflset/en_US/base.js', 'https://www.youtube.com/s/player/f1ca6900/player_ias.vflset/en_US/base.js',
'cu3wyu6LQn2hse', 'jvxetvmlI9AN9Q', 'cu3wyu6LQn2hse', 'jvxetvmlI9AN9Q',
), ),
(
'https://www.youtube.com/s/player/8040e515/player_ias.vflset/en_US/base.js',
'wvOFaY-yjgDuIEg5', 'HkfBFDHmgw4rsw',
),
] ]

View File

@ -1495,7 +1495,7 @@ def process_ie_result(self, ie_result, download=True, extra_info=None):
self.write_debug('Additional URLs: "%s"' % '", "'.join(additional_urls)) self.write_debug('Additional URLs: "%s"' % '", "'.join(additional_urls))
ie_result['additional_entries'] = [ ie_result['additional_entries'] = [
self.extract_info( self.extract_info(
url, download, extra_info, url, download, extra_info=extra_info,
force_generic_extractor=self.params.get('force_generic_extractor')) force_generic_extractor=self.params.get('force_generic_extractor'))
for url in additional_urls for url in additional_urls
] ]
@ -2474,9 +2474,6 @@ def is_wellformed(f):
info_dict['id'], automatic_captions, 'automatic captions') info_dict['id'], automatic_captions, 'automatic captions')
self.list_subtitles(info_dict['id'], subtitles, 'subtitles') self.list_subtitles(info_dict['id'], subtitles, 'subtitles')
if self.params.get('listformats') or interactive_format_selection: if self.params.get('listformats') or interactive_format_selection:
if not info_dict.get('formats') and not info_dict.get('url'):
self.to_screen('%s has no formats' % info_dict['id'])
else:
self.list_formats(info_dict) self.list_formats(info_dict)
if list_only: if list_only:
# Without this printing, -F --print-json will not work # Without this printing, -F --print-json will not work
@ -3361,6 +3358,11 @@ def _list_format_headers(self, *headers):
return headers return headers
def list_formats(self, info_dict): def list_formats(self, info_dict):
if not info_dict.get('formats') and not info_dict.get('url'):
self.to_screen('%s has no formats' % info_dict['id'])
return
self.to_screen('[info] Available formats for %s:' % info_dict['id'])
formats = info_dict.get('formats', [info_dict]) formats = info_dict.get('formats', [info_dict])
new_format = self.params.get('listformats_table', True) is not False new_format = self.params.get('listformats_table', True) is not False
if new_format: if new_format:
@ -3375,7 +3377,7 @@ def list_formats(self, info_dict):
delim, delim,
format_field(f, 'filesize', ' \t%s', func=format_bytes) + format_field(f, 'filesize_approx', '~\t%s', func=format_bytes), format_field(f, 'filesize', ' \t%s', func=format_bytes) + format_field(f, 'filesize_approx', '~\t%s', func=format_bytes),
format_field(f, 'tbr', '\t%dk'), format_field(f, 'tbr', '\t%dk'),
shorten_protocol_name(f.get('protocol', '').replace('native', 'n')), shorten_protocol_name(f.get('protocol', '')),
delim, delim,
format_field(f, 'vcodec', default='unknown').replace( format_field(f, 'vcodec', default='unknown').replace(
'none', 'none',
@ -3411,8 +3413,6 @@ def list_formats(self, info_dict):
if f.get('preference') is None or f['preference'] >= -1000] if f.get('preference') is None or f['preference'] >= -1000]
header_line = ['format code', 'extension', 'resolution', 'note'] header_line = ['format code', 'extension', 'resolution', 'note']
self.to_screen(
'[info] Available formats for %s:' % info_dict['id'])
self.to_stdout(render_table( self.to_stdout(render_table(
header_line, table, header_line, table,
extra_gap=(0 if new_format else 1), extra_gap=(0 if new_format else 1),

View File

@ -18,6 +18,7 @@
) )
from .compat import ( from .compat import (
compat_getpass, compat_getpass,
compat_os_name,
compat_shlex_quote, compat_shlex_quote,
workaround_optparse_bug9161, workaround_optparse_bug9161,
) )
@ -95,7 +96,8 @@ def _real_main(argv=None):
if opts.batchfile is not None: if opts.batchfile is not None:
try: try:
if opts.batchfile == '-': if opts.batchfile == '-':
write_string('Reading URLs from stdin:\n') write_string('Reading URLs from stdin - EOF (%s) to end:\n' % (
'Ctrl+Z' if compat_os_name == 'nt' else 'Ctrl+D'))
batchfd = sys.stdin batchfd = sys.stdin
else: else:
batchfd = io.open( batchfd = io.open(
@ -518,7 +520,7 @@ def report_unplayable_conflict(opt_name, arg, default=False, allowed=None):
if len(dur) == 2 and all(t is not None for t in dur): if len(dur) == 2 and all(t is not None for t in dur):
remove_ranges.append(tuple(dur)) remove_ranges.append(tuple(dur))
continue continue
parser.error(f'invalid --remove-chapters time range {regex!r}. Must be of the form ?start-end') parser.error(f'invalid --remove-chapters time range {regex!r}. Must be of the form *start-end')
try: try:
remove_chapters_patterns.append(re.compile(regex)) remove_chapters_patterns.append(re.compile(regex))
except re.error as err: except re.error as err:

View File

@ -397,6 +397,7 @@ def download(self, filename, info_dict, subtitle=False):
'status': 'finished', 'status': 'finished',
'total_bytes': os.path.getsize(encodeFilename(filename)), 'total_bytes': os.path.getsize(encodeFilename(filename)),
}, info_dict) }, info_dict)
self._finish_multiline_status()
return True, False return True, False
if subtitle is False: if subtitle is False:

View File

@ -340,7 +340,7 @@ def _find_secret_formats(self, formats, video_id):
yield { yield {
**base_format, **base_format,
'format_id': join_nonempty('sec', height), 'format_id': join_nonempty('sec', height),
'url': re.sub(r'(QualityLevels\()\d+(\))', fr'\<1>{bitrate}\2', base_url), 'url': re.sub(r'(QualityLevels\()\d+(\))', fr'\1{bitrate}\2', base_url),
'width': int_or_none(video_quality.attrib.get('MaxWidth')), 'width': int_or_none(video_quality.attrib.get('MaxWidth')),
'tbr': bitrate / 1000.0, 'tbr': bitrate / 1000.0,
'height': height, 'height': height,

View File

@ -616,7 +616,7 @@ def extract(self, url):
kwargs = { kwargs = {
'video_id': e.video_id or self.get_temp_id(url), 'video_id': e.video_id or self.get_temp_id(url),
'ie': self.IE_NAME, 'ie': self.IE_NAME,
'tb': e.traceback, 'tb': e.traceback or sys.exc_info()[2],
'expected': e.expected, 'expected': e.expected,
'cause': e.cause 'cause': e.cause
} }
@ -1574,7 +1574,7 @@ class FormatSort:
'vcodec': {'type': 'ordered', 'regex': True, 'vcodec': {'type': 'ordered', 'regex': True,
'order': ['av0?1', 'vp0?9.2', 'vp0?9', '[hx]265|he?vc?', '[hx]264|avc', 'vp0?8', 'mp4v|h263', 'theora', '', None, 'none']}, 'order': ['av0?1', 'vp0?9.2', 'vp0?9', '[hx]265|he?vc?', '[hx]264|avc', 'vp0?8', 'mp4v|h263', 'theora', '', None, 'none']},
'acodec': {'type': 'ordered', 'regex': True, 'acodec': {'type': 'ordered', 'regex': True,
'order': ['opus', 'vorbis', 'aac', 'mp?4a?', 'mp3', 'e-?a?c-?3', 'ac-?3', 'dts', '', None, 'none']}, 'order': ['[af]lac', 'wav|aiff', 'opus', 'vorbis', 'aac', 'mp?4a?', 'mp3', 'e-?a?c-?3', 'ac-?3', 'dts', '', None, 'none']},
'hdr': {'type': 'ordered', 'regex': True, 'field': 'dynamic_range', 'hdr': {'type': 'ordered', 'regex': True, 'field': 'dynamic_range',
'order': ['dv', '(hdr)?12', r'(hdr)?10\+', '(hdr)?10', 'hlg', '', 'sdr', None]}, 'order': ['dv', '(hdr)?12', r'(hdr)?10\+', '(hdr)?10', 'hlg', '', 'sdr', None]},
'proto': {'type': 'ordered', 'regex': True, 'field': 'protocol', 'proto': {'type': 'ordered', 'regex': True, 'field': 'protocol',

View File

@ -41,7 +41,7 @@ class FancodeVodIE(InfoExtractor):
_ACCESS_TOKEN = None _ACCESS_TOKEN = None
_NETRC_MACHINE = 'fancode' _NETRC_MACHINE = 'fancode'
_LOGIN_HINT = 'Use "--user refresh --password <refresh_token>" to login using a refresh token' _LOGIN_HINT = 'Use "--username refresh --password <refresh_token>" to login using a refresh token'
headers = { headers = {
'content-type': 'application/json', 'content-type': 'application/json',

View File

@ -258,8 +258,7 @@ def _extract_urls(webpage):
webpage) webpage)
def _extract_count(self, pattern, webpage, name): def _extract_count(self, pattern, webpage, name):
return str_to_int(self._search_regex( return str_to_int(self._search_regex(pattern, webpage, '%s count' % name, default=None))
pattern, webpage, '%s count' % name, fatal=False))
def _real_extract(self, url): def _real_extract(self, url):
mobj = self._match_valid_url(url) mobj = self._match_valid_url(url)

View File

@ -99,7 +99,7 @@ class RoosterTeethIE(RoosterTeethBaseIE):
'series': 'Million Dollars, But...', 'series': 'Million Dollars, But...',
'episode': 'Million Dollars, But... The Game Announcement', 'episode': 'Million Dollars, But... The Game Announcement',
}, },
'skip_download': 'm3u8', 'params': {'skip_download': True},
}, { }, {
'url': 'https://roosterteeth.com/watch/rwby-bonus-25', 'url': 'https://roosterteeth.com/watch/rwby-bonus-25',
'info_dict': { 'info_dict': {
@ -112,7 +112,7 @@ class RoosterTeethIE(RoosterTeethBaseIE):
'thumbnail': r're:^https?://.*\.(png|jpe?g)$', 'thumbnail': r're:^https?://.*\.(png|jpe?g)$',
'ext': 'mp4', 'ext': 'mp4',
}, },
'skip_download': 'm3u8', 'params': {'skip_download': True},
}, { }, {
'url': 'http://achievementhunter.roosterteeth.com/episode/off-topic-the-achievement-hunter-podcast-2016-i-didn-t-think-it-would-pass-31', 'url': 'http://achievementhunter.roosterteeth.com/episode/off-topic-the-achievement-hunter-podcast-2016-i-didn-t-think-it-would-pass-31',
'only_matching': True, 'only_matching': True,

View File

@ -130,7 +130,7 @@ def _login(self):
elif username is not None: elif username is not None:
self.report_warning( self.report_warning(
'Login using username and password is not currently supported. ' 'Login using username and password is not currently supported. '
'Use "--user oauth --password <oauth_token>" to login using an oauth token') 'Use "--username oauth --password <oauth_token>" to login using an oauth token')
r''' r'''
def genDevId(): def genDevId():

View File

@ -6,9 +6,10 @@
from ..utils import ( from ..utils import (
ExtractorError, ExtractorError,
smuggle_url, smuggle_url,
str_or_none,
traverse_obj, traverse_obj,
unsmuggle_url,
unified_strdate, unified_strdate,
unsmuggle_url,
) )
import itertools import itertools
@ -25,9 +26,9 @@ def _extract_from_playlist_data(self, value):
'id': voice_id, 'id': voice_id,
'title': compat_str(value.get('PlaylistName')), 'title': compat_str(value.get('PlaylistName')),
'uploader': value.get('SpeakerName'), 'uploader': value.get('SpeakerName'),
'uploader_id': compat_str(value.get('SpeakerId')), 'uploader_id': str_or_none(value.get('SpeakerId')),
'channel': value.get('ChannelName'), 'channel': value.get('ChannelName'),
'channel_id': compat_str(value.get('ChannelId')), 'channel_id': str_or_none(value.get('ChannelId')),
'upload_date': upload_date, 'upload_date': upload_date,
} }

View File

@ -668,7 +668,7 @@ def _dict_from_options_callback(
downloader.add_option( downloader.add_option(
'-N', '--concurrent-fragments', '-N', '--concurrent-fragments',
dest='concurrent_fragment_downloads', metavar='N', default=1, type=int, dest='concurrent_fragment_downloads', metavar='N', default=1, type=int,
help='Number of fragments of a dash/hlsnative video that should be download concurrently (default is %default)') help='Number of fragments of a dash/hlsnative video that should be downloaded concurrently (default is %default)')
downloader.add_option( downloader.add_option(
'-r', '--limit-rate', '--rate-limit', '-r', '--limit-rate', '--rate-limit',
dest='ratelimit', metavar='RATE', dest='ratelimit', metavar='RATE',

View File

@ -99,7 +99,7 @@ def f(info):
class MetadataFromFieldPP(MetadataParserPP): class MetadataFromFieldPP(MetadataParserPP):
@classmethod @classmethod
def to_action(cls, f): def to_action(cls, f):
match = re.match(r'(?P<in>.*?)(?<!\\):(?P<out>.+)$', f) match = re.match(r'(?s)(?P<in>.*?)(?<!\\):(?P<out>.+)$', f)
if match is None: if match is None:
raise ValueError(f'it should be FROM:TO, not {f!r}') raise ValueError(f'it should be FROM:TO, not {f!r}')
return ( return (

View File

@ -257,7 +257,7 @@ def update_self(to_screen, verbose, opener):
write_string( write_string(
'DeprecationWarning: "yt_dlp.update.update_self" is deprecated and may be removed in a future version. ' 'DeprecationWarning: "yt_dlp.update.update_self" is deprecated and may be removed in a future version. '
'Use "yt_dlp.update.run_update(ydl)" instead') 'Use "yt_dlp.update.run_update(ydl)" instead\n')
class FakeYDL(): class FakeYDL():
_opener = opener _opener = opener

View File

@ -1862,7 +1862,6 @@ def _windows_write_string(s, out):
False if it has yet to be written out.""" False if it has yet to be written out."""
# Adapted from http://stackoverflow.com/a/3259271/35070 # Adapted from http://stackoverflow.com/a/3259271/35070
import ctypes
import ctypes.wintypes import ctypes.wintypes
WIN_OUTPUT_IDS = { WIN_OUTPUT_IDS = {
@ -3193,30 +3192,29 @@ def parse_codecs(codecs_str):
if codec in ('avc1', 'avc2', 'avc3', 'avc4', 'vp9', 'vp8', 'hev1', 'hev2', if codec in ('avc1', 'avc2', 'avc3', 'avc4', 'vp9', 'vp8', 'hev1', 'hev2',
'h263', 'h264', 'mp4v', 'hvc1', 'av1', 'theora', 'dvh1', 'dvhe'): 'h263', 'h264', 'mp4v', 'hvc1', 'av1', 'theora', 'dvh1', 'dvhe'):
if not vcodec: if not vcodec:
vcodec = '.'.join(parts[:4]) if codec in ('vp9', 'av1') else full_codec vcodec = '.'.join(parts[:4]) if codec in ('vp9', 'av1', 'hvc1') else full_codec
if codec in ('dvh1', 'dvhe'): if codec in ('dvh1', 'dvhe'):
hdr = 'DV' hdr = 'DV'
elif codec == 'av1' and len(parts) > 3 and parts[3] == '10': elif codec == 'av1' and len(parts) > 3 and parts[3] == '10':
hdr = 'HDR10' hdr = 'HDR10'
elif full_codec.replace('0', '').startswith('vp9.2'): elif full_codec.replace('0', '').startswith('vp9.2'):
hdr = 'HDR10' hdr = 'HDR10'
elif codec in ('mp4a', 'opus', 'vorbis', 'mp3', 'aac', 'ac-3', 'ec-3', 'eac3', 'dtsc', 'dtse', 'dtsh', 'dtsl'): elif codec in ('flac', 'mp4a', 'opus', 'vorbis', 'mp3', 'aac', 'ac-3', 'ec-3', 'eac3', 'dtsc', 'dtse', 'dtsh', 'dtsl'):
if not acodec: if not acodec:
acodec = full_codec acodec = full_codec
else: else:
write_string('WARNING: Unknown codec %s\n' % full_codec, sys.stderr) write_string('WARNING: Unknown codec %s\n' % full_codec, sys.stderr)
if not vcodec and not acodec: if vcodec or acodec:
if len(split_codecs) == 2:
return {
'vcodec': split_codecs[0],
'acodec': split_codecs[1],
}
else:
return { return {
'vcodec': vcodec or 'none', 'vcodec': vcodec or 'none',
'acodec': acodec or 'none', 'acodec': acodec or 'none',
'dynamic_range': hdr, 'dynamic_range': hdr,
} }
elif len(split_codecs) == 2:
return {
'vcodec': split_codecs[0],
'acodec': split_codecs[1],
}
return {} return {}