imggaming.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. # coding: utf-8
  2. from __future__ import unicode_literals
  3. import json
  4. import re
  5. from .common import InfoExtractor
  6. from ..compat import compat_HTTPError
  7. from ..utils import (
  8. ExtractorError,
  9. int_or_none,
  10. str_or_none,
  11. try_get,
  12. )
  13. class ImgGamingBaseIE(InfoExtractor):
  14. _API_BASE = 'https://dce-frontoffice.imggaming.com/api/v2/'
  15. _API_KEY = '857a1e5d-e35e-4fdf-805b-a87b6f8364bf'
  16. _DOMAIN = None
  17. _HEADERS = None
  18. _LOGIN_REQUIRED = True
  19. _LOGIN_SUFFIX = ''
  20. _MANIFEST_HEADERS = {'Accept-Encoding': 'identity'}
  21. _REALM = None
  22. _TOKEN = None
  23. _VALID_URL_TEMPL = r'https?://%s/(?P<type>live|playlist|video)/(?P<id>\d+)(?:\?.*?\bplaylistId=(?P<playlist_id>\d+))?'
  24. def _real_initialize(self):
  25. if not self._LOGIN_REQUIRED:
  26. return
  27. self._HEADERS = {
  28. 'Realm': 'dce.' + self._REALM,
  29. 'x-api-key': self._API_KEY,
  30. }
  31. email, password = self._get_login_info()
  32. if email is None:
  33. self.raise_login_required()
  34. p_headers = self._HEADERS.copy()
  35. p_headers['Content-Type'] = 'application/json'
  36. self._HEADERS['Authorization'] = 'Bearer ' + self._download_json(
  37. self._API_BASE + 'login' + self._LOGIN_SUFFIX,
  38. None, 'Logging in', data=json.dumps({
  39. 'id': email,
  40. 'secret': password,
  41. }).encode(), headers=p_headers)['authorisationToken']
  42. def _call_api(self, path, media_id):
  43. return self._download_json(
  44. self._API_BASE + path + media_id, media_id, headers=self._HEADERS)
  45. def _extract_media_id(self, url, display_id):
  46. return display_id
  47. def _extract_dve_api_url(self, media_id, media_type):
  48. stream_path = 'stream'
  49. if media_type == 'video':
  50. stream_path += '/vod/'
  51. else:
  52. stream_path += '?eventId='
  53. try:
  54. return self._call_api(
  55. stream_path, media_id)['playerUrlCallback']
  56. except ExtractorError as e:
  57. if isinstance(e.cause, compat_HTTPError) and e.cause.code == 403:
  58. raise ExtractorError(
  59. self._parse_json(e.cause.read().decode(), media_id)['messages'][0],
  60. expected=True)
  61. raise
  62. def _real_extract(self, url):
  63. media_type, display_id, playlist_id = re.match(self._VALID_URL, url).groups()
  64. media_id = self._extract_media_id(url, display_id)
  65. if playlist_id:
  66. if self._downloader.params.get('noplaylist'):
  67. self.to_screen('Downloading just video %s because of --no-playlist' % media_id)
  68. else:
  69. self.to_screen('Downloading playlist %s - add --no-playlist to just download video' % playlist_id)
  70. media_type, media_id = 'playlist', playlist_id
  71. if media_type == 'playlist':
  72. playlist = self._call_api('vod/playlist/', media_id)
  73. entries = []
  74. for video in try_get(playlist, lambda x: x['videos']['vods']) or []:
  75. video_id = str_or_none(video.get('id'))
  76. if not video_id:
  77. continue
  78. entries.append(self.url_result(
  79. 'https://%s/video/%s' % (self._DOMAIN, video_id),
  80. self.ie_key(), video_id))
  81. return self.playlist_result(
  82. entries, media_id, playlist.get('title'),
  83. playlist.get('description'))
  84. dve_api_url = self._extract_dve_api_url(media_id, media_type)
  85. video_data = self._download_json(dve_api_url, media_id)
  86. is_live = media_type == 'live'
  87. if is_live:
  88. title = self._live_title(self._call_api('event/', media_id)['title'])
  89. else:
  90. title = video_data['name']
  91. formats = []
  92. for proto in ('hls', 'dash'):
  93. media_url = video_data.get(proto + 'Url') or try_get(video_data, lambda x: x[proto]['url'])
  94. if not media_url:
  95. continue
  96. if proto == 'hls':
  97. m3u8_formats = self._extract_m3u8_formats(
  98. media_url, media_id, 'mp4', 'm3u8' if is_live else 'm3u8_native',
  99. m3u8_id='hls', fatal=False, headers=self._MANIFEST_HEADERS)
  100. for f in m3u8_formats:
  101. f.setdefault('http_headers', {}).update(self._MANIFEST_HEADERS)
  102. formats.append(f)
  103. else:
  104. formats.extend(self._extract_mpd_formats(
  105. media_url, media_id, mpd_id='dash', fatal=False,
  106. headers=self._MANIFEST_HEADERS))
  107. self._sort_formats(formats)
  108. subtitles = {}
  109. for subtitle in video_data.get('subtitles', []):
  110. subtitle_url = subtitle.get('url')
  111. if not subtitle_url:
  112. continue
  113. subtitles.setdefault(subtitle.get('lang', 'en_US'), []).append({
  114. 'url': subtitle_url,
  115. })
  116. return {
  117. 'id': media_id,
  118. 'display_id': display_id,
  119. 'title': title,
  120. 'formats': formats,
  121. 'thumbnail': video_data.get('thumbnailUrl'),
  122. 'description': video_data.get('description'),
  123. 'duration': int_or_none(video_data.get('duration')),
  124. 'tags': video_data.get('tags'),
  125. 'is_live': is_live,
  126. 'subtitles': subtitles,
  127. }