1
0
mirror of https://github.com/yt-dlp/yt-dlp.git synced 2025-06-27 08:58:30 +00:00

Fix: HTTP Error 503 - Service Unavailable

This commit is contained in:
chauhantirth 2025-06-23 21:45:01 +05:30
parent 73bf102116
commit c0080d0441

View File

@ -21,6 +21,7 @@
class HotStarBaseIE(InfoExtractor):
_BASE_URL = 'https://www.hotstar.com'
_API_URL = 'https://api.hotstar.com'
_API_URL_V2 = 'https://apix.hotstar.com'
_AKAMAI_ENCRYPTION_KEY = b'\x05\xfc\x1a\x01\xca\xc9\x4b\xc4\x12\xfc\x53\x12\x07\x75\xf9\xee'
def _call_api_v1(self, path, *args, **kwargs):
@ -34,41 +35,53 @@ def _call_api_impl(self, path, video_id, query, st=None, cookies=None):
auth = f'st={st}~exp={exp}~acl=/*'
auth += '~hmac=' + hmac.new(self._AKAMAI_ENCRYPTION_KEY, auth.encode(), hashlib.sha256).hexdigest()
if cookies and cookies.get('userUP'):
token = cookies.get('userUP').value
else:
token = self._download_json(
f'{self._API_URL}/um/v3/users',
video_id, note='Downloading token',
data=json.dumps({'device_ids': [{'id': str(uuid.uuid4()), 'type': 'device_id'}]}).encode(),
headers={
'hotstarauth': auth,
'x-hs-platform': 'PCTV', # or 'web'
'Content-Type': 'application/json',
})['user_identity']
if cookies:
if cookies.get('userUP'):
token = cookies.get('userUP').value
else:
token = self._download_json(
f'{self._API_URL}/um/v3/users',
video_id, note='Downloading token',
data=json.dumps({'device_ids': [{'id': str(uuid.uuid4()), 'type': 'device_id'}]}).encode(),
headers={
'hotstarauth': auth,
'x-hs-platform': 'PCTV', # or 'web'
'Content-Type': 'application/json',
})['user_identity']
if cookies.get('deviceId'):
device_id = cookies.get('deviceId').value
else:
device_id = str(uuid.uuid4())
response = self._download_json(
f'{self._API_URL}/{path}', video_id, query=query,
f'{self._API_URL_V2}/{path}', video_id, query=query,
headers={
'hotstarauth': auth,
'x-hs-appversion': '6.72.2',
'x-hs-platform': 'web',
'x-hs-usertoken': token,
"user-agent": "Disney+;in.startv.hotstar.dplus.tv/23.08.14.4.2915 (Android/13)",
"hotstarauth": auth,
"x-hs-usertoken": token,
"x-hs-device-id": device_id,
"x-hs-client": "platform:androidtv;app_id:in.startv.hotstar.dplus.tv;app_version:23.08.14.4;os:Android;os_version:13;schema_version:0.0.970",
"x-hs-platform": "androidtv",
"content-type": "application/json",
})
if response['message'] != "Playback URL's fetched successfully":
if not response['success']:
raise ExtractorError(
response['message'], expected=True)
return response['data']
'Unintended response! Try again later or report this issue if problem persist', expected=True)
return response['success']
def _call_api_v2(self, path, video_id, st=None, cookies=None):
def _call_api_v2(self, path, video_id, st=None, cookies=None,
content_type=None, video_codec='h264', resolution='hd', range='sdr'):
return self._call_api_impl(
f'{path}/content/{video_id}', video_id, st=st, cookies=cookies, query={
'desired-config': 'audio_channel:stereo|container:fmp4|dynamic_range:hdr|encryption:plain|ladder:tv|package:dash|resolution:fhd|subs-tag:HotstarVIP|video_codec:h265',
'device-id': cookies.get('device_id').value if cookies.get('device_id') else str(uuid.uuid4()),
'os-name': 'Windows',
'os-version': '10',
})
f'{path}', video_id, st=st, cookies=cookies,
query={
"content_id": video_id,
"filters": f"content_type={content_type}",
"client_capabilities": "{\"package\":[\"dash\",\"hls\"],\"container\":[\"fmp4br\",\"fmp4\"],\"ads\":[\"non_ssai\",\"ssai\"],\"audio_channel\":[\"atmos\",\"dolby51\",\"stereo\"],\"encryption\":[\"plain\",\"widevine\"],\"video_codec\":[\"" + video_codec + "\"],\"ladder\":[\"tv\",\"full\"],\"resolution\":[\"" + resolution + "\"],\"true_resolution\":[\"" + resolution + "\"],\"dynamic_range\":[\"" + range + "\"]}",
"drm_parameters": "{\"widevine_security_level\":[\"SW_SECURE_DECODE\",\"SW_SECURE_CRYPTO\"],\"hdcp_version\":[\"HDCP_V2_2\",\"HDCP_V2_1\",\"HDCP_V2\",\"HDCP_V1\"]}"
})
def _playlist_entries(self, path, item_id, root=None, **kwargs):
results = self._call_api_v1(path, item_id, **kwargs)['body']['results']
@ -208,6 +221,13 @@ class HotStarIE(HotStarBaseIE):
None: 'content',
}
_CONTENT_TYPE = {
'movie': 'MOVIE',
'episode': 'SHOW',
'match': 'SPORTS',
None: 'content'
}
_IGNORE_MAP = {
'res': 'resolution',
'vcodec': 'video_codec',
@ -230,6 +250,7 @@ def _video_url(cls, video_id, video_type=None, *, slug='ignore_me', root=None):
def _real_extract(self, url):
video_id, video_type = self._match_valid_url(url).group('id', 'type')
video_type = self._TYPE.get(video_type, video_type)
content_type = self._CONTENT_TYPE.get(video_type, video_type)
cookies = self._get_cookies(url) # Cookies before any request
video_data = traverse_obj(
@ -239,25 +260,37 @@ def _real_extract(self, url):
if not self.get_param('allow_unplayable_formats') and video_data.get('drmProtected'):
self.report_drm(video_id)
content_type = video_data.get('assetType') or video_data.get('contentType') or content_type
# See https://github.com/yt-dlp/yt-dlp/issues/396
st = self._download_webpage_handle(f'{self._BASE_URL}/in', video_id)[1].headers.get('x-origin-date')
geo_restricted = False
formats, subs = [], {}
headers = {'Referer': f'{self._BASE_URL}/in'}
_resp = traverse_obj(
self._call_api_v2(
'/v2/pages/watch', video_id, st=st, cookies=cookies,
content_type=content_type, video_codec='h265', resolution='4k', range='hdr'),
('page','spaces','player','widget_wrappers',0,'widget','data','player_config', {dict})) or {}
playback_sets = [
traverse_obj(_resp, (path1, path2, {dict}))
for path1 in ('media_asset', 'media_asset_v2')
for path2 in ('primary', 'fallback')
]
# change to v2 in the future
playback_sets = self._call_api_v2('play/v1/playback', video_id, st=st, cookies=cookies)['playBackSets']
for playback_set in playback_sets:
if not isinstance(playback_set, dict):
continue
tags = str_or_none(playback_set.get('tagsCombination')) or ''
tags = str_or_none(playback_set.get('playback_tags')) or ''
if any(f'{prefix}:{ignore}' in tags
for key, prefix in self._IGNORE_MAP.items()
for ignore in self._configuration_arg(key)):
continue
format_url = url_or_none(playback_set.get('playbackUrl'))
format_url = url_or_none(playback_set.get('content_url'))
if not format_url:
continue
format_url = re.sub(r'(?<=//staragvod)(\d)', r'web\1', format_url)