netverse.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. from .common import InfoExtractor
  2. from .dailymotion import DailymotionIE
  3. from ..utils import smuggle_url, traverse_obj
  4. class NetverseBaseIE(InfoExtractor):
  5. _ENDPOINTS = {
  6. 'watch': 'watchvideo',
  7. 'video': 'watchvideo',
  8. 'webseries': 'webseries',
  9. 'season': 'webseason_videos',
  10. }
  11. def _call_api(self, slug, endpoint, query={}, season_id='', display_id=None):
  12. return self._download_json(
  13. f'https://api.netverse.id/medias/api/v2/{self._ENDPOINTS[endpoint]}/{slug}/{season_id}',
  14. display_id or slug, query=query)
  15. class NetverseIE(NetverseBaseIE):
  16. _VALID_URL = r'https?://(?:\w+\.)?netverse\.id/(?P<type>watch|video)/(?P<display_id>[^/?#&]+)'
  17. _TESTS = [{
  18. # Watch video
  19. 'url': 'https://www.netverse.id/watch/waktu-indonesia-bercanda-edisi-spesial-lebaran-2016',
  20. 'info_dict': {
  21. 'id': 'k4yhqUwINAGtmHx3NkL',
  22. 'title': 'Waktu Indonesia Bercanda - Edisi Spesial Lebaran 2016',
  23. 'ext': 'mp4',
  24. 'season': 'Season 2016',
  25. 'description': 'md5:d41d8cd98f00b204e9800998ecf8427e',
  26. 'thumbnail': r're:https?://s\d+\.dmcdn\.net/v/T7aV31Y0eGRWBbwkK/x1080',
  27. 'episode_number': 22,
  28. 'episode': 'Episode 22',
  29. 'uploader_id': 'x2ir3vq',
  30. 'age_limit': 0,
  31. 'tags': [],
  32. 'view_count': int,
  33. 'display_id': 'waktu-indonesia-bercanda-edisi-spesial-lebaran-2016',
  34. 'duration': 2990,
  35. 'upload_date': '20210722',
  36. 'timestamp': 1626919804,
  37. 'like_count': int,
  38. 'uploader': 'Net Prime',
  39. }
  40. }, {
  41. # series
  42. 'url': 'https://www.netverse.id/watch/jadoo-seorang-model',
  43. 'info_dict': {
  44. 'id': 'x88izwc',
  45. 'title': 'Jadoo Seorang Model',
  46. 'ext': 'mp4',
  47. 'season': 'Season 2',
  48. 'description': 'md5:8a74f70812cca267e19ee0635f0af835',
  49. 'thumbnail': r're:https?://s\d+\.dmcdn\.net/v/Thwuy1YURicFmGu0v/x1080',
  50. 'episode_number': 2,
  51. 'episode': 'Episode 2',
  52. 'view_count': int,
  53. 'like_count': int,
  54. 'display_id': 'jadoo-seorang-model',
  55. 'uploader_id': 'x2ir3vq',
  56. 'duration': 635,
  57. 'timestamp': 1646372927,
  58. 'tags': ['PG069497-hellojadooseason2eps2'],
  59. 'upload_date': '20220304',
  60. 'uploader': 'Net Prime',
  61. 'age_limit': 0,
  62. },
  63. 'skip': 'video get Geo-blocked for some country'
  64. }, {
  65. # non www host
  66. 'url': 'https://netverse.id/watch/tetangga-baru',
  67. 'info_dict': {
  68. 'id': 'k4CNGz7V0HJ7vfwZbXy',
  69. 'ext': 'mp4',
  70. 'title': 'Tetangga Baru',
  71. 'season': 'Season 1',
  72. 'description': 'md5:23fcf70e97d461d3029d25d59b2ccfb9',
  73. 'thumbnail': r're:https?://s\d+\.dmcdn\.net/v/T3Ogm1YEnnyjVKAFF/x1080',
  74. 'episode_number': 1,
  75. 'episode': 'Episode 1',
  76. 'timestamp': 1624538169,
  77. 'view_count': int,
  78. 'upload_date': '20210624',
  79. 'age_limit': 0,
  80. 'uploader_id': 'x2ir3vq',
  81. 'like_count': int,
  82. 'uploader': 'Net Prime',
  83. 'tags': ['PG008534', 'tetangga', 'Baru'],
  84. 'display_id': 'tetangga-baru',
  85. 'duration': 1406,
  86. },
  87. }, {
  88. # /video url
  89. 'url': 'https://www.netverse.id/video/pg067482-hellojadoo-season1',
  90. 'title': 'Namaku Choi Jadoo',
  91. 'info_dict': {
  92. 'id': 'x887jzz',
  93. 'ext': 'mp4',
  94. 'thumbnail': r're:https?://s\d+\.dmcdn\.net/v/TfuZ_1Y6PboJ5An_s/x1080',
  95. 'season': 'Season 1',
  96. 'episode_number': 1,
  97. 'description': 'md5:d4f627b3e7a3f9acdc55f6cdd5ea41d5',
  98. 'title': 'Namaku Choi Jadoo',
  99. 'episode': 'Episode 1',
  100. 'age_limit': 0,
  101. 'like_count': int,
  102. 'view_count': int,
  103. 'tags': ['PG067482', 'PG067482-HelloJadoo-season1'],
  104. 'duration': 780,
  105. 'display_id': 'pg067482-hellojadoo-season1',
  106. 'uploader_id': 'x2ir3vq',
  107. 'uploader': 'Net Prime',
  108. 'timestamp': 1645764984,
  109. 'upload_date': '20220225',
  110. },
  111. 'skip': 'This video get Geo-blocked for some country'
  112. }]
  113. def _real_extract(self, url):
  114. display_id, sites_type = self._match_valid_url(url).group('display_id', 'type')
  115. program_json = self._call_api(display_id, sites_type)
  116. videos = program_json['response']['videos']
  117. return {
  118. '_type': 'url_transparent',
  119. 'ie_key': DailymotionIE.ie_key(),
  120. 'url': smuggle_url(videos['dailymotion_url'], {'query': {'embedder': 'https://www.netverse.id'}}),
  121. 'display_id': display_id,
  122. 'title': videos.get('title'),
  123. 'season': videos.get('season_name'),
  124. 'thumbnail': traverse_obj(videos, ('program_detail', 'thumbnail_image')),
  125. 'description': traverse_obj(videos, ('program_detail', 'description')),
  126. 'episode_number': videos.get('episode_order'),
  127. }
  128. class NetversePlaylistIE(NetverseBaseIE):
  129. _VALID_URL = r'https?://(?:\w+\.)?netverse\.id/(?P<type>webseries)/(?P<display_id>[^/?#&]+)'
  130. _TESTS = [{
  131. # multiple season
  132. 'url': 'https://netverse.id/webseries/tetangga-masa-gitu',
  133. 'info_dict': {
  134. 'id': 'tetangga-masa-gitu',
  135. 'title': 'Tetangga Masa Gitu',
  136. },
  137. 'playlist_count': 519,
  138. }, {
  139. # single season
  140. 'url': 'https://netverse.id/webseries/kelas-internasional',
  141. 'info_dict': {
  142. 'id': 'kelas-internasional',
  143. 'title': 'Kelas Internasional',
  144. },
  145. 'playlist_count': 203,
  146. }]
  147. def parse_playlist(self, json_data, playlist_id):
  148. slug_sample = traverse_obj(json_data, ('related', 'data', ..., 'slug'))[0]
  149. for season in traverse_obj(json_data, ('seasons', ..., 'id')):
  150. playlist_json = self._call_api(
  151. slug_sample, 'season', display_id=playlist_id, season_id=season)
  152. for current_page in range(playlist_json['response']['season_list']['last_page']):
  153. playlist_json = self._call_api(slug_sample, 'season', query={'page': current_page + 1},
  154. season_id=season, display_id=playlist_id)
  155. for slug in traverse_obj(playlist_json, ('response', ..., 'data', ..., 'slug')):
  156. yield self.url_result(f'https://www.netverse.id/video/{slug}', NetverseIE)
  157. def _real_extract(self, url):
  158. playlist_id, sites_type = self._match_valid_url(url).group('display_id', 'type')
  159. playlist_data = self._call_api(playlist_id, sites_type)
  160. return self.playlist_result(
  161. self.parse_playlist(playlist_data['response'], playlist_id),
  162. traverse_obj(playlist_data, ('response', 'webseries_info', 'slug')),
  163. traverse_obj(playlist_data, ('response', 'webseries_info', 'title')))