logo

oasis-root

Compiled tree of Oasis Linux based on own branch at <https://hacktivis.me/git/oasis/> git clone https://anongit.hacktivis.me/git/oasis-root.git

pixivsketch.py (4799B)


  1. from .common import InfoExtractor
  2. from ..networking.exceptions import HTTPError
  3. from ..utils import (
  4. ExtractorError,
  5. traverse_obj,
  6. unified_timestamp,
  7. )
  8. class PixivSketchBaseIE(InfoExtractor):
  9. def _call_api(self, video_id, path, referer, note='Downloading JSON metadata'):
  10. response = self._download_json(f'https://sketch.pixiv.net/api/{path}', video_id, note=note, headers={
  11. 'Referer': referer,
  12. 'X-Requested-With': referer,
  13. })
  14. errors = traverse_obj(response, ('errors', ..., 'message'))
  15. if errors:
  16. raise ExtractorError(' '.join(f'{e}.' for e in errors))
  17. return response.get('data') or {}
  18. class PixivSketchIE(PixivSketchBaseIE):
  19. IE_NAME = 'pixiv:sketch'
  20. _VALID_URL = r'https?://sketch\.pixiv\.net/@(?P<uploader_id>[a-zA-Z0-9_-]+)/lives/(?P<id>\d+)/?'
  21. _TESTS = [{
  22. 'url': 'https://sketch.pixiv.net/@nuhutya/lives/3654620468641830507',
  23. 'info_dict': {
  24. 'id': '7370666691623196569',
  25. 'title': 'まにあえクリスマス!',
  26. 'uploader': 'ぬふちゃ',
  27. 'uploader_id': 'nuhutya',
  28. 'channel_id': '9844815',
  29. 'age_limit': 0,
  30. 'timestamp': 1640351536,
  31. },
  32. 'skip': True,
  33. }, {
  34. # these two (age_limit > 0) requires you to login on website, but it's actually not required for download
  35. 'url': 'https://sketch.pixiv.net/@namahyou/lives/4393103321546851377',
  36. 'info_dict': {
  37. 'id': '4907995960957946943',
  38. 'title': 'クリスマスなんて知らん🖕',
  39. 'uploader': 'すゃもり',
  40. 'uploader_id': 'suya2mori2',
  41. 'channel_id': '31169300',
  42. 'age_limit': 15,
  43. 'timestamp': 1640347640,
  44. },
  45. 'skip': True,
  46. }, {
  47. 'url': 'https://sketch.pixiv.net/@8aki/lives/3553803162487249670',
  48. 'info_dict': {
  49. 'id': '1593420639479156945',
  50. 'title': 'おまけ本作業(リョナ有)',
  51. 'uploader': 'おぶい / Obui',
  52. 'uploader_id': 'oving',
  53. 'channel_id': '17606',
  54. 'age_limit': 18,
  55. 'timestamp': 1640330263,
  56. },
  57. 'skip': True,
  58. }]
  59. def _real_extract(self, url):
  60. video_id, uploader_id = self._match_valid_url(url).group('id', 'uploader_id')
  61. data = self._call_api(video_id, f'lives/{video_id}.json', url)
  62. if not traverse_obj(data, 'is_broadcasting'):
  63. raise ExtractorError(f'This live is offline. Use https://sketch.pixiv.net/@{uploader_id} for ongoing live.', expected=True)
  64. m3u8_url = traverse_obj(data, ('owner', 'hls_movie', 'url'))
  65. formats = self._extract_m3u8_formats(
  66. m3u8_url, video_id, ext='mp4',
  67. entry_protocol='m3u8_native', m3u8_id='hls')
  68. return {
  69. 'id': video_id,
  70. 'title': data.get('name'),
  71. 'formats': formats,
  72. 'uploader': traverse_obj(data, ('user', 'name'), ('owner', 'user', 'name')),
  73. 'uploader_id': traverse_obj(data, ('user', 'unique_name'), ('owner', 'user', 'unique_name')),
  74. 'channel_id': str(traverse_obj(data, ('user', 'pixiv_user_id'), ('owner', 'user', 'pixiv_user_id'))),
  75. 'age_limit': 18 if data.get('is_r18') else 15 if data.get('is_r15') else 0,
  76. 'timestamp': unified_timestamp(data.get('created_at')),
  77. 'is_live': True,
  78. }
  79. class PixivSketchUserIE(PixivSketchBaseIE):
  80. IE_NAME = 'pixiv:sketch:user'
  81. _VALID_URL = r'https?://sketch\.pixiv\.net/@(?P<id>[a-zA-Z0-9_-]+)/?'
  82. _TESTS = [{
  83. 'url': 'https://sketch.pixiv.net/@nuhutya',
  84. 'only_matching': True,
  85. }, {
  86. 'url': 'https://sketch.pixiv.net/@namahyou',
  87. 'only_matching': True,
  88. }, {
  89. 'url': 'https://sketch.pixiv.net/@8aki',
  90. 'only_matching': True,
  91. }]
  92. @classmethod
  93. def suitable(cls, url):
  94. return super().suitable(url) and not PixivSketchIE.suitable(url)
  95. def _real_extract(self, url):
  96. user_id = self._match_id(url)
  97. data = self._call_api(user_id, f'lives/users/@{user_id}.json', url)
  98. if not traverse_obj(data, 'is_broadcasting'):
  99. try:
  100. self._call_api(user_id, 'users/current.json', url, 'Investigating reason for request failure')
  101. except ExtractorError as e:
  102. if isinstance(e.cause, HTTPError) and e.cause.status == 401:
  103. self.raise_login_required(f'Please log in, or use direct link like https://sketch.pixiv.net/@{user_id}/1234567890', method='cookies')
  104. raise ExtractorError('This user is offline', expected=True)
  105. return self.url_result(f'https://sketch.pixiv.net/@{user_id}/lives/{data["id"]}')