playplustv.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import json
  2. from .common import InfoExtractor
  3. from ..compat import compat_HTTPError
  4. from ..utils import (
  5. clean_html,
  6. ExtractorError,
  7. int_or_none,
  8. PUTRequest,
  9. )
  10. class PlayPlusTVIE(InfoExtractor):
  11. _VALID_URL = r'https?://(?:www\.)?playplus\.(?:com|tv)/VOD/(?P<project_id>[0-9]+)/(?P<id>[0-9a-f]{32})'
  12. _TEST = {
  13. 'url': 'https://www.playplus.tv/VOD/7572/db8d274a5163424e967f35a30ddafb8e',
  14. 'md5': 'd078cb89d7ab6b9df37ce23c647aef72',
  15. 'info_dict': {
  16. 'id': 'db8d274a5163424e967f35a30ddafb8e',
  17. 'ext': 'mp4',
  18. 'title': 'Capítulo 179 - Final',
  19. 'description': 'md5:01085d62d8033a1e34121d3c3cabc838',
  20. 'timestamp': 1529992740,
  21. 'upload_date': '20180626',
  22. },
  23. 'skip': 'Requires account credential',
  24. }
  25. _NETRC_MACHINE = 'playplustv'
  26. _GEO_COUNTRIES = ['BR']
  27. _token = None
  28. _profile_id = None
  29. def _call_api(self, resource, video_id=None, query=None):
  30. return self._download_json('https://api.playplus.tv/api/media/v2/get' + resource, video_id, headers={
  31. 'Authorization': 'Bearer ' + self._token,
  32. }, query=query)
  33. def _perform_login(self, username, password):
  34. req = PUTRequest(
  35. 'https://api.playplus.tv/api/web/login', json.dumps({
  36. 'email': username,
  37. 'password': password,
  38. }).encode(), {
  39. 'Content-Type': 'application/json; charset=utf-8',
  40. })
  41. try:
  42. self._token = self._download_json(req, None)['token']
  43. except ExtractorError as e:
  44. if isinstance(e.cause, compat_HTTPError) and e.cause.code == 401:
  45. raise ExtractorError(self._parse_json(
  46. e.cause.read(), None)['errorMessage'], expected=True)
  47. raise
  48. self._profile = self._call_api('Profiles')['list'][0]['_id']
  49. def _real_initialize(self):
  50. if not self._token:
  51. self.raise_login_required(method='password')
  52. def _real_extract(self, url):
  53. project_id, media_id = self._match_valid_url(url).groups()
  54. media = self._call_api(
  55. 'Media', media_id, {
  56. 'profileId': self._profile,
  57. 'projectId': project_id,
  58. 'mediaId': media_id,
  59. })['obj']
  60. title = media['title']
  61. formats = []
  62. for f in media.get('files', []):
  63. f_url = f.get('url')
  64. if not f_url:
  65. continue
  66. file_info = f.get('fileInfo') or {}
  67. formats.append({
  68. 'url': f_url,
  69. 'width': int_or_none(file_info.get('width')),
  70. 'height': int_or_none(file_info.get('height')),
  71. })
  72. thumbnails = []
  73. for thumb in media.get('thumbs', []):
  74. thumb_url = thumb.get('url')
  75. if not thumb_url:
  76. continue
  77. thumbnails.append({
  78. 'url': thumb_url,
  79. 'width': int_or_none(thumb.get('width')),
  80. 'height': int_or_none(thumb.get('height')),
  81. })
  82. return {
  83. 'id': media_id,
  84. 'title': title,
  85. 'formats': formats,
  86. 'thumbnails': thumbnails,
  87. 'description': clean_html(media.get('description')) or media.get('shortDescription'),
  88. 'timestamp': int_or_none(media.get('publishDate'), 1000),
  89. 'view_count': int_or_none(media.get('numberOfViews')),
  90. 'comment_count': int_or_none(media.get('numberOfComments')),
  91. 'tags': media.get('tags'),
  92. }