pkgsrc-Changes archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

CVS commit: pkgsrc/net/yt-dlp



Module Name:    pkgsrc
Committed By:   ryoon
Date:           Wed Aug 19 15:57:23 UTC 2026

Modified Files:
        pkgsrc/net/yt-dlp: Makefile distinfo
Added Files:
        pkgsrc/net/yt-dlp/patches: patch-youtube-fix.diff

Log Message:
net/yt-dlp: Fix download 403 error from youtube.com

* Update YouTube extractor to current.
* Bump PKGREVISION.


To generate a diff of this commit:
cvs rdiff -u -r1.93 -r1.94 pkgsrc/net/yt-dlp/Makefile
cvs rdiff -u -r1.85 -r1.86 pkgsrc/net/yt-dlp/distinfo
cvs rdiff -u -r0 -r1.1 pkgsrc/net/yt-dlp/patches/patch-youtube-fix.diff

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: pkgsrc/net/yt-dlp/Makefile
diff -u pkgsrc/net/yt-dlp/Makefile:1.93 pkgsrc/net/yt-dlp/Makefile:1.94
--- pkgsrc/net/yt-dlp/Makefile:1.93     Mon Jul  6 08:25:46 2026
+++ pkgsrc/net/yt-dlp/Makefile  Wed Aug 19 15:57:23 2026
@@ -1,7 +1,8 @@
-# $NetBSD: Makefile,v 1.93 2026/07/06 08:25:46 wiz Exp $
+# $NetBSD: Makefile,v 1.94 2026/08/19 15:57:23 ryoon Exp $
 
 DISTNAME=      yt_dlp-2026.7.4
 PKGNAME=       ${DISTNAME:S/_/-/}
+PKGREVISION=   1
 CATEGORIES=    net
 MASTER_SITES=  ${MASTER_SITE_PYPI:=y/yt-dlp/}
 
@@ -29,5 +30,8 @@ ALLOW_NETWORK_ACCESS= yes
 # as of 2026.2.21
 # 2483 failed, 3819 passed, 1121 skipped, 3 warnings, 39 subtests passed
 
+post-patch:
+       ${RM} -f ${WRKSRC}/yt_dlp/extractor/youtube/*.py.orig
+
 .include "../../lang/python/wheel.mk"
 .include "../../mk/bsd.pkg.mk"

Index: pkgsrc/net/yt-dlp/distinfo
diff -u pkgsrc/net/yt-dlp/distinfo:1.85 pkgsrc/net/yt-dlp/distinfo:1.86
--- pkgsrc/net/yt-dlp/distinfo:1.85     Mon Jul  6 08:25:46 2026
+++ pkgsrc/net/yt-dlp/distinfo  Wed Aug 19 15:57:23 2026
@@ -1,5 +1,6 @@
-$NetBSD: distinfo,v 1.85 2026/07/06 08:25:46 wiz Exp $
+$NetBSD: distinfo,v 1.86 2026/08/19 15:57:23 ryoon Exp $
 
 BLAKE2s (yt_dlp-2026.7.4.tar.gz) = feda41f9c8f72c7a1c94d55fab15a8cefe29fc55f72d2415245df7c658c4a4be
 SHA512 (yt_dlp-2026.7.4.tar.gz) = b6895848fd17ae69414c22d6104473789d1601a612012567a1d1247801cdf654ab2b1702fd0fadc9c701d5faba3a03b74dcabb4f85d3972031126fff96856f34
 Size (yt_dlp-2026.7.4.tar.gz) = 3049326 bytes
+SHA1 (patch-youtube-fix.diff) = 5087a450489286cd7293aad7471ac724a2ad5408

Added files:

Index: pkgsrc/net/yt-dlp/patches/patch-youtube-fix.diff
diff -u /dev/null pkgsrc/net/yt-dlp/patches/patch-youtube-fix.diff:1.1
--- /dev/null   Wed Aug 19 15:57:23 2026
+++ pkgsrc/net/yt-dlp/patches/patch-youtube-fix.diff    Wed Aug 19 15:57:23 2026
@@ -0,0 +1,363 @@
+$NetBSD: patch-youtube-fix.diff,v 1.1 2026/08/19 15:57:23 ryoon Exp $
+
+* Fix 403 error from youtube.com after 2026-08.
+  From upstream.
+
+--- yt_dlp/extractor/youtube/_base.py  2020-02-02 09:00:00.000000000 +0900
++++ yt_dlp/extractor/youtube/_base.py  2026-08-20 00:27:15.536832077 +0900
+@@ -99,7 +99,7 @@
+         'INNERTUBE_CONTEXT': {
+             'client': {
+                 'clientName': 'WEB',
+-                'clientVersion': '2.20260114.08.00',
++                'clientVersion': '2.20260708.00.00',
+             },
+         },
+         'INNERTUBE_CONTEXT_CLIENT_NAME': 1,
+@@ -107,11 +107,12 @@
+         **WEB_PO_TOKEN_POLICIES,
+     },
+     # Safari UA returns pre-merged video+audio 144p/240p/360p/720p/1080p HLS formats
++    # Since 2026.07, HLS formats are only returned with some logged-in or "trusted" sessions
+     'web_safari': {
+         'INNERTUBE_CONTEXT': {
+             'client': {
+                 'clientName': 'WEB',
+-                'clientVersion': '2.20260114.08.00',
++                'clientVersion': '2.20260708.00.00',
+                 'userAgent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Safari/605.1.15,gzip(gfe)',
+             },
+         },
+@@ -123,7 +124,7 @@
+         'INNERTUBE_CONTEXT': {
+             'client': {
+                 'clientName': 'WEB_EMBEDDED_PLAYER',
+-                'clientVersion': '1.20260115.01.00',
++                'clientVersion': '2.20260708.00.00',
+             },
+         },
+         'INNERTUBE_CONTEXT_CLIENT_NAME': 56,
+@@ -134,7 +135,7 @@
+         'INNERTUBE_CONTEXT': {
+             'client': {
+                 'clientName': 'WEB_REMIX',
+-                'clientVersion': '1.20260114.03.00',
++                'clientVersion': '1.20260707.12.00',
+             },
+         },
+         'INNERTUBE_CONTEXT_CLIENT_NAME': 67,
+@@ -164,7 +165,7 @@
+         'INNERTUBE_CONTEXT': {
+             'client': {
+                 'clientName': 'WEB_CREATOR',
+-                'clientVersion': '1.20260114.05.00',
++                'clientVersion': '1.20260708.06.00',
+             },
+         },
+         'INNERTUBE_CONTEXT_CLIENT_NAME': 62,
+@@ -193,9 +194,9 @@
+         'INNERTUBE_CONTEXT': {
+             'client': {
+                 'clientName': 'ANDROID',
+-                'clientVersion': '21.02.35',
++                'clientVersion': '21.26.364',
+                 'androidSdkVersion': 30,
+-                'userAgent': 'com.google.android.youtube/21.02.35 (Linux; U; Android 11) gzip',
++                'userAgent': 'com.google.android.youtube/21.26.364 (Linux; U; Android 11) gzip',
+                 'osName': 'Android',
+                 'osVersion': '11',
+             },
+@@ -223,6 +224,8 @@
+     },
+     # "Made for kids" videos aren't available with this client
+     # Using a clientVersion>1.65 may return SABR streams only
++    # Since 2026.07, intermittent/selective POT enforcement has been observed for non-HLS formats
++    # Since 2026.08.17, ALL formats (including live HLS and itag 18) are 403'd with version 1.65.10
+     'android_vr': {
+         'INNERTUBE_CONTEXT': {
+             'client': {
+@@ -238,6 +241,24 @@
+         },
+         'INNERTUBE_CONTEXT_CLIENT_NAME': 28,
+         'REQUIRE_JS_PLAYER': False,
++        'GVS_PO_TOKEN_POLICY': {
++            StreamingProtocol.HTTPS: GvsPoTokenPolicy(
++                required=True,
++                recommended=True,
++                not_required_with_player_token=True,
++            ),
++            StreamingProtocol.DASH: GvsPoTokenPolicy(
++                required=True,
++                recommended=True,
++                not_required_with_player_token=True,
++            ),
++            StreamingProtocol.HLS: GvsPoTokenPolicy(
++                required=False,
++                recommended=True,
++                not_required_with_player_token=True,
++            ),
++        },
++        'PLAYER_PO_TOKEN_POLICY': PlayerPoTokenPolicy(required=False, recommended=True),
+     },
+     # iOS clients have HLS live streams. Setting device model to get 60fps formats.
+     # See: https://github.com/TeamNewPipe/NewPipeExtractor/issues/680#issuecomment-1002724558
+@@ -245,10 +266,10 @@
+         'INNERTUBE_CONTEXT': {
+             'client': {
+                 'clientName': 'IOS',
+-                'clientVersion': '21.02.3',
++                'clientVersion': '21.26.4',
+                 'deviceMake': 'Apple',
+                 'deviceModel': 'iPhone16,2',
+-                'userAgent': 'com.google.ios.youtube/21.02.3 (iPhone16,2; U; CPU iOS 18_3_2 like Mac OS X;)',
++                'userAgent': 'com.google.ios.youtube/21.26.4 (iPhone16,2; U; CPU iOS 18_3_2 like Mac OS X;)',
+                 'osName': 'iPhone',
+                 'osVersion': '18.3.2.22D82',
+             },
+@@ -270,13 +291,29 @@
+         'PLAYER_PO_TOKEN_POLICY': PlayerPoTokenPolicy(required=False, recommended=True),
+         'REQUIRE_JS_PLAYER': False,
+     },
++    # "Made for kids" videos aren't available with this client
++    'visionos': {
++        'INNERTUBE_CONTEXT': {
++            'client': {
++                'clientName': 'VISIONOS',
++                'clientVersion': '1.02',
++                'deviceMake': 'Apple',
++                'deviceModel': 'RealityDevice17,1',
++                'userAgent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 15_7_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Safari/605.1.15',
++                'osName': 'visionOS',
++                'osVersion': '26.5.23O471',
++            },
++        },
++        'INNERTUBE_CONTEXT_CLIENT_NAME': 101,
++        'REQUIRE_JS_PLAYER': False,
++    },
+     # mweb has 'ultralow' formats
+     # See: https://github.com/yt-dlp/yt-dlp/pull/557
+     'mweb': {
+         'INNERTUBE_CONTEXT': {
+             'client': {
+                 'clientName': 'MWEB',
+-                'clientVersion': '2.20260115.01.00',
++                'clientVersion': '2.20260708.05.00',
+                 # mweb previously did not require PO Token with this UA
+                 'userAgent': 'Mozilla/5.0 (iPad; CPU OS 16_7_10 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1,gzip(gfe)',
+             },
+@@ -307,7 +344,7 @@
+         'INNERTUBE_CONTEXT': {
+             'client': {
+                 'clientName': 'TVHTML5',
+-                'clientVersion': '7.20260114.12.00',
++                'clientVersion': '7.20260707.07.00',
+                 # See: https://github.com/youtube/cobalt/blob/main/cobalt/browser/user_agent/user_agent_platform_info.cc#L506
+                 'userAgent': 'Mozilla/5.0 (ChromiumStylePlatform) Cobalt/25.lts.30.1034943-gold (unlike Gecko), Unknown_TV_Unknown_0/Unknown (Unknown, Unknown)',
+             },
+@@ -319,12 +356,11 @@
+         'INNERTUBE_CONTEXT': {
+             'client': {
+                 'clientName': 'TVHTML5',
+-                'clientVersion': '5.20260114',
++                'clientVersion': '5.20260707',
+                 'userAgent': 'Mozilla/5.0 (ChromiumStylePlatform) Cobalt/Version',
+             },
+         },
+         'INNERTUBE_CONTEXT_CLIENT_NAME': 7,
+-        'REQUIRE_AUTH': True,
+         'SUPPORTS_COOKIES': True,
+     },
+     'tv_simply': {
+diff -urN yt_dlp-2026.7.4/yt_dlp/extractor/youtube/_tab.py yt-dlp/yt_dlp/extractor/youtube/_tab.py
+--- yt_dlp/extractor/youtube/_tab.py   2020-02-02 09:00:00.000000000 +0900
++++ yt_dlp/extractor/youtube/_tab.py   2026-08-20 00:27:15.538018146 +0900
+@@ -2198,6 +2198,49 @@
+             'extract_flat': True,
+             'playlist_items': '75',
+         },
++    }, {
++        # YoutubeTab_52
++        # "UUMO" is a prefix that can be used for any channel to get a members-only playlist
++        'note': 'flat playlist entry of subscriber_only video',
++        'url': 'https://www.youtube.com/playlist?list=UUMOXuqSBlHAE6Xw-yeJA0Tunw',
++        'info_dict': {
++            'id': 'UUMOXuqSBlHAE6Xw-yeJA0Tunw',
++            'availability': 'public',
++            'title': 'Members-only videos',
++            'description': 'Videos available to members of this channel. Automatically updated.',
++            'tags': [],
++            'modified_date': r're:\d{8}',
++            'channel': 'Linus Tech Tips',
++            'view_count': int,
++            'channel_id': 'UCXuqSBlHAE6Xw-yeJA0Tunw',
++            'channel_url': 'https://www.youtube.com/channel/UCXuqSBlHAE6Xw-yeJA0Tunw',
++            'uploader_url': 'https://www.youtube.com/@LinusTechTips',
++            'uploader_id': '@LinusTechTips',
++            'uploader': 'Linus Tech Tips',
++        },
++        'playlist': [{
++            'info_dict': {
++                # availability is the only value we are testing for here
++                'availability': 'subscriber_only',
++                'id': str,
++                '_type': 'url',
++                'title': str,
++                'duration': int,
++                'url': str,
++                'uploader': str,
++                'uploader_id': str,
++                'uploader_url': str,
++                'channel': str,
++                'channel_id': str,
++                'channel_url': str,
++                'ie_key': 'Youtube',
++            },
++        }],
++        'playlist_mincount': 1,
++        'params': {
++            'extract_flat': True,
++            'playlist_items': '1',
++        },
+     }]
+ 
+     @classmethod
+diff -urN yt_dlp-2026.7.4/yt_dlp/extractor/youtube/_video.py yt-dlp/yt_dlp/extractor/youtube/_video.py
+--- yt_dlp/extractor/youtube/_video.py 2020-02-02 09:00:00.000000000 +0900
++++ yt_dlp/extractor/youtube/_video.py 2026-08-20 00:27:15.538437864 +0900
+@@ -28,6 +28,7 @@
+ from .jsc.provider import JsChallengeRequest, JsChallengeType, NChallengeInput, SigChallengeInput
+ from .pot._director import initialize_pot_director
+ from .pot.provider import PoTokenContext, PoTokenRequest
++from ...networking import HEADRequest
+ from ...utils import (
+     NO_DEFAULT,
+     ExtractorError,
+@@ -139,13 +140,13 @@
+     _RETURN_TYPE = 'video'  # XXX: How to handle multifeed?
+ 
+     _SUBTITLE_FORMATS = ('json3', 'srv1', 'srv2', 'srv3', 'ttml', 'srt', 'vtt')
+-    _DEFAULT_CLIENTS = ('android_vr', 'web_safari')
+-    _DEFAULT_JSLESS_CLIENTS = ('android_vr',)
+-    _DEFAULT_AUTHED_CLIENTS = ('tv_downgraded', 'web_safari')
++    _DEFAULT_CLIENTS = ('visionos', 'web')
++    _DEFAULT_JSLESS_CLIENTS = ('visionos',)
++    _DEFAULT_AUTHED_CLIENTS = ('web_embedded', 'tv_downgraded', 'web')
+     # Premium does not require POT (except for subtitles)
+-    _DEFAULT_PREMIUM_CLIENTS = ('tv_downgraded', 'web_creator')
++    _DEFAULT_PREMIUM_CLIENTS = ('web_creator', 'tv_downgraded', 'web')
+     _WEBPAGE_CLIENTS = ('web', 'web_safari')
+-    _DEFAULT_WEBPAGE_CLIENT = 'web_safari'
++    _DEFAULT_WEBPAGE_CLIENT = 'web'
+ 
+     _GEO_BYPASS = False
+ 
+@@ -1599,13 +1600,13 @@
+         'info_dict': {
+             'id': 'brhfDfLdDZ8',
+             'ext': 'mp4',
+-            'title': 'This is the WORST Movie Science We\'ve Ever Seen',
++            'title': 'Scientists React to Terrible Movie Science | Moonfall (2021)',
+             'description': 'md5:8afd0a3cd69ec63438fc573580436f92',
+             'media_type': 'video',
+-            'uploader': 'Open Sauce',
+-            'uploader_id': '@opensaucelive',
+-            'uploader_url': 'https://www.youtube.com/@opensaucelive',
+-            'channel': 'Open Sauce',
++            'uploader': 'Sauce +',
++            'uploader_id': '@sauceplusofficial',
++            'uploader_url': 'https://www.youtube.com/@sauceplusofficial',
++            'channel': 'Sauce +',
+             'channel_id': 'UC2EiGVmCeD79l_vZ204DUSw',
+             'channel_url': 'https://www.youtube.com/channel/UC2EiGVmCeD79l_vZ204DUSw',
+             'comment_count': int,
+@@ -1613,15 +1614,17 @@
+             'like_count': int,
+             'age_limit': 0,
+             'duration': 1664,
+-            'thumbnail': 'https://i.ytimg.com/vi/brhfDfLdDZ8/hqdefault.jpg',
++            'thumbnail': 'https://i.ytimg.com/vi/brhfDfLdDZ8/sddefault.jpg',
+             'categories': ['Entertainment'],
+             'tags': ['Moonfall', 'Bad Science', 'Open Sauce', 'Sauce+', 'The Backyard Scientist', 'William Osman', 'Allen Pan'],
+-            'creators': ['Open Sauce', 'William Osman 2'],
++            'creators': ['Sauce +', 'William Osman 2'],
+             'timestamp': 1759452918,
+             'upload_date': '20251003',
+             'playable_in_embed': True,
+             'availability': 'public',
+             'live_status': 'not_live',
++            'channel_follower_count': int,
++            'heatmap': 'count:100',
+         },
+         'params': {'skip_download': True},
+     }, {
+@@ -1655,6 +1658,7 @@
+             'playable_in_embed': True,
+             'availability': 'public',
+             'live_status': 'not_live',
++            'channel_follower_count': int,
+         },
+         'params': {'skip_download': True},
+     }, {
+@@ -2036,8 +2040,11 @@
+                 last_seq = last_seq_cache[cache_key]
+             else:
+                 try:
+-                    urlh = self._request_webpage(base_url, None, note=False, errnote=False, fatal=False)
+-                except ExtractorError:
++                    urlh = self._request_webpage(
++                        HEADRequest(base_url), None,
++                        note=False, errnote='Fragment request failed')
++                except ExtractorError as e:
++                    self.write_debug(e.msg)
+                     urlh = None
+                 last_seq = try_get(urlh, lambda x: int_or_none(x.headers['X-Head-Seqnum']))
+                 if urlh:
+@@ -2900,6 +2907,10 @@
+     def _is_unplayable(player_response):
+         return traverse_obj(player_response, ('playabilityStatus', 'status')) == 'UNPLAYABLE'
+ 
++    @staticmethod
++    def _is_error_response(player_response):
++        return traverse_obj(player_response, ('playabilityStatus', 'status')) == 'ERROR'
++
+     def _extract_player_response(self, client, video_id, webpage_ytcfg, player_ytcfg, player_url, initial_pr, visitor_data, data_sync_id, po_token):
+         headers = self.generate_api_headers(
+             ytcfg=player_ytcfg,
+@@ -3132,13 +3143,15 @@
+                     prs.append(pr)
+ 
+             if (
+-                # Is this a "made for kids" video that can't be downloaded with android_vr?
+-                client == 'android_vr' and self._is_unplayable(pr)
++                # Is this a "made for kids" video that can't be downloaded with android_vr/visionos?
++                client in {'android_vr', 'visionos'}
++                and (self._is_unplayable(pr) or self._is_error_response(pr))
+                 and webpage and 'made for kids' in webpage
+                 # ...and is a JS runtime is available?
+                 and any(p.is_available() for p in self._jsc_director.providers.values())
+             ):
+                 append_client('web_embedded')
++                append_client('tv_downgraded')
+ 
+             # web_embedded can work around age-gate and age-verification for some embeddable videos
+             if self._is_agegated(pr) and variant != 'web_embedded':
+@@ -4459,13 +4472,16 @@
+         vsir = get_first(contents, 'videoSecondaryInfoRenderer')
+         if vsir:
+             vor = traverse_obj(vsir, ('owner', 'videoOwnerRenderer'))
+-            collaborators = traverse_obj(vor, (
++            collab_view_models = traverse_obj(vor, (
+                 'attributedTitle', 'commandRuns', ..., 'onTap', 'innertubeCommand', 'showDialogCommand',
+                 'panelLoadingStrategy', 'inlineContent', 'dialogViewModel', 'customContent', 'listViewModel',
+-                'listItems', ..., 'listItemViewModel', 'title', 'content', {str}))
++                'listItems', ..., 'listItemViewModel', {dict}))
++            collaborators = traverse_obj(collab_view_models, (..., 'title', 'content', {str}))
+             info.update({
+                 'channel': self._get_text(vor, 'title') or (collaborators[0] if collaborators else None),
+-                'channel_follower_count': self._get_count(vor, 'subscriberCountText'),
++                'channel_follower_count': (
++                    self._get_count(vor, 'subscriberCountText')
++                    or traverse_obj(collab_view_models, (0, 'rendererContext', 'accessibilityContext', 'label', {parse_count}))),
+                 'creators': collaborators if collaborators else None,
+             })
+ 



Home | Main Index | Thread Index | Old Index