mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2024-11-25 02:45:12 +00:00
parent
460a1c08b9
commit
455a15e2dc
14 changed files with 37 additions and 35 deletions
2
.github/ISSUE_TEMPLATE/1_broken_site.yml
vendored
2
.github/ISSUE_TEMPLATE/1_broken_site.yml
vendored
|
@ -1,4 +1,4 @@
|
||||||
name: Broken site support
|
name: Broken site
|
||||||
description: Report broken or misfunctioning site
|
description: Report broken or misfunctioning site
|
||||||
labels: [triage, site-bug]
|
labels: [triage, site-bug]
|
||||||
body:
|
body:
|
||||||
|
|
2
.github/ISSUE_TEMPLATE/5_feature_request.yml
vendored
2
.github/ISSUE_TEMPLATE/5_feature_request.yml
vendored
|
@ -11,6 +11,8 @@ body:
|
||||||
options:
|
options:
|
||||||
- label: I'm reporting a feature request
|
- label: I'm reporting a feature request
|
||||||
required: true
|
required: true
|
||||||
|
- label: I've looked through the [README](https://github.com/yt-dlp/yt-dlp#readme)
|
||||||
|
required: true
|
||||||
- label: I've verified that I'm running yt-dlp version **2022.01.21**. ([update instructions](https://github.com/yt-dlp/yt-dlp#update))
|
- label: I've verified that I'm running yt-dlp version **2022.01.21**. ([update instructions](https://github.com/yt-dlp/yt-dlp#update))
|
||||||
required: true
|
required: true
|
||||||
- label: I've searched the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues including closed ones. DO NOT post duplicates
|
- label: I've searched the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues including closed ones. DO NOT post duplicates
|
||||||
|
|
3
.github/ISSUE_TEMPLATE/6_question.yml
vendored
3
.github/ISSUE_TEMPLATE/6_question.yml
vendored
|
@ -25,7 +25,8 @@ body:
|
||||||
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
|
If your question contains "isn't working" or "can you add", this is most likely the wrong template.
|
||||||
|
If you are in doubt if this is the right template, use another template!
|
||||||
placeholder: WRITE QUESTION HERE
|
placeholder: WRITE QUESTION HERE
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
name: Broken site support
|
name: Broken site
|
||||||
description: Report broken or misfunctioning site
|
description: Report broken or misfunctioning site
|
||||||
labels: [triage, site-bug]
|
labels: [triage, site-bug]
|
||||||
body:
|
body:
|
||||||
|
|
|
@ -11,6 +11,8 @@ body:
|
||||||
options:
|
options:
|
||||||
- label: I'm reporting a feature request
|
- label: I'm reporting a feature request
|
||||||
required: true
|
required: true
|
||||||
|
- label: I've looked through the [README](https://github.com/yt-dlp/yt-dlp#readme)
|
||||||
|
required: true
|
||||||
- label: I've verified that I'm running yt-dlp version **%(version)s**. ([update instructions](https://github.com/yt-dlp/yt-dlp#update))
|
- label: I've verified that I'm running yt-dlp version **%(version)s**. ([update instructions](https://github.com/yt-dlp/yt-dlp#update))
|
||||||
required: true
|
required: true
|
||||||
- label: I've searched the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues including closed ones. DO NOT post duplicates
|
- label: I've searched the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues including closed ones. DO NOT post duplicates
|
||||||
|
|
3
.github/ISSUE_TEMPLATE_tmpl/6_question.yml
vendored
3
.github/ISSUE_TEMPLATE_tmpl/6_question.yml
vendored
|
@ -25,7 +25,8 @@ body:
|
||||||
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
|
If your question contains "isn't working" or "can you add", this is most likely the wrong template.
|
||||||
|
If you are in doubt if this is the right template, use another template!
|
||||||
placeholder: WRITE QUESTION HERE
|
placeholder: WRITE QUESTION HERE
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
|
@ -113,7 +113,7 @@ ### Is your question about yt-dlp?
|
||||||
|
|
||||||
### Are you willing to share account details if needed?
|
### Are you willing to share account details if needed?
|
||||||
|
|
||||||
The maintainers and potential contributors of the project often do not have an account for the website you are asking support for. So any developer interested in solving your issue may ask you for account details. It is your personal discression whether you are willing to share the account in order for the developer to try and solve your issue. However, if you are unwilling or unable to provide details, they obviously cannot work on the issue and it cannot be solved unless some developer who both has an account and is willing/able to contribute decides to solve it.
|
The maintainers and potential contributors of the project often do not have an account for the website you are asking support for. So any developer interested in solving your issue may ask you for account details. It is your personal discretion whether you are willing to share the account in order for the developer to try and solve your issue. However, if you are unwilling or unable to provide details, they obviously cannot work on the issue and it cannot be solved unless some developer who both has an account and is willing/able to contribute decides to solve it.
|
||||||
|
|
||||||
By sharing an account with anyone, you agree to bear all risks associated with it. The maintainers and yt-dlp can't be held responsible for any misuse of the credentials.
|
By sharing an account with anyone, you agree to bear all risks associated with it. The maintainers and yt-dlp can't be held responsible for any misuse of the credentials.
|
||||||
|
|
||||||
|
@ -254,6 +254,8 @@ ### Mandatory and optional metafields
|
||||||
|
|
||||||
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 all extractors must return a `title`, they must also allow it's extraction to be non-fatal.
|
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 all extractors must return a `title`, they must also allow it's extraction to be non-fatal.
|
||||||
|
|
||||||
|
For pornographic sites, appropriate `age_limit` must also be returned.
|
||||||
|
|
||||||
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 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.
|
||||||
|
|
13
README.md
13
README.md
|
@ -394,7 +394,7 @@ ## Geo-restriction:
|
||||||
option is not present) is used for the
|
option is not present) is used for the
|
||||||
actual downloading
|
actual downloading
|
||||||
--geo-bypass Bypass geographic restriction via faking
|
--geo-bypass Bypass geographic restriction via faking
|
||||||
X-Forwarded-For HTTP header
|
X-Forwarded-For HTTP header (default)
|
||||||
--no-geo-bypass Do not bypass geographic restriction via
|
--no-geo-bypass Do not bypass geographic restriction via
|
||||||
faking X-Forwarded-For HTTP header
|
faking X-Forwarded-For HTTP header
|
||||||
--geo-bypass-country CODE Force bypass geographic restriction with
|
--geo-bypass-country CODE Force bypass geographic restriction with
|
||||||
|
@ -1143,6 +1143,7 @@ # OUTPUT TEMPLATE
|
||||||
|
|
||||||
- `id` (string): Video identifier
|
- `id` (string): Video identifier
|
||||||
- `title` (string): Video title
|
- `title` (string): Video title
|
||||||
|
- `fulltitle` (string): Video title ignoring live timestamp and generic title
|
||||||
- `url` (string): Video URL
|
- `url` (string): Video URL
|
||||||
- `ext` (string): Video filename extension
|
- `ext` (string): Video filename extension
|
||||||
- `alt_title` (string): A secondary title of the video
|
- `alt_title` (string): A secondary title of the video
|
||||||
|
@ -1198,16 +1199,16 @@ # OUTPUT TEMPLATE
|
||||||
- `protocol` (string): The protocol that will be used for the actual download
|
- `protocol` (string): The protocol that will be used for the actual download
|
||||||
- `extractor` (string): Name of the extractor
|
- `extractor` (string): Name of the extractor
|
||||||
- `extractor_key` (string): Key name of the extractor
|
- `extractor_key` (string): Key name of the extractor
|
||||||
- `epoch` (numeric): Unix epoch when creating the file
|
- `epoch` (numeric): Unix epoch of when the information extraction was completed
|
||||||
- `autonumber` (numeric): Number that will be increased with each download, starting at `--autonumber-start`
|
- `autonumber` (numeric): Number that will be increased with each download, starting at `--autonumber-start`
|
||||||
- `video_autonumber` (numeric): Number that will be increased with each video
|
- `video_autonumber` (numeric): Number that will be increased with each video
|
||||||
- `n_entries` (numeric): Total number of extracted items in the playlist
|
- `n_entries` (numeric): Total number of extracted items in the playlist
|
||||||
- `playlist` (string): Name or id of the playlist that contains the video
|
- `playlist_id` (string): Identifier of the playlist that contains the video
|
||||||
|
- `playlist_title` (string): Name of the playlist that contains the video
|
||||||
|
- `playlist` (string): `playlist_id` or `playlist_title`
|
||||||
- `playlist_count` (numeric): Total number of items in the playlist. May not be known if entire playlist is not extracted
|
- `playlist_count` (numeric): Total number of items in the playlist. May not be known if entire playlist is not extracted
|
||||||
- `playlist_index` (numeric): Index of the video in the playlist padded with leading zeros according the final index
|
- `playlist_index` (numeric): Index of the video in the playlist padded with leading zeros according the final index
|
||||||
- `playlist_autonumber` (numeric): Position of the video in the playlist download queue padded with leading zeros according to the total length of the playlist
|
- `playlist_autonumber` (numeric): Position of the video in the playlist download queue padded with leading zeros according to the total length of the playlist
|
||||||
- `playlist_id` (string): Playlist identifier
|
|
||||||
- `playlist_title` (string): Playlist title
|
|
||||||
- `playlist_uploader` (string): Full name of the playlist uploader
|
- `playlist_uploader` (string): Full name of the playlist uploader
|
||||||
- `playlist_uploader_id` (string): Nickname or id of the playlist uploader
|
- `playlist_uploader_id` (string): Nickname or id of the playlist uploader
|
||||||
- `webpage_url` (string): A URL to the video webpage which if given to yt-dlp should allow to get the same result again
|
- `webpage_url` (string): A URL to the video webpage which if given to yt-dlp should allow to get the same result again
|
||||||
|
@ -1552,7 +1553,7 @@ # (https/ftps > http/ftp > m3u8_native > m3u8 > http_dash_segments ...)
|
||||||
|
|
||||||
|
|
||||||
# Download the best video with h264 codec, or the best video if there is no such video
|
# Download the best video with h264 codec, or the best video if there is no such video
|
||||||
$ yt-dlp -f "(bv*+ba/b)[vcodec^=avc1] / (bv*+ba/b)"
|
$ yt-dlp -f "(bv*[vcodec^=avc1]+ba) / (bv*+ba/b)"
|
||||||
|
|
||||||
# Download the best video with best codec no better than h264,
|
# Download the best video with best codec no better than h264,
|
||||||
# or the best video with worst codec if there is no such video
|
# or the best video with worst codec if there is no such video
|
||||||
|
|
|
@ -596,14 +596,14 @@ def check_deprecated(param, option, suggestion):
|
||||||
else:
|
else:
|
||||||
self.params['nooverwrites'] = not self.params['overwrites']
|
self.params['nooverwrites'] = not self.params['overwrites']
|
||||||
|
|
||||||
params.setdefault('forceprint', {})
|
self.params.setdefault('forceprint', {})
|
||||||
params.setdefault('print_to_file', {})
|
self.params.setdefault('print_to_file', {})
|
||||||
|
|
||||||
# Compatibility with older syntax
|
# Compatibility with older syntax
|
||||||
if not isinstance(params['forceprint'], dict):
|
if not isinstance(params['forceprint'], dict):
|
||||||
params['forceprint'] = {'video': params['forceprint']}
|
self.params['forceprint'] = {'video': params['forceprint']}
|
||||||
|
|
||||||
if params.get('bidi_workaround', False):
|
if self.params.get('bidi_workaround', False):
|
||||||
try:
|
try:
|
||||||
import pty
|
import pty
|
||||||
master, slave = pty.openpty()
|
master, slave = pty.openpty()
|
||||||
|
@ -631,7 +631,7 @@ def check_deprecated(param, option, suggestion):
|
||||||
|
|
||||||
if (sys.platform != 'win32'
|
if (sys.platform != 'win32'
|
||||||
and sys.getfilesystemencoding() in ['ascii', 'ANSI_X3.4-1968']
|
and sys.getfilesystemencoding() in ['ascii', 'ANSI_X3.4-1968']
|
||||||
and not params.get('restrictfilenames', False)):
|
and not self.params.get('restrictfilenames', False)):
|
||||||
# Unicode filesystem API will throw errors (#1474, #13027)
|
# Unicode filesystem API will throw errors (#1474, #13027)
|
||||||
self.report_warning(
|
self.report_warning(
|
||||||
'Assuming --restrict-filenames since file system encoding '
|
'Assuming --restrict-filenames since file system encoding '
|
||||||
|
@ -2240,10 +2240,7 @@ def restore_last_token(self):
|
||||||
|
|
||||||
def _calc_headers(self, info_dict):
|
def _calc_headers(self, info_dict):
|
||||||
res = std_headers.copy()
|
res = std_headers.copy()
|
||||||
|
res.update(info_dict.get('http_headers') or {})
|
||||||
add_headers = info_dict.get('http_headers')
|
|
||||||
if add_headers:
|
|
||||||
res.update(add_headers)
|
|
||||||
|
|
||||||
cookies = self._calc_cookies(info_dict)
|
cookies = self._calc_cookies(info_dict)
|
||||||
if cookies:
|
if cookies:
|
||||||
|
@ -2309,6 +2306,8 @@ def process_video_result(self, info_dict, download=True):
|
||||||
raise ExtractorError('Missing "id" field in extractor result', ie=info_dict['extractor'])
|
raise ExtractorError('Missing "id" field in extractor result', ie=info_dict['extractor'])
|
||||||
elif not info_dict.get('id'):
|
elif not info_dict.get('id'):
|
||||||
raise ExtractorError('Extractor failed to obtain "id"', ie=info_dict['extractor'])
|
raise ExtractorError('Extractor failed to obtain "id"', ie=info_dict['extractor'])
|
||||||
|
|
||||||
|
info_dict['fulltitle'] = info_dict.get('title')
|
||||||
if 'title' not in info_dict:
|
if 'title' not in info_dict:
|
||||||
raise ExtractorError('Missing "title" field in extractor result',
|
raise ExtractorError('Missing "title" field in extractor result',
|
||||||
video_id=info_dict['id'], ie=info_dict['extractor'])
|
video_id=info_dict['id'], ie=info_dict['extractor'])
|
||||||
|
@ -2422,9 +2421,6 @@ def sanitize_numeric_fields(info):
|
||||||
if not self.params.get('allow_unplayable_formats'):
|
if not self.params.get('allow_unplayable_formats'):
|
||||||
formats = [f for f in formats if not f.get('has_drm')]
|
formats = [f for f in formats if not f.get('has_drm')]
|
||||||
|
|
||||||
# backward compatibility
|
|
||||||
info_dict['fulltitle'] = info_dict['title']
|
|
||||||
|
|
||||||
if info_dict.get('is_live'):
|
if info_dict.get('is_live'):
|
||||||
get_from_start = bool(self.params.get('live_from_start'))
|
get_from_start = bool(self.params.get('live_from_start'))
|
||||||
formats = [f for f in formats if bool(f.get('is_from_start')) == get_from_start]
|
formats = [f for f in formats if bool(f.get('is_from_start')) == get_from_start]
|
||||||
|
|
|
@ -1291,7 +1291,8 @@ def _og_search_description(self, html, **kargs):
|
||||||
return self._og_search_property('description', html, fatal=False, **kargs)
|
return self._og_search_property('description', html, fatal=False, **kargs)
|
||||||
|
|
||||||
def _og_search_title(self, html, **kargs):
|
def _og_search_title(self, html, **kargs):
|
||||||
return self._og_search_property('title', html, fatal=False, **kargs)
|
kargs.setdefault('fatal', False)
|
||||||
|
return self._og_search_property('title', html, **kargs)
|
||||||
|
|
||||||
def _og_search_video_url(self, html, name='video url', secure=True, **kargs):
|
def _og_search_video_url(self, html, name='video url', secure=True, **kargs):
|
||||||
regexes = self._og_regexes('video') + self._og_regexes('video:url')
|
regexes = self._og_regexes('video') + self._og_regexes('video:url')
|
||||||
|
|
|
@ -5353,7 +5353,7 @@ def _real_extract(self, url):
|
||||||
|
|
||||||
|
|
||||||
class YoutubeMusicSearchURLIE(YoutubeTabBaseInfoExtractor):
|
class YoutubeMusicSearchURLIE(YoutubeTabBaseInfoExtractor):
|
||||||
IE_DESC = 'YouTube music search URLs with sorting and filter support'
|
IE_DESC = 'YouTube music search URLs with selectable sections (Eg: #songs)'
|
||||||
IE_NAME = 'youtube:music:search_url'
|
IE_NAME = 'youtube:music:search_url'
|
||||||
_VALID_URL = r'https?://music\.youtube\.com/search\?([^#]+&)?(?:search_query|q)=(?:[^&]+)(?:[&#]|$)'
|
_VALID_URL = r'https?://music\.youtube\.com/search\?([^#]+&)?(?:search_query|q)=(?:[^&]+)(?:[&#]|$)'
|
||||||
_TESTS = [{
|
_TESTS = [{
|
||||||
|
|
|
@ -381,10 +381,10 @@ def _dict_from_options_callback(
|
||||||
geo.add_option(
|
geo.add_option(
|
||||||
'--geo-bypass',
|
'--geo-bypass',
|
||||||
action='store_true', dest='geo_bypass', default=True,
|
action='store_true', dest='geo_bypass', default=True,
|
||||||
help='Bypass geographic restriction via faking X-Forwarded-For HTTP header')
|
help='Bypass geographic restriction via faking X-Forwarded-For HTTP header (default)')
|
||||||
geo.add_option(
|
geo.add_option(
|
||||||
'--no-geo-bypass',
|
'--no-geo-bypass',
|
||||||
action='store_false', dest='geo_bypass', default=True,
|
action='store_false', dest='geo_bypass',
|
||||||
help='Do not bypass geographic restriction via faking X-Forwarded-For HTTP header')
|
help='Do not bypass geographic restriction via faking X-Forwarded-For HTTP header')
|
||||||
geo.add_option(
|
geo.add_option(
|
||||||
'--geo-bypass-country', metavar='CODE',
|
'--geo-bypass-country', metavar='CODE',
|
||||||
|
|
|
@ -54,7 +54,7 @@ def detect_variant():
|
||||||
'win_dir': 'Auto-update is not supported for unpackaged windows executable; Re-download the latest release',
|
'win_dir': 'Auto-update is not supported for unpackaged windows executable; Re-download the latest release',
|
||||||
'mac_dir': 'Auto-update is not supported for unpackaged MacOS executable; Re-download the latest release',
|
'mac_dir': 'Auto-update is not supported for unpackaged MacOS executable; Re-download the latest release',
|
||||||
'source': 'You cannot update when running from source code; Use git to pull the latest changes',
|
'source': 'You cannot update when running from source code; Use git to pull the latest changes',
|
||||||
'unknown': 'It looks like you installed yt-dlp with a package manager, pip, setup.py or a tarball; Use that to update',
|
'unknown': 'It looks like you installed yt-dlp with a package manager, pip or setup.py; Use that to update',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1018,13 +1018,9 @@ def make_HTTPS_handler(params, **kwargs):
|
||||||
|
|
||||||
|
|
||||||
def bug_reports_message(before=';'):
|
def bug_reports_message(before=';'):
|
||||||
if ytdl_is_updateable():
|
msg = ('please report this issue on https://github.com/yt-dlp/yt-dlp , '
|
||||||
update_cmd = 'type yt-dlp -U to update'
|
'filling out the "Broken site" issue template properly. '
|
||||||
else:
|
'Confirm you are on the latest version using -U')
|
||||||
update_cmd = 'see https://github.com/yt-dlp/yt-dlp on how to update'
|
|
||||||
msg = 'please report this issue on https://github.com/yt-dlp/yt-dlp .'
|
|
||||||
msg += ' Make sure you are using the latest version; %s.' % update_cmd
|
|
||||||
msg += ' Be sure to call yt-dlp with the --verbose flag and include its complete output.'
|
|
||||||
|
|
||||||
before = before.rstrip()
|
before = before.rstrip()
|
||||||
if not before or before.endswith(('.', '!', '?')):
|
if not before or before.endswith(('.', '!', '?')):
|
||||||
|
|
Loading…
Reference in a new issue