wimtv.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. from .common import InfoExtractor
  2. from ..utils import (
  3. ExtractorError,
  4. determine_ext,
  5. parse_duration,
  6. urlencode_postdata,
  7. )
  8. class WimTVIE(InfoExtractor):
  9. _player = None
  10. _UUID_RE = r'[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}'
  11. _VALID_URL = rf'''(?x:
  12. https?://platform\.wim\.tv/
  13. (?:
  14. (?:embed/)?\?
  15. |\#/webtv/.+?/
  16. )
  17. (?P<type>vod|live|cast)[=/]
  18. (?P<id>{_UUID_RE}).*?)'''
  19. _EMBED_REGEX = [rf'<iframe[^>]+src=["\'](?P<url>{_VALID_URL})']
  20. _TESTS = [{
  21. # vod stream
  22. 'url': 'https://platform.wim.tv/embed/?vod=db29fb32-bade-47b6-a3a6-cb69fe80267a',
  23. 'md5': 'db29fb32-bade-47b6-a3a6-cb69fe80267a',
  24. 'info_dict': {
  25. 'id': 'db29fb32-bade-47b6-a3a6-cb69fe80267a',
  26. 'ext': 'mp4',
  27. 'title': 'AMA SUPERCROSS 2020 - R2 ST. LOUIS',
  28. 'duration': 6481,
  29. 'thumbnail': r're:https?://.+?/thumbnail/.+?/720$',
  30. },
  31. 'params': {
  32. 'skip_download': True,
  33. },
  34. }, {
  35. # live stream
  36. 'url': 'https://platform.wim.tv/embed/?live=28e22c22-49db-40f3-8c37-8cbb0ff44556&autostart=true',
  37. 'info_dict': {
  38. 'id': '28e22c22-49db-40f3-8c37-8cbb0ff44556',
  39. 'ext': 'mp4',
  40. 'title': 'Streaming MSmotorTV',
  41. 'is_live': True,
  42. },
  43. 'params': {
  44. 'skip_download': True,
  45. },
  46. }, {
  47. 'url': 'https://platform.wim.tv/#/webtv/automotornews/vod/422492b6-539e-474d-9c6b-68c9d5893365',
  48. 'only_matching': True,
  49. }, {
  50. 'url': 'https://platform.wim.tv/#/webtv/renzoarborechannel/cast/f47e0d15-5b45-455e-bf0d-dba8ffa96365',
  51. 'only_matching': True,
  52. }]
  53. def _real_initialize(self):
  54. if not self._player:
  55. self._get_player_data()
  56. def _get_player_data(self):
  57. msg_id = 'Player data'
  58. self._player = {}
  59. datas = [{
  60. 'url': 'https://platform.wim.tv/common/libs/player/wimtv/wim-rest.js',
  61. 'vars': [{
  62. 'regex': r'appAuth = "(.+?)"',
  63. 'variable': 'app_auth',
  64. }],
  65. }, {
  66. 'url': 'https://platform.wim.tv/common/config/endpointconfig.js',
  67. 'vars': [{
  68. 'regex': r'PRODUCTION_HOSTNAME_THUMB = "(.+?)"',
  69. 'variable': 'thumb_server',
  70. }, {
  71. 'regex': r'PRODUCTION_HOSTNAME_THUMB\s*\+\s*"(.+?)"',
  72. 'variable': 'thumb_server_path',
  73. }],
  74. }]
  75. for data in datas:
  76. temp = self._download_webpage(data['url'], msg_id)
  77. for var in data['vars']:
  78. val = self._search_regex(var['regex'], temp, msg_id)
  79. if not val:
  80. raise ExtractorError('{} not found'.format(var['variable']))
  81. self._player[var['variable']] = val
  82. def _generate_token(self):
  83. json = self._download_json(
  84. 'https://platform.wim.tv/wimtv-server/oauth/token', 'Token generation',
  85. headers={'Authorization': 'Basic {}'.format(self._player['app_auth'])},
  86. data=urlencode_postdata({'grant_type': 'client_credentials'}))
  87. token = json.get('access_token')
  88. if not token:
  89. raise ExtractorError('access token not generated')
  90. return token
  91. def _generate_thumbnail(self, thumb_id, width='720'):
  92. if not thumb_id or not self._player.get('thumb_server'):
  93. return None
  94. if not self._player.get('thumb_server_path'):
  95. self._player['thumb_server_path'] = ''
  96. return '{}{}/asset/thumbnail/{}/{}'.format(
  97. self._player['thumb_server'],
  98. self._player['thumb_server_path'],
  99. thumb_id, width)
  100. def _real_extract(self, url):
  101. urlc = self._match_valid_url(url).groupdict()
  102. video_id = urlc['id']
  103. stream_type = is_live = None
  104. if urlc['type'] in {'live', 'cast'}:
  105. stream_type = urlc['type'] + '/channel'
  106. is_live = True
  107. else:
  108. stream_type = 'vod'
  109. is_live = False
  110. token = self._generate_token()
  111. json = self._download_json(
  112. f'https://platform.wim.tv/wimtv-server/api/public/{stream_type}/{video_id}/play',
  113. video_id, headers={
  114. 'Authorization': f'Bearer {token}',
  115. 'Content-Type': 'application/json',
  116. }, data=b'{}')
  117. formats = []
  118. for src in json.get('srcs') or []:
  119. if src.get('mimeType') == 'application/x-mpegurl':
  120. formats.extend(
  121. self._extract_m3u8_formats(
  122. src.get('uniqueStreamer'), video_id, 'mp4'))
  123. if src.get('mimeType') == 'video/flash':
  124. formats.append({
  125. 'format_id': 'rtmp',
  126. 'url': src.get('uniqueStreamer'),
  127. 'ext': determine_ext(src.get('uniqueStreamer'), 'flv'),
  128. 'rtmp_live': is_live,
  129. })
  130. json = json.get('resource')
  131. thumb = self._generate_thumbnail(json.get('thumbnailId'))
  132. return {
  133. 'id': video_id,
  134. 'title': json.get('title') or json.get('name'),
  135. 'duration': parse_duration(json.get('duration')),
  136. 'formats': formats,
  137. 'thumbnail': thumb,
  138. 'is_live': is_live,
  139. }