yt-dlp 2026.1.25.233128.dev0__py3-none-any.whl → 2026.1.29__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. yt_dlp/YoutubeDL.py +14 -10
  2. yt_dlp/extractor/_extractors.py +9 -2
  3. yt_dlp/extractor/boosty.py +45 -16
  4. yt_dlp/extractor/dailymotion.py +45 -5
  5. yt_dlp/extractor/err.py +68 -0
  6. yt_dlp/extractor/facebook.py +57 -1
  7. yt_dlp/extractor/francetv.py +21 -5
  8. yt_dlp/extractor/frontro.py +4 -4
  9. yt_dlp/extractor/lazy_extractors.py +39 -7
  10. yt_dlp/extractor/lbry.py +1 -0
  11. yt_dlp/extractor/neteasemusic.py +32 -7
  12. yt_dlp/extractor/patreon.py +118 -33
  13. yt_dlp/extractor/pbs.py +18 -0
  14. yt_dlp/extractor/rumble.py +1 -1
  15. yt_dlp/extractor/tarangplus.py +2 -1
  16. yt_dlp/extractor/vimeo.py +16 -1
  17. yt_dlp/extractor/volejtv.py +149 -22
  18. yt_dlp/extractor/wat.py +1 -1
  19. yt_dlp/extractor/whyp.py +15 -11
  20. yt_dlp/extractor/youtube/_base.py +32 -26
  21. yt_dlp/extractor/youtube/_video.py +15 -5
  22. yt_dlp/extractor/youtube/jsc/_builtin/vendor/_info.py +3 -3
  23. yt_dlp/extractor/youtube/jsc/_builtin/vendor/yt.solver.core.js +66 -13
  24. yt_dlp/version.py +5 -5
  25. {yt_dlp-2026.1.25.233128.dev0.data → yt_dlp-2026.1.29.data}/data/share/doc/yt_dlp/README.txt +12 -11
  26. {yt_dlp-2026.1.25.233128.dev0.data → yt_dlp-2026.1.29.data}/data/share/fish/vendor_completions.d/yt-dlp.fish +1 -1
  27. {yt_dlp-2026.1.25.233128.dev0.data → yt_dlp-2026.1.29.data}/data/share/man/man1/yt-dlp.1 +11 -10
  28. {yt_dlp-2026.1.25.233128.dev0.dist-info → yt_dlp-2026.1.29.dist-info}/METADATA +8 -8
  29. {yt_dlp-2026.1.25.233128.dev0.dist-info → yt_dlp-2026.1.29.dist-info}/RECORD +34 -34
  30. {yt_dlp-2026.1.25.233128.dev0.data → yt_dlp-2026.1.29.data}/data/share/bash-completion/completions/yt-dlp +0 -0
  31. {yt_dlp-2026.1.25.233128.dev0.data → yt_dlp-2026.1.29.data}/data/share/zsh/site-functions/_yt-dlp +0 -0
  32. {yt_dlp-2026.1.25.233128.dev0.dist-info → yt_dlp-2026.1.29.dist-info}/WHEEL +0 -0
  33. {yt_dlp-2026.1.25.233128.dev0.dist-info → yt_dlp-2026.1.29.dist-info}/entry_points.txt +0 -0
  34. {yt_dlp-2026.1.25.233128.dev0.dist-info → yt_dlp-2026.1.29.dist-info}/licenses/LICENSE +0 -0
@@ -223,20 +223,6 @@ INNERTUBE_CLIENTS = {
223
223
  },
224
224
  'PLAYER_PO_TOKEN_POLICY': PlayerPoTokenPolicy(required=False, recommended=True),
225
225
  },
226
- # Doesn't require a PoToken for some reason
227
- 'android_sdkless': {
228
- 'INNERTUBE_CONTEXT': {
229
- 'client': {
230
- 'clientName': 'ANDROID',
231
- 'clientVersion': '21.02.35',
232
- 'userAgent': 'com.google.android.youtube/21.02.35 (Linux; U; Android 11) gzip',
233
- 'osName': 'Android',
234
- 'osVersion': '11',
235
- },
236
- },
237
- 'INNERTUBE_CONTEXT_CLIENT_NAME': 3,
238
- 'REQUIRE_JS_PLAYER': False,
239
- },
240
226
  # YouTube Kids videos aren't returned on this client for some reason
241
227
  'android_vr': {
242
228
  'INNERTUBE_CONTEXT': {
@@ -285,6 +271,34 @@ INNERTUBE_CLIENTS = {
285
271
  'PLAYER_PO_TOKEN_POLICY': PlayerPoTokenPolicy(required=False, recommended=True),
286
272
  'REQUIRE_JS_PLAYER': False,
287
273
  },
274
+ 'ios_downgraded': {
275
+ 'INNERTUBE_CONTEXT': {
276
+ 'client': {
277
+ 'clientName': 'IOS',
278
+ 'clientVersion': '19.49.7',
279
+ 'deviceMake': 'Apple',
280
+ 'deviceModel': 'iPhone16,2',
281
+ 'userAgent': 'com.google.ios.youtube/19.49.7 (iPhone16,2; U; CPU iOS 17_5_1 like Mac OS X;)',
282
+ 'osName': 'iPhone',
283
+ 'osVersion': '17.5.1.21F90',
284
+ },
285
+ },
286
+ 'INNERTUBE_CONTEXT_CLIENT_NAME': 5,
287
+ 'GVS_PO_TOKEN_POLICY': {
288
+ StreamingProtocol.HTTPS: GvsPoTokenPolicy(
289
+ required=True,
290
+ recommended=True,
291
+ not_required_with_player_token=True,
292
+ ),
293
+ StreamingProtocol.HLS: GvsPoTokenPolicy(
294
+ required=False,
295
+ recommended=True,
296
+ not_required_with_player_token=True,
297
+ ),
298
+ },
299
+ 'PLAYER_PO_TOKEN_POLICY': PlayerPoTokenPolicy(required=False, recommended=True),
300
+ 'REQUIRE_JS_PLAYER': False,
301
+ },
288
302
  # mweb has 'ultralow' formats
289
303
  # See: https://github.com/yt-dlp/yt-dlp/pull/557
290
304
  'mweb': {
@@ -323,13 +337,12 @@ INNERTUBE_CLIENTS = {
323
337
  'client': {
324
338
  'clientName': 'TVHTML5',
325
339
  'clientVersion': '7.20260114.12.00',
326
- 'userAgent': 'Mozilla/5.0 (ChromiumStylePlatform) Cobalt/Version',
340
+ # See: https://github.com/youtube/cobalt/blob/main/cobalt/browser/user_agent/user_agent_platform_info.cc#L506
341
+ 'userAgent': 'Mozilla/5.0 (ChromiumStylePlatform) Cobalt/25.lts.30.1034943-gold (unlike Gecko), Unknown_TV_Unknown_0/Unknown (Unknown, Unknown)',
327
342
  },
328
343
  },
329
344
  'INNERTUBE_CONTEXT_CLIENT_NAME': 7,
330
345
  'SUPPORTS_COOKIES': True,
331
- # See: https://github.com/youtube/cobalt/blob/main/cobalt/browser/user_agent/user_agent_platform_info.cc#L506
332
- 'AUTHENTICATED_USER_AGENT': 'Mozilla/5.0 (ChromiumStylePlatform) Cobalt/25.lts.30.1034943-gold (unlike Gecko), Unknown_TV_Unknown_0/Unknown (Unknown, Unknown)',
333
346
  },
334
347
  'tv_downgraded': {
335
348
  'INNERTUBE_CONTEXT': {
@@ -340,6 +353,7 @@ INNERTUBE_CLIENTS = {
340
353
  },
341
354
  },
342
355
  'INNERTUBE_CONTEXT_CLIENT_NAME': 7,
356
+ 'REQUIRE_AUTH': True,
343
357
  'SUPPORTS_COOKIES': True,
344
358
  },
345
359
  'tv_simply': {
@@ -418,7 +432,6 @@ def build_innertube_clients():
418
432
  ytcfg.setdefault('SUPPORTS_COOKIES', False)
419
433
  ytcfg.setdefault('SUPPORTS_AD_PLAYBACK_CONTEXT', False)
420
434
  ytcfg.setdefault('PLAYER_PARAMS', None)
421
- ytcfg.setdefault('AUTHENTICATED_USER_AGENT', None)
422
435
  ytcfg['INNERTUBE_CONTEXT']['client'].setdefault('hl', 'en')
423
436
 
424
437
  _, base_client, variant = _split_innertube_client(client)
@@ -703,14 +716,7 @@ class YoutubeBaseInfoExtractor(InfoExtractor):
703
716
  _YT_INITIAL_PLAYER_RESPONSE_RE = r'ytInitialPlayerResponse\s*='
704
717
 
705
718
  def _get_default_ytcfg(self, client='web'):
706
- ytcfg = copy.deepcopy(INNERTUBE_CLIENTS[client])
707
-
708
- # Currently, only the tv client needs to use an alternative user-agent when logged-in
709
- if ytcfg.get('AUTHENTICATED_USER_AGENT') and self.is_authenticated:
710
- client_context = ytcfg.setdefault('INNERTUBE_CONTEXT', {}).setdefault('client', {})
711
- client_context['userAgent'] = ytcfg['AUTHENTICATED_USER_AGENT']
712
-
713
- return ytcfg
719
+ return copy.deepcopy(INNERTUBE_CLIENTS[client])
714
720
 
715
721
  def _get_innertube_host(self, client='web'):
716
722
  return INNERTUBE_CLIENTS[client]['INNERTUBE_HOST']
@@ -145,8 +145,8 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
145
145
  r'\b(?P<id>vfl[a-zA-Z0-9_-]+)\b.*?\.js$',
146
146
  )
147
147
  _SUBTITLE_FORMATS = ('json3', 'srv1', 'srv2', 'srv3', 'ttml', 'srt', 'vtt')
148
- _DEFAULT_CLIENTS = ('android_sdkless', 'web', 'web_safari')
149
- _DEFAULT_JSLESS_CLIENTS = ('android_sdkless',)
148
+ _DEFAULT_CLIENTS = ('android_vr', 'ios_downgraded', 'web', 'web_safari')
149
+ _DEFAULT_JSLESS_CLIENTS = ('android_vr', 'ios_downgraded')
150
150
  _DEFAULT_AUTHED_CLIENTS = ('tv_downgraded', 'web', 'web_safari')
151
151
  # Premium does not require POT (except for subtitles)
152
152
  _DEFAULT_PREMIUM_CLIENTS = ('tv_downgraded', 'web_creator', 'web')
@@ -1690,7 +1690,8 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
1690
1690
  'playable_in_embed': True,
1691
1691
  'availability': 'public',
1692
1692
  'live_status': 'not_live',
1693
- 'comment_count': 15, # XXX: minimum
1693
+ 'comment_count': 15, # XXX: minimum, but investigate if this changes
1694
+ 'comments': 'count:15',
1694
1695
  },
1695
1696
  'params': {
1696
1697
  'skip_download': True,
@@ -1723,7 +1724,12 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
1723
1724
  'playable_in_embed': True,
1724
1725
  'availability': 'unlisted',
1725
1726
  'live_status': 'not_live',
1726
- 'comment_count': 9, # XXX: minimum
1727
+ 'comment_count': 9, # XXX: minimum, but investigate if this changes
1728
+ 'comments': 'count:9',
1729
+ },
1730
+ 'params': {
1731
+ 'skip_download': True,
1732
+ 'getcomments': True,
1727
1733
  },
1728
1734
  }]
1729
1735
  _WEBPAGE_TESTS = [{
@@ -1884,7 +1890,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
1884
1890
  'tv': 'tv-player-ias.vflset/tv-player-ias.js',
1885
1891
  'tv_es6': 'tv-player-es6.vflset/tv-player-es6.js',
1886
1892
  'phone': 'player-plasma-ias-phone-en_US.vflset/base.js',
1887
- 'tablet': 'player-plasma-ias-tablet-en_US.vflset/base.js',
1893
+ 'tablet': 'player-plasma-ias-tablet-en_US.vflset/base.js', # Dead since 19712d96 (2025.11.06)
1888
1894
  }
1889
1895
  _INVERSE_PLAYER_JS_VARIANT_MAP = {v: k for k, v in _PLAYER_JS_VARIANT_MAP.items()}
1890
1896
 
@@ -3589,6 +3595,10 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
3589
3595
  if client_name == 'web_safari' and proto == 'hls' and live_status != 'is_live':
3590
3596
  f['source_preference'] -= 1
3591
3597
 
3598
+ # Safeguard against inevitable ios_downgraded client breakage
3599
+ if client_name == 'ios_downgraded' and proto == 'hls' and live_status != 'is_live':
3600
+ f['__needs_testing'] = True
3601
+
3592
3602
  if missing_pot:
3593
3603
  f['format_note'] = join_nonempty(f.get('format_note'), 'MISSING POT', delim=' ')
3594
3604
  f['source_preference'] -= 20
@@ -1,10 +1,10 @@
1
1
  # This file is generated by devscripts/update_ejs.py. DO NOT MODIFY!
2
2
 
3
- VERSION = '0.3.2'
3
+ VERSION = '0.4.0'
4
4
  HASHES = {
5
5
  'yt.solver.bun.lib.js': '6ff45e94de9f0ea936a183c48173cfa9ce526ee4b7544cd556428427c1dd53c8073ef0174e79b320252bf0e7c64b0032cc1cf9c4358f3fda59033b7caa01c241',
6
- 'yt.solver.core.js': '0cd96b2d3f319dfa62cae689efa7d930ef1706e95f5921794db5089b2262957ec0a17d73938d8975ea35d0309cbfb4c8e4418d5e219837215eee242890c8b64d',
7
- 'yt.solver.core.min.js': '370d627703002b4a73b10027702734a3de9484f6b56b739942be1dc2b60fee49dee2aa86ed117d1c8ae1ac55181d326481f1fe2e2e8d5211154d48e2a55dac51',
6
+ 'yt.solver.core.js': '05964b458d92a65d4fb7a90bcb5921c9fed2370f4e4f2f25badb41f28aff9069e0b3c4e5bf1baf2d3021787b67fc6093cefa44de30cffdc6f9fb25532484003b',
7
+ 'yt.solver.core.min.js': '0cd3c0b37e095d3cca99443b58fe03980ac3bf2e777c2485c23e1f6052b5ede9f07c7f1c79a9c3af3258ea91a228f099741e7eb07b53125b5dcc84bb4c0054f3',
8
8
  'yt.solver.deno.lib.js': '9c8ee3ab6c23e443a5a951e3ac73c6b8c1c8fb34335e7058a07bf99d349be5573611de00536dcd03ecd3cf34014c4e9b536081de37af3637c5390c6a6fd6a0f0',
9
9
  'yt.solver.lib.js': '1ee3753a8222fc855f5c39db30a9ccbb7967dbe1fb810e86dc9a89aa073a0907f294c720e9b65427d560a35aa1ce6af19ef854d9126a05ca00afe03f72047733',
10
10
  'yt.solver.lib.min.js': '8420c259ad16e99ce004e4651ac1bcabb53b4457bf5668a97a9359be9a998a789fee8ab124ee17f91a2ea8fd84e0f2b2fc8eabcaf0b16a186ba734cf422ad053',
@@ -60,6 +60,26 @@ var jsc = (function (meriyah, astring) {
60
60
  }
61
61
  return value;
62
62
  }
63
+ const nsigExpression = {
64
+ type: 'VariableDeclaration',
65
+ kind: 'var',
66
+ declarations: [
67
+ {
68
+ type: 'VariableDeclarator',
69
+ init: {
70
+ type: 'CallExpression',
71
+ callee: { type: 'Identifier' },
72
+ arguments: [
73
+ { type: 'Literal' },
74
+ {
75
+ type: 'CallExpression',
76
+ callee: { type: 'Identifier', name: 'decodeURIComponent' },
77
+ },
78
+ ],
79
+ },
80
+ },
81
+ ],
82
+ };
63
83
  const logicalExpression = {
64
84
  type: 'ExpressionStatement',
65
85
  expression: {
@@ -186,24 +206,57 @@ var jsc = (function (meriyah, astring) {
186
206
  'call',
187
207
  (_8) => _8(-2),
188
208
  ]);
189
- if (!matchesStructure(relevantExpression, logicalExpression)) {
190
- return null;
191
- }
192
- if (
209
+ let call = null;
210
+ if (matchesStructure(relevantExpression, logicalExpression)) {
211
+ if (
212
+ _optionalChain$2([
213
+ relevantExpression,
214
+ 'optionalAccess',
215
+ (_9) => _9.type,
216
+ ]) !== 'ExpressionStatement' ||
217
+ relevantExpression.expression.type !== 'LogicalExpression' ||
218
+ relevantExpression.expression.right.type !== 'SequenceExpression' ||
219
+ relevantExpression.expression.right.expressions[0].type !==
220
+ 'AssignmentExpression' ||
221
+ relevantExpression.expression.right.expressions[0].right.type !==
222
+ 'CallExpression'
223
+ ) {
224
+ return null;
225
+ }
226
+ call = relevantExpression.expression.right.expressions[0].right;
227
+ } else if (
193
228
  _optionalChain$2([
194
229
  relevantExpression,
195
230
  'optionalAccess',
196
- (_9) => _9.type,
197
- ]) !== 'ExpressionStatement' ||
198
- relevantExpression.expression.type !== 'LogicalExpression' ||
199
- relevantExpression.expression.right.type !== 'SequenceExpression' ||
200
- relevantExpression.expression.right.expressions[0].type !==
201
- 'AssignmentExpression'
231
+ (_10) => _10.type,
232
+ ]) === 'IfStatement' &&
233
+ relevantExpression.consequent.type === 'BlockStatement'
202
234
  ) {
203
- return null;
235
+ for (const n of relevantExpression.consequent.body) {
236
+ if (!matchesStructure(n, nsigExpression)) {
237
+ continue;
238
+ }
239
+ if (
240
+ n.type !== 'VariableDeclaration' ||
241
+ _optionalChain$2([
242
+ n,
243
+ 'access',
244
+ (_11) => _11.declarations,
245
+ 'access',
246
+ (_12) => _12[0],
247
+ 'access',
248
+ (_13) => _13.init,
249
+ 'optionalAccess',
250
+ (_14) => _14.type,
251
+ ]) !== 'CallExpression'
252
+ ) {
253
+ continue;
254
+ }
255
+ call = n.declarations[0].init;
256
+ break;
257
+ }
204
258
  }
205
- const call = relevantExpression.expression.right.expressions[0].right;
206
- if (call.type !== 'CallExpression' || call.callee.type !== 'Identifier') {
259
+ if (call === null) {
207
260
  return null;
208
261
  }
209
262
  return {
yt_dlp/version.py CHANGED
@@ -1,15 +1,15 @@
1
1
  # Autogenerated by devscripts/update-version.py
2
2
 
3
- __version__ = '2026.01.25.233128'
3
+ __version__ = '2026.01.29'
4
4
 
5
- RELEASE_GIT_HEAD = 'e3f0d8b731b40176bcc632bf92cfe5149402b202'
5
+ RELEASE_GIT_HEAD = '8b275536d945c4b3d07b6c520677922c67a7c10f'
6
6
 
7
7
  VARIANT = 'pip'
8
8
 
9
9
  UPDATE_HINT = 'You installed yt-dlp with pip or using the wheel from PyPi; Use that to update'
10
10
 
11
- CHANNEL = 'nightly'
11
+ CHANNEL = 'stable'
12
12
 
13
- ORIGIN = 'yt-dlp/yt-dlp-nightly-builds'
13
+ ORIGIN = 'yt-dlp/yt-dlp'
14
14
 
15
- _pkg_version = '2026.01.25.233128dev'
15
+ _pkg_version = '2026.01.29'
@@ -265,8 +265,8 @@ Strongly recommended
265
265
  Important: What you need is ffmpeg binary, NOT the Python package of
266
266
  the same name
267
267
 
268
- - yt-dlp-ejs - Required for deciphering YouTube n/sig values. Licensed
269
- under Unlicense, bundles MIT and ISC components.
268
+ - yt-dlp-ejs - Required for full YouTube support. Licensed under
269
+ Unlicense, bundles MIT and ISC components.
270
270
 
271
271
  A JavaScript runtime/engine like deno (recommended), node.js, bun,
272
272
  or QuickJS is also required to run yt-dlp-ejs. See the wiki.
@@ -409,7 +409,7 @@ General Options:
409
409
  --no-update Do not check for updates (default)
410
410
  --update-to [CHANNEL]@[TAG] Upgrade/downgrade to a specific version.
411
411
  CHANNEL can be a repository as well. CHANNEL
412
- and TAG default to "nightly" and "latest"
412
+ and TAG default to "stable" and "latest"
413
413
  respectively if omitted; See "UPDATE" for
414
414
  details. Supported channels: stable,
415
415
  nightly, master
@@ -2312,11 +2312,11 @@ youtube
2312
2312
  respectively
2313
2313
  - player_client: Clients to extract video data from. The currently
2314
2314
  available clients are web, web_safari, web_embedded, web_music,
2315
- web_creator, mweb, ios, android, android_sdkless, android_vr, tv,
2315
+ web_creator, mweb, ios, ios_downgraded, android, android_vr, tv,
2316
2316
  tv_simply, tv_downgraded, and tv_embedded. By default,
2317
- android_sdkless,web,web_safari is used. If no JavaScript
2318
- runtime/engine is available, then only android_sdkless is used. If
2319
- logged-in cookies are passed to yt-dlp, then
2317
+ android_vr,ios_downgraded,web,web_safari is used. If no JavaScript
2318
+ runtime/engine is available, then android_vr,ios_downgraded is used.
2319
+ If logged-in cookies are passed to yt-dlp, then
2320
2320
  tv_downgraded,web,web_safari is used for free accounts and
2321
2321
  tv_downgraded,web_creator,web is used for premium accounts. The
2322
2322
  web_music client is added for music.youtube.com URLs when logged-in
@@ -2591,10 +2591,11 @@ tver
2591
2591
  vimeo
2592
2592
 
2593
2593
  - client: Client to extract video data from. The currently available
2594
- clients are android, ios, and web. Only one client can be used. The
2595
- web client is used by default. The web client only works with
2596
- account cookies or login credentials. The android and ios clients
2597
- only work with previously cached OAuth tokens
2594
+ clients are android, ios, macos and web. Only one client can be
2595
+ used. The macos client is used by default, but the web client is
2596
+ used when logged-in. The web client only works with account cookies
2597
+ or login credentials. The android and ios clients only work with
2598
+ previously cached OAuth tokens
2598
2599
  - original_format_policy: Policy for when to try extracting original
2599
2600
  formats. One of always, never, or auto. The default auto policy
2600
2601
  tries to avoid exceeding the web client's API rate-limit by only
@@ -3,7 +3,7 @@ complete --command yt-dlp --long-option help --short-option h --description 'Pri
3
3
  complete --command yt-dlp --long-option version --description 'Print program version and exit'
4
4
  complete --command yt-dlp --long-option update --short-option U --description 'Check if updates are available. You installed yt-dlp from a manual build or with a package manager; Use that to update'
5
5
  complete --command yt-dlp --long-option no-update --description 'Do not check for updates (default)'
6
- complete --command yt-dlp --long-option update-to --description 'Upgrade/downgrade to a specific version. CHANNEL can be a repository as well. CHANNEL and TAG default to "nightly" and "latest" respectively if omitted; See "UPDATE" for details. Supported channels: stable, nightly, master'
6
+ complete --command yt-dlp --long-option update-to --description 'Upgrade/downgrade to a specific version. CHANNEL can be a repository as well. CHANNEL and TAG default to "stable" and "latest" respectively if omitted; See "UPDATE" for details. Supported channels: stable, nightly, master'
7
7
  complete --command yt-dlp --long-option ignore-errors --short-option i --description 'Ignore download and postprocessing errors. The download will be considered successful even if the postprocessing fails'
8
8
  complete --command yt-dlp --long-option no-abort-on-error --description 'Continue with next video on download errors; e.g. to skip unavailable videos in a playlist (default)'
9
9
  complete --command yt-dlp --long-option abort-on-error --description 'Abort downloading of further videos if an error occurs (Alias: --no-ignore-errors)'
@@ -48,7 +48,7 @@ Do not check for updates (default)
48
48
  --update-to \f[I][CHANNEL]\[at][TAG]\f[R]
49
49
  Upgrade/downgrade to a specific version.
50
50
  CHANNEL can be a repository as well.
51
- CHANNEL and TAG default to \[dq]nightly\[dq] and \[dq]latest\[dq]
51
+ CHANNEL and TAG default to \[dq]stable\[dq] and \[dq]latest\[dq]
52
52
  respectively if omitted; See \[dq]UPDATE\[dq] for details.
53
53
  Supported channels: stable, nightly, master
54
54
  .TP
@@ -2713,12 +2713,12 @@ respectively
2713
2713
  \f[V]player_client\f[R]: Clients to extract video data from.
2714
2714
  The currently available clients are \f[V]web\f[R], \f[V]web_safari\f[R],
2715
2715
  \f[V]web_embedded\f[R], \f[V]web_music\f[R], \f[V]web_creator\f[R],
2716
- \f[V]mweb\f[R], \f[V]ios\f[R], \f[V]android\f[R],
2717
- \f[V]android_sdkless\f[R], \f[V]android_vr\f[R], \f[V]tv\f[R],
2716
+ \f[V]mweb\f[R], \f[V]ios\f[R], \f[V]ios_downgraded\f[R],
2717
+ \f[V]android\f[R], \f[V]android_vr\f[R], \f[V]tv\f[R],
2718
2718
  \f[V]tv_simply\f[R], \f[V]tv_downgraded\f[R], and \f[V]tv_embedded\f[R].
2719
- By default, \f[V]android_sdkless,web,web_safari\f[R] is used.
2720
- If no JavaScript runtime/engine is available, then only
2721
- \f[V]android_sdkless\f[R] is used.
2719
+ By default, \f[V]android_vr,ios_downgraded,web,web_safari\f[R] is used.
2720
+ If no JavaScript runtime/engine is available, then
2721
+ \f[V]android_vr,ios_downgraded\f[R] is used.
2722
2722
  If logged-in cookies are passed to yt-dlp, then
2723
2723
  \f[V]tv_downgraded,web,web_safari\f[R] is used for free accounts and
2724
2724
  \f[V]tv_downgraded,web_creator,web\f[R] is used for premium accounts.
@@ -3075,9 +3075,10 @@ Default is \f[V]asc\f[R]
3075
3075
  .IP \[bu] 2
3076
3076
  \f[V]client\f[R]: Client to extract video data from.
3077
3077
  The currently available clients are \f[V]android\f[R], \f[V]ios\f[R],
3078
- and \f[V]web\f[R].
3078
+ \f[V]macos\f[R] and \f[V]web\f[R].
3079
3079
  Only one client can be used.
3080
- The \f[V]web\f[R] client is used by default.
3080
+ The \f[V]macos\f[R] client is used by default, but the \f[V]web\f[R]
3081
+ client is used when logged-in.
3081
3082
  The \f[V]web\f[R] client only works with account cookies or login
3082
3083
  credentials.
3083
3084
  The \f[V]android\f[R] and \f[V]ios\f[R] clients only work with
@@ -3215,8 +3216,8 @@ for details on the specific issues solved by these builds
3215
3216
  name (https://pypi.org/project/ffmpeg)
3216
3217
  .RE
3217
3218
  .IP \[bu] 2
3218
- \f[B]yt-dlp-ejs\f[R] (https://github.com/yt-dlp/ejs) - Required for
3219
- deciphering YouTube n/sig values.
3219
+ \f[B]yt-dlp-ejs\f[R] (https://github.com/yt-dlp/ejs) - Required for full
3220
+ YouTube support.
3220
3221
  Licensed under
3221
3222
  Unlicense (https://github.com/yt-dlp/ejs/blob/main/LICENSE), bundles
3222
3223
  MIT (https://github.com/davidbonnet/astring/blob/main/LICENSE) and
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: yt-dlp
3
- Version: 2026.1.25.233128.dev0
3
+ Version: 2026.1.29
4
4
  Summary: A feature-rich command-line audio/video downloader
5
5
  Project-URL: Documentation, https://github.com/yt-dlp/yt-dlp#readme
6
6
  Project-URL: Repository, https://github.com/yt-dlp/yt-dlp
7
7
  Project-URL: Tracker, https://github.com/yt-dlp/yt-dlp/issues
8
8
  Project-URL: Funding, https://github.com/yt-dlp/yt-dlp/blob/master/Maintainers.md#maintainers
9
9
  Author-email: pukkandan <pukkandan.ytdlp@gmail.com>
10
- Maintainer-email: maintainers@yt-dlp.org, Grub4K <contact@grub4k.xyz>, bashonly <bashonly@protonmail.com>, coletdjnz <coletdjnz@protonmail.com>, sepro <sepro@sepr0.com>
10
+ Maintainer-email: maintainers@yt-dlp.org, Grub4K <contact@grub4k.dev>, bashonly <bashonly@protonmail.com>, coletdjnz <coletdjnz@protonmail.com>
11
11
  License-Expression: Unlicense
12
12
  License-File: LICENSE
13
13
  Keywords: cli,downloader,sponsorblock,youtube-dl,youtube-downloader,yt-dlp
@@ -46,9 +46,9 @@ Requires-Dist: pycryptodomex; extra == 'default'
46
46
  Requires-Dist: requests<3,>=2.32.2; extra == 'default'
47
47
  Requires-Dist: urllib3<3,>=2.0.2; extra == 'default'
48
48
  Requires-Dist: websockets>=13.0; extra == 'default'
49
- Requires-Dist: yt-dlp-ejs==0.3.2; extra == 'default'
49
+ Requires-Dist: yt-dlp-ejs==0.4.0; extra == 'default'
50
50
  Provides-Extra: deno
51
- Requires-Dist: deno>=2.6.5; extra == 'deno'
51
+ Requires-Dist: deno>=2.6.6; extra == 'deno'
52
52
  Provides-Extra: dev
53
53
  Requires-Dist: autopep8~=2.0; extra == 'dev'
54
54
  Requires-Dist: pre-commit; extra == 'dev'
@@ -287,7 +287,7 @@ While all the other dependencies are optional, `ffmpeg`, `ffprobe`, `yt-dlp-ejs`
287
287
 
288
288
  **Important**: What you need is ffmpeg *binary*, **NOT** [the Python package of the same name](https://pypi.org/project/ffmpeg)
289
289
 
290
- * [**yt-dlp-ejs**](https://github.com/yt-dlp/ejs) - Required for deciphering YouTube n/sig values. Licensed under [Unlicense](https://github.com/yt-dlp/ejs/blob/main/LICENSE), bundles [MIT](https://github.com/davidbonnet/astring/blob/main/LICENSE) and [ISC](https://github.com/meriyah/meriyah/blob/main/LICENSE.md) components.
290
+ * [**yt-dlp-ejs**](https://github.com/yt-dlp/ejs) - Required for full YouTube support. Licensed under [Unlicense](https://github.com/yt-dlp/ejs/blob/main/LICENSE), bundles [MIT](https://github.com/davidbonnet/astring/blob/main/LICENSE) and [ISC](https://github.com/meriyah/meriyah/blob/main/LICENSE.md) components.
291
291
 
292
292
  A JavaScript runtime/engine like [**deno**](https://deno.land) (recommended), [**node.js**](https://nodejs.org), [**bun**](https://bun.sh), or [**QuickJS**](https://bellard.org/quickjs/) is also required to run yt-dlp-ejs. See [the wiki](https://github.com/yt-dlp/yt-dlp/wiki/EJS).
293
293
 
@@ -388,7 +388,7 @@ Tip: Use `CTRL`+`F` (or `Command`+`F`) to search by keywords
388
388
  --no-update Do not check for updates (default)
389
389
  --update-to [CHANNEL]@[TAG] Upgrade/downgrade to a specific version.
390
390
  CHANNEL can be a repository as well. CHANNEL
391
- and TAG default to "nightly" and "latest"
391
+ and TAG default to "stable" and "latest"
392
392
  respectively if omitted; See "UPDATE" for
393
393
  details. Supported channels: stable,
394
394
  nightly, master
@@ -1934,7 +1934,7 @@ The following extractors use this feature:
1934
1934
  #### youtube
1935
1935
  * `lang`: Prefer translated metadata (`title`, `description` etc) of this language code (case-sensitive). By default, the video primary language metadata is preferred, with a fallback to `en` translated. See [youtube/_base.py](https://github.com/yt-dlp/yt-dlp/blob/415b4c9f955b1a0391204bd24a7132590e7b3bdb/yt_dlp/extractor/youtube/_base.py#L402-L409) for the list of supported content language codes
1936
1936
  * `skip`: One or more of `hls`, `dash` or `translated_subs` to skip extraction of the m3u8 manifests, dash manifests and [auto-translated subtitles](https://github.com/yt-dlp/yt-dlp/issues/4090#issuecomment-1158102032) respectively
1937
- * `player_client`: Clients to extract video data from. The currently available clients are `web`, `web_safari`, `web_embedded`, `web_music`, `web_creator`, `mweb`, `ios`, `android`, `android_sdkless`, `android_vr`, `tv`, `tv_simply`, `tv_downgraded`, and `tv_embedded`. By default, `android_sdkless,web,web_safari` is used. If no JavaScript runtime/engine is available, then only `android_sdkless` is used. If logged-in cookies are passed to yt-dlp, then `tv_downgraded,web,web_safari` is used for free accounts and `tv_downgraded,web_creator,web` is used for premium accounts. The `web_music` client is added for `music.youtube.com` URLs when logged-in cookies are used. The `web_embedded` client is added for age-restricted videos but only works if the video is embeddable. The `tv_embedded` and `web_creator` clients are added for age-restricted videos if account age-verification is required. Some clients, such as `web` and `web_music`, require a `po_token` for their formats to be downloadable. Some clients, such as `web_creator`, will only work with authentication. Not all clients support authentication via cookies. You can use `default` for the default clients, or you can use `all` for all clients (not recommended). You can prefix a client with `-` to exclude it, e.g. `youtube:player_client=default,-ios`
1937
+ * `player_client`: Clients to extract video data from. The currently available clients are `web`, `web_safari`, `web_embedded`, `web_music`, `web_creator`, `mweb`, `ios`, `ios_downgraded`, `android`, `android_vr`, `tv`, `tv_simply`, `tv_downgraded`, and `tv_embedded`. By default, `android_vr,ios_downgraded,web,web_safari` is used. If no JavaScript runtime/engine is available, then `android_vr,ios_downgraded` is used. If logged-in cookies are passed to yt-dlp, then `tv_downgraded,web,web_safari` is used for free accounts and `tv_downgraded,web_creator,web` is used for premium accounts. The `web_music` client is added for `music.youtube.com` URLs when logged-in cookies are used. The `web_embedded` client is added for age-restricted videos but only works if the video is embeddable. The `tv_embedded` and `web_creator` clients are added for age-restricted videos if account age-verification is required. Some clients, such as `web` and `web_music`, require a `po_token` for their formats to be downloadable. Some clients, such as `web_creator`, will only work with authentication. Not all clients support authentication via cookies. You can use `default` for the default clients, or you can use `all` for all clients (not recommended). You can prefix a client with `-` to exclude it, e.g. `youtube:player_client=default,-ios`
1938
1938
  * `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), `initial_data` (skip initial data/next ep request). While these options can help reduce the number of requests needed or avoid some rate-limiting, they could cause issues such as missing formats or metadata. See [#860](https://github.com/yt-dlp/yt-dlp/pull/860) and [#12826](https://github.com/yt-dlp/yt-dlp/issues/12826) for more details
1939
1939
  * `webpage_skip`: Skip extraction of embedded webpage data. One or both of `player_response`, `initial_data`. These options are for testing purposes and don't skip any network requests
1940
1940
  * `player_params`: YouTube player parameters to use for player requests. Will overwrite any default ones set by yt-dlp.
@@ -2046,7 +2046,7 @@ The following extractors use this feature:
2046
2046
  * `backend`: Backend API to use for extraction - one of `streaks` (default) or `brightcove` (deprecated)
2047
2047
 
2048
2048
  #### vimeo
2049
- * `client`: Client to extract video data from. The currently available clients are `android`, `ios`, and `web`. Only one client can be used. The `web` client is used by default. The `web` client only works with account cookies or login credentials. The `android` and `ios` clients only work with previously cached OAuth tokens
2049
+ * `client`: Client to extract video data from. The currently available clients are `android`, `ios`, `macos` and `web`. Only one client can be used. The `macos` client is used by default, but the `web` client is used when logged-in. The `web` client only works with account cookies or login credentials. The `android` and `ios` clients only work with previously cached OAuth tokens
2050
2050
  * `original_format_policy`: Policy for when to try extracting original formats. One of `always`, `never`, or `auto`. The default `auto` policy tries to avoid exceeding the web client's API rate-limit by only making an extra request when Vimeo publicizes the video's downloadability
2051
2051
 
2052
2052
  **Note**: These options may be changed/removed in the future without concern for backward compatibility