From 876b5f767258d5656a61b9763a7736ccaeca4292 Mon Sep 17 00:00:00 2001 From: helpimnotdrowning <35247379+helpimnotdrowning@users.noreply.github.com> Date: Thu, 26 Jun 2025 15:29:20 -0500 Subject: [PATCH 1/4] [ie/kick] Extract sub-only downloads `XSRF-TOKEN` cookie was no longer being passed so downloads would 403. Found that `session_token` now contained the expected value. --- yt_dlp/extractor/kick.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/yt_dlp/extractor/kick.py b/yt_dlp/extractor/kick.py index 1f001d421..13427d916 100644 --- a/yt_dlp/extractor/kick.py +++ b/yt_dlp/extractor/kick.py @@ -1,4 +1,6 @@ +from urllib import parse + from .common import InfoExtractor from ..networking import HEADRequest from ..utils import ( @@ -19,13 +21,12 @@ class KickBaseIE(InfoExtractor): def _real_initialize(self): self._request_webpage( HEADRequest('https://kick.com/'), None, 'Setting up session', fatal=False, impersonate=True) - xsrf_token = self._get_cookies('https://kick.com/').get('XSRF-TOKEN') - if not xsrf_token: - self.write_debug('kick.com did not set XSRF-TOKEN cookie') + session_token = self._get_cookies('https://kick.com/').get('session_token') + if not session_token: + self.write_debug('kick.com did not set session_token cookie') KickBaseIE._API_HEADERS = { - 'Authorization': f'Bearer {xsrf_token.value}', - 'X-XSRF-TOKEN': xsrf_token.value, - } if xsrf_token else {} + 'Authorization': f'Bearer {parse.unquote(session_token.value)}', + } if session_token else {} def _call_api(self, path, display_id, note='Downloading API JSON', headers={}, **kwargs): return self._download_json( From 4f208f71516092f2e9a849cd99afe8aa699c2b38 Mon Sep 17 00:00:00 2001 From: helpimnotdrowning <35247379+helpimnotdrowning@users.noreply.github.com> Date: Thu, 26 Jun 2025 18:19:39 -0500 Subject: [PATCH 2/4] `_real_initialize()` -> cached `_api_headers` field implement review suggestions --- yt_dlp/extractor/kick.py | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/yt_dlp/extractor/kick.py b/yt_dlp/extractor/kick.py index 13427d916..a5aaa13ab 100644 --- a/yt_dlp/extractor/kick.py +++ b/yt_dlp/extractor/kick.py @@ -1,14 +1,13 @@ -from urllib import parse +import functools +import urllib.parse from .common import InfoExtractor -from ..networking import HEADRequest from ..utils import ( UserNotLive, determine_ext, float_or_none, int_or_none, - merge_dicts, parse_iso8601, str_or_none, traverse_obj, @@ -18,20 +17,18 @@ class KickBaseIE(InfoExtractor): - def _real_initialize(self): - self._request_webpage( - HEADRequest('https://kick.com/'), None, 'Setting up session', fatal=False, impersonate=True) - session_token = self._get_cookies('https://kick.com/').get('session_token') - if not session_token: - self.write_debug('kick.com did not set session_token cookie') - KickBaseIE._API_HEADERS = { - 'Authorization': f'Bearer {parse.unquote(session_token.value)}', - } if session_token else {} + @functools.cached_property + def _api_headers(self): + token = traverse_obj( + self._get_cookies('https://kick.com/'), + ('session_token', 'value', {urllib.parse.unquote}), + ) + return {'Authorization': f'Bearer {token}'} if token else {} def _call_api(self, path, display_id, note='Downloading API JSON', headers={}, **kwargs): return self._download_json( f'https://kick.com/api/{path}', display_id, note=note, - headers=merge_dicts(headers, self._API_HEADERS), impersonate=True, **kwargs) + headers={**self._api_headers, **headers}, impersonate=True, **kwargs) class KickIE(KickBaseIE): From fcf614b829bcee7c96e437cc5fc336f2c40104b9 Mon Sep 17 00:00:00 2001 From: bashonly <88596187+bashonly@users.noreply.github.com> Date: Fri, 27 Jun 2025 03:38:25 +0000 Subject: [PATCH 3/4] formatting --- yt_dlp/extractor/kick.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/yt_dlp/extractor/kick.py b/yt_dlp/extractor/kick.py index a5aaa13ab..cf51475f3 100644 --- a/yt_dlp/extractor/kick.py +++ b/yt_dlp/extractor/kick.py @@ -21,8 +21,7 @@ class KickBaseIE(InfoExtractor): def _api_headers(self): token = traverse_obj( self._get_cookies('https://kick.com/'), - ('session_token', 'value', {urllib.parse.unquote}), - ) + ('session_token', 'value', {urllib.parse.unquote})) return {'Authorization': f'Bearer {token}'} if token else {} def _call_api(self, path, display_id, note='Downloading API JSON', headers={}, **kwargs): From 6e3c184fbf15e4809dc84f39b628a8c41debe909 Mon Sep 17 00:00:00 2001 From: bashonly <88596187+bashonly@users.noreply.github.com> Date: Fri, 27 Jun 2025 03:39:03 +0000 Subject: [PATCH 4/4] Apply suggestions from code review --- yt_dlp/extractor/kick.py | 1 - 1 file changed, 1 deletion(-) diff --git a/yt_dlp/extractor/kick.py b/yt_dlp/extractor/kick.py index cf51475f3..8049e1e34 100644 --- a/yt_dlp/extractor/kick.py +++ b/yt_dlp/extractor/kick.py @@ -1,4 +1,3 @@ - import functools import urllib.parse