@sansenjian/qq-music-api 2.2.1 → 2.2.9

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 (353) hide show
  1. package/CHANGELOG.md +124 -33
  2. package/README.md +2 -0
  3. package/dist/app.js +77 -0
  4. package/dist/config/service-config.js +37 -0
  5. package/dist/config/user-info.js +59 -0
  6. package/dist/index.js +3 -0
  7. package/dist/jest.config.js +52 -0
  8. package/dist/middlewares/fallback-middleware.js +29 -0
  9. package/dist/middlewares/koa-cors.js +63 -0
  10. package/dist/module/apis/UCommon/UCommon.js +10 -0
  11. package/dist/module/apis/album/getAlbumInfo.js +23 -0
  12. package/dist/module/apis/comments/getComments.js +24 -0
  13. package/dist/module/apis/digitalAlbum/getDigitalAlbumLists.js +22 -0
  14. package/dist/module/apis/downloadQQMusic.js +48 -0
  15. package/dist/module/apis/extend/getPlaylistTags.js +158 -0
  16. package/dist/module/apis/music/getLyric.js +32 -0
  17. package/dist/module/apis/music/getMusicPlay.js +187 -0
  18. package/dist/module/apis/mv/getMvByTag.js +23 -0
  19. package/dist/module/apis/radio/getRadioLists.js +26 -0
  20. package/dist/module/apis/rank/getTopLists.js +35 -0
  21. package/dist/module/apis/recommend/getDailyRecommend.js +124 -0
  22. package/dist/module/apis/recommend/getPersonalRecommend.js +114 -0
  23. package/dist/module/apis/search/getHotKey.js +25 -0
  24. package/dist/module/apis/search/getSearchByKey.js +32 -0
  25. package/dist/module/apis/search/getSmartbox.js +40 -0
  26. package/dist/module/apis/singers/getSimilarSinger.js +24 -0
  27. package/dist/module/apis/singers/getSingerDesc.js +24 -0
  28. package/dist/module/apis/singers/getSingerMv.js +23 -0
  29. package/dist/module/apis/singers/getSingerStarNum.js +23 -0
  30. package/dist/module/apis/songLists/songListCategories.js +23 -0
  31. package/dist/module/apis/songLists/songListDetail.js +28 -0
  32. package/dist/module/apis/songLists/songLists.js +35 -0
  33. package/dist/module/apis/u_common.js +62 -0
  34. package/dist/module/apis/user/checkQQLoginQr.js +189 -0
  35. package/dist/module/apis/user/getQQLoginQr.js +23 -0
  36. package/dist/module/apis/user/getUserAvatar.js +25 -0
  37. package/dist/module/apis/user/getUserLikedSongs.js +129 -0
  38. package/dist/module/apis/user/getUserPlaylists.js +138 -0
  39. package/dist/module/apis/y_common.js +69 -0
  40. package/dist/module/config.js +24 -0
  41. package/dist/module/index.js +72 -0
  42. package/dist/package.json +120 -0
  43. package/dist/routers/context/batchGetSongInfo.js +48 -0
  44. package/dist/routers/context/batchGetSongLists.js +35 -0
  45. package/dist/routers/context/checkQQLoginQr.js +16 -0
  46. package/dist/routers/context/cookies.js +36 -0
  47. package/dist/routers/context/getAlbumInfo.js +22 -0
  48. package/dist/routers/context/getComments.js +31 -0
  49. package/dist/routers/context/getDailyRecommend.js +33 -0
  50. package/dist/routers/context/getDigitalAlbumLists.js +16 -0
  51. package/dist/routers/context/getDownloadQQMusic.js +16 -0
  52. package/dist/routers/context/getHotkey.js +20 -0
  53. package/dist/routers/context/getImageUrl.js +25 -0
  54. package/dist/routers/context/getLyric.js +29 -0
  55. package/dist/routers/context/getMusicPlay.js +33 -0
  56. package/dist/routers/context/getMv.js +51 -0
  57. package/dist/routers/context/getMvByTag.js +16 -0
  58. package/dist/routers/context/getMvPlay.js +104 -0
  59. package/dist/routers/context/getNewDisks.js +52 -0
  60. package/dist/routers/context/getPersonalRecommend.js +42 -0
  61. package/dist/routers/context/getPlaylistTags.js +54 -0
  62. package/dist/routers/context/getQQLoginQr.js +14 -0
  63. package/dist/routers/context/getRadioLists.js +16 -0
  64. package/dist/routers/context/getRanks.js +53 -0
  65. package/dist/routers/context/getRecommend.js +88 -0
  66. package/dist/routers/context/getSearchByKey.js +32 -0
  67. package/dist/routers/context/getSimilarSinger.js +27 -0
  68. package/dist/routers/context/getSingerAlbum.js +48 -0
  69. package/dist/routers/context/getSingerDesc.js +28 -0
  70. package/dist/routers/context/getSingerHotsong.js +48 -0
  71. package/dist/routers/context/getSingerList.js +39 -0
  72. package/dist/routers/context/getSingerMv.js +36 -0
  73. package/dist/routers/context/getSingerStarNum.js +27 -0
  74. package/dist/routers/context/getSmartbox.js +27 -0
  75. package/dist/routers/context/getSongInfo.js +40 -0
  76. package/dist/routers/context/getSongListCategories.js +22 -0
  77. package/dist/routers/context/getSongListDetail.js +17 -0
  78. package/dist/routers/context/getSongLists.js +25 -0
  79. package/dist/routers/context/getTicketInfo.js +47 -0
  80. package/dist/routers/context/getTopLists.js +16 -0
  81. package/dist/routers/context/getUserAvatar.js +35 -0
  82. package/dist/routers/context/getUserLikedSongs.js +24 -0
  83. package/dist/routers/context/getUserPlaylists.js +27 -0
  84. package/dist/routers/context/index.js +98 -0
  85. package/dist/routers/router.js +69 -0
  86. package/dist/routers/types.js +2 -0
  87. package/dist/routers/util.js +219 -0
  88. package/dist/scripts/run-tests-with-flags.js +139 -0
  89. package/dist/types/api.js +55 -0
  90. package/dist/util/apiResponse.js +88 -0
  91. package/dist/util/colors.js +19 -0
  92. package/dist/util/cookie.js +34 -0
  93. package/dist/util/cookieResolver.js +66 -0
  94. package/dist/util/loginUtils.js +30 -0
  95. package/dist/util/lyricParse.js +72 -0
  96. package/dist/util/request.js +118 -0
  97. package/docs-dist/404.html +24 -0
  98. package/docs-dist/CHANGELOG-ARCHITECTURE.html +131 -0
  99. package/docs-dist/COOKIE_CONFIG_GUIDE.html +39 -0
  100. package/docs-dist/FALLBACK_MODE_GUIDE.html +101 -0
  101. package/docs-dist/README.html +447 -0
  102. package/docs-dist/TEST_USER_PLAYLISTS.html +42 -0
  103. package/docs-dist/USER_AVATAR_GUIDE.html +100 -0
  104. package/docs-dist/api/comments.html +48 -0
  105. package/docs-dist/api/index.html +27 -0
  106. package/docs-dist/api/music.html +51 -0
  107. package/docs-dist/api/other.html +33 -0
  108. package/docs-dist/api/playlist.html +77 -0
  109. package/docs-dist/api/rank.html +48 -0
  110. package/docs-dist/api/search.html +62 -0
  111. package/docs-dist/api/singer.html +47 -0
  112. package/docs-dist/api/user.html +64 -0
  113. package/docs-dist/assets/CHANGELOG-ARCHITECTURE.md.r40JGJZK.js +105 -0
  114. package/docs-dist/assets/CHANGELOG-ARCHITECTURE.md.r40JGJZK.lean.js +1 -0
  115. package/docs-dist/assets/COOKIE_CONFIG_GUIDE.md.BVXl7WHu.js +13 -0
  116. package/docs-dist/assets/COOKIE_CONFIG_GUIDE.md.BVXl7WHu.lean.js +1 -0
  117. package/docs-dist/assets/FALLBACK_MODE_GUIDE.md.BBdcIdh_.js +75 -0
  118. package/docs-dist/assets/FALLBACK_MODE_GUIDE.md.BBdcIdh_.lean.js +1 -0
  119. package/docs-dist/assets/README.md.D6Tw0nRd.js +421 -0
  120. package/docs-dist/assets/README.md.D6Tw0nRd.lean.js +1 -0
  121. package/docs-dist/assets/TEST_USER_PLAYLISTS.md.DSt20Igj.js +16 -0
  122. package/docs-dist/assets/TEST_USER_PLAYLISTS.md.DSt20Igj.lean.js +1 -0
  123. package/docs-dist/assets/USER_AVATAR_GUIDE.md.CVHPs2Dn.js +74 -0
  124. package/docs-dist/assets/USER_AVATAR_GUIDE.md.CVHPs2Dn.lean.js +1 -0
  125. package/docs-dist/assets/api_comments.md.79Q_C8Qp.js +22 -0
  126. package/docs-dist/assets/api_comments.md.79Q_C8Qp.lean.js +1 -0
  127. package/docs-dist/assets/api_index.md.CU3By8tw.js +1 -0
  128. package/docs-dist/assets/api_index.md.CU3By8tw.lean.js +1 -0
  129. package/docs-dist/assets/api_music.md.B1AzLePX.js +25 -0
  130. package/docs-dist/assets/api_music.md.B1AzLePX.lean.js +1 -0
  131. package/docs-dist/assets/api_other.md.DCg4bzA7.js +7 -0
  132. package/docs-dist/assets/api_other.md.DCg4bzA7.lean.js +1 -0
  133. package/docs-dist/assets/api_playlist.md.8ACJ3QqD.js +51 -0
  134. package/docs-dist/assets/api_playlist.md.8ACJ3QqD.lean.js +1 -0
  135. package/docs-dist/assets/api_rank.md.B8IP2ZRy.js +22 -0
  136. package/docs-dist/assets/api_rank.md.B8IP2ZRy.lean.js +1 -0
  137. package/docs-dist/assets/api_search.md.DO9J6nvp.js +36 -0
  138. package/docs-dist/assets/api_search.md.DO9J6nvp.lean.js +1 -0
  139. package/docs-dist/assets/api_singer.md.CcL32xuN.js +21 -0
  140. package/docs-dist/assets/api_singer.md.CcL32xuN.lean.js +1 -0
  141. package/docs-dist/assets/api_user.md.Cb7Ky3Sn.js +38 -0
  142. package/docs-dist/assets/api_user.md.Cb7Ky3Sn.lean.js +1 -0
  143. package/docs-dist/assets/app.CSainqD9.js +1 -0
  144. package/docs-dist/assets/chunks/@localSearchIndexroot.BKleDIv-.js +1 -0
  145. package/docs-dist/assets/chunks/VPLocalSearchBox.BUBaq7tw.js +9 -0
  146. package/docs-dist/assets/chunks/framework.aJbMEiY9.js +19 -0
  147. package/docs-dist/assets/chunks/theme.CzMhU0Ps.js +2 -0
  148. package/docs-dist/assets/guide_architecture.md.CzgqynmB.js +258 -0
  149. package/docs-dist/assets/guide_architecture.md.CzgqynmB.lean.js +1 -0
  150. package/docs-dist/assets/guide_authentication.md.a8yTA8Xe.js +4 -0
  151. package/docs-dist/assets/guide_authentication.md.a8yTA8Xe.lean.js +1 -0
  152. package/docs-dist/assets/guide_index.md.BgUUL6fI.js +1 -0
  153. package/docs-dist/assets/guide_index.md.BgUUL6fI.lean.js +1 -0
  154. package/docs-dist/assets/guide_installation.md.BCZ4jBl_.js +7 -0
  155. package/docs-dist/assets/guide_installation.md.BCZ4jBl_.lean.js +1 -0
  156. package/docs-dist/assets/guide_quickstart.md.9-4dA6wS.js +13 -0
  157. package/docs-dist/assets/guide_quickstart.md.9-4dA6wS.lean.js +1 -0
  158. package/docs-dist/assets/index.md.z0hAJioN.js +1 -0
  159. package/docs-dist/assets/index.md.z0hAJioN.lean.js +1 -0
  160. package/docs-dist/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
  161. package/docs-dist/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
  162. package/docs-dist/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
  163. package/docs-dist/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
  164. package/docs-dist/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
  165. package/docs-dist/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
  166. package/docs-dist/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
  167. package/docs-dist/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
  168. package/docs-dist/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
  169. package/docs-dist/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
  170. package/docs-dist/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
  171. package/docs-dist/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
  172. package/docs-dist/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
  173. package/docs-dist/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
  174. package/docs-dist/assets/reference_response-format.md.VvQTLDZr.js +12 -0
  175. package/docs-dist/assets/reference_response-format.md.VvQTLDZr.lean.js +1 -0
  176. package/docs-dist/assets/style.DM4qKDd4.css +1 -0
  177. package/docs-dist/guide/architecture.html +284 -0
  178. package/docs-dist/guide/authentication.html +30 -0
  179. package/docs-dist/guide/index.html +27 -0
  180. package/docs-dist/guide/installation.html +33 -0
  181. package/docs-dist/guide/quickstart.html +39 -0
  182. package/docs-dist/hashmap.json +1 -0
  183. package/docs-dist/index.html +27 -0
  184. package/docs-dist/logo.svg +4 -0
  185. package/docs-dist/reference/response-format.html +38 -0
  186. package/docs-dist/version.json +7 -0
  187. package/docs-dist/vp-icons.css +1 -0
  188. package/package.json +31 -17
  189. package/.babelrc +0 -7
  190. package/.dockerignore +0 -5
  191. package/.editorconfig +0 -31
  192. package/.eslintrc.json +0 -22
  193. package/.github/workflows/deploy-docs.yml +0 -54
  194. package/.github/workflows/release.yml +0 -37
  195. package/.github/workflows/test.yml +0 -70
  196. package/.husky/commit-msg +0 -1
  197. package/.husky/pre-commit +0 -1
  198. package/.prettierignore +0 -1
  199. package/.prettierrc +0 -9
  200. package/AGENTS.md +0 -153
  201. package/Dockerfile +0 -18
  202. package/QQ/351/237/263/344/271/220-v0.xmind +0 -0
  203. package/QQ/351/237/263/344/271/220-v1.xmind +0 -0
  204. package/app.ts +0 -68
  205. package/commitlint.config.js +0 -20
  206. package/config/user-info.ts +0 -71
  207. package/index.ts +0 -1
  208. package/jest.config.ts +0 -41
  209. package/middlewares/koa-cors.ts +0 -81
  210. package/module/apis/UCommon/UCommon.ts +0 -13
  211. package/module/apis/album/getAlbumInfo.ts +0 -22
  212. package/module/apis/comments/getComments.ts +0 -23
  213. package/module/apis/digitalAlbum/getDigitalAlbumLists.ts +0 -23
  214. package/module/apis/downloadQQMusic.ts +0 -51
  215. package/module/apis/music/getLyric.ts +0 -34
  216. package/module/apis/mv/getMvByTag.ts +0 -24
  217. package/module/apis/radio/getRadioLists.ts +0 -27
  218. package/module/apis/rank/getTopLists.ts +0 -37
  219. package/module/apis/search/getHotKey.ts +0 -24
  220. package/module/apis/search/getSearchByKey.ts +0 -31
  221. package/module/apis/search/getSmartbox.ts +0 -43
  222. package/module/apis/singers/getSimilarSinger.ts +0 -25
  223. package/module/apis/singers/getSingerDesc.ts +0 -25
  224. package/module/apis/singers/getSingerMv.ts +0 -24
  225. package/module/apis/singers/getSingerStarNum.ts +0 -24
  226. package/module/apis/songLists/songListCategories.ts +0 -22
  227. package/module/apis/songLists/songListDetail.ts +0 -27
  228. package/module/apis/songLists/songLists.ts +0 -35
  229. package/module/apis/u_common.ts +0 -29
  230. package/module/apis/user/checkQQLoginQr.ts +0 -230
  231. package/module/apis/user/getQQLoginQr.ts +0 -28
  232. package/module/apis/user/getUserAvatar.ts +0 -32
  233. package/module/apis/user/getUserLikedSongs.ts +0 -145
  234. package/module/apis/user/getUserPlaylists.ts +0 -163
  235. package/module/apis/y_common.ts +0 -44
  236. package/module/config.ts +0 -24
  237. package/module/index.ts +0 -95
  238. package/music.png +0 -0
  239. package/pnpm-workspace.yaml +0 -2
  240. package/public/index.html +0 -430
  241. package/routers/context/batchGetSongInfo.ts +0 -60
  242. package/routers/context/batchGetSongLists.ts +0 -46
  243. package/routers/context/checkQQLoginQr.ts +0 -19
  244. package/routers/context/cookies.ts +0 -38
  245. package/routers/context/getAlbumInfo.ts +0 -31
  246. package/routers/context/getComments.ts +0 -51
  247. package/routers/context/getDigitalAlbumLists.ts +0 -18
  248. package/routers/context/getDownloadQQMusic.ts +0 -17
  249. package/routers/context/getHotkey.ts +0 -25
  250. package/routers/context/getImageUrl.ts +0 -29
  251. package/routers/context/getLyric.ts +0 -32
  252. package/routers/context/getMusicPlay.ts +0 -102
  253. package/routers/context/getMv.ts +0 -61
  254. package/routers/context/getMvByTag.ts +0 -18
  255. package/routers/context/getMvPlay.ts +0 -114
  256. package/routers/context/getNewDisks.ts +0 -58
  257. package/routers/context/getQQLoginQr.ts +0 -16
  258. package/routers/context/getRadioLists.ts +0 -18
  259. package/routers/context/getRanks.ts +0 -67
  260. package/routers/context/getRecommend.ts +0 -92
  261. package/routers/context/getSearchByKey.ts +0 -34
  262. package/routers/context/getSimilarSinger.ts +0 -29
  263. package/routers/context/getSingerAlbum.ts +0 -58
  264. package/routers/context/getSingerDesc.ts +0 -30
  265. package/routers/context/getSingerHotsong.ts +0 -58
  266. package/routers/context/getSingerList.ts +0 -56
  267. package/routers/context/getSingerMv.ts +0 -41
  268. package/routers/context/getSingerStarNum.ts +0 -29
  269. package/routers/context/getSmartbox.ts +0 -27
  270. package/routers/context/getSongInfo.ts +0 -51
  271. package/routers/context/getSongListCategories.ts +0 -23
  272. package/routers/context/getSongListDetail.ts +0 -22
  273. package/routers/context/getSongLists.ts +0 -30
  274. package/routers/context/getTicketInfo.ts +0 -51
  275. package/routers/context/getTopLists.ts +0 -18
  276. package/routers/context/getUserAvatar.ts +0 -53
  277. package/routers/context/getUserLikedSongs.ts +0 -28
  278. package/routers/context/getUserPlaylists.ts +0 -29
  279. package/routers/context/index.ts +0 -87
  280. package/routers/router.ts +0 -88
  281. package/routers/types.ts +0 -18
  282. package/routers/util.ts +0 -231
  283. package/screenshot/album-image.png +0 -0
  284. package/screenshot/batchGetSongInfo.png +0 -0
  285. package/screenshot/batchGetSongLists.png +0 -0
  286. package/screenshot/downloadQQMusic.png +0 -0
  287. package/screenshot/get-album-image.png +0 -0
  288. package/screenshot/get-play-all-data.png +0 -0
  289. package/screenshot/get-song-album-id.png +0 -0
  290. package/screenshot/get-song-id.png +0 -0
  291. package/screenshot/get-song-image.png +0 -0
  292. package/screenshot/getAlbumInfo.png +0 -0
  293. package/screenshot/getComments-id.png +0 -0
  294. package/screenshot/getComments-param.png +0 -0
  295. package/screenshot/getComments.png +0 -0
  296. package/screenshot/getDigitalAlbumLists.png +0 -0
  297. package/screenshot/getLyric-parse.png +0 -0
  298. package/screenshot/getLyric.png +0 -0
  299. package/screenshot/getMusicPlay.png +0 -0
  300. package/screenshot/getMv.png +0 -0
  301. package/screenshot/getMvByTag.png +0 -0
  302. package/screenshot/getMvPlay.png +0 -0
  303. package/screenshot/getNewDisks.png +0 -0
  304. package/screenshot/getRadioLists.png +0 -0
  305. package/screenshot/getRanks.png +0 -0
  306. package/screenshot/getRecommend.png +0 -0
  307. package/screenshot/getSearchByKey.png +0 -0
  308. package/screenshot/getSimilarSinger.png +0 -0
  309. package/screenshot/getSingerAlbum.png +0 -0
  310. package/screenshot/getSingerDesc.png +0 -0
  311. package/screenshot/getSingerHotsong.png +0 -0
  312. package/screenshot/getSingerList.png +0 -0
  313. package/screenshot/getSingerMv-default.png +0 -0
  314. package/screenshot/getSingerMv-listen.png +0 -0
  315. package/screenshot/getSingerMv-time.png +0 -0
  316. package/screenshot/getSingerStarNum.png +0 -0
  317. package/screenshot/getSmartbox.png +0 -0
  318. package/screenshot/getSongInfo.png +0 -0
  319. package/screenshot/getSongListCategories.png +0 -0
  320. package/screenshot/getSongListDetail.png +0 -0
  321. package/screenshot/getSongLists-params.png +0 -0
  322. package/screenshot/getSongLists.png +0 -0
  323. package/screenshot/getTicketInfo.png +0 -0
  324. package/screenshot/getTopLists.png +0 -0
  325. package/screenshot/gethotkey.png +0 -0
  326. package/screenshot/just-get-play-url.png +0 -0
  327. package/screenshot/musicPlay.png +0 -0
  328. package/screenshot/new-feature-error-tips.png +0 -0
  329. package/screenshot/normalize-cookie.png +0 -0
  330. package/screenshot/qq-music-v0.png +0 -0
  331. package/screenshot/qq-music.png +0 -0
  332. package/screenshot/song-image.png +0 -0
  333. package/screenshot/song-quality-128.png +0 -0
  334. package/screenshot/song-quality-m4a.png +0 -0
  335. package/scripts/build-images.js +0 -36
  336. package/scripts/commit-push.sh +0 -103
  337. package/tests/integration/api/api.test.ts +0 -852
  338. package/tests/integration/middleware/cors.test.ts +0 -41
  339. package/tests/setup/jest.setup.ts +0 -15
  340. package/tests/setup/testUtils.ts +0 -35
  341. package/tests/unit/util/request.test.ts +0 -177
  342. package/tsconfig.json +0 -20
  343. package/tsconfig.test.json +0 -8
  344. package/types/api.ts +0 -105
  345. package/types/global.d.ts +0 -26
  346. package/types/index.d.ts +0 -97
  347. package/util/apiResponse.ts +0 -97
  348. package/util/colors.ts +0 -31
  349. package/util/cookie.ts +0 -40
  350. package/util/loginUtils.ts +0 -26
  351. package/util/lyricParse.ts +0 -86
  352. package/util/request.ts +0 -141
  353. package/vercel.json +0 -15
package/AGENTS.md DELETED
@@ -1,153 +0,0 @@
1
- # AGENTS.md
2
-
3
- ## 项目概览
4
-
5
- 这是一个基于 Koa 的 QQ 音乐 API 服务项目,当前代码库已完成从 JavaScript 到 TypeScript 的迁移。
6
-
7
- - 运行时:Node.js 20+
8
- - 开发语言:TypeScript
9
- - Web 框架:Koa 2
10
- - 路由系统:@koa/router
11
- - 文档系统:VitePress
12
- - 测试框架:Jest
13
-
14
- ## 启动与构建
15
-
16
- ### 安装依赖
17
-
18
- ```bash
19
- npm install
20
- ```
21
-
22
- ### 开发模式
23
-
24
- ```bash
25
- npm run dev
26
- ```
27
-
28
- 默认启动入口为 `app.ts`,默认端口为 `3200`。
29
-
30
- ### 生产构建
31
-
32
- ```bash
33
- npm run build
34
- ```
35
-
36
- ### 生产运行
37
-
38
- ```bash
39
- npm run start
40
- ```
41
-
42
- ## 常用命令
43
-
44
- ```bash
45
- npm run dev # 本地开发
46
- npm run build # TypeScript 编译
47
- npm run start # 运行 dist/app.js
48
- npm run test # 运行测试
49
- npm run test:watch # 测试监听模式
50
- npm run test:coverage # 测试覆盖率
51
- npm run docs:dev # 启动文档站点
52
- npm run docs:build # 构建文档
53
- npm run eslint # 执行 ESLint 自动修复
54
- npm run prettier # 执行 Prettier 格式化
55
- ```
56
-
57
- ## 目录结构
58
-
59
- ```text
60
- app.ts 应用启动入口
61
- index.ts 包导出入口
62
- module/ API 请求封装层
63
- routers/ HTTP 控制器与路由注册
64
- middlewares/ Koa 中间件
65
- util/ 通用工具函数
66
- config/ 运行时配置
67
- types/ 全局类型与公共类型定义
68
- docs/ VitePress 文档站点
69
- tests/ 单元测试与集成测试
70
- public/ 静态资源
71
- scripts/ 辅助脚本
72
- ```
73
-
74
- ## 分层说明
75
-
76
- ### module/
77
-
78
- 负责直接请求 QQ 音乐相关接口,通常只处理:
79
-
80
- - 请求参数拼装
81
- - 调用上游接口
82
- - 基础数据格式转换
83
- - 返回统一响应结构
84
-
85
- ### routers/context/
86
-
87
- 负责 HTTP 层控制器逻辑,通常只处理:
88
-
89
- - 读取 `ctx.query` 或 `ctx.request.body`
90
- - 参数校验
91
- - 调用 `module/` 中对应能力
92
- - 设置 `ctx.body` 与 `ctx.status`
93
-
94
- ### routers/router.ts
95
-
96
- 负责统一注册所有路由。
97
-
98
- ### util/
99
-
100
- 放置跨模块复用的通用逻辑,例如响应包装、颜色输出等。
101
-
102
- ## 编码约定
103
-
104
- 1. 新增功能时,优先保持现有目录分层,不要把路由逻辑和接口请求逻辑混写。
105
- 2. 新增接口时,通常需要同时补充:
106
- - `module/apis/...` 中的接口实现
107
- - `routers/context/...` 中的控制器
108
- - `routers/context/index.ts` 或相关导出
109
- - `routers/router.ts` 中的路由注册
110
- - 必要时补充文档与测试
111
- 3. 统一使用 TypeScript,避免继续引入新的 `.js` 业务文件。
112
- 4. 尽量复用已有类型定义,公共类型优先放到 `types/`。
113
- 5. 保持返回结构一致,优先复用已有响应工具。
114
- 6. 修改全局配置或 Cookie 相关逻辑时,注意兼容扫码登录相关接口。
115
-
116
- ## 测试与验证
117
-
118
- 提交前建议至少执行:
119
-
120
- ```bash
121
- npm run build
122
- npm run test
123
- ```
124
-
125
- 如果修改了文档,再执行:
126
-
127
- ```bash
128
- npm run docs:build
129
- ```
130
-
131
- 如果修改了格式或风格敏感文件,再执行:
132
-
133
- ```bash
134
- npm run eslint
135
- npm run prettier
136
- ```
137
-
138
- ## 关键注意事项
139
-
140
- 1. 项目默认端口为 `3200`。
141
- 2. 生产启动依赖 `dist/` 目录,因此发布前必须先执行构建。
142
- 3. 当前仓库包含扫码登录相关接口实现,不要在未理解流程前随意调整登录状态字段。
143
- 4. 文档内容位于 `docs/`,接口能力变更时要同步更新文档。
144
- 5. 现有测试以 Jest 为主,新增行为建议补充对应测试。
145
-
146
- ## 建议的开发流程
147
-
148
- 1. 阅读相关模块现有实现。
149
- 2. 在 `module/` 增加或调整接口能力。
150
- 3. 在 `routers/context/` 接入 HTTP 控制器。
151
- 4. 在路由层完成注册。
152
- 5. 补充类型、测试与文档。
153
- 6. 执行构建和测试,确认无误后再提交。
package/Dockerfile DELETED
@@ -1,18 +0,0 @@
1
- FROM node:22
2
-
3
- LABEL maintainer="Rain120 <1085131904@qq.com>"
4
-
5
- # Create app directory
6
- WORKDIR /app
7
-
8
- COPY package.json .
9
-
10
- RUN yarn install --registry=https://registry.npmmirror.com
11
-
12
- COPY . .
13
-
14
- EXPOSE 3200
15
-
16
- ENTRYPOINT ["npm", "run"]
17
-
18
- CMD ["start"]
Binary file
Binary file
package/app.ts DELETED
@@ -1,68 +0,0 @@
1
- import 'reflect-metadata';
2
- import Koa from 'koa';
3
- import bodyParser from 'koa-bodyparser';
4
- import path from 'path';
5
- import koaStatic from 'koa-static';
6
- import chalk from 'chalk';
7
- import cors from './middlewares/koa-cors';
8
- import router from './routers/router';
9
- import cookieMiddleware from './util/cookie';
10
- import colors from './util/colors';
11
- import userInfoImport from './config/user-info';
12
- import pkg from './package.json';
13
- import type { UserInfo } from './types/global';
14
-
15
- const app = new Koa();
16
-
17
- global.userInfo = userInfoImport as UserInfo;
18
-
19
- console.log(chalk.green('\n🥳🎉 We had supported config the user cookies. \n'));
20
- console.log(colors.info(`Current Version: ${pkg.version}`));
21
-
22
- if(!((global.userInfo as any).loginUin || (global.userInfo as any).uin)){
23
- console.log(chalk.yellow(`😔 The configuration ${chalk.red('loginUin')} or your ${chalk.red('cookie')} in file ${chalk.green('config/user-info')} has not configured. \n`));
24
- }
25
-
26
- if (!(global.userInfo as any).cookie) {
27
- console.log(chalk.yellow(`😔 The configuration ${chalk.red('cookie')} in file ${chalk.green('config/user-info')} has not configured. \n`));
28
- }
29
-
30
- app.use(bodyParser());
31
- app.use(cookieMiddleware() as any);
32
- app.use(koaStatic(
33
- path.join(__dirname, 'public')
34
- ));
35
-
36
- // logger
37
- app.use(async (ctx, next) => {
38
- await next();
39
- const rt = ctx.response.get('X-Response-Time');
40
- console.log(colors.prompt(`${ctx.method} ${ctx.url} - ${rt}`));
41
- });
42
-
43
- // cors
44
- app.use(cors({
45
- origin: ctx => (ctx.request as any).header?.origin || '*',
46
- exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'],
47
- maxAge: 5,
48
- credentials: true,
49
- allowMethods: ['GET', 'POST', 'DELETE'],
50
- allowHeaders: ['Content-Type', 'Authorization', 'Accept'],
51
- }) as any);
52
-
53
- // x-response-time
54
- app.use(async (ctx, next) => {
55
- const start = Date.now();
56
- await next();
57
- const ms = Date.now() - start;
58
- ctx.set('X-Response-Time', `${ms}ms`);
59
- });
60
-
61
- app.use(router.routes())
62
- .use(router.allowedMethods());
63
-
64
- const PORT: number = typeof process.env.PORT === 'string' ? parseInt(process.env.PORT, 10) : (process.env.PORT || 3200);
65
-
66
- (app.listen as any)(PORT, () => {
67
- console.log(colors.prompt(`server running @ http://localhost:${PORT}`));
68
- });
@@ -1,20 +0,0 @@
1
- /*
2
- * @Author: Rainy
3
- * @Date: 2020-07-03 18:47:30
4
- * @LastEditors: Rainy
5
- * @LastEditTime: 2020-07-03 18:51:11
6
- */
7
-
8
- module.exports = {
9
- extends: ['@commitlint/config-conventional'],
10
- rules: {
11
- 'type-enum': [
12
- 2,
13
- 'always',
14
- ['feat', 'fix', 'docs', 'style', 'refactor', 'perf', 'test', 'build', 'ci', 'chore', 'revert', 'config'],
15
- ],
16
- 'subject-full-stop': [0, 'never'],
17
- 'subject-case': [0, 'never'],
18
- 'header-max-length': [0, 'always', 150],
19
- },
20
- };
@@ -1,71 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
-
4
- interface UserInfo {
5
- loginUin: string;
6
- uin?: string;
7
- cookie: string;
8
- cookieList: string[];
9
- cookieObject: Record<string, string>;
10
- refreshData: (cookie: string) => any;
11
- [key: string]: any;
12
- }
13
-
14
- let userInfo: UserInfo = { loginUin: '', cookie: '', cookieList: [], cookieObject: {}, refreshData: () => ({}) };
15
- let cookieList: string[] = [];
16
- let cookieObject: Record<string, string> = {};
17
-
18
- const infoPath = path.join(__dirname, './user-info.json');
19
- if (!fs.existsSync(infoPath)) {
20
- fs.writeFileSync(infoPath, '{}', 'utf-8');
21
- }
22
-
23
- const initData = () => {
24
- try {
25
- const parsed = JSON.parse(fs.readFileSync(infoPath, 'utf-8'));
26
- userInfo = {
27
- loginUin: parsed.loginUin || '',
28
- cookie: parsed.cookie || '',
29
- cookieList: [],
30
- cookieObject: {},
31
- refreshData: () => ({})
32
- };
33
- } catch (e) {
34
- userInfo = { loginUin: '', cookie: '', cookieList: [], cookieObject: {}, refreshData: () => ({}) };
35
- }
36
- cookieList = (userInfo.cookie || '').split('; ').map(_ => _.trim());
37
-
38
- cookieObject = {};
39
- cookieList.filter(Boolean).forEach(_ => {
40
- if (_) {
41
- const [key, value = ''] = _.split('=');
42
- cookieObject[key] = value;
43
- }
44
- });
45
- };
46
-
47
- const refreshData = (cookie: string) => {
48
- const uinMatch = cookie.match(/ uin=([^;]+)/);
49
- const uin = uinMatch ? uinMatch[1] : '';
50
- fs.writeFileSync(infoPath, JSON.stringify({ loginUin: uin, cookie }), 'utf-8');
51
- initData();
52
- return {
53
- ...userInfo,
54
- uin: userInfo.loginUin || cookieObject.uin,
55
- cookieList,
56
- cookieObject
57
- };
58
- };
59
-
60
- initData();
61
-
62
- const exportObj: UserInfo = {
63
- loginUin: userInfo?.loginUin || '',
64
- uin: userInfo?.loginUin || cookieObject?.uin || '',
65
- cookie: userInfo?.cookie || '',
66
- cookieList: cookieList || [],
67
- cookieObject: cookieObject || {},
68
- refreshData
69
- };
70
-
71
- export default exportObj as UserInfo;
package/index.ts DELETED
@@ -1 +0,0 @@
1
- import './app';
package/jest.config.ts DELETED
@@ -1,41 +0,0 @@
1
- import type { Config } from 'jest';
2
-
3
- const config: Config = {
4
- preset: 'ts-jest',
5
- testEnvironment: 'node',
6
- testMatch: ['**/tests/**/*.test.ts'],
7
- collectCoverageFrom: [
8
- 'module/**/*.ts',
9
- 'routers/**/*.ts',
10
- 'util/**/*.ts',
11
- '!**/node_modules/**',
12
- '!**/tests/**',
13
- '!**/dist/**'
14
- ],
15
- coverageDirectory: 'coverage',
16
- coverageReporters: ['text', 'lcov', 'html'],
17
- coverageThreshold: {
18
- global: {
19
- branches: 50,
20
- functions: 50,
21
- lines: 50,
22
- statements: 50
23
- }
24
- },
25
- setupFilesAfterEnv: ['<rootDir>/tests/setup/jest.setup.ts'],
26
- modulePathIgnorePatterns: ['<rootDir>/dist/'],
27
- testTimeout: 10000,
28
- verbose: true,
29
- moduleNameMapper: {
30
- '^@module/(.*)$': '<rootDir>/module/$1',
31
- '^@routers/(.*)$': '<rootDir>/routers/$1',
32
- '^@util/(.*)$': '<rootDir>/util/$1'
33
- },
34
- transform: {
35
- '^.+\.ts$': ['ts-jest', {
36
- tsconfig: 'tsconfig.test.json'
37
- }]
38
- }
39
- };
40
-
41
- export default config;
@@ -1,81 +0,0 @@
1
- import { Context, Next } from 'koa';
2
-
3
- export interface CorsOptions {
4
- origin?: string | ((ctx: Context) => string);
5
- exposeHeaders?: string[];
6
- maxAge?: number;
7
- credentials?: boolean;
8
- allowMethods?: string[];
9
- allowHeaders?: string[];
10
- }
11
-
12
- function crossOrigin(options: CorsOptions = {}) {
13
- const defaultOptions: CorsOptions = {
14
- allowMethods: ['GET', 'PUT', 'POST', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
15
- };
16
-
17
- options = Object.assign({}, defaultOptions, options);
18
-
19
- return async function cors(ctx: Context, next: Next) {
20
- ctx.vary('Origin');
21
-
22
- let origin: string;
23
- if (typeof options.origin === 'function') {
24
- origin = options.origin(ctx);
25
- } else {
26
- origin = options.origin || ctx.get('Origin') || '*';
27
- }
28
-
29
- if (!origin) {
30
- return await next();
31
- }
32
-
33
- ctx.set('Access-Control-Allow-Origin', origin);
34
-
35
- if (ctx.method === 'OPTIONS') {
36
- if (!ctx.get('Access-Control-Request-Method')) {
37
- return await next();
38
- }
39
-
40
- if (options.maxAge) {
41
- ctx.set('Access-Control-Max-Age', String(options.maxAge));
42
- }
43
-
44
- if (options.credentials === true) {
45
- ctx.set('Access-Control-Allow-Credentials', 'true');
46
- }
47
-
48
- if (options.allowMethods) {
49
- ctx.set('Access-Control-Allow-Methods', options.allowMethods.join(','));
50
- }
51
-
52
- if (options.allowHeaders) {
53
- ctx.set('Access-Control-Allow-Headers', options.allowHeaders.join(','));
54
- } else {
55
- ctx.set('Access-Control-Allow-Headers', ctx.get('Access-Control-Request-Headers'));
56
- }
57
-
58
- ctx.status = 204;
59
- } else {
60
- if (options.credentials === true) {
61
- if (origin === '*') {
62
- ctx.remove('Access-Control-Allow-Credentials');
63
- } else {
64
- ctx.set('Access-Control-Allow-Credentials', 'true');
65
- }
66
- }
67
-
68
- if (options.exposeHeaders) {
69
- ctx.set('Access-Control-Expose-Headers', options.exposeHeaders.join(','));
70
- }
71
-
72
- try {
73
- await next();
74
- } catch (err) {
75
- throw err;
76
- }
77
- }
78
- };
79
- }
80
-
81
- export default crossOrigin;
@@ -1,13 +0,0 @@
1
- import { AxiosRequestConfig, Method } from 'axios';
2
- import u_common from '../u_common';
3
-
4
- interface UCommonParams {
5
- method?: Method | string;
6
- params?: any;
7
- option?: AxiosRequestConfig;
8
- }
9
-
10
- export default ({ method = 'get', params = {}, option = {} }: UCommonParams) => {
11
- const options: AxiosRequestConfig = { ...option, params };
12
- return u_common({ method, options });
13
- };
@@ -1,22 +0,0 @@
1
- import { handleApi } from '../../../util/apiResponse';
2
- import y_common from '../y_common';
3
- import type { ApiOptions } from '../../../types/api';
4
-
5
- export default async ({ method = 'get', params = {}, option = {} }: ApiOptions) => {
6
- const data = {
7
- ...params,
8
- format: 'json',
9
- outCharset: 'utf-8'
10
- };
11
- const options = {
12
- ...option,
13
- params: data
14
- };
15
- return handleApi(
16
- y_common({
17
- url: '/v8/fcg-bin/fcg_v8_album_info_cp.fcg',
18
- method: method as string,
19
- options
20
- })
21
- );
22
- };
@@ -1,23 +0,0 @@
1
- import { handleApi } from '../../../util/apiResponse';
2
- import y_common from '../y_common';
3
- import type { ApiOptions } from '../../../types/api';
4
-
5
- export default async ({ method = 'get', params = {}, option = {} }: ApiOptions) => {
6
- const data = {
7
- ...params,
8
- format: 'json',
9
- outCharset: 'GB2312',
10
- domain: 'qq.com',
11
- ct: 24,
12
- cv: 10101010,
13
- needmusiccrit: 0
14
- };
15
- const options = { ...option, params: data };
16
- return handleApi(
17
- y_common({
18
- url: '/base/fcgi-bin/fcg_global_comment_h5.fcg',
19
- method: method as string,
20
- options
21
- })
22
- );
23
- };
@@ -1,23 +0,0 @@
1
- import request from '../../../util/request';
2
- import { handleApi } from '../../../util/apiResponse';
3
- import type { ApiOptions } from '../../../types/api';
4
-
5
- export default async ({ method = 'get', params = {}, option = {} }: ApiOptions) => {
6
- const data = Object.assign(params, {
7
- format: 'json',
8
- outCharset: 'utf-8',
9
- cmd: 'pc_index_new'
10
- });
11
-
12
- const options = Object.assign(option, {
13
- params: data
14
- });
15
-
16
- return handleApi(
17
- request({
18
- url: '/v8/fcg-bin/musicmall.fcg',
19
- method: method as import('axios').Method,
20
- options
21
- })
22
- );
23
- };
@@ -1,51 +0,0 @@
1
- import { AxiosRequestConfig, Method } from 'axios';
2
- import request from '../../util/request';
3
-
4
- interface DownloadOptions {
5
- method?: Method | string;
6
- params?: any;
7
- option?: AxiosRequestConfig;
8
- }
9
-
10
- export default ({ method = 'get', params = {}, option = {} }: DownloadOptions) => {
11
- const data = {
12
- ...params,
13
- format: 'jsonp',
14
- jsonpCallback: 'MusicJsonCallback',
15
- platform: 'yqq'
16
- };
17
- const options: AxiosRequestConfig = {
18
- ...option,
19
- headers: {
20
- host: 'y.qq.com',
21
- referer: 'https://y.qq.com/',
22
- ...(option.headers || {})
23
- },
24
- params: data
25
- };
26
- return request('/download/download.js', method as Method, options, 'y')
27
- .then(res => {
28
- let response = res.data;
29
- if (typeof response === 'string') {
30
- const reg = /^\w+\(({[^()]+})\)$/;
31
- const matches = response.match(reg);
32
- if (matches) {
33
- response = JSON.parse(matches[1]);
34
- }
35
- }
36
- return {
37
- status: 200,
38
- body: {
39
- response
40
- }
41
- };
42
- })
43
- .catch(error => {
44
- console.log('error', error);
45
- return {
46
- body: {
47
- error
48
- }
49
- };
50
- });
51
- };
@@ -1,34 +0,0 @@
1
- import { lyricParse } from '../../../util/lyricParse';
2
- import request from '../../../util/request';
3
- import { handleApi } from '../../../util/apiResponse';
4
- import type { ApiOptions } from '../../../types/api';
5
-
6
- export default async ({ method = 'get', params = {}, option = {}, isFormat = false }: ApiOptions) => {
7
- const data = Object.assign(params, {
8
- format: 'json',
9
- outCharset: 'utf-8',
10
- pcachetime: Date.now()
11
- });
12
-
13
- const options = Object.assign(option, {
14
- params: data
15
- });
16
-
17
- return handleApi(
18
- request({
19
- url: '/lyric/fcgi-bin/fcg_query_lyric_new.fcg',
20
- method: method as import('axios').Method,
21
- options
22
- }),
23
- {
24
- transformData: (resData: Record<string, any>) => {
25
- const lyricString = resData && resData.lyric && Buffer.from(resData.lyric, 'base64').toString();
26
- const lyric = isFormat && lyricString ? lyricParse(lyricString) : lyricString;
27
- return {
28
- ...resData,
29
- lyric
30
- };
31
- }
32
- }
33
- );
34
- };
@@ -1,24 +0,0 @@
1
- import request from '../../../util/request';
2
- import { handleApi } from '../../../util/apiResponse';
3
- import type { ApiOptions } from '../../../types/api';
4
-
5
- export default async ({ method = 'get', params = {}, option = {} }: ApiOptions) => {
6
- const data = Object.assign(params, {
7
- format: 'json',
8
- outCharset: 'GB2312',
9
- cmd: 'shoubo',
10
- lan: 'all'
11
- });
12
-
13
- const options = Object.assign(option, {
14
- params: data
15
- });
16
-
17
- return handleApi(
18
- request({
19
- url: '/mv/fcgi-bin/getmv_by_tag',
20
- method: method as import('axios').Method,
21
- options
22
- })
23
- );
24
- };
@@ -1,27 +0,0 @@
1
- import request from '../../../util/request';
2
- import { handleApi } from '../../../util/apiResponse';
3
- import type { ApiOptions } from '../../../types/api';
4
-
5
- export default async ({ method = 'get', params = {}, option = {} }: ApiOptions) => {
6
- const data = Object.assign(params, {
7
- format: 'json',
8
- outCharset: 'utf-8',
9
- channel: 'radio',
10
- page: 'index',
11
- tpl: 'wk',
12
- new: 1,
13
- p: Math.round(1)
14
- });
15
-
16
- const options = Object.assign(option, {
17
- params: data
18
- });
19
-
20
- return handleApi(
21
- request({
22
- url: '/v8/fcg-bin/fcg_v8_radiolist.fcg',
23
- method: method as import('axios').Method,
24
- options
25
- })
26
- );
27
- };