nekohacker.py 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import re
  2. from .common import InfoExtractor
  3. from ..utils import (
  4. ExtractorError,
  5. determine_ext,
  6. extract_attributes,
  7. get_element_by_class,
  8. get_element_text_and_html_by_tag,
  9. parse_duration,
  10. traverse_obj,
  11. try_call,
  12. url_or_none,
  13. )
  14. class NekoHackerIE(InfoExtractor):
  15. _VALID_URL = r'https?://(?:www\.)?nekohacker\.com/(?P<id>(?!free-dl)[\w-]+)'
  16. _TESTS = [{
  17. 'url': 'https://nekohacker.com/nekoverse/',
  18. 'info_dict': {
  19. 'id': 'nekoverse',
  20. 'title': 'Nekoverse',
  21. },
  22. 'playlist': [
  23. {
  24. 'url': 'https://nekohacker.com/wp-content/uploads/2022/11/01-Spaceship.mp3',
  25. 'md5': '44223701ebedba0467ebda4cc07fb3aa',
  26. 'info_dict': {
  27. 'id': '1712',
  28. 'ext': 'mp3',
  29. 'title': 'Spaceship',
  30. 'thumbnail': 'https://nekohacker.com/wp-content/uploads/2022/11/Nekoverse_Artwork-1024x1024.jpg',
  31. 'vcodec': 'none',
  32. 'acodec': 'mp3',
  33. 'release_date': '20221101',
  34. 'album': 'Nekoverse',
  35. 'artist': 'Neko Hacker',
  36. 'track': 'Spaceship',
  37. 'track_number': 1,
  38. 'duration': 195.0,
  39. },
  40. },
  41. {
  42. 'url': 'https://nekohacker.com/wp-content/uploads/2022/11/02-City-Runner.mp3',
  43. 'md5': '8f853c71719389d32bbbd3f1a87b3f08',
  44. 'info_dict': {
  45. 'id': '1713',
  46. 'ext': 'mp3',
  47. 'title': 'City Runner',
  48. 'thumbnail': 'https://nekohacker.com/wp-content/uploads/2022/11/Nekoverse_Artwork-1024x1024.jpg',
  49. 'vcodec': 'none',
  50. 'acodec': 'mp3',
  51. 'release_date': '20221101',
  52. 'album': 'Nekoverse',
  53. 'artist': 'Neko Hacker',
  54. 'track': 'City Runner',
  55. 'track_number': 2,
  56. 'duration': 148.0,
  57. },
  58. },
  59. {
  60. 'url': 'https://nekohacker.com/wp-content/uploads/2022/11/03-Nature-Talk.mp3',
  61. 'md5': '5a8a8ae852720cee4c0ac95c7d1a7450',
  62. 'info_dict': {
  63. 'id': '1714',
  64. 'ext': 'mp3',
  65. 'title': 'Nature Talk',
  66. 'thumbnail': 'https://nekohacker.com/wp-content/uploads/2022/11/Nekoverse_Artwork-1024x1024.jpg',
  67. 'vcodec': 'none',
  68. 'acodec': 'mp3',
  69. 'release_date': '20221101',
  70. 'album': 'Nekoverse',
  71. 'artist': 'Neko Hacker',
  72. 'track': 'Nature Talk',
  73. 'track_number': 3,
  74. 'duration': 174.0,
  75. },
  76. },
  77. {
  78. 'url': 'https://nekohacker.com/wp-content/uploads/2022/11/04-Crystal-World.mp3',
  79. 'md5': 'd8e59a48061764e50d92386a294abd50',
  80. 'info_dict': {
  81. 'id': '1715',
  82. 'ext': 'mp3',
  83. 'title': 'Crystal World',
  84. 'thumbnail': 'https://nekohacker.com/wp-content/uploads/2022/11/Nekoverse_Artwork-1024x1024.jpg',
  85. 'vcodec': 'none',
  86. 'acodec': 'mp3',
  87. 'release_date': '20221101',
  88. 'album': 'Nekoverse',
  89. 'artist': 'Neko Hacker',
  90. 'track': 'Crystal World',
  91. 'track_number': 4,
  92. 'duration': 199.0,
  93. },
  94. },
  95. ],
  96. }, {
  97. 'url': 'https://nekohacker.com/susume/',
  98. 'info_dict': {
  99. 'id': 'susume',
  100. 'title': '進め!むじなカンパニー',
  101. },
  102. 'playlist': [
  103. {
  104. 'url': 'https://nekohacker.com/wp-content/uploads/2021/01/進め!むじなカンパニー-feat.-六科なじむ-CV_-日高里菜-割戶真友-CV_-金元寿子-軽井沢ユキ-CV_-上坂すみれ-出稼ぎガルシア-CV_-金子彩花-.mp3',
  105. 'md5': 'fb13f008aa81f26ba48f91fd2d6186ce',
  106. 'info_dict': {
  107. 'id': '711',
  108. 'ext': 'mp3',
  109. 'title': 'md5:1a5fcbc96ca3c3265b1c6f9f79f30fd0',
  110. 'thumbnail': 'https://nekohacker.com/wp-content/uploads/2021/01/OP表-1024x1024.png',
  111. 'vcodec': 'none',
  112. 'acodec': 'mp3',
  113. 'release_date': '20210115',
  114. 'album': '進め!むじなカンパニー',
  115. 'artist': 'Neko Hacker',
  116. 'track': 'md5:1a5fcbc96ca3c3265b1c6f9f79f30fd0',
  117. 'track_number': 1,
  118. },
  119. },
  120. {
  121. 'url': 'https://nekohacker.com/wp-content/uploads/2021/01/むじな-de-なじむ-feat.-六科なじむ-CV_-日高里菜-.mp3',
  122. 'md5': '028803f70241df512b7764e73396fdd1',
  123. 'info_dict': {
  124. 'id': '709',
  125. 'ext': 'mp3',
  126. 'title': 'むじな de なじむ feat. 六科なじむ (CV: 日高里菜 )',
  127. 'thumbnail': 'https://nekohacker.com/wp-content/uploads/2021/01/OP表-1024x1024.png',
  128. 'vcodec': 'none',
  129. 'acodec': 'mp3',
  130. 'release_date': '20210115',
  131. 'album': '進め!むじなカンパニー',
  132. 'artist': 'Neko Hacker',
  133. 'track': 'むじな de なじむ feat. 六科なじむ (CV: 日高里菜 )',
  134. 'track_number': 2,
  135. },
  136. },
  137. {
  138. 'url': 'https://nekohacker.com/wp-content/uploads/2021/01/進め!むじなカンパニー-instrumental.mp3',
  139. 'md5': 'adde9e9a16e1da5e602b579c247d0fb9',
  140. 'info_dict': {
  141. 'id': '710',
  142. 'ext': 'mp3',
  143. 'title': '進め!むじなカンパニー (instrumental)',
  144. 'thumbnail': 'https://nekohacker.com/wp-content/uploads/2021/01/OP表-1024x1024.png',
  145. 'vcodec': 'none',
  146. 'acodec': 'mp3',
  147. 'release_date': '20210115',
  148. 'album': '進め!むじなカンパニー',
  149. 'artist': 'Neko Hacker',
  150. 'track': '進め!むじなカンパニー (instrumental)',
  151. 'track_number': 3,
  152. },
  153. },
  154. {
  155. 'url': 'https://nekohacker.com/wp-content/uploads/2021/01/むじな-de-なじむ-instrumental.mp3',
  156. 'md5': 'ebb0443039cf5f9ff7fd557ed9b23599',
  157. 'info_dict': {
  158. 'id': '712',
  159. 'ext': 'mp3',
  160. 'title': 'むじな de なじむ (instrumental)',
  161. 'thumbnail': 'https://nekohacker.com/wp-content/uploads/2021/01/OP表-1024x1024.png',
  162. 'vcodec': 'none',
  163. 'acodec': 'mp3',
  164. 'release_date': '20210115',
  165. 'album': '進め!むじなカンパニー',
  166. 'artist': 'Neko Hacker',
  167. 'track': 'むじな de なじむ (instrumental)',
  168. 'track_number': 4,
  169. },
  170. },
  171. ],
  172. }]
  173. def _real_extract(self, url):
  174. playlist_id = self._match_id(url)
  175. webpage = self._download_webpage(url, playlist_id)
  176. playlist = get_element_by_class('playlist', webpage)
  177. if not playlist:
  178. iframe = try_call(lambda: get_element_text_and_html_by_tag('iframe', webpage)[1]) or ''
  179. iframe_src = url_or_none(extract_attributes(iframe).get('src'))
  180. if not iframe_src:
  181. raise ExtractorError('No playlist or embed found in webpage')
  182. elif re.match(r'https?://(?:\w+\.)?spotify\.com/', iframe_src):
  183. raise ExtractorError('Spotify embeds are not supported', expected=True)
  184. return self.url_result(url, 'Generic')
  185. entries = []
  186. for track_number, track in enumerate(re.findall(r'(<li[^>]+data-audiopath[^>]+>)', playlist), 1):
  187. entry = traverse_obj(extract_attributes(track), {
  188. 'url': ('data-audiopath', {url_or_none}),
  189. 'ext': ('data-audiopath', {determine_ext}),
  190. 'id': 'data-trackid',
  191. 'title': 'data-tracktitle',
  192. 'track': 'data-tracktitle',
  193. 'album': 'data-albumtitle',
  194. 'duration': ('data-tracktime', {parse_duration}),
  195. 'release_date': ('data-releasedate', {lambda x: re.match(r'\d{8}', x.replace('.', ''))}, 0),
  196. 'thumbnail': ('data-albumart', {url_or_none}),
  197. })
  198. entries.append({
  199. **entry,
  200. 'track_number': track_number,
  201. 'artist': 'Neko Hacker',
  202. 'vcodec': 'none',
  203. 'acodec': 'mp3' if entry['ext'] == 'mp3' else None,
  204. })
  205. return self.playlist_result(entries, playlist_id, traverse_obj(entries, (0, 'album')))