[cleanup] Fix some typos (#2033)

Authored by: unit193
This commit is contained in:
Unit 193 2021-12-19 10:18:06 -05:00 committed by GitHub
parent dd0228ce1f
commit e75bb0d6c3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 58 additions and 58 deletions

View file

@ -215,7 +215,7 @@ ## Adding support for a new site
$ flake8 yt_dlp/extractor/yourextractor.py $ flake8 yt_dlp/extractor/yourextractor.py
1. Make sure your code works under all [Python](https://www.python.org/) versions supported by yt-dlp, namely CPython and PyPy for Python 3.6 and above. Backward compatability is not required for even older versions of Python. 1. Make sure your code works under all [Python](https://www.python.org/) versions supported by yt-dlp, namely CPython and PyPy for Python 3.6 and above. Backward compatibility is not required for even older versions of Python.
1. When the tests pass, [add](https://git-scm.com/docs/git-add) the new files, [commit](https://git-scm.com/docs/git-commit) them and [push](https://git-scm.com/docs/git-push) the result, like this: 1. When the tests pass, [add](https://git-scm.com/docs/git-add) the new files, [commit](https://git-scm.com/docs/git-commit) them and [push](https://git-scm.com/docs/git-push) the result, like this:
$ git add yt_dlp/extractor/extractors.py $ git add yt_dlp/extractor/extractors.py
@ -243,7 +243,7 @@ ### Mandatory and optional metafields
- `title` (media title) - `title` (media title)
- `url` (media download URL) or `formats` - `url` (media download URL) or `formats`
The aforementioned metafields are the critical data that the extraction does not make any sense without and if any of them fail to be extracted then the extractor is considered completely broken. While, in fact, only `id` is technically mandatory, due to compatability reasons, yt-dlp also treats `title` as mandatory. The extractor is allowed to return the info dict without url or formats in some special cases if it allows the user to extract usefull information with `--ignore-no-formats-error` - Eg: when the video is a live stream that has not started yet. The aforementioned metafields are the critical data that the extraction does not make any sense without and if any of them fail to be extracted then the extractor is considered completely broken. While, in fact, only `id` is technically mandatory, due to compatibility reasons, yt-dlp also treats `title` as mandatory. The extractor is allowed to return the info dict without url or formats in some special cases if it allows the user to extract usefull information with `--ignore-no-formats-error` - Eg: when the video is a live stream that has not started yet.
[Any field](yt_dlp/extractor/common.py#219-L426) apart from the aforementioned ones are considered **optional**. That means that extraction should be **tolerant** to situations when sources for these fields can potentially be unavailable (even if they are always available at the moment) and **future-proof** in order not to break the extraction of general purpose mandatory fields. [Any field](yt_dlp/extractor/common.py#219-L426) apart from the aforementioned ones are considered **optional**. That means that extraction should be **tolerant** to situations when sources for these fields can potentially be unavailable (even if they are always available at the moment) and **future-proof** in order not to break the extraction of general purpose mandatory fields.

View file

@ -97,7 +97,7 @@ # NEW FEATURES
* **Aria2c with HLS/DASH**: You can use `aria2c` as the external downloader for DASH(mpd) and HLS(m3u8) formats * **Aria2c with HLS/DASH**: You can use `aria2c` as the external downloader for DASH(mpd) and HLS(m3u8) formats
* **New and fixed extractors**: Many new extractors have been added and a lot of exisiting ones have been fixed. See the [changelog](Changelog.md) or the [list of supported sites](supportedsites.md) * **New and fixed extractors**: Many new extractors have been added and a lot of existing ones have been fixed. See the [changelog](Changelog.md) or the [list of supported sites](supportedsites.md)
* **New MSOs**: Philo, Spectrum, SlingTV, Cablevision, RCN * **New MSOs**: Philo, Spectrum, SlingTV, Cablevision, RCN
@ -127,7 +127,7 @@ ### Differences in default behavior
* `avconv` is not supported as as an alternative to `ffmpeg` * `avconv` is not supported as 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 prefered. 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
* Unlike youtube-dlc, yt-dlp does not allow merging multiple audio/video streams into one file by default (since this conflicts with the use of `-f bv*+ba`). If needed, this feature must be enabled using `--audio-multistreams` and `--video-multistreams`. You can also use `--compat-options multistreams` to enable both * Unlike youtube-dlc, yt-dlp does not allow merging multiple audio/video streams into one file by default (since this conflicts with the use of `-f bv*+ba`). If needed, this feature must be enabled using `--audio-multistreams` and `--video-multistreams`. You can also use `--compat-options multistreams` to enable both
* `--ignore-errors` is enabled by default. Use `--abort-on-error` or `--compat-options abort-on-error` to abort on errors instead * `--ignore-errors` is enabled by default. Use `--abort-on-error` or `--compat-options abort-on-error` to abort on errors instead
* When writing metadata files such as thumbnails, description or infojson, the same information (if available) is also written for playlists. Use `--no-write-playlist-metafiles` or `--compat-options no-playlist-metafiles` to not write these files * When writing metadata files such as thumbnails, description or infojson, the same information (if available) is also written for playlists. Use `--no-write-playlist-metafiles` or `--compat-options no-playlist-metafiles` to not write these files
@ -142,7 +142,7 @@ ### Differences in default behavior
* If `ffmpeg` is used as the downloader, the downloading and merging of formats happen in a single step when possible. Use `--compat-options no-direct-merge` to revert this * If `ffmpeg` is used as the downloader, the downloading and merging of formats happen in a single step when possible. Use `--compat-options no-direct-merge` to revert this
* Thumbnail embedding in `mp4` is done with mutagen if possible. Use `--compat-options embed-thumbnail-atomicparsley` to force the use of AtomicParsley instead * Thumbnail embedding in `mp4` is done with mutagen if possible. Use `--compat-options embed-thumbnail-atomicparsley` to force the use of AtomicParsley instead
* Some private fields such as filenames are removed by default from the infojson. Use `--no-clean-infojson` or `--compat-options no-clean-infojson` to revert this * Some private fields such as filenames are removed by default from the infojson. Use `--no-clean-infojson` or `--compat-options no-clean-infojson` to revert this
* When `--embed-subs` and `--write-subs` are used together, the subtitles are written to disk and also embedded in the media file. You can use just `--embed-subs` to embed the subs and automatically delete the seperate file. See [#630 (comment)](https://github.com/yt-dlp/yt-dlp/issues/630#issuecomment-893659460) for more info. `--compat-options no-keep-subs` can be used to revert this * When `--embed-subs` and `--write-subs` are used together, the subtitles are written to disk and also embedded in the media file. You can use just `--embed-subs` to embed the subs and automatically delete the separate file. See [#630 (comment)](https://github.com/yt-dlp/yt-dlp/issues/630#issuecomment-893659460) for more info. `--compat-options no-keep-subs` can be used to revert this
For ease of use, a few more compat options are available: For ease of use, a few more compat options are available:
* `--compat-options all`: Use all compat options * `--compat-options all`: Use all compat options
@ -248,9 +248,9 @@ ## DEPENDENCIES
On windows, [Microsoft Visual C++ 2010 SP1 Redistributable Package (x86)](https://download.microsoft.com/download/1/6/5/165255E7-1014-4D0A-B094-B6A430A6BFFC/vcredist_x86.exe) is also necessary to run yt-dlp. You probably already have this, but if the executable throws an error due to missing `MSVCR100.dll` you need to install it manually. On windows, [Microsoft Visual C++ 2010 SP1 Redistributable Package (x86)](https://download.microsoft.com/download/1/6/5/165255E7-1014-4D0A-B094-B6A430A6BFFC/vcredist_x86.exe) is also necessary to run yt-dlp. You probably already have this, but if the executable throws an error due to missing `MSVCR100.dll` you need to install it manually.
--> -->
While all the other dependancies 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 seperate 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. Licence [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)
@ -266,7 +266,7 @@ ## DEPENDENCIES
The Windows and MacOS standalone release binaries are already built with the python interpreter, mutagen, pycryptodomex and websockets included. The Windows and MacOS standalone release binaries are already built with the python interpreter, mutagen, pycryptodomex and websockets included.
**Note**: There are some regressions in newer ffmpeg versions that causes various issues when used alongside yt-dlp. Since ffmpeg is such an important dependancy, we provide [custom builds](https://github.com/yt-dlp/FFmpeg-Builds/wiki/Latest#latest-autobuilds) with patches for these issues at [yt-dlp/FFmpeg-Builds](https://github.com/yt-dlp/FFmpeg-Builds). See [the readme](https://github.com/yt-dlp/FFmpeg-Builds#patches-applied) for details on the specifc issues solved by these builds **Note**: There are some regressions in newer ffmpeg versions that causes various issues when used alongside yt-dlp. Since ffmpeg is such an important dependency, we provide [custom builds](https://github.com/yt-dlp/FFmpeg-Builds/wiki/Latest#latest-autobuilds) with patches for these issues at [yt-dlp/FFmpeg-Builds](https://github.com/yt-dlp/FFmpeg-Builds). See [the readme](https://github.com/yt-dlp/FFmpeg-Builds#patches-applied) for details on the specific issues solved by these builds
## COMPILE ## COMPILE
@ -924,7 +924,7 @@ ## Post-Processing Options:
(default) (default)
--force-keyframes-at-cuts Force keyframes around the chapters before --force-keyframes-at-cuts Force keyframes around the chapters before
removing/splitting them. Requires a removing/splitting them. Requires a
reencode and thus is very slow, but the re-encode and thus is very slow, but the
resulting video may have fewer artifacts resulting video may have fewer artifacts
around the cuts around the cuts
--no-force-keyframes-at-cuts Do not force keyframes around the chapters --no-force-keyframes-at-cuts Do not force keyframes around the chapters
@ -932,7 +932,7 @@ ## Post-Processing Options:
--use-postprocessor NAME[:ARGS] The (case sensitive) name of plugin --use-postprocessor NAME[:ARGS] The (case sensitive) name of plugin
postprocessors to be enabled, and postprocessors to be enabled, and
(optionally) arguments to be passed to it, (optionally) arguments to be passed to it,
seperated by a colon ":". ARGS are a separated by a colon ":". ARGS are a
semicolon ";" delimited list of NAME=VALUE. semicolon ";" delimited list of NAME=VALUE.
The "when" argument determines when the The "when" argument determines when the
postprocessor is invoked. It can be one of postprocessor is invoked. It can be one of
@ -1074,13 +1074,13 @@ # OUTPUT TEMPLATE
1. **Date/time Formatting**: Date/time fields can be formatted according to [strftime formatting](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes) by specifying it separated from the field name using a `>`. Eg: `%(duration>%H-%M-%S)s`, `%(upload_date>%Y-%m-%d)s`, `%(epoch-3600>%H-%M-%S)s` 1. **Date/time Formatting**: Date/time fields can be formatted according to [strftime formatting](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes) by specifying it separated from the field name using a `>`. Eg: `%(duration>%H-%M-%S)s`, `%(upload_date>%Y-%m-%d)s`, `%(epoch-3600>%H-%M-%S)s`
1. **Alternatives**: Alternate fields can be specified seperated with a `,`. Eg: `%(release_date>%Y,upload_date>%Y|Unknown)s` 1. **Alternatives**: Alternate fields can be specified separated with a `,`. Eg: `%(release_date>%Y,upload_date>%Y|Unknown)s`
1. **Replacement**: A replacement value can specified using a `&` separator. If the field is *not* empty, this replacement value will be used instead of the actual field content. This is done after alternate fields are considered; thus the replacement is used if *any* of the alternative fields is *not* empty. 1. **Replacement**: A replacement value can specified using a `&` separator. If the field is *not* empty, this replacement value will be used instead of the actual field content. This is done after alternate fields are considered; thus the replacement is used if *any* of the alternative fields is *not* empty.
1. **Default**: A literal default value can be specified for when the field is empty using a `|` seperator. This overrides `--output-na-template`. Eg: `%(uploader|Unknown)s` 1. **Default**: A literal default value can be specified for when the field is empty using a `|` separator. This overrides `--output-na-template`. Eg: `%(uploader|Unknown)s`
1. **More Conversions**: In addition to the normal format types `diouxXeEfFgGcrs`, `B`, `j`, `l`, `q` can be used for converting to **B**ytes, **j**son (flag `#` for pretty-printing), a comma seperated **l**ist (flag `#` for `\n` newline-seperated) and a string **q**uoted for the terminal (flag `#` to split a list into different arguments), respectively 1. **More Conversions**: In addition to the normal format types `diouxXeEfFgGcrs`, `B`, `j`, `l`, `q` can be used for converting to **B**ytes, **j**son (flag `#` for pretty-printing), a comma separated **l**ist (flag `#` for `\n` newline-separated) and a string **q**uoted for the terminal (flag `#` to split a list into different arguments), respectively
1. **Unicode normalization**: The format type `U` can be used for NFC [unicode normalization](https://docs.python.org/3/library/unicodedata.html#unicodedata.normalize). The alternate form flag (`#`) changes the normalization to NFD and the conversion flag `+` can be used for NFKC/NFKD compatibility equivalence normalization. Eg: `%(title)+.100U` is NFKC 1. **Unicode normalization**: The format type `U` can be used for NFC [unicode normalization](https://docs.python.org/3/library/unicodedata.html#unicodedata.normalize). The alternate form flag (`#`) changes the normalization to NFD and the conversion flag `+` can be used for NFKC/NFKD compatibility equivalence normalization. Eg: `%(title)+.100U` is NFKC
@ -1365,7 +1365,7 @@ ## Sorting Formats
- `vcodec`: Video Codec (`av01` > `vp9.2` > `vp9` > `h265` > `h264` > `vp8` > `h263` > `theora` > other > unknown) - `vcodec`: Video Codec (`av01` > `vp9.2` > `vp9` > `h265` > `h264` > `vp8` > `h263` > `theora` > other > unknown)
- `acodec`: Audio Codec (`opus` > `vorbis` > `aac` > `mp4a` > `mp3` > `eac3` > `ac3` > `dts` > other > unknown) - `acodec`: Audio Codec (`opus` > `vorbis` > `aac` > `mp4a` > `mp3` > `eac3` > `ac3` > `dts` > other > unknown)
- `codec`: Equivalent to `vcodec,acodec` - `codec`: Equivalent to `vcodec,acodec`
- `vext`: Video Extension (`mp4` > `webm` > `flv` > other > unknown). If `--prefer-free-formats` is used, `webm` is prefered. - `vext`: Video Extension (`mp4` > `webm` > `flv` > other > unknown). If `--prefer-free-formats` is used, `webm` is preferred.
- `aext`: Audio Extension (`m4a` > `aac` > `mp3` > `ogg` > `opus` > `webm` > other > unknown). If `--prefer-free-formats` is used, the order changes to `opus` > `ogg` > `webm` > `m4a` > `mp3` > `aac`. - `aext`: Audio Extension (`m4a` > `aac` > `mp3` > `ogg` > `opus` > `webm` > other > unknown). If `--prefer-free-formats` is used, the order changes to `opus` > `ogg` > `webm` > `m4a` > `mp3` > `aac`.
- `ext`: Equivalent to `vext,aext` - `ext`: Equivalent to `vext,aext`
- `filesize`: Exact filesize, if known in advance - `filesize`: Exact filesize, if known in advance
@ -1388,7 +1388,7 @@ ## Sorting Formats
The fields `hasvid` and `ie_pref` are always given highest priority in sorting, irrespective of the user-defined order. This behaviour can be changed by using `--format-sort-force`. Apart from these, the default order used is: `lang,quality,res,fps,hdr:12,codec:vp9.2,size,br,asr,proto,ext,hasaud,source,id`. The extractors may override this default order, but they cannot override the user-provided order. The fields `hasvid` and `ie_pref` are always given highest priority in sorting, irrespective of the user-defined order. This behaviour can be changed by using `--format-sort-force`. Apart from these, the default order used is: `lang,quality,res,fps,hdr:12,codec:vp9.2,size,br,asr,proto,ext,hasaud,source,id`. The extractors may override this default order, but they cannot override the user-provided order.
Note that the default has `codec:vp9.2`; i.e. `av1` is not prefered. Similarly, the default for hdr is `hdr:12`; i.e. dolby vision is not prefered. These choices are made since DV and AV1 formats are not yet fully compatible with most devices. This may be changed in the future as more devices become capable of smoothly playing back these formats. Note that the default has `codec:vp9.2`; i.e. `av1` is not preferred. Similarly, the default for hdr is `hdr:12`; i.e. dolby vision is not preferred. These choices are made since DV and AV1 formats are not yet fully compatible with most devices. This may be changed in the future as more devices become capable of smoothly playing back these formats.
If your format selector is `worst`, the last item is selected after sorting. This means it will select the format that is worst in all respects. Most of the time, what you actually want is the video with the smallest filesize instead. So it is generally better to use `-f best -S +size,+br,+res,+fps`. If your format selector is `worst`, the last item is selected after sorting. This means it will select the format that is worst in all respects. Most of the time, what you actually want is the video with the smallest filesize instead. So it is generally better to use `-f best -S +size,+br,+res,+fps`.
@ -1587,7 +1587,7 @@ #### youtube
* `player_skip`: Skip some network requests that are generally needed for robust extraction. One or more of `configs` (skip client configs), `webpage` (skip initial webpage), `js` (skip js player). While these options can help reduce the number of requests needed or avoid some rate-limiting, they could cause some issues. See [#860](https://github.com/yt-dlp/yt-dlp/pull/860) for more details * `player_skip`: Skip some network requests that are generally needed for robust extraction. One or more of `configs` (skip client configs), `webpage` (skip initial webpage), `js` (skip js player). While these options can help reduce the number of requests needed or avoid some rate-limiting, they could cause some issues. See [#860](https://github.com/yt-dlp/yt-dlp/pull/860) for more details
* `include_live_dash`: Include live dash formats (These formats don't download properly) * `include_live_dash`: Include live dash formats (These formats don't download properly)
* `comment_sort`: `top` or `new` (default) - choose comment sorting mode (on YouTube's side) * `comment_sort`: `top` or `new` (default) - choose comment sorting mode (on YouTube's side)
* `max_comments`: Limit the amount of comments to gather. Comma-seperated list of integers representing `max-comments,max-parents,max-replies,max-replies-per-thread`. Default is `all,all,all,all`. * `max_comments`: Limit the amount of comments to gather. Comma-separated list of integers representing `max-comments,max-parents,max-replies,max-replies-per-thread`. Default is `all,all,all,all`.
* E.g. `all,all,1000,10` will get a maximum of 1000 replies total, with up to 10 replies per thread. `1000,all,100` will get a maximum of 1000 comments, with a maximum of 100 replies total. * E.g. `all,all,1000,10` will get a maximum of 1000 replies total, with up to 10 replies per thread. `1000,all,100` will get a maximum of 1000 comments, with a maximum of 100 replies total.
* `max_comment_depth` Maximum depth for nested comments. YouTube supports depths 1 or 2 (default) * `max_comment_depth` Maximum depth for nested comments. YouTube supports depths 1 or 2 (default)
* **Deprecated**: Set `max-replies` to `0` or `all` in `max_comments` instead (e.g. `max_comments=all,all,0` to get no replies) * **Deprecated**: Set `max-replies` to `0` or `all` in `max_comments` instead (e.g. `max_comments=all,all,0` to get no replies)
@ -1655,7 +1655,7 @@ # EMBEDDING YT-DLP
class MyLogger: class MyLogger:
def debug(self, msg): def debug(self, msg):
# For compatability with youtube-dl, both debug and info are passed into debug # For compatibility with youtube-dl, both debug and info are passed into debug
# You can distinguish them by the prefix '[debug] ' # You can distinguish them by the prefix '[debug] '
if msg.startswith('[debug] '): if msg.startswith('[debug] '):
pass pass
@ -1708,7 +1708,7 @@ # See "progress_hooks" in the docstring of yt_dlp.YoutubeDL
'format_id': f'{best_video["format_id"]}+{best_audio["format_id"]}', 'format_id': f'{best_video["format_id"]}+{best_audio["format_id"]}',
'ext': best_video['ext'], 'ext': best_video['ext'],
'requested_formats': [best_video, best_audio], 'requested_formats': [best_video, best_audio],
# Must be + seperated list of protocols # Must be + separated list of protocols
'protocol': f'{best_video["protocol"]}+{best_audio["protocol"]}' 'protocol': f'{best_video["protocol"]}+{best_audio["protocol"]}'
} }

View file

@ -40,7 +40,7 @@ def main():
'--icon=devscripts/logo.ico', '--icon=devscripts/logo.ico',
'--upx-exclude=vcruntime140.dll', '--upx-exclude=vcruntime140.dll',
'--noconfirm', '--noconfirm',
*dependancy_options(), *dependency_options(),
*opts, *opts,
'yt_dlp/__main__.py', 'yt_dlp/__main__.py',
] ]
@ -73,11 +73,11 @@ def version_to_list(version):
return list(map(int, version_list)) + [0] * (4 - len(version_list)) return list(map(int, version_list)) + [0] * (4 - len(version_list))
def dependancy_options(): def dependency_options():
dependancies = [pycryptodome_module(), 'mutagen'] + collect_submodules('websockets') dependencies = [pycryptodome_module(), 'mutagen'] + collect_submodules('websockets')
excluded_modules = ['test', 'ytdlp_plugins', 'youtube-dl', 'youtube-dlc'] excluded_modules = ['test', 'ytdlp_plugins', 'youtube-dl', 'youtube-dlc']
yield from (f'--hidden-import={module}' for module in dependancies) yield from (f'--hidden-import={module}' for module in dependencies)
yield from (f'--exclude-module={module}' for module in excluded_modules) yield from (f'--exclude-module={module}' for module in excluded_modules)

View file

@ -2730,7 +2730,7 @@ def process_info(self, info_dict):
_infojson_written = self._write_info_json('video', info_dict, infofn) _infojson_written = self._write_info_json('video', info_dict, infofn)
if _infojson_written: if _infojson_written:
info_dict['infojson_filename'] = infofn info_dict['infojson_filename'] = infofn
# For backward compatability, even though it was a private field # For backward compatibility, even though it was a private field
info_dict['__infojson_filename'] = infofn info_dict['__infojson_filename'] = infofn
elif _infojson_written is None: elif _infojson_written is None:
return return

View file

@ -80,7 +80,7 @@ def _real_extract(self, url):
'format_id': '%s-%d' % (determine_protocol(f), tbr), 'format_id': '%s-%d' % (determine_protocol(f), tbr),
'tbr': tbr, 'tbr': tbr,
}) })
# 'tbr' was explicitly set to be prefered over 'height' originally, # 'tbr' was explicitly set to be preferred over 'height' originally,
# So this is being kept unless someone can confirm this is unnecessary # So this is being kept unless someone can confirm this is unnecessary
self._sort_formats(info_dict['formats'], ('tbr', 'res')) self._sort_formats(info_dict['formats'], ('tbr', 'res'))

View file

@ -87,7 +87,7 @@ def _named_object(self, namespace, obj):
return name return name
@staticmethod @staticmethod
def _seperate(expr, delim=',', max_split=None): def _separate(expr, delim=',', max_split=None):
if not expr: if not expr:
return return
counters = {k: 0 for k in _MATCHING_PARENS.values()} counters = {k: 0 for k in _MATCHING_PARENS.values()}
@ -111,17 +111,17 @@ def _seperate(expr, delim=',', max_split=None):
yield expr[start:] yield expr[start:]
@staticmethod @staticmethod
def _seperate_at_paren(expr, delim): def _separate_at_paren(expr, delim):
seperated = list(JSInterpreter._seperate(expr, delim, 1)) separated = list(JSInterpreter._separate(expr, delim, 1))
if len(seperated) < 2: if len(separated) < 2:
raise ExtractorError(f'No terminating paren {delim} in {expr}') raise ExtractorError(f'No terminating paren {delim} in {expr}')
return seperated[0][1:].strip(), seperated[1].strip() return separated[0][1:].strip(), separated[1].strip()
def interpret_statement(self, stmt, local_vars, allow_recursion=100): def interpret_statement(self, stmt, local_vars, allow_recursion=100):
if allow_recursion < 0: if allow_recursion < 0:
raise ExtractorError('Recursion limit reached') raise ExtractorError('Recursion limit reached')
sub_statements = list(self._seperate(stmt, ';')) sub_statements = list(self._separate(stmt, ';'))
stmt = (sub_statements or ['']).pop() stmt = (sub_statements or ['']).pop()
for sub_stmt in sub_statements: for sub_stmt in sub_statements:
ret, should_abort = self.interpret_statement(sub_stmt, local_vars, allow_recursion - 1) ret, should_abort = self.interpret_statement(sub_stmt, local_vars, allow_recursion - 1)
@ -151,7 +151,7 @@ def interpret_expression(self, expr, local_vars, allow_recursion):
return None return None
if expr.startswith('{'): if expr.startswith('{'):
inner, outer = self._seperate_at_paren(expr, '}') inner, outer = self._separate_at_paren(expr, '}')
inner, should_abort = self.interpret_statement(inner, local_vars, allow_recursion - 1) inner, should_abort = self.interpret_statement(inner, local_vars, allow_recursion - 1)
if not outer or should_abort: if not outer or should_abort:
return inner return inner
@ -159,7 +159,7 @@ def interpret_expression(self, expr, local_vars, allow_recursion):
expr = json.dumps(inner) + outer expr = json.dumps(inner) + outer
if expr.startswith('('): if expr.startswith('('):
inner, outer = self._seperate_at_paren(expr, ')') inner, outer = self._separate_at_paren(expr, ')')
inner = self.interpret_expression(inner, local_vars, allow_recursion) inner = self.interpret_expression(inner, local_vars, allow_recursion)
if not outer: if not outer:
return inner return inner
@ -167,16 +167,16 @@ def interpret_expression(self, expr, local_vars, allow_recursion):
expr = json.dumps(inner) + outer expr = json.dumps(inner) + outer
if expr.startswith('['): if expr.startswith('['):
inner, outer = self._seperate_at_paren(expr, ']') inner, outer = self._separate_at_paren(expr, ']')
name = self._named_object(local_vars, [ name = self._named_object(local_vars, [
self.interpret_expression(item, local_vars, allow_recursion) self.interpret_expression(item, local_vars, allow_recursion)
for item in self._seperate(inner)]) for item in self._separate(inner)])
expr = name + outer expr = name + outer
m = re.match(r'try\s*', expr) m = re.match(r'try\s*', expr)
if m: if m:
if expr[m.end()] == '{': if expr[m.end()] == '{':
try_expr, expr = self._seperate_at_paren(expr[m.end():], '}') try_expr, expr = self._separate_at_paren(expr[m.end():], '}')
else: else:
try_expr, expr = expr[m.end() - 1:], '' try_expr, expr = expr[m.end() - 1:], ''
ret, should_abort = self.interpret_statement(try_expr, local_vars, allow_recursion - 1) ret, should_abort = self.interpret_statement(try_expr, local_vars, allow_recursion - 1)
@ -187,23 +187,23 @@ def interpret_expression(self, expr, local_vars, allow_recursion):
m = re.match(r'catch\s*\(', expr) m = re.match(r'catch\s*\(', expr)
if m: if m:
# We ignore the catch block # We ignore the catch block
_, expr = self._seperate_at_paren(expr, '}') _, expr = self._separate_at_paren(expr, '}')
return self.interpret_statement(expr, local_vars, allow_recursion - 1)[0] return self.interpret_statement(expr, local_vars, allow_recursion - 1)[0]
m = re.match(r'for\s*\(', expr) m = re.match(r'for\s*\(', expr)
if m: if m:
constructor, remaining = self._seperate_at_paren(expr[m.end() - 1:], ')') constructor, remaining = self._separate_at_paren(expr[m.end() - 1:], ')')
if remaining.startswith('{'): if remaining.startswith('{'):
body, expr = self._seperate_at_paren(remaining, '}') body, expr = self._separate_at_paren(remaining, '}')
else: else:
m = re.match(r'switch\s*\(', remaining) # FIXME m = re.match(r'switch\s*\(', remaining) # FIXME
if m: if m:
switch_val, remaining = self._seperate_at_paren(remaining[m.end() - 1:], ')') switch_val, remaining = self._separate_at_paren(remaining[m.end() - 1:], ')')
body, expr = self._seperate_at_paren(remaining, '}') body, expr = self._separate_at_paren(remaining, '}')
body = 'switch(%s){%s}' % (switch_val, body) body = 'switch(%s){%s}' % (switch_val, body)
else: else:
body, expr = remaining, '' body, expr = remaining, ''
start, cndn, increment = self._seperate(constructor, ';') start, cndn, increment = self._separate(constructor, ';')
if self.interpret_statement(start, local_vars, allow_recursion - 1)[1]: if self.interpret_statement(start, local_vars, allow_recursion - 1)[1]:
raise ExtractorError( raise ExtractorError(
f'Premature return in the initialization of a for loop in {constructor!r}') f'Premature return in the initialization of a for loop in {constructor!r}')
@ -225,14 +225,14 @@ def interpret_expression(self, expr, local_vars, allow_recursion):
m = re.match(r'switch\s*\(', expr) m = re.match(r'switch\s*\(', expr)
if m: if m:
switch_val, remaining = self._seperate_at_paren(expr[m.end() - 1:], ')') switch_val, remaining = self._separate_at_paren(expr[m.end() - 1:], ')')
switch_val = self.interpret_expression(switch_val, local_vars, allow_recursion) switch_val = self.interpret_expression(switch_val, local_vars, allow_recursion)
body, expr = self._seperate_at_paren(remaining, '}') body, expr = self._separate_at_paren(remaining, '}')
items = body.replace('default:', 'case default:').split('case ')[1:] items = body.replace('default:', 'case default:').split('case ')[1:]
for default in (False, True): for default in (False, True):
matched = False matched = False
for item in items: for item in items:
case, stmt = [i.strip() for i in self._seperate(item, ':', 1)] case, stmt = [i.strip() for i in self._separate(item, ':', 1)]
if default: if default:
matched = matched or case == 'default' matched = matched or case == 'default'
elif not matched: elif not matched:
@ -249,8 +249,8 @@ def interpret_expression(self, expr, local_vars, allow_recursion):
break break
return self.interpret_statement(expr, local_vars, allow_recursion - 1)[0] return self.interpret_statement(expr, local_vars, allow_recursion - 1)[0]
# Comma seperated statements # Comma separated statements
sub_expressions = list(self._seperate(expr)) sub_expressions = list(self._separate(expr))
expr = sub_expressions.pop().strip() if sub_expressions else '' expr = sub_expressions.pop().strip() if sub_expressions else ''
for sub_expr in sub_expressions: for sub_expr in sub_expressions:
self.interpret_expression(sub_expr, local_vars, allow_recursion) self.interpret_expression(sub_expr, local_vars, allow_recursion)
@ -318,11 +318,11 @@ def interpret_expression(self, expr, local_vars, allow_recursion):
return val[idx] return val[idx]
for op, opfunc in _OPERATORS: for op, opfunc in _OPERATORS:
seperated = list(self._seperate(expr, op)) separated = list(self._separate(expr, op))
if len(seperated) < 2: if len(separated) < 2:
continue continue
right_val = seperated.pop() right_val = separated.pop()
left_val = op.join(seperated) left_val = op.join(separated)
left_val, should_abort = self.interpret_statement( left_val, should_abort = self.interpret_statement(
left_val, local_vars, allow_recursion - 1) left_val, local_vars, allow_recursion - 1)
if should_abort: if should_abort:
@ -341,7 +341,7 @@ def interpret_expression(self, expr, local_vars, allow_recursion):
member = remove_quotes(m.group('member') or m.group('member2')) member = remove_quotes(m.group('member') or m.group('member2'))
arg_str = expr[m.end():] arg_str = expr[m.end():]
if arg_str.startswith('('): if arg_str.startswith('('):
arg_str, remaining = self._seperate_at_paren(arg_str, ')') arg_str, remaining = self._separate_at_paren(arg_str, ')')
else: else:
arg_str, remaining = None, arg_str arg_str, remaining = None, arg_str
@ -370,7 +370,7 @@ def eval_method():
# Function call # Function call
argvals = [ argvals = [
self.interpret_expression(v, local_vars, allow_recursion) self.interpret_expression(v, local_vars, allow_recursion)
for v in self._seperate(arg_str)] for v in self._separate(arg_str)]
if obj == str: if obj == str:
if member == 'fromCharCode': if member == 'fromCharCode':
@ -453,7 +453,7 @@ def eval_method():
fname = m.group('func') fname = m.group('func')
argvals = tuple([ argvals = tuple([
int(v) if v.isdigit() else local_vars[v] int(v) if v.isdigit() else local_vars[v]
for v in self._seperate(m.group('args'))]) for v in self._separate(m.group('args'))])
if fname in local_vars: if fname in local_vars:
return local_vars[fname](argvals) return local_vars[fname](argvals)
elif fname not in self._functions: elif fname not in self._functions:
@ -495,7 +495,7 @@ def extract_function_code(self, funcname):
(?P<code>\{(?:(?!};)[^"]|"([^"]|\\")*")+\})''' % ( (?P<code>\{(?:(?!};)[^"]|"([^"]|\\")*")+\})''' % (
re.escape(funcname), re.escape(funcname), re.escape(funcname)), re.escape(funcname), re.escape(funcname), re.escape(funcname)),
self.code) self.code)
code, _ = self._seperate_at_paren(func_m.group('code'), '}') # refine the match code, _ = self._separate_at_paren(func_m.group('code'), '}') # refine the match
if func_m is None: if func_m is None:
raise ExtractorError('Could not find JS function %r' % funcname) raise ExtractorError('Could not find JS function %r' % funcname)
return func_m.group('args').split(','), code return func_m.group('args').split(','), code
@ -510,7 +510,7 @@ def extract_function_from_code(self, argnames, code, *global_stack):
if mobj is None: if mobj is None:
break break
start, body_start = mobj.span() start, body_start = mobj.span()
body, remaining = self._seperate_at_paren(code[body_start - 1:], '}') body, remaining = self._separate_at_paren(code[body_start - 1:], '}')
name = self._named_object( name = self._named_object(
local_vars, local_vars,
self.extract_function_from_code( self.extract_function_from_code(
@ -532,7 +532,7 @@ def resf(args, **kwargs):
**kwargs **kwargs
}) })
var_stack = LocalNameSpace(local_vars, *global_stack) var_stack = LocalNameSpace(local_vars, *global_stack)
for stmt in self._seperate(code.replace('\n', ''), ';'): for stmt in self._separate(code.replace('\n', ''), ';'):
ret, should_abort = self.interpret_statement(stmt, var_stack) ret, should_abort = self.interpret_statement(stmt, var_stack)
if should_abort: if should_abort:
break break

View file

@ -1434,7 +1434,7 @@ def _dict_from_options_callback(
action='store_true', dest='force_keyframes_at_cuts', default=False, action='store_true', dest='force_keyframes_at_cuts', default=False,
help=( help=(
'Force keyframes around the chapters before removing/splitting them. ' 'Force keyframes around the chapters before removing/splitting them. '
'Requires a reencode and thus is very slow, but the resulting video ' 'Requires a re-encode and thus is very slow, but the resulting video '
'may have fewer artifacts around the cuts')) 'may have fewer artifacts around the cuts'))
postproc.add_option( postproc.add_option(
'--no-force-keyframes-at-cuts', '--no-force-keyframes-at-cuts',
@ -1452,7 +1452,7 @@ def _dict_from_options_callback(
'process': lambda val: dict(_postprocessor_opts_parser(*val.split(':', 1))) 'process': lambda val: dict(_postprocessor_opts_parser(*val.split(':', 1)))
}, help=( }, help=(
'The (case sensitive) name of plugin postprocessors to be enabled, ' 'The (case sensitive) name of plugin postprocessors to be enabled, '
'and (optionally) arguments to be passed to it, seperated by a colon ":". ' 'and (optionally) arguments to be passed to it, separated by a colon ":". '
'ARGS are a semicolon ";" delimited list of NAME=VALUE. ' 'ARGS are a semicolon ";" delimited list of NAME=VALUE. '
'The "when" argument determines when the postprocessor is invoked. ' 'The "when" argument determines when the postprocessor is invoked. '
'It can be one of "pre_process" (after extraction), ' 'It can be one of "pre_process" (after extraction), '