@neteasecloudmusicapienhanced/api 4.29.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (412) hide show
  1. package/LICENSE +21 -0
  2. package/README.MD +178 -0
  3. package/app.js +18 -0
  4. package/data/deviceid.txt +24641 -0
  5. package/generateConfig.js +24 -0
  6. package/interface.d.ts +1834 -0
  7. package/main.js +63 -0
  8. package/module/activate_init_profile.js +9 -0
  9. package/module/aidj_content_rcmd.js +28 -0
  10. package/module/album.js +6 -0
  11. package/module/album_detail.js +12 -0
  12. package/module/album_detail_dynamic.js +12 -0
  13. package/module/album_list.js +16 -0
  14. package/module/album_list_style.js +15 -0
  15. package/module/album_new.js +11 -0
  16. package/module/album_newest.js +6 -0
  17. package/module/album_privilege.js +9 -0
  18. package/module/album_songsaleboard.js +19 -0
  19. package/module/album_sub.js +10 -0
  20. package/module/album_sublist.js +11 -0
  21. package/module/api.js +21 -0
  22. package/module/artist_album.js +15 -0
  23. package/module/artist_desc.js +9 -0
  24. package/module/artist_detail.js +10 -0
  25. package/module/artist_detail_dynamic.js +9 -0
  26. package/module/artist_fans.js +11 -0
  27. package/module/artist_follow_count.js +13 -0
  28. package/module/artist_list.js +33 -0
  29. package/module/artist_mv.js +12 -0
  30. package/module/artist_new_mv.js +12 -0
  31. package/module/artist_new_song.js +12 -0
  32. package/module/artist_songs.js +12 -0
  33. package/module/artist_sub.js +11 -0
  34. package/module/artist_sublist.js +11 -0
  35. package/module/artist_top_song.js +8 -0
  36. package/module/artist_video.js +15 -0
  37. package/module/artists.js +6 -0
  38. package/module/audio_match.js +19 -0
  39. package/module/avatar_upload.js +22 -0
  40. package/module/banner.js +16 -0
  41. package/module/batch.js +12 -0
  42. package/module/broadcast_category_region_get.js +11 -0
  43. package/module/broadcast_channel_collect_list.js +12 -0
  44. package/module/broadcast_channel_currentinfo.js +13 -0
  45. package/module/broadcast_channel_list.js +13 -0
  46. package/module/broadcast_sub.js +12 -0
  47. package/module/calendar.js +8 -0
  48. package/module/captcha_sent.js +11 -0
  49. package/module/captcha_verify.js +11 -0
  50. package/module/cellphone_existence_check.js +10 -0
  51. package/module/check_music.js +30 -0
  52. package/module/cloud.js +146 -0
  53. package/module/cloud_import.js +39 -0
  54. package/module/cloud_match.js +13 -0
  55. package/module/cloudsearch.js +13 -0
  56. package/module/comment.js +30 -0
  57. package/module/comment_album.js +16 -0
  58. package/module/comment_dj.js +16 -0
  59. package/module/comment_event.js +15 -0
  60. package/module/comment_floor.js +16 -0
  61. package/module/comment_hot.js +18 -0
  62. package/module/comment_hug_list.js +20 -0
  63. package/module/comment_like.js +20 -0
  64. package/module/comment_music.js +16 -0
  65. package/module/comment_mv.js +16 -0
  66. package/module/comment_new.js +37 -0
  67. package/module/comment_playlist.js +16 -0
  68. package/module/comment_video.js +16 -0
  69. package/module/countries_code_list.js +6 -0
  70. package/module/creator_authinfo_get.js +6 -0
  71. package/module/daily_signin.js +16 -0
  72. package/module/digitalAlbum_detail.js +13 -0
  73. package/module/digitalAlbum_ordering.js +22 -0
  74. package/module/digitalAlbum_purchased.js +15 -0
  75. package/module/digitalAlbum_sales.js +13 -0
  76. package/module/djRadio_top.js +15 -0
  77. package/module/dj_banner.js +6 -0
  78. package/module/dj_category_excludehot.js +10 -0
  79. package/module/dj_category_recommend.js +10 -0
  80. package/module/dj_catelist.js +6 -0
  81. package/module/dj_detail.js +9 -0
  82. package/module/dj_hot.js +10 -0
  83. package/module/dj_paygift.js +15 -0
  84. package/module/dj_personalize_recommend.js +12 -0
  85. package/module/dj_program.js +12 -0
  86. package/module/dj_program_detail.js +9 -0
  87. package/module/dj_program_toplist.js +10 -0
  88. package/module/dj_program_toplist_hours.js +13 -0
  89. package/module/dj_radio_hot.js +11 -0
  90. package/module/dj_recommend.js +6 -0
  91. package/module/dj_recommend_type.js +32 -0
  92. package/module/dj_sub.js +10 -0
  93. package/module/dj_sublist.js +11 -0
  94. package/module/dj_subscriber.js +12 -0
  95. package/module/dj_today_perfered.js +13 -0
  96. package/module/dj_toplist.js +14 -0
  97. package/module/dj_toplist_hours.js +10 -0
  98. package/module/dj_toplist_newcomer.js +9 -0
  99. package/module/dj_toplist_pay.js +9 -0
  100. package/module/dj_toplist_popular.js +10 -0
  101. package/module/eapi_decrypt.js +27 -0
  102. package/module/event.js +10 -0
  103. package/module/event_del.js +9 -0
  104. package/module/event_forward.js +11 -0
  105. package/module/fanscenter_basicinfo_age_get.js +6 -0
  106. package/module/fanscenter_basicinfo_gender_get.js +10 -0
  107. package/module/fanscenter_basicinfo_province_get.js +10 -0
  108. package/module/fanscenter_overview_get.js +6 -0
  109. package/module/fanscenter_trend_list.js +10 -0
  110. package/module/fm_trash.js +11 -0
  111. package/module/follow.js +11 -0
  112. package/module/get_userids.js +7 -0
  113. package/module/history_recommend_songs.js +11 -0
  114. package/module/history_recommend_songs_detail.js +13 -0
  115. package/module/homepage_block_page.js +8 -0
  116. package/module/homepage_dragon_ball.js +10 -0
  117. package/module/hot_topic.js +10 -0
  118. package/module/hug_comment.js +16 -0
  119. package/module/inner_version.js +16 -0
  120. package/module/like.js +13 -0
  121. package/module/likelist.js +9 -0
  122. package/module/listen_data_realtime_report.js +11 -0
  123. package/module/listen_data_report.js +12 -0
  124. package/module/listen_data_today_song.js +9 -0
  125. package/module/listen_data_total.js +9 -0
  126. package/module/listen_data_year_report.js +9 -0
  127. package/module/listentogether_accept.js +13 -0
  128. package/module/listentogether_end.js +9 -0
  129. package/module/listentogether_heatbeat.js +12 -0
  130. package/module/listentogether_play_command.js +21 -0
  131. package/module/listentogether_room_check.js +9 -0
  132. package/module/listentogether_room_create.js +9 -0
  133. package/module/listentogether_status.js +10 -0
  134. package/module/listentogether_sync_list_command.js +26 -0
  135. package/module/listentogether_sync_playlist_get.js +13 -0
  136. package/module/login.js +41 -0
  137. package/module/login_cellphone.js +40 -0
  138. package/module/login_qr_check.js +29 -0
  139. package/module/login_qr_create.js +30 -0
  140. package/module/login_qr_key.js +19 -0
  141. package/module/login_refresh.js +21 -0
  142. package/module/login_status.js +21 -0
  143. package/module/logout.js +6 -0
  144. package/module/lyric.js +14 -0
  145. package/module/lyric_new.js +17 -0
  146. package/module/mlog_music_rcmd.js +13 -0
  147. package/module/mlog_to_video.js +13 -0
  148. package/module/mlog_url.js +11 -0
  149. package/module/msg_comments.js +17 -0
  150. package/module/msg_forwards.js +11 -0
  151. package/module/msg_notices.js +10 -0
  152. package/module/msg_private.js +11 -0
  153. package/module/msg_private_history.js +12 -0
  154. package/module/msg_recentcontact.js +11 -0
  155. package/module/music_first_listen_info.js +13 -0
  156. package/module/musician_cloudbean.js +7 -0
  157. package/module/musician_cloudbean_obtain.js +14 -0
  158. package/module/musician_data_overview.js +11 -0
  159. package/module/musician_play_trend.js +14 -0
  160. package/module/musician_sign.js +7 -0
  161. package/module/musician_tasks.js +11 -0
  162. package/module/musician_tasks_new.js +11 -0
  163. package/module/mv_all.js +16 -0
  164. package/module/mv_detail.js +9 -0
  165. package/module/mv_detail_info.js +14 -0
  166. package/module/mv_exclusive_rcmd.js +10 -0
  167. package/module/mv_first.js +12 -0
  168. package/module/mv_sub.js +11 -0
  169. package/module/mv_sublist.js +15 -0
  170. package/module/mv_url.js +14 -0
  171. package/module/nickname_check.js +7 -0
  172. package/module/personal_fm.js +6 -0
  173. package/module/personal_fm_mode.js +14 -0
  174. package/module/personalized.js +16 -0
  175. package/module/personalized_djprogram.js +10 -0
  176. package/module/personalized_mv.js +6 -0
  177. package/module/personalized_newsong.js +15 -0
  178. package/module/personalized_privatecontent.js +10 -0
  179. package/module/personalized_privatecontent_list.js +15 -0
  180. package/module/pl_count.js +6 -0
  181. package/module/playlist_category_list.js +11 -0
  182. package/module/playlist_catlist.js +6 -0
  183. package/module/playlist_cover_update.js +32 -0
  184. package/module/playlist_create.js +11 -0
  185. package/module/playlist_delete.js +9 -0
  186. package/module/playlist_desc_update.js +10 -0
  187. package/module/playlist_detail.js +11 -0
  188. package/module/playlist_detail_dynamic.js +11 -0
  189. package/module/playlist_detail_rcmd_get.js +11 -0
  190. package/module/playlist_highquality_tags.js +10 -0
  191. package/module/playlist_hot.js +6 -0
  192. package/module/playlist_import_name_task_create.js +62 -0
  193. package/module/playlist_import_task_status.js +11 -0
  194. package/module/playlist_mylike.js +12 -0
  195. package/module/playlist_name_update.js +10 -0
  196. package/module/playlist_order_update.js +13 -0
  197. package/module/playlist_privacy.js +10 -0
  198. package/module/playlist_subscribe.js +14 -0
  199. package/module/playlist_subscribers.js +11 -0
  200. package/module/playlist_tags_update.js +10 -0
  201. package/module/playlist_track_add.js +16 -0
  202. package/module/playlist_track_all.js +31 -0
  203. package/module/playlist_track_delete.js +20 -0
  204. package/module/playlist_tracks.js +45 -0
  205. package/module/playlist_update.js +13 -0
  206. package/module/playlist_update_playcount.js +9 -0
  207. package/module/playlist_video_recent.js +9 -0
  208. package/module/playmode_intelligence_list.js +13 -0
  209. package/module/playmode_song_vector.js +8 -0
  210. package/module/program_recommend.js +15 -0
  211. package/module/rebind.js +16 -0
  212. package/module/recent_listen_list.js +7 -0
  213. package/module/recommend_resource.js +10 -0
  214. package/module/recommend_songs.js +11 -0
  215. package/module/recommend_songs_dislike.js +14 -0
  216. package/module/record_recent_album.js +11 -0
  217. package/module/record_recent_dj.js +11 -0
  218. package/module/record_recent_playlist.js +11 -0
  219. package/module/record_recent_song.js +11 -0
  220. package/module/record_recent_video.js +11 -0
  221. package/module/record_recent_voice.js +11 -0
  222. package/module/register_anonimous.js +52 -0
  223. package/module/register_cellphone.js +15 -0
  224. package/module/related_allvideo.js +14 -0
  225. package/module/related_playlist.js +32 -0
  226. package/module/resource_like.js +14 -0
  227. package/module/scrobble.js +26 -0
  228. package/module/search.js +21 -0
  229. package/module/search_default.js +6 -0
  230. package/module/search_hot.js +9 -0
  231. package/module/search_hot_detail.js +6 -0
  232. package/module/search_match.js +18 -0
  233. package/module/search_multimatch.js +14 -0
  234. package/module/search_suggest.js +14 -0
  235. package/module/send_album.js +12 -0
  236. package/module/send_playlist.js +12 -0
  237. package/module/send_song.js +12 -0
  238. package/module/send_text.js +11 -0
  239. package/module/setting.js +7 -0
  240. package/module/share_resource.js +11 -0
  241. package/module/sheet_list.js +9 -0
  242. package/module/sheet_preview.js +8 -0
  243. package/module/sign_happy_info.js +5 -0
  244. package/module/signin_progress.js +13 -0
  245. package/module/simi_artist.js +12 -0
  246. package/module/simi_mv.js +9 -0
  247. package/module/simi_playlist.js +15 -0
  248. package/module/simi_song.js +15 -0
  249. package/module/simi_user.js +11 -0
  250. package/module/song_chorus.js +11 -0
  251. package/module/song_detail.js +11 -0
  252. package/module/song_downlist.js +11 -0
  253. package/module/song_download_url.js +10 -0
  254. package/module/song_download_url_v1.js +13 -0
  255. package/module/song_dynamic_cover.js +9 -0
  256. package/module/song_like_check.js +9 -0
  257. package/module/song_lyrics_mark.js +9 -0
  258. package/module/song_lyrics_mark_add.js +12 -0
  259. package/module/song_lyrics_mark_del.js +9 -0
  260. package/module/song_lyrics_mark_user_page.js +14 -0
  261. package/module/song_monthdownlist.js +11 -0
  262. package/module/song_music_detail.js +9 -0
  263. package/module/song_order_update.js +12 -0
  264. package/module/song_purchased.js +14 -0
  265. package/module/song_red_count.js +9 -0
  266. package/module/song_singledownlist.js +11 -0
  267. package/module/song_url.js +26 -0
  268. package/module/song_url_match.js +35 -0
  269. package/module/song_url_ncmget.js +75 -0
  270. package/module/song_url_unblock.js +35 -0
  271. package/module/song_url_v1.js +54 -0
  272. package/module/song_wiki_summary.js +8 -0
  273. package/module/starpick_comments_summary.js +12 -0
  274. package/module/style_album.js +16 -0
  275. package/module/style_artist.js +16 -0
  276. package/module/style_detail.js +9 -0
  277. package/module/style_list.js +7 -0
  278. package/module/style_playlist.js +16 -0
  279. package/module/style_preference.js +11 -0
  280. package/module/style_song.js +12 -0
  281. package/module/summary_annual.js +12 -0
  282. package/module/threshold_detail_get.js +10 -0
  283. package/module/top_album.js +22 -0
  284. package/module/top_artists.js +11 -0
  285. package/module/top_list.js +20 -0
  286. package/module/top_mv.js +12 -0
  287. package/module/top_playlist.js +22 -0
  288. package/module/top_playlist_highquality.js +16 -0
  289. package/module/top_song.js +16 -0
  290. package/module/topic_detail.js +7 -0
  291. package/module/topic_detail_event_hot.js +7 -0
  292. package/module/topic_sublist.js +11 -0
  293. package/module/toplist.js +6 -0
  294. package/module/toplist_artist.js +12 -0
  295. package/module/toplist_detail.js +6 -0
  296. package/module/toplist_detail_v2.js +6 -0
  297. package/module/ugc_album_get.js +8 -0
  298. package/module/ugc_artist_get.js +8 -0
  299. package/module/ugc_artist_search.js +10 -0
  300. package/module/ugc_detail.js +17 -0
  301. package/module/ugc_mv_get.js +8 -0
  302. package/module/ugc_song_get.js +8 -0
  303. package/module/ugc_user_devote.js +6 -0
  304. package/module/user_account.js +5 -0
  305. package/module/user_audio.js +9 -0
  306. package/module/user_binding.js +9 -0
  307. package/module/user_bindingcellphone.js +15 -0
  308. package/module/user_cloud.js +10 -0
  309. package/module/user_cloud_del.js +9 -0
  310. package/module/user_cloud_detail.js +10 -0
  311. package/module/user_comment_history.js +15 -0
  312. package/module/user_detail.js +15 -0
  313. package/module/user_detail_new.js +20 -0
  314. package/module/user_dj.js +14 -0
  315. package/module/user_event.js +12 -0
  316. package/module/user_follow_mixed.js +23 -0
  317. package/module/user_followeds.js +17 -0
  318. package/module/user_follows.js +15 -0
  319. package/module/user_level.js +7 -0
  320. package/module/user_medal.js +11 -0
  321. package/module/user_mutualfollow_get.js +9 -0
  322. package/module/user_playlist.js +12 -0
  323. package/module/user_record.js +10 -0
  324. package/module/user_replacephone.js +14 -0
  325. package/module/user_social_status.js +11 -0
  326. package/module/user_social_status_edit.js +16 -0
  327. package/module/user_social_status_rcmd.js +5 -0
  328. package/module/user_social_status_support.js +5 -0
  329. package/module/user_subcount.js +6 -0
  330. package/module/user_update.js +15 -0
  331. package/module/verify_getQr.js +39 -0
  332. package/module/verify_qrcodestatus.js +12 -0
  333. package/module/video_category_list.js +15 -0
  334. package/module/video_detail.js +13 -0
  335. package/module/video_detail_info.js +14 -0
  336. package/module/video_group.js +16 -0
  337. package/module/video_group_list.js +11 -0
  338. package/module/video_sub.js +14 -0
  339. package/module/video_timeline_all.js +17 -0
  340. package/module/video_timeline_recommend.js +13 -0
  341. package/module/video_url.js +10 -0
  342. package/module/vip_growthpoint.js +11 -0
  343. package/module/vip_growthpoint_details.js +14 -0
  344. package/module/vip_growthpoint_get.js +13 -0
  345. package/module/vip_info.js +12 -0
  346. package/module/vip_info_v2.js +12 -0
  347. package/module/vip_tasks.js +11 -0
  348. package/module/vip_timemachine.js +17 -0
  349. package/module/voice_delete.js +7 -0
  350. package/module/voice_detail.js +7 -0
  351. package/module/voice_lyric.js +7 -0
  352. package/module/voice_upload.js +186 -0
  353. package/module/voicelist_detail.js +11 -0
  354. package/module/voicelist_list.js +13 -0
  355. package/module/voicelist_list_search.js +14 -0
  356. package/module/voicelist_search.js +14 -0
  357. package/module/voicelist_trans.js +15 -0
  358. package/module/weblog.js +10 -0
  359. package/module/yunbei.js +6 -0
  360. package/module/yunbei_expense.js +8 -0
  361. package/module/yunbei_info.js +5 -0
  362. package/module/yunbei_rcmd_song.js +17 -0
  363. package/module/yunbei_rcmd_song_history.js +16 -0
  364. package/module/yunbei_receipt.js +8 -0
  365. package/module/yunbei_sign.js +5 -0
  366. package/module/yunbei_task_finish.js +12 -0
  367. package/module/yunbei_tasks.js +9 -0
  368. package/module/yunbei_tasks_todo.js +9 -0
  369. package/module/yunbei_today.js +5 -0
  370. package/package.json +104 -0
  371. package/plugins/songUpload.js +61 -0
  372. package/plugins/upload.js +37 -0
  373. package/public/api.html +127 -0
  374. package/public/audio_match_demo/afp.js +1627 -0
  375. package/public/audio_match_demo/afp.wasm.js +5 -0
  376. package/public/audio_match_demo/index.html +199 -0
  377. package/public/audio_match_demo/rec.js +49 -0
  378. package/public/avatar_update.html +73 -0
  379. package/public/cloud.html +104 -0
  380. package/public/docs/.nojekyll +0 -0
  381. package/public/docs/_coverpage.md +13 -0
  382. package/public/docs/favicon.ico +0 -0
  383. package/public/docs/home.md +4857 -0
  384. package/public/docs/icon.png +0 -0
  385. package/public/docs/index.html +47 -0
  386. package/public/docs/ncmapireborn.png +0 -0
  387. package/public/docs/sw.js +90 -0
  388. package/public/eapi_decrypt.html +77 -0
  389. package/public/home.html +41 -0
  390. package/public/index.html +313 -0
  391. package/public/listen_together_host.html +324 -0
  392. package/public/login.html +47 -0
  393. package/public/playlist_cover_update.html +77 -0
  394. package/public/playlist_import.html +262 -0
  395. package/public/qrlogin-nocookie.html +72 -0
  396. package/public/qrlogin.html +71 -0
  397. package/public/static/docs.png +0 -0
  398. package/public/static/eapi_params.png +0 -0
  399. package/public/static/eapi_response.png +0 -0
  400. package/public/static/screenshot1.png +0 -0
  401. package/public/unblock_test.html +123 -0
  402. package/public/voice_upload.html +128 -0
  403. package/server.js +366 -0
  404. package/util/apicache.js +833 -0
  405. package/util/client-sign.js +169 -0
  406. package/util/config.json +20 -0
  407. package/util/crypto.js +135 -0
  408. package/util/index.js +159 -0
  409. package/util/logger.js +29 -0
  410. package/util/memory-cache.js +71 -0
  411. package/util/option.js +14 -0
  412. package/util/request.js +364 -0
package/server.js ADDED
@@ -0,0 +1,366 @@
1
+ require("dotenv").config();
2
+ const fs = require('fs')
3
+ const path = require('path')
4
+ const express = require('express')
5
+ const request = require('./util/request')
6
+ const packageJSON = require('./package.json')
7
+ const exec = require('child_process').exec
8
+ const cache = require('./util/apicache').middleware
9
+ const { cookieToJson } = require('./util/index')
10
+ const fileUpload = require('express-fileupload')
11
+ const decode = require('safe-decode-uri-component')
12
+ const logger = require('./util/logger.js')
13
+
14
+ /**
15
+ * The version check result.
16
+ * @readonly
17
+ * @enum {number}
18
+ */
19
+ const VERSION_CHECK_RESULT = {
20
+ FAILED: -1,
21
+ NOT_LATEST: 0,
22
+ LATEST: 1,
23
+ }
24
+
25
+ /**
26
+ * @typedef {{
27
+ * identifier?: string,
28
+ * route: string,
29
+ * module: any
30
+ * }} ModuleDefinition
31
+ */
32
+
33
+ /**
34
+ * @typedef {{
35
+ * port?: number,
36
+ * host?: string,
37
+ * checkVersion?: boolean,
38
+ * moduleDefs?: ModuleDefinition[]
39
+ * }} NcmApiOptions
40
+ */
41
+
42
+ /**
43
+ * @typedef {{
44
+ * status: VERSION_CHECK_RESULT,
45
+ * ourVersion?: string,
46
+ * npmVersion?: string,
47
+ * }} VersionCheckResult
48
+ */
49
+
50
+ /**
51
+ * @typedef {{
52
+ * server?: import('http').Server,
53
+ * }} ExpressExtension
54
+ */
55
+
56
+ /**
57
+ * Get the module definitions dynamically.
58
+ *
59
+ * @param {string} modulesPath The path to modules (JS).
60
+ * @param {Record<string, string>} [specificRoute] The specific route of specific modules.
61
+ * @param {boolean} [doRequire] If true, require() the module directly.
62
+ * Otherwise, print out the module path. Default to true.
63
+ * @returns {Promise<ModuleDefinition[]>} The module definitions.
64
+ *
65
+ * @example getModuleDefinitions("./module", {"album_new.js": "/album/create"})
66
+ */
67
+ async function getModulesDefinitions(
68
+ modulesPath,
69
+ specificRoute,
70
+ doRequire = true,
71
+ ) {
72
+ const files = await fs.promises.readdir(modulesPath)
73
+ const parseRoute = (/** @type {string} */ fileName) =>
74
+ specificRoute && fileName in specificRoute
75
+ ? specificRoute[fileName]
76
+ : `/${fileName.replace(/\.js$/i, '').replace(/_/g, '/')}`
77
+
78
+ const modules = files
79
+ .reverse()
80
+ .filter((file) => file.endsWith('.js'))
81
+ .map((file) => {
82
+ const identifier = file.split('.').shift()
83
+ const route = parseRoute(file)
84
+ const modulePath = path.join(modulesPath, file)
85
+ const module = doRequire ? require(modulePath) : modulePath
86
+
87
+ return { identifier, route, module }
88
+ })
89
+
90
+ return modules
91
+ }
92
+
93
+ /**
94
+ * Check if the version of this API is latest.
95
+ *
96
+ * @returns {Promise<VersionCheckResult>} If true, this API is up-to-date;
97
+ * otherwise, this API should be upgraded and you would
98
+ * need to notify users to upgrade it manually.
99
+ */
100
+ async function checkVersion() {
101
+ return new Promise((resolve) => {
102
+ exec('npm info NeteaseCloudMusicApiEnhanced version', (err, stdout) => {
103
+ if (!err) {
104
+ let version = stdout.trim()
105
+
106
+ /**
107
+ * @param {VERSION_CHECK_RESULT} status
108
+ */
109
+ const resolveStatus = (status) =>
110
+ resolve({
111
+ status,
112
+ ourVersion: packageJSON.version,
113
+ npmVersion: version,
114
+ })
115
+
116
+ resolveStatus(
117
+ packageJSON.version < version
118
+ ? VERSION_CHECK_RESULT.NOT_LATEST
119
+ : VERSION_CHECK_RESULT.LATEST,
120
+ )
121
+ } else {
122
+ resolve({
123
+ status: VERSION_CHECK_RESULT.FAILED,
124
+ })
125
+ }
126
+ })
127
+ })
128
+ }
129
+
130
+ /**
131
+ * Construct the server of NCM API.
132
+ *
133
+ * @param {ModuleDefinition[]} [moduleDefs] Customized module definitions [advanced]
134
+ * @returns {Promise<import("express").Express>} The server instance.
135
+ */
136
+ async function consturctServer(moduleDefs) {
137
+ const app = express()
138
+ const { CORS_ALLOW_ORIGIN } = process.env
139
+ app.set('trust proxy', true)
140
+
141
+ /**
142
+ * Serving static files
143
+ */
144
+ app.use(express.static(path.join(__dirname, 'public')))
145
+ /**
146
+ * CORS & Preflight request
147
+ */
148
+ app.use((req, res, next) => {
149
+ if (req.path !== '/' && !req.path.includes('.')) {
150
+ res.set({
151
+ 'Access-Control-Allow-Credentials': true,
152
+ 'Access-Control-Allow-Origin':
153
+ CORS_ALLOW_ORIGIN || req.headers.origin || '*',
154
+ 'Access-Control-Allow-Headers': 'X-Requested-With,Content-Type',
155
+ 'Access-Control-Allow-Methods': 'PUT,POST,GET,DELETE,OPTIONS',
156
+ 'Content-Type': 'application/json; charset=utf-8',
157
+ })
158
+ }
159
+ req.method === 'OPTIONS' ? res.status(204).end() : next()
160
+ })
161
+
162
+ /**
163
+ * Cookie Parser
164
+ */
165
+ app.use((req, _, next) => {
166
+ req.cookies = {}
167
+ //;(req.headers.cookie || '').split(/\s*;\s*/).forEach((pair) => { // Polynomial regular expression //
168
+ ;(req.headers.cookie || '').split(/;\s+|(?<!\s)\s+$/g).forEach((pair) => {
169
+ let crack = pair.indexOf('=')
170
+ if (crack < 1 || crack == pair.length - 1) return
171
+ req.cookies[decode(pair.slice(0, crack)).trim()] = decode(
172
+ pair.slice(crack + 1),
173
+ ).trim()
174
+ })
175
+ next()
176
+ })
177
+
178
+ /**
179
+ * Body Parser and File Upload
180
+ */
181
+ app.use(express.json({ limit: '50mb' }))
182
+ app.use(express.urlencoded({ extended: false, limit: '50mb' }))
183
+
184
+ app.use(fileUpload())
185
+
186
+ /**
187
+ * Cache
188
+ */
189
+ app.use(cache('2 minutes', (_, res) => res.statusCode === 200))
190
+
191
+ /**
192
+ * Special Routers
193
+ */
194
+ const special = {
195
+ 'daily_signin.js': '/daily_signin',
196
+ 'fm_trash.js': '/fm_trash',
197
+ 'personal_fm.js': '/personal_fm',
198
+ }
199
+
200
+ /**
201
+ * Load every modules in this directory
202
+ */
203
+ const moduleDefinitions =
204
+ moduleDefs ||
205
+ (await getModulesDefinitions(path.join(__dirname, 'module'), special))
206
+
207
+ for (const moduleDef of moduleDefinitions) {
208
+ // Register the route.
209
+ app.use(moduleDef.route, async (req, res) => {
210
+ ;[req.query, req.body].forEach((item) => {
211
+ // item may be undefined (some environments / middlewares).
212
+ // Guard access to avoid "Cannot read properties of undefined (reading 'cookie')".
213
+ if (item && typeof item.cookie === 'string') {
214
+ item.cookie = cookieToJson(decode(item.cookie))
215
+ }
216
+ })
217
+
218
+ let query = Object.assign(
219
+ {},
220
+ { cookie: req.cookies },
221
+ req.query,
222
+ req.body,
223
+ req.files,
224
+ )
225
+
226
+ try {
227
+ const moduleResponse = await moduleDef.module(query, (...params) => {
228
+ // 参数注入客户端IP
229
+ const obj = [...params]
230
+ let ip = req.ip
231
+
232
+ if (ip.substring(0, 7) == '::ffff:') {
233
+ ip = ip.substring(7)
234
+ }
235
+ if (ip == '::1') {
236
+ ip = global.cnIp
237
+ }
238
+ // logger.info(ip)
239
+ obj[3] = {
240
+ ...obj[3],
241
+ ip,
242
+ }
243
+ return request(...obj)
244
+ })
245
+ logger.info(`Request Success: ${decode(req.originalUrl)}`)
246
+
247
+ if (
248
+ (req.baseUrl === '/song/url/v1' || req.baseUrl === '/song/url') &&
249
+ process.env.ENABLE_GENERAL_UNBLOCK === 'true'
250
+ ) {
251
+ const song = moduleResponse['body']['data'][0]
252
+ if (song.freeTrialInfo !== null || !song.url || [1, 4].includes(song.fee)) {
253
+ const match = require('@unblockneteasemusic/server')
254
+ const source = process.env.UNBLOCK_SOURCE ? process.env.UNBLOCK_SOURCE.split(',') : ['pyncmd', 'bodian', 'kuwo', 'qq', 'migu', 'kugou']
255
+ logger.info("开始解灰", source)
256
+ const { url } = await match(req.query.id, source)
257
+ song.url = url
258
+ song.freeTrialInfo = 'null'
259
+ logger.info("解灰成功!")
260
+ }
261
+ if (song.url.includes('kuwo')) {
262
+ const proxy = process.env.PROXY_URL;
263
+ const useProxy = process.env.ENABLE_PROXY || 'false'
264
+ if (useProxy === 'true' && proxy) {song.proxyUrl = proxy + song.url}
265
+ }
266
+ }
267
+
268
+ const cookies = moduleResponse.cookie
269
+ if (!query.noCookie) {
270
+ if (Array.isArray(cookies) && cookies.length > 0) {
271
+ if (req.protocol === 'https') {
272
+ // Try to fix CORS SameSite Problem
273
+ res.append(
274
+ 'Set-Cookie',
275
+ cookies.map((cookie) => {
276
+ return cookie + '; SameSite=None; Secure'
277
+ }),
278
+ )
279
+ } else {
280
+ res.append('Set-Cookie', cookies)
281
+ }
282
+ }
283
+ }
284
+ res.status(moduleResponse.status).send(moduleResponse.body)
285
+ } catch (/** @type {*} */ moduleResponse) {
286
+ logger.error(`${decode(req.originalUrl)}`, {
287
+ status: moduleResponse.status,
288
+ body: moduleResponse.body,
289
+ })
290
+ if (!moduleResponse.body) {
291
+ res.status(404).send({
292
+ code: 404,
293
+ data: null,
294
+ msg: 'Not Found',
295
+ })
296
+ return
297
+ }
298
+ if (moduleResponse.body.code == '301')
299
+ moduleResponse.body.msg = '需要登录'
300
+ if (!query.noCookie) {
301
+ res.append('Set-Cookie', moduleResponse.cookie)
302
+ }
303
+
304
+ res.status(moduleResponse.status).send(moduleResponse.body)
305
+ }
306
+ })
307
+ }
308
+
309
+ return app
310
+ }
311
+
312
+ /**
313
+ * Serve the NCM API.
314
+ * @param {NcmApiOptions} options
315
+ * @returns {Promise<import('express').Express & ExpressExtension>}
316
+ */
317
+ async function serveNcmApi(options) {
318
+ const port = Number(options.port || process.env.PORT || '3000')
319
+ const host = options.host || process.env.HOST || ''
320
+
321
+ const checkVersionSubmission =
322
+ options.checkVersion &&
323
+ checkVersion().then(({ npmVersion, ourVersion, status }) => {
324
+ if (status == VERSION_CHECK_RESULT.NOT_LATEST) {
325
+ logger.info(
326
+ `最新版本: ${npmVersion}, 当前版本: ${ourVersion}, 请及时更新`,
327
+ )
328
+ }
329
+ })
330
+ const constructServerSubmission = consturctServer(options.moduleDefs)
331
+
332
+ const [_, app] = await Promise.all([
333
+ checkVersionSubmission,
334
+ constructServerSubmission,
335
+ ])
336
+
337
+ /** @type {import('express').Express & ExpressExtension} */
338
+ const appExt = app
339
+ appExt.server = app.listen(port, host, () => {
340
+ console.log(`
341
+ _ _ _____ __ __
342
+ | \\ | |/ ____| \\/ |
343
+ | \\| | | | \\ / |
344
+ | . \` | | | |\\/| |
345
+ | |\\ | |____| | | |
346
+ |_| \\_|\\_____|_| |_|
347
+ `)
348
+ console.log(`
349
+ ╔═╗╔═╗╦ ╔═╗╔╗╔╦ ╦╔═╗╔╗╔╔═╗╔═╗╔╦╗
350
+ ╠═╣╠═╝║ ║╣ ║║║╠═╣╠═╣║║║║ ║╣ ║║
351
+ ╩ ╩╩ ╩ ╚═╝╝╚╝╩ ╩╩ ╩╝╚╝╚═╝╚═╝═╩╝
352
+ `)
353
+ logger.info(`
354
+ - Server started successfully @ http://${host ? host : 'localhost'}:${port}
355
+ - Environment: ${process.env.NODE_ENV || 'development'}
356
+ - Node Version: ${process.version}
357
+ - Process ID: ${process.pid}`)
358
+ })
359
+
360
+ return appExt
361
+ }
362
+
363
+ module.exports = {
364
+ serveNcmApi,
365
+ getModulesDefinitions,
366
+ }