@sansenjian/qq-music-api 2.2.1 → 2.2.7

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 (344) hide show
  1. package/CHANGELOG.md +120 -42
  2. package/dist/app.js +58 -0
  3. package/dist/config/user-info.js +59 -0
  4. package/dist/index.js +3 -0
  5. package/dist/jest.config.js +40 -0
  6. package/dist/middlewares/koa-cors.js +63 -0
  7. package/dist/module/apis/UCommon/UCommon.js +10 -0
  8. package/dist/module/apis/album/getAlbumInfo.js +23 -0
  9. package/dist/module/apis/comments/getComments.js +24 -0
  10. package/dist/module/apis/digitalAlbum/getDigitalAlbumLists.js +22 -0
  11. package/dist/module/apis/downloadQQMusic.js +48 -0
  12. package/dist/module/apis/extend/getPlaylistTags.js +158 -0
  13. package/dist/module/apis/music/getLyric.js +32 -0
  14. package/dist/module/apis/mv/getMvByTag.js +23 -0
  15. package/dist/module/apis/radio/getRadioLists.js +26 -0
  16. package/dist/module/apis/rank/getTopLists.js +35 -0
  17. package/dist/module/apis/recommend/getDailyRecommend.js +124 -0
  18. package/dist/module/apis/recommend/getPersonalRecommend.js +114 -0
  19. package/dist/module/apis/search/getHotKey.js +25 -0
  20. package/dist/module/apis/search/getSearchByKey.js +32 -0
  21. package/dist/module/apis/search/getSmartbox.js +40 -0
  22. package/dist/module/apis/singers/getSimilarSinger.js +24 -0
  23. package/dist/module/apis/singers/getSingerDesc.js +24 -0
  24. package/dist/module/apis/singers/getSingerMv.js +23 -0
  25. package/dist/module/apis/singers/getSingerStarNum.js +23 -0
  26. package/dist/module/apis/songLists/songListCategories.js +23 -0
  27. package/dist/module/apis/songLists/songListDetail.js +28 -0
  28. package/dist/module/apis/songLists/songLists.js +35 -0
  29. package/dist/module/apis/u_common.js +56 -0
  30. package/dist/module/apis/user/checkQQLoginQr.js +189 -0
  31. package/dist/module/apis/user/getQQLoginQr.js +23 -0
  32. package/dist/module/apis/user/getUserAvatar.js +25 -0
  33. package/dist/module/apis/user/getUserLikedSongs.js +129 -0
  34. package/dist/module/apis/user/getUserPlaylists.js +138 -0
  35. package/dist/module/apis/y_common.js +69 -0
  36. package/dist/module/config.js +24 -0
  37. package/dist/module/index.js +70 -0
  38. package/dist/package.json +117 -0
  39. package/dist/routers/context/batchGetSongInfo.js +53 -0
  40. package/dist/routers/context/batchGetSongLists.js +37 -0
  41. package/dist/routers/context/checkQQLoginQr.js +16 -0
  42. package/dist/routers/context/cookies.js +36 -0
  43. package/dist/routers/context/getAlbumInfo.js +29 -0
  44. package/dist/routers/context/getComments.js +38 -0
  45. package/dist/routers/context/getDailyRecommend.js +45 -0
  46. package/dist/routers/context/getDigitalAlbumLists.js +16 -0
  47. package/dist/routers/context/getDownloadQQMusic.js +16 -0
  48. package/dist/routers/context/getHotkey.js +21 -0
  49. package/dist/routers/context/getImageUrl.js +25 -0
  50. package/dist/routers/context/getLyric.js +29 -0
  51. package/dist/routers/context/getMusicPlay.js +91 -0
  52. package/dist/routers/context/getMv.js +57 -0
  53. package/dist/routers/context/getMvByTag.js +16 -0
  54. package/dist/routers/context/getMvPlay.js +105 -0
  55. package/dist/routers/context/getNewDisks.js +52 -0
  56. package/dist/routers/context/getPersonalRecommend.js +54 -0
  57. package/dist/routers/context/getPlaylistTags.js +60 -0
  58. package/dist/routers/context/getQQLoginQr.js +14 -0
  59. package/dist/routers/context/getRadioLists.js +16 -0
  60. package/dist/routers/context/getRanks.js +60 -0
  61. package/dist/routers/context/getRecommend.js +88 -0
  62. package/dist/routers/context/getSearchByKey.js +32 -0
  63. package/dist/routers/context/getSimilarSinger.js +27 -0
  64. package/dist/routers/context/getSingerAlbum.js +54 -0
  65. package/dist/routers/context/getSingerDesc.js +28 -0
  66. package/dist/routers/context/getSingerHotsong.js +54 -0
  67. package/dist/routers/context/getSingerList.js +51 -0
  68. package/dist/routers/context/getSingerMv.js +36 -0
  69. package/dist/routers/context/getSingerStarNum.js +27 -0
  70. package/dist/routers/context/getSmartbox.js +27 -0
  71. package/dist/routers/context/getSongInfo.js +47 -0
  72. package/dist/routers/context/getSongListCategories.js +23 -0
  73. package/dist/routers/context/getSongListDetail.js +19 -0
  74. package/dist/routers/context/getSongLists.js +25 -0
  75. package/dist/routers/context/getTicketInfo.js +47 -0
  76. package/dist/routers/context/getTopLists.js +16 -0
  77. package/dist/routers/context/getUserAvatar.js +48 -0
  78. package/dist/routers/context/getUserLikedSongs.js +24 -0
  79. package/dist/routers/context/getUserPlaylists.js +24 -0
  80. package/dist/routers/context/index.js +107 -0
  81. package/dist/routers/router.js +69 -0
  82. package/dist/routers/types.js +2 -0
  83. package/dist/routers/util.js +188 -0
  84. package/dist/types/api.js +55 -0
  85. package/dist/util/apiResponse.js +88 -0
  86. package/dist/util/colors.js +19 -0
  87. package/dist/util/cookie.js +26 -0
  88. package/dist/util/loginUtils.js +30 -0
  89. package/dist/util/lyricParse.js +72 -0
  90. package/dist/util/request.js +109 -0
  91. package/docs-dist/404.html +24 -0
  92. package/docs-dist/CHANGELOG-ARCHITECTURE.html +131 -0
  93. package/docs-dist/COOKIE_CONFIG_GUIDE.html +39 -0
  94. package/docs-dist/README.html +447 -0
  95. package/docs-dist/TEST_USER_PLAYLISTS.html +42 -0
  96. package/docs-dist/USER_AVATAR_GUIDE.html +100 -0
  97. package/docs-dist/api/comments.html +48 -0
  98. package/docs-dist/api/index.html +27 -0
  99. package/docs-dist/api/music.html +51 -0
  100. package/docs-dist/api/other.html +33 -0
  101. package/docs-dist/api/playlist.html +77 -0
  102. package/docs-dist/api/rank.html +48 -0
  103. package/docs-dist/api/search.html +62 -0
  104. package/docs-dist/api/singer.html +47 -0
  105. package/docs-dist/api/user.html +64 -0
  106. package/docs-dist/assets/CHANGELOG-ARCHITECTURE.md.BOe0ZtyR.js +105 -0
  107. package/docs-dist/assets/CHANGELOG-ARCHITECTURE.md.BOe0ZtyR.lean.js +1 -0
  108. package/docs-dist/assets/COOKIE_CONFIG_GUIDE.md.D68AwXR2.js +13 -0
  109. package/docs-dist/assets/COOKIE_CONFIG_GUIDE.md.D68AwXR2.lean.js +1 -0
  110. package/docs-dist/assets/README.md.ZJQGJ1Gb.js +421 -0
  111. package/docs-dist/assets/README.md.ZJQGJ1Gb.lean.js +1 -0
  112. package/docs-dist/assets/TEST_USER_PLAYLISTS.md.C02575X2.js +16 -0
  113. package/docs-dist/assets/TEST_USER_PLAYLISTS.md.C02575X2.lean.js +1 -0
  114. package/docs-dist/assets/USER_AVATAR_GUIDE.md.BOqjn5Cm.js +74 -0
  115. package/docs-dist/assets/USER_AVATAR_GUIDE.md.BOqjn5Cm.lean.js +1 -0
  116. package/docs-dist/assets/api_comments.md.DADvndEA.js +22 -0
  117. package/docs-dist/assets/api_comments.md.DADvndEA.lean.js +1 -0
  118. package/docs-dist/assets/api_index.md.D5IASxxG.js +1 -0
  119. package/docs-dist/assets/api_index.md.D5IASxxG.lean.js +1 -0
  120. package/docs-dist/assets/api_music.md.BgB8NmZq.js +25 -0
  121. package/docs-dist/assets/api_music.md.BgB8NmZq.lean.js +1 -0
  122. package/docs-dist/assets/api_other.md.BkRWXX2z.js +7 -0
  123. package/docs-dist/assets/api_other.md.BkRWXX2z.lean.js +1 -0
  124. package/docs-dist/assets/api_playlist.md.Dc0hTrZ4.js +51 -0
  125. package/docs-dist/assets/api_playlist.md.Dc0hTrZ4.lean.js +1 -0
  126. package/docs-dist/assets/api_rank.md.DRisCFyT.js +22 -0
  127. package/docs-dist/assets/api_rank.md.DRisCFyT.lean.js +1 -0
  128. package/docs-dist/assets/api_search.md.DNnMUZK0.js +36 -0
  129. package/docs-dist/assets/api_search.md.DNnMUZK0.lean.js +1 -0
  130. package/docs-dist/assets/api_singer.md.DCmuxQkk.js +21 -0
  131. package/docs-dist/assets/api_singer.md.DCmuxQkk.lean.js +1 -0
  132. package/docs-dist/assets/api_user.md.Cjm9GG3z.js +38 -0
  133. package/docs-dist/assets/api_user.md.Cjm9GG3z.lean.js +1 -0
  134. package/docs-dist/assets/app.Dx_1wB58.js +1 -0
  135. package/docs-dist/assets/chunks/@localSearchIndexroot.CMY5EIwU.js +1 -0
  136. package/docs-dist/assets/chunks/VPLocalSearchBox.DwKWtsdX.js +9 -0
  137. package/docs-dist/assets/chunks/framework.o40iizuP.js +19 -0
  138. package/docs-dist/assets/chunks/theme.pGVgJ9Cx.js +2 -0
  139. package/docs-dist/assets/guide_architecture.md.DGtNyuMH.js +258 -0
  140. package/docs-dist/assets/guide_architecture.md.DGtNyuMH.lean.js +1 -0
  141. package/docs-dist/assets/guide_authentication.md.mtI5LfCw.js +4 -0
  142. package/docs-dist/assets/guide_authentication.md.mtI5LfCw.lean.js +1 -0
  143. package/docs-dist/assets/guide_index.md.B-0SG46T.js +1 -0
  144. package/docs-dist/assets/guide_index.md.B-0SG46T.lean.js +1 -0
  145. package/docs-dist/assets/guide_installation.md.k-KpAfxv.js +7 -0
  146. package/docs-dist/assets/guide_installation.md.k-KpAfxv.lean.js +1 -0
  147. package/docs-dist/assets/guide_quickstart.md.Bff_KFOD.js +13 -0
  148. package/docs-dist/assets/guide_quickstart.md.Bff_KFOD.lean.js +1 -0
  149. package/docs-dist/assets/index.md.xrs-uIyo.js +1 -0
  150. package/docs-dist/assets/index.md.xrs-uIyo.lean.js +1 -0
  151. package/docs-dist/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
  152. package/docs-dist/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
  153. package/docs-dist/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
  154. package/docs-dist/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
  155. package/docs-dist/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
  156. package/docs-dist/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
  157. package/docs-dist/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
  158. package/docs-dist/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
  159. package/docs-dist/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
  160. package/docs-dist/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
  161. package/docs-dist/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
  162. package/docs-dist/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
  163. package/docs-dist/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
  164. package/docs-dist/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
  165. package/docs-dist/assets/reference_response-format.md.DKYTK6uJ.js +12 -0
  166. package/docs-dist/assets/reference_response-format.md.DKYTK6uJ.lean.js +1 -0
  167. package/docs-dist/assets/style.DM4qKDd4.css +1 -0
  168. package/docs-dist/guide/architecture.html +284 -0
  169. package/docs-dist/guide/authentication.html +30 -0
  170. package/docs-dist/guide/index.html +27 -0
  171. package/docs-dist/guide/installation.html +33 -0
  172. package/docs-dist/guide/quickstart.html +39 -0
  173. package/docs-dist/hashmap.json +1 -0
  174. package/docs-dist/index.html +27 -0
  175. package/docs-dist/logo.svg +4 -0
  176. package/docs-dist/reference/response-format.html +38 -0
  177. package/docs-dist/version.json +7 -0
  178. package/docs-dist/vp-icons.css +1 -0
  179. package/package.json +28 -17
  180. package/.babelrc +0 -7
  181. package/.dockerignore +0 -5
  182. package/.editorconfig +0 -31
  183. package/.eslintrc.json +0 -22
  184. package/.github/workflows/deploy-docs.yml +0 -54
  185. package/.github/workflows/release.yml +0 -37
  186. package/.github/workflows/test.yml +0 -70
  187. package/.husky/commit-msg +0 -1
  188. package/.husky/pre-commit +0 -1
  189. package/.prettierignore +0 -1
  190. package/.prettierrc +0 -9
  191. package/AGENTS.md +0 -153
  192. package/Dockerfile +0 -18
  193. package/QQ/351/237/263/344/271/220-v0.xmind +0 -0
  194. package/QQ/351/237/263/344/271/220-v1.xmind +0 -0
  195. package/app.ts +0 -68
  196. package/commitlint.config.js +0 -20
  197. package/config/user-info.ts +0 -71
  198. package/index.ts +0 -1
  199. package/jest.config.ts +0 -41
  200. package/middlewares/koa-cors.ts +0 -81
  201. package/module/apis/UCommon/UCommon.ts +0 -13
  202. package/module/apis/album/getAlbumInfo.ts +0 -22
  203. package/module/apis/comments/getComments.ts +0 -23
  204. package/module/apis/digitalAlbum/getDigitalAlbumLists.ts +0 -23
  205. package/module/apis/downloadQQMusic.ts +0 -51
  206. package/module/apis/music/getLyric.ts +0 -34
  207. package/module/apis/mv/getMvByTag.ts +0 -24
  208. package/module/apis/radio/getRadioLists.ts +0 -27
  209. package/module/apis/rank/getTopLists.ts +0 -37
  210. package/module/apis/search/getHotKey.ts +0 -24
  211. package/module/apis/search/getSearchByKey.ts +0 -31
  212. package/module/apis/search/getSmartbox.ts +0 -43
  213. package/module/apis/singers/getSimilarSinger.ts +0 -25
  214. package/module/apis/singers/getSingerDesc.ts +0 -25
  215. package/module/apis/singers/getSingerMv.ts +0 -24
  216. package/module/apis/singers/getSingerStarNum.ts +0 -24
  217. package/module/apis/songLists/songListCategories.ts +0 -22
  218. package/module/apis/songLists/songListDetail.ts +0 -27
  219. package/module/apis/songLists/songLists.ts +0 -35
  220. package/module/apis/u_common.ts +0 -29
  221. package/module/apis/user/checkQQLoginQr.ts +0 -230
  222. package/module/apis/user/getQQLoginQr.ts +0 -28
  223. package/module/apis/user/getUserAvatar.ts +0 -32
  224. package/module/apis/user/getUserLikedSongs.ts +0 -145
  225. package/module/apis/user/getUserPlaylists.ts +0 -163
  226. package/module/apis/y_common.ts +0 -44
  227. package/module/config.ts +0 -24
  228. package/module/index.ts +0 -95
  229. package/music.png +0 -0
  230. package/pnpm-workspace.yaml +0 -2
  231. package/public/index.html +0 -430
  232. package/routers/context/batchGetSongInfo.ts +0 -60
  233. package/routers/context/batchGetSongLists.ts +0 -46
  234. package/routers/context/checkQQLoginQr.ts +0 -19
  235. package/routers/context/cookies.ts +0 -38
  236. package/routers/context/getAlbumInfo.ts +0 -31
  237. package/routers/context/getComments.ts +0 -51
  238. package/routers/context/getDigitalAlbumLists.ts +0 -18
  239. package/routers/context/getDownloadQQMusic.ts +0 -17
  240. package/routers/context/getHotkey.ts +0 -25
  241. package/routers/context/getImageUrl.ts +0 -29
  242. package/routers/context/getLyric.ts +0 -32
  243. package/routers/context/getMusicPlay.ts +0 -102
  244. package/routers/context/getMv.ts +0 -61
  245. package/routers/context/getMvByTag.ts +0 -18
  246. package/routers/context/getMvPlay.ts +0 -114
  247. package/routers/context/getNewDisks.ts +0 -58
  248. package/routers/context/getQQLoginQr.ts +0 -16
  249. package/routers/context/getRadioLists.ts +0 -18
  250. package/routers/context/getRanks.ts +0 -67
  251. package/routers/context/getRecommend.ts +0 -92
  252. package/routers/context/getSearchByKey.ts +0 -34
  253. package/routers/context/getSimilarSinger.ts +0 -29
  254. package/routers/context/getSingerAlbum.ts +0 -58
  255. package/routers/context/getSingerDesc.ts +0 -30
  256. package/routers/context/getSingerHotsong.ts +0 -58
  257. package/routers/context/getSingerList.ts +0 -56
  258. package/routers/context/getSingerMv.ts +0 -41
  259. package/routers/context/getSingerStarNum.ts +0 -29
  260. package/routers/context/getSmartbox.ts +0 -27
  261. package/routers/context/getSongInfo.ts +0 -51
  262. package/routers/context/getSongListCategories.ts +0 -23
  263. package/routers/context/getSongListDetail.ts +0 -22
  264. package/routers/context/getSongLists.ts +0 -30
  265. package/routers/context/getTicketInfo.ts +0 -51
  266. package/routers/context/getTopLists.ts +0 -18
  267. package/routers/context/getUserAvatar.ts +0 -53
  268. package/routers/context/getUserLikedSongs.ts +0 -28
  269. package/routers/context/getUserPlaylists.ts +0 -29
  270. package/routers/context/index.ts +0 -87
  271. package/routers/router.ts +0 -88
  272. package/routers/types.ts +0 -18
  273. package/routers/util.ts +0 -231
  274. package/screenshot/album-image.png +0 -0
  275. package/screenshot/batchGetSongInfo.png +0 -0
  276. package/screenshot/batchGetSongLists.png +0 -0
  277. package/screenshot/downloadQQMusic.png +0 -0
  278. package/screenshot/get-album-image.png +0 -0
  279. package/screenshot/get-play-all-data.png +0 -0
  280. package/screenshot/get-song-album-id.png +0 -0
  281. package/screenshot/get-song-id.png +0 -0
  282. package/screenshot/get-song-image.png +0 -0
  283. package/screenshot/getAlbumInfo.png +0 -0
  284. package/screenshot/getComments-id.png +0 -0
  285. package/screenshot/getComments-param.png +0 -0
  286. package/screenshot/getComments.png +0 -0
  287. package/screenshot/getDigitalAlbumLists.png +0 -0
  288. package/screenshot/getLyric-parse.png +0 -0
  289. package/screenshot/getLyric.png +0 -0
  290. package/screenshot/getMusicPlay.png +0 -0
  291. package/screenshot/getMv.png +0 -0
  292. package/screenshot/getMvByTag.png +0 -0
  293. package/screenshot/getMvPlay.png +0 -0
  294. package/screenshot/getNewDisks.png +0 -0
  295. package/screenshot/getRadioLists.png +0 -0
  296. package/screenshot/getRanks.png +0 -0
  297. package/screenshot/getRecommend.png +0 -0
  298. package/screenshot/getSearchByKey.png +0 -0
  299. package/screenshot/getSimilarSinger.png +0 -0
  300. package/screenshot/getSingerAlbum.png +0 -0
  301. package/screenshot/getSingerDesc.png +0 -0
  302. package/screenshot/getSingerHotsong.png +0 -0
  303. package/screenshot/getSingerList.png +0 -0
  304. package/screenshot/getSingerMv-default.png +0 -0
  305. package/screenshot/getSingerMv-listen.png +0 -0
  306. package/screenshot/getSingerMv-time.png +0 -0
  307. package/screenshot/getSingerStarNum.png +0 -0
  308. package/screenshot/getSmartbox.png +0 -0
  309. package/screenshot/getSongInfo.png +0 -0
  310. package/screenshot/getSongListCategories.png +0 -0
  311. package/screenshot/getSongListDetail.png +0 -0
  312. package/screenshot/getSongLists-params.png +0 -0
  313. package/screenshot/getSongLists.png +0 -0
  314. package/screenshot/getTicketInfo.png +0 -0
  315. package/screenshot/getTopLists.png +0 -0
  316. package/screenshot/gethotkey.png +0 -0
  317. package/screenshot/just-get-play-url.png +0 -0
  318. package/screenshot/musicPlay.png +0 -0
  319. package/screenshot/new-feature-error-tips.png +0 -0
  320. package/screenshot/normalize-cookie.png +0 -0
  321. package/screenshot/qq-music-v0.png +0 -0
  322. package/screenshot/qq-music.png +0 -0
  323. package/screenshot/song-image.png +0 -0
  324. package/screenshot/song-quality-128.png +0 -0
  325. package/screenshot/song-quality-m4a.png +0 -0
  326. package/scripts/build-images.js +0 -36
  327. package/scripts/commit-push.sh +0 -103
  328. package/tests/integration/api/api.test.ts +0 -852
  329. package/tests/integration/middleware/cors.test.ts +0 -41
  330. package/tests/setup/jest.setup.ts +0 -15
  331. package/tests/setup/testUtils.ts +0 -35
  332. package/tests/unit/util/request.test.ts +0 -177
  333. package/tsconfig.json +0 -20
  334. package/tsconfig.test.json +0 -8
  335. package/types/api.ts +0 -105
  336. package/types/global.d.ts +0 -26
  337. package/types/index.d.ts +0 -97
  338. package/util/apiResponse.ts +0 -97
  339. package/util/colors.ts +0 -31
  340. package/util/cookie.ts +0 -40
  341. package/util/loginUtils.ts +0 -26
  342. package/util/lyricParse.ts +0 -86
  343. package/util/request.ts +0 -141
  344. package/vercel.json +0 -15
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const request_1 = __importDefault(require("../../../util/request"));
7
+ const apiResponse_1 = require("../../../util/apiResponse");
8
+ exports.default = async ({ method = 'get', params = {}, option = {} }) => {
9
+ const data = Object.assign(params, {
10
+ format: 'json',
11
+ outCharset: 'utf-8',
12
+ utf8: 1,
13
+ rnd: Date.now()
14
+ });
15
+ const options = Object.assign(option, {
16
+ params: data
17
+ });
18
+ return (0, apiResponse_1.handleApi)((0, request_1.default)({
19
+ url: '/rsc/fcgi-bin/fcg_order_singer_getnum.fcg',
20
+ method: method,
21
+ options
22
+ }));
23
+ };
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const apiResponse_1 = require("../../../util/apiResponse");
7
+ const y_common_1 = __importDefault(require("../y_common"));
8
+ exports.default = async ({ method = 'get', params = {}, option = {} }) => {
9
+ const data = {
10
+ ...params,
11
+ format: 'json',
12
+ outCharset: 'utf-8'
13
+ };
14
+ const options = {
15
+ ...option,
16
+ params: data
17
+ };
18
+ return (0, apiResponse_1.handleApi)((0, y_common_1.default)({
19
+ url: '/splcloud/fcgi-bin/fcg_get_diss_tag_conf.fcg',
20
+ method: method,
21
+ options
22
+ }));
23
+ };
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const apiResponse_1 = require("../../../util/apiResponse");
7
+ const y_common_1 = __importDefault(require("../y_common"));
8
+ exports.default = async ({ method = 'get', params = {}, option = {} }) => {
9
+ const data = {
10
+ ...params,
11
+ format: 'json',
12
+ outCharset: 'utf-8',
13
+ type: 1,
14
+ json: 1,
15
+ utf8: 1,
16
+ onlysong: 0,
17
+ new_format: 1
18
+ };
19
+ const options = {
20
+ ...option,
21
+ params: data
22
+ };
23
+ return (0, apiResponse_1.handleApi)((0, y_common_1.default)({
24
+ url: '/qzone/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg',
25
+ method: method,
26
+ options
27
+ }));
28
+ };
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const apiResponse_1 = require("../../../util/apiResponse");
7
+ const y_common_1 = __importDefault(require("../y_common"));
8
+ exports.default = async ({ method = 'get', params = {}, option = {} }) => {
9
+ const data = {
10
+ ...params,
11
+ format: 'json',
12
+ outCharset: 'utf-8',
13
+ picmid: 1
14
+ };
15
+ const options = {
16
+ ...option,
17
+ params: data
18
+ };
19
+ return (0, apiResponse_1.handleApi)((0, y_common_1.default)({
20
+ url: '/splcloud/fcgi-bin/fcg_get_diss_by_tag.fcg',
21
+ method: method,
22
+ options
23
+ }), {
24
+ transformData: (response) => {
25
+ if (typeof response === 'string') {
26
+ const reg = /^\w+\(([^()]+)\)$/;
27
+ const matches = response.match(reg);
28
+ if (matches) {
29
+ return JSON.parse(matches[1]);
30
+ }
31
+ }
32
+ return response;
33
+ }
34
+ });
35
+ };
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const request_1 = __importDefault(require("../../util/request"));
40
+ const config = __importStar(require("../config"));
41
+ exports.default = ({ options = {}, method = 'get' }) => {
42
+ const opts = { ...options };
43
+ // Merge commonParams into params for query string
44
+ opts.params = { ...config.commonParams, ...(opts.params || {}) };
45
+ opts.headers = {
46
+ referer: 'https://y.qq.com/portal/player.html',
47
+ host: 'u.y.qq.com',
48
+ 'content-type': 'application/x-www-form-urlencoded',
49
+ ...(opts.headers || {})
50
+ };
51
+ if (process.env.DEBUG === 'true') {
52
+ const logOpts = { ...opts, headers: { ...opts.headers, cookie: '[REDACTED]' } };
53
+ console.log('https://u.y.qq.com/cgi-bin/musicu.fcg', { opts: logOpts });
54
+ }
55
+ return (0, request_1.default)('https://u.y.qq.com/cgi-bin/musicu.fcg', method, opts, 'u');
56
+ };
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const apiResponse_1 = require("../../../util/apiResponse");
4
+ const loginUtils_1 = require("../../../util/loginUtils");
5
+ const REQUEST_TIMEOUT_MS = 10000;
6
+ const DEBUG_ENABLED = process.env.DEBUG === 'true';
7
+ const debugLog = (message, payload) => {
8
+ if (DEBUG_ENABLED) {
9
+ console.log(`[checkQQLoginQr] ${message}`, payload ?? '');
10
+ }
11
+ };
12
+ const parseSetCookie = (setCookieHeader) => {
13
+ if (!setCookieHeader)
14
+ return [];
15
+ const cookies = [];
16
+ const parts = setCookieHeader.split(/,(?=\s*[a-zA-Z_]+=)/);
17
+ for (const part of parts) {
18
+ const cookiePair = part.split(';')[0].trim();
19
+ if (cookiePair && cookiePair.includes('=') && cookiePair.split('=')[1]) {
20
+ cookies.push(cookiePair);
21
+ }
22
+ }
23
+ return cookies;
24
+ };
25
+ const fetchWithTimeout = async (input, init = {}, timeout = REQUEST_TIMEOUT_MS) => {
26
+ const controller = new AbortController();
27
+ const timer = setTimeout(() => controller.abort(), timeout);
28
+ try {
29
+ return await fetch(input, {
30
+ ...init,
31
+ signal: controller.signal
32
+ });
33
+ }
34
+ finally {
35
+ clearTimeout(timer);
36
+ }
37
+ };
38
+ const buildLoginSession = (cookie) => {
39
+ const cookieList = cookie
40
+ .split(';')
41
+ .map(item => item.trim())
42
+ .filter(Boolean);
43
+ const cookieObject = {};
44
+ cookieList.forEach(item => {
45
+ const [key, value = ''] = item.split('=');
46
+ if (key && value) {
47
+ cookieObject[key] = value;
48
+ }
49
+ });
50
+ const loginUin = cookieObject.uin || '';
51
+ return {
52
+ loginUin,
53
+ uin: loginUin,
54
+ cookie,
55
+ cookieList,
56
+ cookieObject
57
+ };
58
+ };
59
+ const checkQQLoginQr = async ({ method = 'get', params = {}, option = {} }) => {
60
+ const { ptqrtoken, qrsig } = params;
61
+ if (!ptqrtoken || !qrsig) {
62
+ return (0, apiResponse_1.errorResponse)('参数错误', 400);
63
+ }
64
+ try {
65
+ const url = `https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https%3A%2F%2Fgraph.qq.com%2Foauth2.0%2Flogin_jump&ptqrtoken=${ptqrtoken}&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-1711022193435&js_ver=23111510&js_type=1&login_sig=du-YS1h8*0GqVqcrru0pXkpwVg2DYw-DtbFulJ62IgPf6vfiJe*4ONVrYc5hMUNE&pt_uistyle=40&aid=716027609&daid=383&pt_3rd_aid=100497308&&o1vId=3674fc47871e9c407d8838690b355408&pt_js_version=v1.48.1`;
66
+ const response = await fetchWithTimeout(url, { headers: { Cookie: `qrsig=${qrsig}` } });
67
+ const data = (await response.text()) || '';
68
+ const cookieMap = new Map();
69
+ const setCookie = (setCookieHeader) => {
70
+ const cookies = parseSetCookie(setCookieHeader);
71
+ for (const cookie of cookies) {
72
+ const [name] = cookie.split('=');
73
+ cookieMap.set(name, cookie);
74
+ }
75
+ };
76
+ setCookie(response.headers.get('Set-Cookie'));
77
+ const refresh = data.includes('已失效');
78
+ if (!data.includes('登录成功')) {
79
+ return (0, apiResponse_1.customResponse)({
80
+ isOk: false,
81
+ refresh,
82
+ message: (refresh && '二维码已失效') || '未扫描二维码'
83
+ }, 200);
84
+ }
85
+ const allCookie = () => Array.from(cookieMap.values());
86
+ const urlMatch = data.match(/(?:'((?:https?|ftp):\/\/[^\s/$.?#].[^\s]*)')/g);
87
+ if (!urlMatch || !urlMatch[0]) {
88
+ return (0, apiResponse_1.errorResponse)('Failed to extract checkSigUrl from response', 502);
89
+ }
90
+ const checkSigUrl = urlMatch[0].replace(/'/g, '');
91
+ const checkSigRes = await fetchWithTimeout(checkSigUrl, {
92
+ redirect: 'manual',
93
+ headers: { Cookie: allCookie().join('; ') }
94
+ });
95
+ const checkSigCookie = checkSigRes.headers.get('Set-Cookie');
96
+ const pSkeyMatch = checkSigCookie?.match(/p_skey=([^;]+)/);
97
+ if (!pSkeyMatch || !pSkeyMatch[1]) {
98
+ return (0, apiResponse_1.errorResponse)('Failed to extract p_skey from response', 502);
99
+ }
100
+ const p_skey = pSkeyMatch[1];
101
+ const gtk = (0, loginUtils_1.getGtk)(p_skey);
102
+ setCookie(checkSigCookie);
103
+ const authorizeUrl = 'https://graph.qq.com/oauth2.0/authorize';
104
+ const getAuthorizeData = (g_tk) => {
105
+ const data = new FormData();
106
+ data.append('response_type', 'code');
107
+ data.append('client_id', '100497308');
108
+ data.append('redirect_uri', 'https://y.qq.com/portal/wx_redirect.html?login_type=1&surl=https://y.qq.com/');
109
+ data.append('scope', 'get_user_info,get_app_friends');
110
+ data.append('state', 'state');
111
+ data.append('switch', '');
112
+ data.append('from_ptlogin', '1');
113
+ data.append('src', '1');
114
+ data.append('update_auth', '1');
115
+ data.append('openapi', '1010_1030');
116
+ data.append('g_tk', g_tk.toString());
117
+ data.append('auth_time', new Date().toString());
118
+ data.append('ui', (0, loginUtils_1.getGuid)());
119
+ return data;
120
+ };
121
+ const authorizeRes = await fetchWithTimeout(authorizeUrl, {
122
+ redirect: 'manual',
123
+ method: 'POST',
124
+ body: getAuthorizeData(gtk),
125
+ headers: {
126
+ Cookie: allCookie().join('; ')
127
+ }
128
+ });
129
+ setCookie(authorizeRes.headers.get('Set-Cookie'));
130
+ const location = authorizeRes.headers.get('Location');
131
+ const contentType = authorizeRes.headers.get('Content-Type');
132
+ debugLog('authorize response meta', {
133
+ status: authorizeRes.status,
134
+ redirected: authorizeRes.redirected,
135
+ hasLocation: Boolean(location),
136
+ contentType
137
+ });
138
+ if (authorizeRes.status < 300 || authorizeRes.status >= 400 || !location) {
139
+ return (0, apiResponse_1.errorResponse)('授权响应异常,未返回跳转地址', 502);
140
+ }
141
+ const codeMatch = location.match(/[?&]code=([^&]+)/);
142
+ if (!codeMatch || !codeMatch[1]) {
143
+ debugLog('authorize location parse failed', { location });
144
+ return (0, apiResponse_1.errorResponse)('授权响应中未找到 code 参数', 502);
145
+ }
146
+ const code = codeMatch[1];
147
+ const getFcgReqData = (g_tk, code) => {
148
+ const data = {
149
+ comm: {
150
+ g_tk,
151
+ platform: 'yqq',
152
+ ct: 24,
153
+ cv: 0
154
+ },
155
+ req: {
156
+ module: 'QQConnectLogin.LoginServer',
157
+ method: 'QQLogin',
158
+ param: {
159
+ code
160
+ }
161
+ }
162
+ };
163
+ return JSON.stringify(data);
164
+ };
165
+ const loginUrl = 'https://u.y.qq.com/cgi-bin/musicu.fcg';
166
+ const loginRes = await fetchWithTimeout(loginUrl, {
167
+ method: 'POST',
168
+ body: getFcgReqData(gtk, code),
169
+ headers: {
170
+ 'Content-Type': 'application/x-www-form-urlencoded',
171
+ Cookie: allCookie().join('; ')
172
+ }
173
+ });
174
+ setCookie(loginRes.headers.get('Set-Cookie'));
175
+ const sessionCookie = allCookie().join('; ');
176
+ return (0, apiResponse_1.customResponse)({
177
+ isOk: true,
178
+ message: '登录成功',
179
+ session: buildLoginSession(sessionCookie)
180
+ }, 200);
181
+ }
182
+ catch (error) {
183
+ if (error.name === 'AbortError') {
184
+ return (0, apiResponse_1.errorResponse)('登录检查超时', 504);
185
+ }
186
+ return (0, apiResponse_1.errorResponse)('登录检查失败', 502);
187
+ }
188
+ };
189
+ exports.default = checkQQLoginQr;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const apiResponse_1 = require("../../../util/apiResponse");
4
+ const loginUtils_1 = require("../../../util/loginUtils");
5
+ const getQQLoginQr = async ({ method = 'get', params = {}, option = {} }) => {
6
+ try {
7
+ const url = 'https://ssl.ptlogin2.qq.com/ptqrshow?appid=716027609&e=2&l=M&s=3&d=72&v=4&t=0.9698127522807933&daid=383&pt_3rd_aid=100497308&u1=https%3A%2F%2Fgraph.qq.com%2Foauth2.0%2Flogin_jump';
8
+ const response = await fetch(url);
9
+ const data = await response.arrayBuffer();
10
+ const img = 'data:image/png;base64,' + (data && Buffer.from(data).toString('base64'));
11
+ const cookieHeader = response.headers.get('Set-Cookie');
12
+ const match = cookieHeader?.match(/qrsig=([^;]+)/);
13
+ if (!match) {
14
+ return (0, apiResponse_1.errorResponse)('Failed to get qrsig from response', 502);
15
+ }
16
+ const qrsig = match[1];
17
+ return (0, apiResponse_1.customResponse)({ img, ptqrtoken: (0, loginUtils_1.hash33)(qrsig), qrsig }, 200);
18
+ }
19
+ catch (error) {
20
+ return (0, apiResponse_1.errorResponse)('Failed to fetch QQ login QR', 502);
21
+ }
22
+ };
23
+ exports.default = getQQLoginQr;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getUserAvatar = void 0;
4
+ // 获取 QQ 用户头像
5
+ const getUserAvatar = async (params) => {
6
+ const { k, uin, size = 140 } = params;
7
+ // 如果提供了 k 参数,使用 k 参数获取头像
8
+ if (k) {
9
+ const url = `https://thirdqq.qlogo.cn/g?b=sdk&k=${k}&s=${size}`;
10
+ return {
11
+ avatarUrl: url,
12
+ message: '头像 URL 获取成功'
13
+ };
14
+ }
15
+ // 如果提供了 uin,尝试从 uin 获取头像
16
+ if (uin) {
17
+ const url = `https://q.qlogo.cn/headimg_dl?dst_uin=${uin}&spec=${size}`;
18
+ return {
19
+ avatarUrl: url,
20
+ message: '头像 URL 获取成功'
21
+ };
22
+ }
23
+ throw new Error('缺少 k 或 uin 参数');
24
+ };
25
+ exports.getUserAvatar = getUserAvatar;
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getUserLikedSongs = void 0;
7
+ const request_1 = __importDefault(require("../../../util/request"));
8
+ const apiResponse_1 = require("../../../util/apiResponse");
9
+ const DEBUG_ENABLED = process.env.DEBUG === 'true';
10
+ const debugLog = (message, payload) => {
11
+ if (DEBUG_ENABLED) {
12
+ console.log(`[getUserLikedSongs] ${message}`, payload ?? '');
13
+ }
14
+ };
15
+ // 获取用户喜欢的歌曲列表
16
+ // 注意:此接口需要有效的 QQ 音乐 Cookie 才能正常工作
17
+ const getUserLikedSongs = async (params) => {
18
+ const { uin, offset = 0, limit = 30 } = params;
19
+ const page = Math.floor(offset / limit) + 1;
20
+ // 使用 c6.y.qq.com/rsc/fcgi-bin/fcg_get_profile_homepage.fcg 接口
21
+ // 通过 mymusic 字段获取用户喜欢的歌曲信息
22
+ const url = 'https://c6.y.qq.com/rsc/fcgi-bin/fcg_get_profile_homepage.fcg';
23
+ try {
24
+ debugLog('request meta', {
25
+ url,
26
+ uin,
27
+ offset,
28
+ limit,
29
+ page,
30
+ hasGlobalCookie: Boolean(global.userInfo?.cookie),
31
+ cookieLength: global.userInfo?.cookie?.length || 0
32
+ });
33
+ const response = await (0, request_1.default)({
34
+ url,
35
+ method: 'GET',
36
+ isUUrl: 'u',
37
+ options: {
38
+ params: {
39
+ _: Date.now(),
40
+ cv: 4747474,
41
+ ct: 24,
42
+ format: 'json',
43
+ inCharset: 'utf-8',
44
+ outCharset: 'utf-8',
45
+ notice: 0,
46
+ platform: 'yqq.json',
47
+ needNewCode: 0,
48
+ uin: Number.parseInt(uin, 10),
49
+ g_tk_new_20200303: 0,
50
+ g_tk: 0,
51
+ cid: 205360838,
52
+ userid: Number.parseInt(uin, 10),
53
+ reqfrom: 1,
54
+ reqtype: 0,
55
+ hostUin: 0,
56
+ loginUin: Number.parseInt(uin, 10)
57
+ },
58
+ headers: {
59
+ Referer: `https://y.qq.com/portal/profile.html?uin=${uin}`,
60
+ Cookie: global.userInfo?.cookie || ''
61
+ }
62
+ }
63
+ });
64
+ const payload = response.data;
65
+ debugLog('upstream payload summary', {
66
+ topLevelKeys: payload && typeof payload === 'object' ? Object.keys(payload) : null,
67
+ code: payload?.code,
68
+ hasData: Boolean(payload?.data),
69
+ dataKeys: payload?.data && typeof payload.data === 'object' ? Object.keys(payload.data) : []
70
+ });
71
+ if (!payload || typeof payload !== 'object') {
72
+ debugLog('invalid payload received', payload);
73
+ return (0, apiResponse_1.errorResponse)('用户喜欢的歌曲响应格式无效', 502);
74
+ }
75
+ if (typeof payload.code === 'number' && payload.code !== 0) {
76
+ debugLog('upstream business error payload', payload);
77
+ return (0, apiResponse_1.errorResponse)(payload.msg || payload.message || '获取用户喜欢的歌曲失败', 502);
78
+ }
79
+ // 从 mymusic 字段中提取喜欢的歌曲信息
80
+ // mymusic 数组中的第一个元素通常包含"我喜欢"歌单的信息
81
+ const mymusic = payload?.data?.mymusic;
82
+ let likedSongsInfo = null;
83
+ if (Array.isArray(mymusic)) {
84
+ // 查找"我喜欢"歌单(通常 title 包含"喜欢"或 type 为 1)
85
+ likedSongsInfo = mymusic.find((item) => {
86
+ return item?.title && (item.title.includes('喜欢') || item.type === 1);
87
+ });
88
+ }
89
+ debugLog('liked songs info', likedSongsInfo);
90
+ if (!likedSongsInfo) {
91
+ debugLog('no liked songs info found in mymusic');
92
+ return (0, apiResponse_1.customResponse)({
93
+ response: {
94
+ code: 0,
95
+ data: {
96
+ songs: [],
97
+ total: 0,
98
+ hasMore: false
99
+ }
100
+ }
101
+ }, 200);
102
+ }
103
+ // 返回喜欢的歌曲信息(包含歌单 ID 和统计信息)
104
+ // 注意:完整的歌曲列表需要通过 musics.fcg 接口获取(需要二进制加密)
105
+ // 这里先返回歌单基本信息
106
+ return (0, apiResponse_1.customResponse)({
107
+ response: {
108
+ code: 0,
109
+ data: {
110
+ songs: [likedSongsInfo],
111
+ total: likedSongsInfo.num0 || 0,
112
+ hasMore: false,
113
+ info: {
114
+ title: likedSongsInfo.title,
115
+ songCount: likedSongsInfo.num0,
116
+ albumCount: likedSongsInfo.num1,
117
+ playlistCount: likedSongsInfo.num2,
118
+ id: likedSongsInfo.id
119
+ }
120
+ }
121
+ }
122
+ }, 200);
123
+ }
124
+ catch (error) {
125
+ console.error('获取用户喜欢的歌曲失败:', error);
126
+ return (0, apiResponse_1.errorResponse)(error.message || '获取用户喜欢的歌曲失败', 502);
127
+ }
128
+ };
129
+ exports.getUserLikedSongs = getUserLikedSongs;
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getUserPlaylists = void 0;
7
+ const request_1 = __importDefault(require("../../../util/request"));
8
+ const apiResponse_1 = require("../../../util/apiResponse");
9
+ const DEBUG_ENABLED = process.env.DEBUG === 'true';
10
+ const debugLog = (message, payload) => {
11
+ if (DEBUG_ENABLED) {
12
+ console.log(`[getUserPlaylists] ${message}`, payload ?? '');
13
+ }
14
+ };
15
+ const getNamedCandidateEntries = (payload) => [
16
+ ['data.mydiss.list', payload?.data?.mydiss?.list],
17
+ ['data.mymusic', payload?.data?.mymusic],
18
+ ['data.createdDissList', payload?.data?.createdDissList],
19
+ ['data.createdList', payload?.data?.createdList],
20
+ ['data.creator', payload?.data?.creator],
21
+ ['data.creator.playlist', payload?.data?.creator?.playlist],
22
+ ['data.creator.playlists', payload?.data?.creator?.playlists],
23
+ ['data.playlist', payload?.data?.playlist],
24
+ ['data.playlists', payload?.data?.playlists],
25
+ ['mydiss.list', payload?.mydiss?.list],
26
+ ['mymusic', payload?.mymusic],
27
+ ['createdDissList', payload?.createdDissList],
28
+ ['createdList', payload?.createdList],
29
+ ['creator', payload?.creator],
30
+ ['creator.playlist', payload?.creator?.playlist],
31
+ ['creator.playlists', payload?.creator?.playlists],
32
+ ['playlist', payload?.playlist],
33
+ ['playlists', payload?.playlists]
34
+ ];
35
+ const extractPlaylists = (payload) => {
36
+ debugLog('payload top-level keys', Object.keys(payload || {}));
37
+ debugLog('payload.data keys', payload?.data && typeof payload.data === 'object' ? Object.keys(payload.data) : []);
38
+ const matchedEntry = getNamedCandidateEntries(payload).find(([, candidate]) => Array.isArray(candidate));
39
+ if (matchedEntry) {
40
+ const [candidatePath, playlists] = matchedEntry;
41
+ debugLog('matched playlist candidate', {
42
+ candidatePath,
43
+ length: playlists.length
44
+ });
45
+ return playlists;
46
+ }
47
+ debugLog('playlist candidates summary', getNamedCandidateEntries(payload).map(([candidatePath, candidate]) => ({
48
+ candidatePath,
49
+ type: Array.isArray(candidate) ? 'array' : typeof candidate,
50
+ keys: candidate && typeof candidate === 'object' && !Array.isArray(candidate) ? Object.keys(candidate) : undefined
51
+ })));
52
+ throw new Error('用户歌单响应中未找到歌单列表字段');
53
+ };
54
+ const getErrorMessage = (payload) => {
55
+ const candidates = [payload.message, payload.msg, payload.errmsg, payload.error];
56
+ const matched = candidates.find(candidate => typeof candidate === 'string' && candidate.trim() !== '');
57
+ return matched || '获取用户歌单失败';
58
+ };
59
+ // 获取用户创建的歌单
60
+ // 注意:此接口需要有效的 QQ 音乐 Cookie 才能正常工作
61
+ const getUserPlaylists = async (params) => {
62
+ const { uin, offset = 0, limit = 30 } = params;
63
+ // 使用 c6.y.qq.com/rsc/fcgi-bin/fcg_get_profile_homepage.fcg 接口
64
+ // 这是通过 Chrome DevTools 抓包发现的实际使用的接口
65
+ const url = 'https://c6.y.qq.com/rsc/fcgi-bin/fcg_get_profile_homepage.fcg';
66
+ const pageOffset = offset % limit;
67
+ try {
68
+ debugLog('request meta', {
69
+ url,
70
+ uin,
71
+ offset,
72
+ limit,
73
+ pageOffset,
74
+ hasGlobalCookie: Boolean(global.userInfo?.cookie),
75
+ cookieLength: global.userInfo?.cookie?.length || 0
76
+ });
77
+ const response = await (0, request_1.default)({
78
+ url,
79
+ method: 'GET',
80
+ isUUrl: 'u',
81
+ options: {
82
+ params: {
83
+ _: Date.now(),
84
+ cv: 4747474,
85
+ ct: 24,
86
+ format: 'json',
87
+ inCharset: 'utf-8',
88
+ outCharset: 'utf-8',
89
+ notice: 0,
90
+ platform: 'yqq.json',
91
+ needNewCode: 0,
92
+ uin: Number.parseInt(uin, 10),
93
+ g_tk_new_20200303: 0,
94
+ g_tk: 0,
95
+ cid: 205360838,
96
+ userid: Number.parseInt(uin, 10),
97
+ reqfrom: 1,
98
+ reqtype: 0,
99
+ hostUin: 0,
100
+ loginUin: Number.parseInt(uin, 10)
101
+ },
102
+ headers: {
103
+ Referer: `https://y.qq.com/portal/profile.html?uin=${uin}`,
104
+ Cookie: global.userInfo?.cookie || ''
105
+ }
106
+ }
107
+ });
108
+ const payload = response.data;
109
+ debugLog('upstream payload summary', {
110
+ topLevelKeys: payload && typeof payload === 'object' ? Object.keys(payload) : null,
111
+ code: payload?.code,
112
+ hasData: Boolean(payload?.data),
113
+ dataKeys: payload?.data && typeof payload.data === 'object' ? Object.keys(payload.data) : []
114
+ });
115
+ if (!payload || typeof payload !== 'object') {
116
+ debugLog('invalid payload received', payload);
117
+ return (0, apiResponse_1.errorResponse)('用户歌单响应格式无效', 502);
118
+ }
119
+ if (typeof payload.code === 'number' && payload.code !== 0) {
120
+ debugLog('upstream business error payload', payload);
121
+ return (0, apiResponse_1.errorResponse)(getErrorMessage(payload), 502);
122
+ }
123
+ const upstreamPlaylists = extractPlaylists(payload);
124
+ const playlists = pageOffset > 0 ? upstreamPlaylists.slice(pageOffset, pageOffset + limit) : upstreamPlaylists;
125
+ debugLog('final response contract', {
126
+ wrapper: 'customResponse',
127
+ expectedBodyShape: { response: { code: 0, data: { playlists: '...' } } },
128
+ upstreamLength: upstreamPlaylists.length,
129
+ normalizedLength: playlists.length
130
+ });
131
+ return (0, apiResponse_1.customResponse)({ response: { code: 0, data: { playlists } } }, 200);
132
+ }
133
+ catch (error) {
134
+ console.error('获取用户歌单失败:', error);
135
+ return (0, apiResponse_1.errorResponse)(error.message || '获取用户歌单失败', 502);
136
+ }
137
+ };
138
+ exports.getUserPlaylists = getUserPlaylists;