playplustv.py 3.6 KB

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