logo

youtube-dl

[mirror] Download/Watch videos from video hostersgit clone https://hacktivis.me/git/mirror/youtube-dl.git

minds.py (6915B)


  1. # coding: utf-8
  2. from __future__ import unicode_literals
  3. from .common import InfoExtractor
  4. from ..compat import compat_str
  5. from ..utils import (
  6. clean_html,
  7. int_or_none,
  8. str_or_none,
  9. strip_or_none,
  10. )
  11. class MindsBaseIE(InfoExtractor):
  12. _VALID_URL_BASE = r'https?://(?:www\.)?minds\.com/'
  13. def _call_api(self, path, video_id, resource, query=None):
  14. api_url = 'https://www.minds.com/api/' + path
  15. token = self._get_cookies(api_url).get('XSRF-TOKEN')
  16. return self._download_json(
  17. api_url, video_id, 'Downloading %s JSON metadata' % resource, headers={
  18. 'Referer': 'https://www.minds.com/',
  19. 'X-XSRF-TOKEN': token.value if token else '',
  20. }, query=query)
  21. class MindsIE(MindsBaseIE):
  22. IE_NAME = 'minds'
  23. _VALID_URL = MindsBaseIE._VALID_URL_BASE + r'(?:media|newsfeed|archive/view)/(?P<id>[0-9]+)'
  24. _TESTS = [{
  25. 'url': 'https://www.minds.com/media/100000000000086822',
  26. 'md5': '215a658184a419764852239d4970b045',
  27. 'info_dict': {
  28. 'id': '100000000000086822',
  29. 'ext': 'mp4',
  30. 'title': 'Minds intro sequence',
  31. 'thumbnail': r're:https?://.+\.png',
  32. 'uploader_id': 'ottman',
  33. 'upload_date': '20130524',
  34. 'timestamp': 1369404826,
  35. 'uploader': 'Bill Ottman',
  36. 'view_count': int,
  37. 'like_count': int,
  38. 'dislike_count': int,
  39. 'tags': ['animation'],
  40. 'comment_count': int,
  41. 'license': 'attribution-cc',
  42. },
  43. }, {
  44. # entity.type == 'activity' and empty title
  45. 'url': 'https://www.minds.com/newsfeed/798025111988506624',
  46. 'md5': 'b2733a74af78d7fd3f541c4cbbaa5950',
  47. 'info_dict': {
  48. 'id': '798022190320226304',
  49. 'ext': 'mp4',
  50. 'title': '798022190320226304',
  51. 'uploader': 'ColinFlaherty',
  52. 'upload_date': '20180111',
  53. 'timestamp': 1515639316,
  54. 'uploader_id': 'ColinFlaherty',
  55. },
  56. }, {
  57. 'url': 'https://www.minds.com/archive/view/715172106794442752',
  58. 'only_matching': True,
  59. }, {
  60. # youtube perma_url
  61. 'url': 'https://www.minds.com/newsfeed/1197131838022602752',
  62. 'only_matching': True,
  63. }]
  64. def _real_extract(self, url):
  65. entity_id = self._match_id(url)
  66. entity = self._call_api(
  67. 'v1/entities/entity/' + entity_id, entity_id, 'entity')['entity']
  68. if entity.get('type') == 'activity':
  69. if entity.get('custom_type') == 'video':
  70. video_id = entity['entity_guid']
  71. else:
  72. return self.url_result(entity['perma_url'])
  73. else:
  74. assert (entity['subtype'] == 'video')
  75. video_id = entity_id
  76. # 1080p and webm formats available only on the sources array
  77. video = self._call_api(
  78. 'v2/media/video/' + video_id, video_id, 'video')
  79. formats = []
  80. for source in (video.get('sources') or []):
  81. src = source.get('src')
  82. if not src:
  83. continue
  84. formats.append({
  85. 'format_id': source.get('label'),
  86. 'height': int_or_none(source.get('size')),
  87. 'url': src,
  88. })
  89. self._sort_formats(formats)
  90. entity = video.get('entity') or entity
  91. owner = entity.get('ownerObj') or {}
  92. uploader_id = owner.get('username')
  93. tags = entity.get('tags')
  94. if tags and isinstance(tags, compat_str):
  95. tags = [tags]
  96. thumbnail = None
  97. poster = video.get('poster') or entity.get('thumbnail_src')
  98. if poster:
  99. urlh = self._request_webpage(poster, video_id, fatal=False)
  100. if urlh:
  101. thumbnail = urlh.geturl()
  102. return {
  103. 'id': video_id,
  104. 'title': entity.get('title') or video_id,
  105. 'formats': formats,
  106. 'description': clean_html(entity.get('description')) or None,
  107. 'license': str_or_none(entity.get('license')),
  108. 'timestamp': int_or_none(entity.get('time_created')),
  109. 'uploader': strip_or_none(owner.get('name')),
  110. 'uploader_id': uploader_id,
  111. 'uploader_url': 'https://www.minds.com/' + uploader_id if uploader_id else None,
  112. 'view_count': int_or_none(entity.get('play:count')),
  113. 'like_count': int_or_none(entity.get('thumbs:up:count')),
  114. 'dislike_count': int_or_none(entity.get('thumbs:down:count')),
  115. 'tags': tags,
  116. 'comment_count': int_or_none(entity.get('comments:count')),
  117. 'thumbnail': thumbnail,
  118. }
  119. class MindsFeedBaseIE(MindsBaseIE):
  120. _PAGE_SIZE = 150
  121. def _entries(self, feed_id):
  122. query = {'limit': self._PAGE_SIZE, 'sync': 1}
  123. i = 1
  124. while True:
  125. data = self._call_api(
  126. 'v2/feeds/container/%s/videos' % feed_id,
  127. feed_id, 'page %s' % i, query)
  128. entities = data.get('entities') or []
  129. for entity in entities:
  130. guid = entity.get('guid')
  131. if not guid:
  132. continue
  133. yield self.url_result(
  134. 'https://www.minds.com/newsfeed/' + guid,
  135. MindsIE.ie_key(), guid)
  136. query['from_timestamp'] = data['load-next']
  137. if not (query['from_timestamp'] and len(entities) == self._PAGE_SIZE):
  138. break
  139. i += 1
  140. def _real_extract(self, url):
  141. feed_id = self._match_id(url)
  142. feed = self._call_api(
  143. 'v1/%s/%s' % (self._FEED_PATH, feed_id),
  144. feed_id, self._FEED_TYPE)[self._FEED_TYPE]
  145. return self.playlist_result(
  146. self._entries(feed['guid']), feed_id,
  147. strip_or_none(feed.get('name')),
  148. feed.get('briefdescription'))
  149. class MindsChannelIE(MindsFeedBaseIE):
  150. _FEED_TYPE = 'channel'
  151. IE_NAME = 'minds:' + _FEED_TYPE
  152. _VALID_URL = MindsBaseIE._VALID_URL_BASE + r'(?!(?:newsfeed|media|api|archive|groups)/)(?P<id>[^/?&#]+)'
  153. _FEED_PATH = 'channel'
  154. _TEST = {
  155. 'url': 'https://www.minds.com/ottman',
  156. 'info_dict': {
  157. 'id': 'ottman',
  158. 'title': 'Bill Ottman',
  159. 'description': 'Co-creator & CEO @minds',
  160. },
  161. 'playlist_mincount': 54,
  162. }
  163. class MindsGroupIE(MindsFeedBaseIE):
  164. _FEED_TYPE = 'group'
  165. IE_NAME = 'minds:' + _FEED_TYPE
  166. _VALID_URL = MindsBaseIE._VALID_URL_BASE + r'groups/profile/(?P<id>[0-9]+)'
  167. _FEED_PATH = 'groups/group'
  168. _TEST = {
  169. 'url': 'https://www.minds.com/groups/profile/785582576369672204/feed/videos',
  170. 'info_dict': {
  171. 'id': '785582576369672204',
  172. 'title': 'Cooking Videos',
  173. },
  174. 'playlist_mincount': 1,
  175. }