mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2025-06-28 01:18:30 +00:00
Fix: HTTP Error 503 - Service Unavailable
This commit is contained in:
parent
73bf102116
commit
c0080d0441
@ -21,6 +21,7 @@
|
|||||||
class HotStarBaseIE(InfoExtractor):
|
class HotStarBaseIE(InfoExtractor):
|
||||||
_BASE_URL = 'https://www.hotstar.com'
|
_BASE_URL = 'https://www.hotstar.com'
|
||||||
_API_URL = 'https://api.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'
|
_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):
|
def _call_api_v1(self, path, *args, **kwargs):
|
||||||
@ -34,7 +35,8 @@ def _call_api_impl(self, path, video_id, query, st=None, cookies=None):
|
|||||||
auth = f'st={st}~exp={exp}~acl=/*'
|
auth = f'st={st}~exp={exp}~acl=/*'
|
||||||
auth += '~hmac=' + hmac.new(self._AKAMAI_ENCRYPTION_KEY, auth.encode(), hashlib.sha256).hexdigest()
|
auth += '~hmac=' + hmac.new(self._AKAMAI_ENCRYPTION_KEY, auth.encode(), hashlib.sha256).hexdigest()
|
||||||
|
|
||||||
if cookies and cookies.get('userUP'):
|
if cookies:
|
||||||
|
if cookies.get('userUP'):
|
||||||
token = cookies.get('userUP').value
|
token = cookies.get('userUP').value
|
||||||
else:
|
else:
|
||||||
token = self._download_json(
|
token = self._download_json(
|
||||||
@ -47,27 +49,38 @@ def _call_api_impl(self, path, video_id, query, st=None, cookies=None):
|
|||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
})['user_identity']
|
})['user_identity']
|
||||||
|
|
||||||
|
if cookies.get('deviceId'):
|
||||||
|
device_id = cookies.get('deviceId').value
|
||||||
|
else:
|
||||||
|
device_id = str(uuid.uuid4())
|
||||||
|
|
||||||
response = self._download_json(
|
response = self._download_json(
|
||||||
f'{self._API_URL}/{path}', video_id, query=query,
|
f'{self._API_URL_V2}/{path}', video_id, query=query,
|
||||||
headers={
|
headers={
|
||||||
'hotstarauth': auth,
|
"user-agent": "Disney+;in.startv.hotstar.dplus.tv/23.08.14.4.2915 (Android/13)",
|
||||||
'x-hs-appversion': '6.72.2',
|
"hotstarauth": auth,
|
||||||
'x-hs-platform': 'web',
|
"x-hs-usertoken": token,
|
||||||
'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(
|
raise ExtractorError(
|
||||||
response['message'], expected=True)
|
'Unintended response! Try again later or report this issue if problem persist', expected=True)
|
||||||
return response['data']
|
return response['success']
|
||||||
|
|
||||||
|
def _call_api_v2(self, path, video_id, st=None, cookies=None,
|
||||||
|
content_type=None, video_codec='h264', resolution='hd', range='sdr'):
|
||||||
|
|
||||||
def _call_api_v2(self, path, video_id, st=None, cookies=None):
|
|
||||||
return self._call_api_impl(
|
return self._call_api_impl(
|
||||||
f'{path}/content/{video_id}', video_id, st=st, cookies=cookies, query={
|
f'{path}', video_id, st=st, cookies=cookies,
|
||||||
'desired-config': 'audio_channel:stereo|container:fmp4|dynamic_range:hdr|encryption:plain|ladder:tv|package:dash|resolution:fhd|subs-tag:HotstarVIP|video_codec:h265',
|
query={
|
||||||
'device-id': cookies.get('device_id').value if cookies.get('device_id') else str(uuid.uuid4()),
|
"content_id": video_id,
|
||||||
'os-name': 'Windows',
|
"filters": f"content_type={content_type}",
|
||||||
'os-version': '10',
|
"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):
|
def _playlist_entries(self, path, item_id, root=None, **kwargs):
|
||||||
@ -208,6 +221,13 @@ class HotStarIE(HotStarBaseIE):
|
|||||||
None: 'content',
|
None: 'content',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_CONTENT_TYPE = {
|
||||||
|
'movie': 'MOVIE',
|
||||||
|
'episode': 'SHOW',
|
||||||
|
'match': 'SPORTS',
|
||||||
|
None: 'content'
|
||||||
|
}
|
||||||
|
|
||||||
_IGNORE_MAP = {
|
_IGNORE_MAP = {
|
||||||
'res': 'resolution',
|
'res': 'resolution',
|
||||||
'vcodec': 'video_codec',
|
'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):
|
def _real_extract(self, url):
|
||||||
video_id, video_type = self._match_valid_url(url).group('id', 'type')
|
video_id, video_type = self._match_valid_url(url).group('id', 'type')
|
||||||
video_type = self._TYPE.get(video_type, video_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
|
cookies = self._get_cookies(url) # Cookies before any request
|
||||||
|
|
||||||
video_data = traverse_obj(
|
video_data = traverse_obj(
|
||||||
@ -239,6 +260,8 @@ def _real_extract(self, url):
|
|||||||
if not self.get_param('allow_unplayable_formats') and video_data.get('drmProtected'):
|
if not self.get_param('allow_unplayable_formats') and video_data.get('drmProtected'):
|
||||||
self.report_drm(video_id)
|
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
|
# 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')
|
st = self._download_webpage_handle(f'{self._BASE_URL}/in', video_id)[1].headers.get('x-origin-date')
|
||||||
|
|
||||||
@ -246,18 +269,28 @@ def _real_extract(self, url):
|
|||||||
formats, subs = [], {}
|
formats, subs = [], {}
|
||||||
headers = {'Referer': f'{self._BASE_URL}/in'}
|
headers = {'Referer': f'{self._BASE_URL}/in'}
|
||||||
|
|
||||||
# change to v2 in the future
|
_resp = traverse_obj(
|
||||||
playback_sets = self._call_api_v2('play/v1/playback', video_id, st=st, cookies=cookies)['playBackSets']
|
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')
|
||||||
|
]
|
||||||
|
|
||||||
for playback_set in playback_sets:
|
for playback_set in playback_sets:
|
||||||
if not isinstance(playback_set, dict):
|
if not isinstance(playback_set, dict):
|
||||||
continue
|
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
|
if any(f'{prefix}:{ignore}' in tags
|
||||||
for key, prefix in self._IGNORE_MAP.items()
|
for key, prefix in self._IGNORE_MAP.items()
|
||||||
for ignore in self._configuration_arg(key)):
|
for ignore in self._configuration_arg(key)):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
format_url = url_or_none(playback_set.get('playbackUrl'))
|
format_url = url_or_none(playback_set.get('content_url'))
|
||||||
if not format_url:
|
if not format_url:
|
||||||
continue
|
continue
|
||||||
format_url = re.sub(r'(?<=//staragvod)(\d)', r'web\1', format_url)
|
format_url = re.sub(r'(?<=//staragvod)(\d)', r'web\1', format_url)
|
||||||
|
Loading…
Reference in New Issue
Block a user