laola1tv.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. import json
  2. import re
  3. from .common import InfoExtractor
  4. from ..utils import (
  5. ExtractorError,
  6. unified_strdate,
  7. urlencode_postdata,
  8. xpath_element,
  9. xpath_text,
  10. update_url_query,
  11. js_to_json,
  12. )
  13. class Laola1TvEmbedIE(InfoExtractor):
  14. IE_NAME = 'laola1tv:embed'
  15. _VALID_URL = r'https?://(?:www\.)?laola1\.tv/titanplayer\.php\?.*?\bvideoid=(?P<id>\d+)'
  16. _TESTS = [{
  17. # flashvars.premium = "false";
  18. 'url': 'https://www.laola1.tv/titanplayer.php?videoid=708065&type=V&lang=en&portal=int&customer=1024',
  19. 'info_dict': {
  20. 'id': '708065',
  21. 'ext': 'mp4',
  22. 'title': 'MA Long CHN - FAN Zhendong CHN',
  23. 'uploader': 'ITTF - International Table Tennis Federation',
  24. 'upload_date': '20161211',
  25. },
  26. }]
  27. def _extract_token_url(self, stream_access_url, video_id, data):
  28. return self._download_json(
  29. self._proto_relative_url(stream_access_url, 'https:'), video_id,
  30. headers={
  31. 'Content-Type': 'application/json',
  32. }, data=json.dumps(data).encode())['data']['stream-access'][0]
  33. def _extract_formats(self, token_url, video_id):
  34. token_doc = self._download_xml(
  35. token_url, video_id, 'Downloading token',
  36. headers=self.geo_verification_headers())
  37. token_attrib = xpath_element(token_doc, './/token').attrib
  38. if token_attrib['status'] != '0':
  39. raise ExtractorError(
  40. 'Token error: %s' % token_attrib['comment'], expected=True)
  41. formats = self._extract_akamai_formats(
  42. '%s?hdnea=%s' % (token_attrib['url'], token_attrib['auth']),
  43. video_id)
  44. return formats
  45. def _real_extract(self, url):
  46. video_id = self._match_id(url)
  47. webpage = self._download_webpage(url, video_id)
  48. flash_vars = self._search_regex(
  49. r'(?s)flashvars\s*=\s*({.+?});', webpage, 'flash vars')
  50. def get_flashvar(x, *args, **kwargs):
  51. flash_var = self._search_regex(
  52. r'%s\s*:\s*"([^"]+)"' % x,
  53. flash_vars, x, default=None)
  54. if not flash_var:
  55. flash_var = self._search_regex([
  56. r'flashvars\.%s\s*=\s*"([^"]+)"' % x,
  57. r'%s\s*=\s*"([^"]+)"' % x],
  58. webpage, x, *args, **kwargs)
  59. return flash_var
  60. hd_doc = self._download_xml(
  61. 'http://www.laola1.tv/server/hd_video.php', video_id, query={
  62. 'play': get_flashvar('streamid'),
  63. 'partner': get_flashvar('partnerid'),
  64. 'portal': get_flashvar('portalid'),
  65. 'lang': get_flashvar('sprache'),
  66. 'v5ident': '',
  67. })
  68. _v = lambda x, **k: xpath_text(hd_doc, './/video/' + x, **k)
  69. title = _v('title', fatal=True)
  70. token_url = None
  71. premium = get_flashvar('premium', default=None)
  72. if premium:
  73. token_url = update_url_query(
  74. _v('url', fatal=True), {
  75. 'timestamp': get_flashvar('timestamp'),
  76. 'auth': get_flashvar('auth'),
  77. })
  78. else:
  79. data_abo = urlencode_postdata(
  80. dict((i, v) for i, v in enumerate(_v('req_liga_abos').split(','))))
  81. stream_access_url = update_url_query(
  82. 'https://club.laola1.tv/sp/laola1/api/v3/user/session/premium/player/stream-access', {
  83. 'videoId': _v('id'),
  84. 'target': self._search_regex(r'vs_target = (\d+);', webpage, 'vs target'),
  85. 'label': _v('label'),
  86. 'area': _v('area'),
  87. })
  88. token_url = self._extract_token_url(stream_access_url, video_id, data_abo)
  89. formats = self._extract_formats(token_url, video_id)
  90. categories_str = _v('meta_sports')
  91. categories = categories_str.split(',') if categories_str else []
  92. is_live = _v('islive') == 'true'
  93. return {
  94. 'id': video_id,
  95. 'title': title,
  96. 'upload_date': unified_strdate(_v('time_date')),
  97. 'uploader': _v('meta_organisation'),
  98. 'categories': categories,
  99. 'is_live': is_live,
  100. 'formats': formats,
  101. }
  102. class Laola1TvBaseIE(Laola1TvEmbedIE): # XXX: Do not subclass from concrete IE
  103. def _extract_video(self, url):
  104. display_id = self._match_id(url)
  105. webpage = self._download_webpage(url, display_id)
  106. if 'Dieser Livestream ist bereits beendet.' in webpage:
  107. raise ExtractorError('This live stream has already finished.', expected=True)
  108. conf = self._parse_json(self._search_regex(
  109. r'(?s)conf\s*=\s*({.+?});', webpage, 'conf'),
  110. display_id,
  111. transform_source=lambda s: js_to_json(re.sub(r'shareurl:.+,', '', s)))
  112. video_id = conf['videoid']
  113. config = self._download_json(conf['configUrl'], video_id, query={
  114. 'videoid': video_id,
  115. 'partnerid': conf['partnerid'],
  116. 'language': conf.get('language', ''),
  117. 'portal': conf.get('portalid', ''),
  118. })
  119. error = config.get('error')
  120. if error:
  121. raise ExtractorError('%s said: %s' % (self.IE_NAME, error), expected=True)
  122. video_data = config['video']
  123. title = video_data['title']
  124. is_live = video_data.get('isLivestream') and video_data.get('isLive')
  125. meta = video_data.get('metaInformation')
  126. sports = meta.get('sports')
  127. categories = sports.split(',') if sports else []
  128. token_url = self._extract_token_url(
  129. video_data['streamAccess'], video_id,
  130. video_data['abo']['required'])
  131. formats = self._extract_formats(token_url, video_id)
  132. return {
  133. 'id': video_id,
  134. 'display_id': display_id,
  135. 'title': title,
  136. 'description': video_data.get('description'),
  137. 'thumbnail': video_data.get('image'),
  138. 'categories': categories,
  139. 'formats': formats,
  140. 'is_live': is_live,
  141. }
  142. class Laola1TvIE(Laola1TvBaseIE):
  143. IE_NAME = 'laola1tv'
  144. _VALID_URL = r'https?://(?:www\.)?laola1\.tv/[a-z]+-[a-z]+/[^/]+/(?P<id>[^/?#&]+)'
  145. _TESTS = [{
  146. 'url': 'http://www.laola1.tv/de-de/video/straubing-tigers-koelner-haie/227883.html',
  147. 'info_dict': {
  148. 'id': '227883',
  149. 'display_id': 'straubing-tigers-koelner-haie',
  150. 'ext': 'flv',
  151. 'title': 'Straubing Tigers - Kölner Haie',
  152. 'upload_date': '20140912',
  153. 'is_live': False,
  154. 'categories': ['Eishockey'],
  155. },
  156. 'params': {
  157. 'skip_download': True,
  158. },
  159. }, {
  160. 'url': 'http://www.laola1.tv/de-de/video/straubing-tigers-koelner-haie',
  161. 'info_dict': {
  162. 'id': '464602',
  163. 'display_id': 'straubing-tigers-koelner-haie',
  164. 'ext': 'flv',
  165. 'title': 'Straubing Tigers - Kölner Haie',
  166. 'upload_date': '20160129',
  167. 'is_live': False,
  168. 'categories': ['Eishockey'],
  169. },
  170. 'params': {
  171. 'skip_download': True,
  172. },
  173. }, {
  174. 'url': 'http://www.laola1.tv/de-de/livestream/2016-03-22-belogorie-belgorod-trentino-diatec-lde',
  175. 'info_dict': {
  176. 'id': '487850',
  177. 'display_id': '2016-03-22-belogorie-belgorod-trentino-diatec-lde',
  178. 'ext': 'flv',
  179. 'title': 'Belogorie BELGOROD - TRENTINO Diatec',
  180. 'upload_date': '20160322',
  181. 'uploader': 'CEV - Europäischer Volleyball Verband',
  182. 'is_live': True,
  183. 'categories': ['Volleyball'],
  184. },
  185. 'params': {
  186. 'skip_download': True,
  187. },
  188. 'skip': 'This live stream has already finished.',
  189. }]
  190. def _real_extract(self, url):
  191. return self._extract_video(url)
  192. class EHFTVIE(Laola1TvBaseIE):
  193. IE_NAME = 'ehftv'
  194. _VALID_URL = r'https?://(?:www\.)?ehftv\.com/[a-z]+(?:-[a-z]+)?/[^/]+/(?P<id>[^/?#&]+)'
  195. _TESTS = [{
  196. 'url': 'https://www.ehftv.com/int/video/paris-saint-germain-handball-pge-vive-kielce/1166761',
  197. 'info_dict': {
  198. 'id': '1166761',
  199. 'display_id': 'paris-saint-germain-handball-pge-vive-kielce',
  200. 'ext': 'mp4',
  201. 'title': 'Paris Saint-Germain Handball - PGE Vive Kielce',
  202. 'is_live': False,
  203. 'categories': ['Handball'],
  204. },
  205. 'params': {
  206. 'skip_download': True,
  207. },
  208. }]
  209. def _real_extract(self, url):
  210. return self._extract_video(url)
  211. class ITTFIE(InfoExtractor):
  212. _VALID_URL = r'https?://tv\.ittf\.com/video/[^/]+/(?P<id>\d+)'
  213. _TEST = {
  214. 'url': 'https://tv.ittf.com/video/peng-wang-wei-matsudaira-kenta/951802',
  215. 'only_matching': True,
  216. }
  217. def _real_extract(self, url):
  218. return self.url_result(
  219. update_url_query('https://www.laola1.tv/titanplayer.php', {
  220. 'videoid': self._match_id(url),
  221. 'type': 'V',
  222. 'lang': 'en',
  223. 'portal': 'int',
  224. 'customer': 1024,
  225. }), Laola1TvEmbedIE.ie_key())