You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

176 lines
7.0 KiB

  1. # coding: utf-8
  2. from __future__ import unicode_literals
  3. import re
  4. from .common import InfoExtractor
  5. from ..utils import (
  6. int_or_none,
  7. determine_ext,
  8. )
  9. class LimeLightBaseIE(InfoExtractor):
  10. def get_playlist_service(self, id, method):
  11. return self._download_json(self.PLAYLIST_SERVICE_URL % (id, method), id)
  12. def get_api(self, orgId, id, method):
  13. return self._download_json(self.API_URL % (orgId, id, method), id)
  14. def process_data(self, mobileUrls, streams, properties):
  15. video_id = properties['media_id']
  16. formats = []
  17. for mobileUrl in mobileUrls:
  18. if '.m3u8' in mobileUrl['mobileUrl']:
  19. formats.extend(self._extract_m3u8_formats(mobileUrl['mobileUrl'], video_id))
  20. else:
  21. formats.append({'url': mobileUrl['mobileUrl']})
  22. for stream in streams:
  23. if '.f4m' in stream['url']:
  24. formats.extend(self._extract_f4m_formats(stream['url'], video_id))
  25. else:
  26. fmt = {
  27. 'url': stream.get('url'),
  28. 'abr': stream.get('audioBitRate'),
  29. 'vbr': stream.get('videoBitRate'),
  30. 'fps': stream.get('videoFrameRate'),
  31. 'width': stream.get('videoWidthInPixels'),
  32. 'height': stream.get('videoHeightInPixels'),
  33. 'ext': determine_ext(stream.get('url'))
  34. }
  35. rtmp = re.search(r'^(?P<url>rtmp://[^/]+/(?P<app>.+))/(?P<playpath>mp4:.+)$', stream['url'])
  36. if rtmp:
  37. fmt.update({
  38. 'url': rtmp.group('url'),
  39. 'play_path': rtmp.group('playpath'),
  40. 'app': rtmp.group('app'),
  41. })
  42. formats.append(fmt)
  43. self._sort_formats(formats)
  44. title = properties['title']
  45. description = properties.get('description')
  46. timestamp = properties.get('create_date')
  47. duration = int_or_none(properties.get('duration_in_milliseconds'))
  48. filesize = properties.get('total_storage_in_bytes')
  49. categories = [properties.get('category')]
  50. thumbnails = [{
  51. 'url': thumbnail.get('url'),
  52. 'width': int_or_none(thumbnail.get('width')),
  53. 'height': int_or_none(thumbnail.get('height')),
  54. } for thumbnail in properties.get('thumbnails')]
  55. subtitles = {caption.get('language_code'): [{'url': caption.get('url')}] for caption in properties.get('captions')}
  56. return {
  57. 'id': video_id,
  58. 'title': title,
  59. 'description': description,
  60. 'formats': formats,
  61. 'timestamp': timestamp,
  62. 'duration': duration,
  63. 'filesize': filesize,
  64. 'categories': categories,
  65. 'thumbnails': thumbnails,
  66. 'subtitles': subtitles,
  67. }
  68. class LimeLightMediaIE(LimeLightBaseIE):
  69. IE_NAME = 'limelight'
  70. _VALID_URL = r'http://link\.videoplatform\.limelight\.com/media/?.*mediaId=(?P<id>[a-z0-9]{32})'
  71. _TEST = {
  72. 'url': 'http://link.videoplatform.limelight.com/media/?mediaId=3ffd040b522b4485b6d84effc750cd86',
  73. 'md5': '3213605088be599705677ef785db6972',
  74. 'info_dict': {
  75. 'id': '3ffd040b522b4485b6d84effc750cd86',
  76. 'ext': 'mp4',
  77. 'title': 'HaP and the HB Prince Trailer',
  78. 'description': 'As Harry Potter begins his 6th year at Hogwarts School of Witchcraft and Wizardry, he discovers an old book marked mysteriously "This book is the property of the Half-Blood Prince" and begins to learn more about Lord Voldemort\'s dark past.',
  79. 'thumbnail': 're:^https?://.*\.jpeg$',
  80. 'duration': 144230,
  81. 'timestamp': 1244136834,
  82. "upload_date": "20090604",
  83. }
  84. }
  85. PLAYLIST_SERVICE_URL = 'http://production-ps.lvp.llnw.net/r/PlaylistService/media/%s/%s'
  86. API_URL = 'http://api.video.limelight.com/rest/organizations/%s/media/%s/%s.json'
  87. def _real_extract(self, url):
  88. video_id = self._match_id(url)
  89. mobile_json_data = self.get_playlist_service(video_id, 'getMobilePlaylistByMediaId')
  90. pc_json_data = self.get_playlist_service(video_id, 'getPlaylistByMediaId')
  91. properties = self.get_api(pc_json_data['orgId'], video_id, 'properties')
  92. return self.process_data(mobile_json_data['mediaList'][0]['mobileUrls'], pc_json_data['playlistItems'][0]['streams'], properties)
  93. class LimeLightChannelIE(LimeLightBaseIE):
  94. IE_NAME = 'limelight:channel'
  95. _VALID_URL = r'http://link\.videoplatform\.limelight\.com/media/?.*channelId=(?P<id>[a-z0-9]{32})'
  96. _TEST = {
  97. 'url': 'http://link.videoplatform.limelight.com/media/?channelId=ab6a524c379342f9b23642917020c082',
  98. 'info_dict': {
  99. 'id': 'ab6a524c379342f9b23642917020c082',
  100. 'title': 'Javascript Sample Code',
  101. },
  102. 'playlist_mincount': 3,
  103. }
  104. PLAYLIST_SERVICE_URL = 'http://production-ps.lvp.llnw.net/r/PlaylistService/channel/%s/%s'
  105. API_URL = 'http://api.video.limelight.com/rest/organizations/%s/channels/%s/%s.json'
  106. def _real_extract(self, url):
  107. channel_id = self._match_id(url)
  108. mobile_json_data = self.get_playlist_service(channel_id, 'getMobilePlaylistWithNItemsByChannelId?begin=0&count=-1')
  109. pc_json_data = self.get_playlist_service(channel_id, 'getPlaylistByChannelId')
  110. medias = self.get_api(pc_json_data['orgId'], channel_id, 'media')
  111. entries = []
  112. for i in range(len(medias['media_list'])):
  113. entries.append(self.process_data(mobile_json_data['mediaList'][i]['mobileUrls'], pc_json_data['playlistItems'][i]['streams'], medias['media_list'][i]))
  114. return {
  115. 'id': channel_id,
  116. 'title': pc_json_data['title'],
  117. 'entries': entries,
  118. '_type': 'playlist',
  119. }
  120. class LimeLightChannelListIE(LimeLightBaseIE):
  121. IE_NAME = 'limelight:channel_list'
  122. _VALID_URL = r'http://link\.videoplatform\.limelight\.com/media/?.*channelListId=(?P<id>[a-z0-9]{32})'
  123. _TEST = {
  124. 'url': 'http://link.videoplatform.limelight.com/media/?channelListId=301b117890c4465c8179ede21fd92e2b',
  125. 'info_dict': {
  126. 'id': '301b117890c4465c8179ede21fd92e2b',
  127. 'title': 'Website - Hero Player',
  128. },
  129. 'playlist_mincount': 2,
  130. }
  131. PLAYLIST_SERVICE_URL = 'http://production-ps.lvp.llnw.net/r/PlaylistService/channel_list/%s/%s'
  132. def _real_extract(self, url):
  133. channel_list_id = self._match_id(url)
  134. json_data = self.get_playlist_service(channel_list_id, 'getMobileChannelListById')
  135. entries = []
  136. for channel in json_data['channelList']:
  137. entries.append({
  138. 'url': 'http://link.videoplatform.limelight.com/media/?channelId=%s' % channel['id'],
  139. '_type': 'url',
  140. 'ie_key': 'LimeLightChannel',
  141. })
  142. return {
  143. 'id': channel_list_id,
  144. 'title': json_data['title'],
  145. 'entries': entries,
  146. '_type': 'playlist',
  147. }