From 00c18032c3330d11177813dd43bde66e700dbc2f Mon Sep 17 00:00:00 2001 From: girst Date: Fri, 30 Jul 2021 10:45:01 +0200 Subject: [PATCH] further enhance age-gate bypass only non-embeddable, age-gated videos can't be played now. we try the embedded version first, since this works on all videos that don't have embedding disabled by the uploader. only on those, we fetch the /watch version. if it still doesn't work, we look at the error message to determine if this was an age-gate or another error. further values for clientScreen (extracted from player/base.js): EMBED,WATCH,CHANNEL,LIVE_MONITOR,WATCH_FULL_SCREEN,ADUNIT,UNKNOWN --- app/common/common.py | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/app/common/common.py b/app/common/common.py index cfe54a3..5005e1b 100644 --- a/app/common/common.py +++ b/app/common/common.py @@ -199,7 +199,7 @@ def update_channel(db, xmldata, from_webhook=False): return True -def get_video_info(video_id, sts=0, algo="", _embed=False): +def get_video_info(video_id, sts=0, algo="", _embed=True): """ returns: best-quality muxed video stream, stream map, player_response, error-type/mesage error types: player, malformed, livestream, geolocked, agegated, no-url, exhausted @@ -212,18 +212,15 @@ def get_video_info(video_id, sts=0, algo="", _embed=False): today = datetime.now(timezone.utc).strftime("%Y%m%d") # XXX: anticaptcha hasn't been adapted # XXX: this is not cached any more! - # note: age-gated works as long as it's embeddable (HtVdAasjOgU ok, XgnwCQzjau8 bad, SkRSXFQerZs tvhtml5-only) r = requests.post("https://www.youtube-nocookie.com/youtubei/v1/player?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8", json={ 'videoId': video_id, 'context': { 'client': { 'gl': 'US', 'hl': 'en', - 'clientName': 'WEB_EMBEDDED_PLAYER' if _embed else 'WEB', + 'clientName': 'WEB', 'clientVersion': f'2.{today}.01.01', - 'clientScreen': 'EMBED', - #"clientName": "ANDROID", - #"clientVersion": "16.02", + **({'clientScreen': 'EMBED'} if _embed else {}), }, 'thirdParty': {'embedUrl': 'http://example.com/'} }, @@ -241,18 +238,22 @@ def get_video_info(video_id, sts=0, algo="", _embed=False): playabilityReason = metadata['playabilityStatus'].get('reason', '//'.join(metadata['playabilityStatus'].get('messages',[]))) player_error = f"{playabilityStatus}: {playabilityReason}" - #if playabilityStatus == "UNPLAYABLE": XXX: do we need that still? - if (playabilityStatus == "LOGIN_REQUIRED" - and "confirm your age" in metadata['playabilityStatus'].get('reason','') - and sts != 0 # only need metadata when no sts (via pubsubhubbub) - and not _embed + # "Watch on YouTube" button is visible => "Playback on other websites + # has been disabled by the video owner." => retry detailpage API + if (playabilityStatus == "UNPLAYABLE" and + 'proceedButton' in metadata['playabilityStatus'] \ + .get('errorScreen',{}).get('playerErrorMessageRenderer',{}) + and sts != 0 # only need metadata when no sts (via pubsubhubbub) + and _embed + ): - _, _, metadata_embed, error_embed, _ = get_video_info(video_id, sts, algo, True) + _, _, metadata_embed, error_embed, errormsg_embed = get_video_info(video_id, sts, algo, _embed=False) if not error_embed: - metadata['streamingData'] = metadata_embed['streamingData'] - metadata['playabilityStatus'] = metadata_embed['playabilityStatus'] - else: + metadata = metadata_embed + elif errormsg_embed == "LOGIN_REQUIRED: Sign in to confirm your age": return None, None, metadata, 'agegated', player_error + else: + return None, None, metadata, error_embed, errormsg_embed else: # without videoDetails, there's only the error message maybe_metadata = metadata if 'videoDetails' in metadata else None -- 2.39.3