[youtube] Show if video is private, unlisted etc in new field availability (#188)

Closes: #185, https://github.com/ytdl-org/youtube-dl/issues/25631

Authored by: colethedj, pukkandan
This commit is contained in:
Matthew 2021-03-21 21:23:34 +00:00 committed by pukkandan
parent 037cc66ec8
commit c224251aad
No known key found for this signature in database
GPG key ID: 0F00D95A001F4698
3 changed files with 46 additions and 2 deletions

View file

@ -857,6 +857,7 @@ # OUTPUT TEMPLATE
- `is_live` (boolean): Whether this video is a live stream or a fixed-length video - `is_live` (boolean): Whether this video is a live stream or a fixed-length video
- `was_live` (boolean): Whether this video was originally a live stream - `was_live` (boolean): Whether this video was originally a live stream
- `playable_in_embed` (string): Whether this video is allowed to play in embedded players on other sites - `playable_in_embed` (string): Whether this video is allowed to play in embedded players on other sites
- `availability` (string): Whether the video is 'private', 'premium_only', 'subscriber_only', 'needs_auth', 'unlisted' or 'public'
- `start_time` (numeric): Time in seconds where the reproduction should start, as specified in the URL - `start_time` (numeric): Time in seconds where the reproduction should start, as specified in the URL
- `end_time` (numeric): Time in seconds where the reproduction should end, as specified in the URL - `end_time` (numeric): Time in seconds where the reproduction should end, as specified in the URL
- `format` (string): A human-readable description of the format - `format` (string): A human-readable description of the format

View file

@ -301,7 +301,11 @@ class InfoExtractor(object):
playable_in_embed: Whether this video is allowed to play in embedded playable_in_embed: Whether this video is allowed to play in embedded
players on other sites. Can be True (=always allowed), players on other sites. Can be True (=always allowed),
False (=never allowed), None (=unknown), or a string False (=never allowed), None (=unknown), or a string
specifying the criteria for embedability (Eg: 'whitelist'). specifying the criteria for embedability (Eg: 'whitelist')
availability: Under what condition the video is available. One of
'private', 'premium_only', 'subscriber_only', 'needs_auth',
'unlisted' or 'public'. Use 'InfoExtractor._availability'
to set it
__post_extractor: A function to be called just before the metadata is __post_extractor: A function to be called just before the metadata is
written to either disk, logger or console. The function written to either disk, logger or console. The function
must return a dict which will be added to the info_dict. must return a dict which will be added to the info_dict.
@ -3332,6 +3336,20 @@ def _generic_id(self, url):
def _generic_title(self, url): def _generic_title(self, url):
return compat_urllib_parse_unquote(os.path.splitext(url_basename(url))[0]) return compat_urllib_parse_unquote(os.path.splitext(url_basename(url))[0])
@staticmethod
def _availability(is_private, needs_premium, needs_subscription, needs_auth, is_unlisted):
all_known = all(map(
lambda x: x is not None,
(is_private, needs_premium, needs_subscription, needs_auth, is_unlisted)))
return (
'private' if is_private
else 'premium_only' if needs_premium
else 'subscriber_only' if needs_subscription
else 'needs_auth' if needs_auth
else 'unlisted' if is_unlisted
else 'public' if all_known
else None)
class SearchInfoExtractor(InfoExtractor): class SearchInfoExtractor(InfoExtractor):
""" """

View file

@ -25,6 +25,7 @@
) )
from ..jsinterp import JSInterpreter from ..jsinterp import JSInterpreter
from ..utils import ( from ..utils import (
bool_or_none,
clean_html, clean_html,
dict_get, dict_get,
ExtractorError, ExtractorError,
@ -2066,7 +2067,7 @@ def feed_entry(name):
'tags': keywords, 'tags': keywords,
'is_live': is_live, 'is_live': is_live,
'playable_in_embed': playability_status.get('playableInEmbed'), 'playable_in_embed': playability_status.get('playableInEmbed'),
'was_live': video_details.get('isLiveContent') 'was_live': video_details.get('isLiveContent'),
} }
pctr = try_get( pctr = try_get(
@ -2283,6 +2284,30 @@ def chapter_time(mmlir):
if v: if v:
info[d_k] = v info[d_k] = v
is_private = bool_or_none(video_details.get('isPrivate'))
is_unlisted = bool_or_none(microformat.get('isUnlisted'))
is_membersonly = None
if initial_data and is_private is not None:
is_membersonly = False
contents = try_get(initial_data, lambda x: x['contents']['twoColumnWatchNextResults']['results']['results']['contents'], list)
for content in contents or []:
badges = try_get(content, lambda x: x['videoPrimaryInfoRenderer']['badges'], list)
for badge in badges or []:
label = try_get(badge, lambda x: x['metadataBadgeRenderer']['label']) or ''
if label.lower() == 'members only':
is_membersonly = True
break
if is_membersonly:
break
# TODO: Add this for playlists
info['availability'] = self._availability(
is_private=is_private,
needs_premium=False, # Youtube no longer have premium-only videos?
needs_subscription=is_membersonly,
needs_auth=info['age_limit'] >= 18,
is_unlisted=None if is_private is None else is_unlisted)
# get xsrf for annotations or comments # get xsrf for annotations or comments
get_annotations = self._downloader.params.get('writeannotations', False) get_annotations = self._downloader.params.get('writeannotations', False)
get_comments = self._downloader.params.get('getcomments', False) get_comments = self._downloader.params.get('getcomments', False)