@sansenjian/qq-music-api 2.2.7 → 2.2.10

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 (121) hide show
  1. package/CHANGELOG.md +23 -1
  2. package/README.md +2 -0
  3. package/dist/api/index.js +9 -0
  4. package/dist/app.js +30 -45
  5. package/dist/config/service-config.js +37 -0
  6. package/dist/index.js +13 -1
  7. package/dist/jest.config.js +14 -2
  8. package/dist/koaApp.js +45 -0
  9. package/dist/middlewares/fallback-middleware.js +29 -0
  10. package/dist/module/apis/music/getLyric.js +220 -16
  11. package/dist/module/apis/music/getMusicPlay.js +187 -0
  12. package/dist/module/apis/u_common.js +8 -2
  13. package/dist/module/apis/user/getUserPlaylists.js +5 -5
  14. package/dist/module/index.js +3 -1
  15. package/dist/package.json +5 -2
  16. package/dist/routers/context/batchGetSongInfo.js +11 -16
  17. package/dist/routers/context/batchGetSongLists.js +18 -20
  18. package/dist/routers/context/getAlbumInfo.js +10 -17
  19. package/dist/routers/context/getComments.js +12 -19
  20. package/dist/routers/context/getDailyRecommend.js +5 -17
  21. package/dist/routers/context/getHotkey.js +7 -8
  22. package/dist/routers/context/getLyric.js +12 -2
  23. package/dist/routers/context/getMusicPlay.js +23 -81
  24. package/dist/routers/context/getMv.js +16 -22
  25. package/dist/routers/context/getMvPlay.js +48 -49
  26. package/dist/routers/context/getPersonalRecommend.js +13 -25
  27. package/dist/routers/context/getPlaylistTags.js +20 -26
  28. package/dist/routers/context/getRanks.js +9 -16
  29. package/dist/routers/context/getSingerAlbum.js +16 -22
  30. package/dist/routers/context/getSingerHotsong.js +16 -22
  31. package/dist/routers/context/getSingerList.js +9 -21
  32. package/dist/routers/context/getSongInfo.js +9 -16
  33. package/dist/routers/context/getSongListCategories.js +6 -7
  34. package/dist/routers/context/getSongListDetail.js +6 -8
  35. package/dist/routers/context/getUserAvatar.js +20 -33
  36. package/dist/routers/context/getUserPlaylists.js +6 -3
  37. package/dist/routers/context/index.js +94 -103
  38. package/dist/routers/util.js +31 -0
  39. package/dist/scripts/run-tests-with-flags.js +139 -0
  40. package/dist/util/cookie.js +15 -7
  41. package/dist/util/cookieResolver.js +66 -0
  42. package/dist/util/request.js +15 -6
  43. package/docs-dist/404.html +2 -2
  44. package/docs-dist/CHANGELOG-ARCHITECTURE.html +6 -6
  45. package/docs-dist/COOKIE_CONFIG_GUIDE.html +6 -6
  46. package/docs-dist/FALLBACK_MODE_GUIDE.html +101 -0
  47. package/docs-dist/README.html +6 -6
  48. package/docs-dist/TEST_USER_PLAYLISTS.html +6 -6
  49. package/docs-dist/USER_AVATAR_GUIDE.html +6 -6
  50. package/docs-dist/api/comments.html +6 -6
  51. package/docs-dist/api/index.html +6 -6
  52. package/docs-dist/api/music.html +6 -6
  53. package/docs-dist/api/other.html +6 -6
  54. package/docs-dist/api/playlist.html +6 -6
  55. package/docs-dist/api/rank.html +6 -6
  56. package/docs-dist/api/search.html +6 -6
  57. package/docs-dist/api/singer.html +6 -6
  58. package/docs-dist/api/user.html +6 -6
  59. package/docs-dist/assets/{CHANGELOG-ARCHITECTURE.md.BOe0ZtyR.js → CHANGELOG-ARCHITECTURE.md.DV9Xr7ve.js} +1 -1
  60. package/docs-dist/assets/{CHANGELOG-ARCHITECTURE.md.BOe0ZtyR.lean.js → CHANGELOG-ARCHITECTURE.md.DV9Xr7ve.lean.js} +1 -1
  61. package/docs-dist/assets/{COOKIE_CONFIG_GUIDE.md.D68AwXR2.js → COOKIE_CONFIG_GUIDE.md.B2-aTdcH.js} +1 -1
  62. package/docs-dist/assets/{COOKIE_CONFIG_GUIDE.md.D68AwXR2.lean.js → COOKIE_CONFIG_GUIDE.md.B2-aTdcH.lean.js} +1 -1
  63. package/docs-dist/assets/FALLBACK_MODE_GUIDE.md.0wqXqYxw.js +75 -0
  64. package/docs-dist/assets/FALLBACK_MODE_GUIDE.md.0wqXqYxw.lean.js +1 -0
  65. package/docs-dist/assets/{README.md.ZJQGJ1Gb.js → README.md.DFCMeLFa.js} +1 -1
  66. package/docs-dist/assets/{README.md.ZJQGJ1Gb.lean.js → README.md.DFCMeLFa.lean.js} +1 -1
  67. package/docs-dist/assets/{TEST_USER_PLAYLISTS.md.C02575X2.js → TEST_USER_PLAYLISTS.md.Bj0AVpHw.js} +1 -1
  68. package/docs-dist/assets/{TEST_USER_PLAYLISTS.md.C02575X2.lean.js → TEST_USER_PLAYLISTS.md.Bj0AVpHw.lean.js} +1 -1
  69. package/docs-dist/assets/{USER_AVATAR_GUIDE.md.BOqjn5Cm.js → USER_AVATAR_GUIDE.md.CGPI9GUj.js} +1 -1
  70. package/docs-dist/assets/{USER_AVATAR_GUIDE.md.BOqjn5Cm.lean.js → USER_AVATAR_GUIDE.md.CGPI9GUj.lean.js} +1 -1
  71. package/docs-dist/assets/{api_comments.md.DADvndEA.js → api_comments.md.CATvWhrg.js} +1 -1
  72. package/docs-dist/assets/{api_comments.md.DADvndEA.lean.js → api_comments.md.CATvWhrg.lean.js} +1 -1
  73. package/docs-dist/assets/{api_index.md.D5IASxxG.js → api_index.md.Dqx3qXyO.js} +1 -1
  74. package/docs-dist/assets/{api_index.md.D5IASxxG.lean.js → api_index.md.Dqx3qXyO.lean.js} +1 -1
  75. package/docs-dist/assets/{api_music.md.BgB8NmZq.js → api_music.md.D20_neZB.js} +1 -1
  76. package/docs-dist/assets/{api_music.md.BgB8NmZq.lean.js → api_music.md.D20_neZB.lean.js} +1 -1
  77. package/docs-dist/assets/{api_other.md.BkRWXX2z.js → api_other.md.CXyEsl8R.js} +1 -1
  78. package/docs-dist/assets/{api_other.md.BkRWXX2z.lean.js → api_other.md.CXyEsl8R.lean.js} +1 -1
  79. package/docs-dist/assets/{api_playlist.md.Dc0hTrZ4.js → api_playlist.md.CyLdLRR9.js} +1 -1
  80. package/docs-dist/assets/{api_playlist.md.Dc0hTrZ4.lean.js → api_playlist.md.CyLdLRR9.lean.js} +1 -1
  81. package/docs-dist/assets/{api_rank.md.DRisCFyT.js → api_rank.md.Z3xyYG_S.js} +1 -1
  82. package/docs-dist/assets/{api_rank.md.DRisCFyT.lean.js → api_rank.md.Z3xyYG_S.lean.js} +1 -1
  83. package/docs-dist/assets/{api_search.md.DNnMUZK0.js → api_search.md.D_lbFmYo.js} +1 -1
  84. package/docs-dist/assets/{api_search.md.DNnMUZK0.lean.js → api_search.md.D_lbFmYo.lean.js} +1 -1
  85. package/docs-dist/assets/{api_singer.md.DCmuxQkk.js → api_singer.md.BbyYE88D.js} +1 -1
  86. package/docs-dist/assets/{api_singer.md.DCmuxQkk.lean.js → api_singer.md.BbyYE88D.lean.js} +1 -1
  87. package/docs-dist/assets/{api_user.md.Cjm9GG3z.js → api_user.md.4WdmTXIB.js} +1 -1
  88. package/docs-dist/assets/{api_user.md.Cjm9GG3z.lean.js → api_user.md.4WdmTXIB.lean.js} +1 -1
  89. package/docs-dist/assets/{app.Dx_1wB58.js → app.2f7gcITE.js} +1 -1
  90. package/docs-dist/assets/chunks/@localSearchIndexroot.D461xa5C.js +1 -0
  91. package/docs-dist/assets/chunks/{VPLocalSearchBox.DwKWtsdX.js → VPLocalSearchBox.BiPSl83v.js} +1 -1
  92. package/docs-dist/assets/chunks/framework.aJbMEiY9.js +19 -0
  93. package/docs-dist/assets/chunks/{theme.pGVgJ9Cx.js → theme.BrMPT0hE.js} +2 -2
  94. package/docs-dist/assets/{guide_architecture.md.DGtNyuMH.js → guide_architecture.md.D_46khUI.js} +1 -1
  95. package/docs-dist/assets/{guide_architecture.md.DGtNyuMH.lean.js → guide_architecture.md.D_46khUI.lean.js} +1 -1
  96. package/docs-dist/assets/{guide_authentication.md.mtI5LfCw.js → guide_authentication.md.nCiAu07w.js} +1 -1
  97. package/docs-dist/assets/{guide_authentication.md.mtI5LfCw.lean.js → guide_authentication.md.nCiAu07w.lean.js} +1 -1
  98. package/docs-dist/assets/{guide_index.md.B-0SG46T.js → guide_index.md.gLozHqz5.js} +1 -1
  99. package/docs-dist/assets/{guide_index.md.B-0SG46T.lean.js → guide_index.md.gLozHqz5.lean.js} +1 -1
  100. package/docs-dist/assets/{guide_installation.md.k-KpAfxv.js → guide_installation.md.BUDl8zk1.js} +1 -1
  101. package/docs-dist/assets/guide_installation.md.BUDl8zk1.lean.js +1 -0
  102. package/docs-dist/assets/{guide_quickstart.md.Bff_KFOD.js → guide_quickstart.md.COQUzUN9.js} +1 -1
  103. package/docs-dist/assets/guide_quickstart.md.COQUzUN9.lean.js +1 -0
  104. package/docs-dist/assets/{index.md.xrs-uIyo.js → index.md.DBZfQ2kF.js} +1 -1
  105. package/docs-dist/assets/{index.md.xrs-uIyo.lean.js → index.md.DBZfQ2kF.lean.js} +1 -1
  106. package/docs-dist/assets/{reference_response-format.md.DKYTK6uJ.js → reference_response-format.md.yrdeqFUN.js} +1 -1
  107. package/docs-dist/assets/{reference_response-format.md.DKYTK6uJ.lean.js → reference_response-format.md.yrdeqFUN.lean.js} +1 -1
  108. package/docs-dist/guide/architecture.html +6 -6
  109. package/docs-dist/guide/authentication.html +6 -6
  110. package/docs-dist/guide/index.html +6 -6
  111. package/docs-dist/guide/installation.html +6 -6
  112. package/docs-dist/guide/quickstart.html +6 -6
  113. package/docs-dist/hashmap.json +1 -1
  114. package/docs-dist/index.html +5 -5
  115. package/docs-dist/reference/response-format.html +6 -6
  116. package/docs-dist/version.json +3 -3
  117. package/package.json +5 -2
  118. package/docs-dist/assets/chunks/@localSearchIndexroot.CMY5EIwU.js +0 -1
  119. package/docs-dist/assets/chunks/framework.o40iizuP.js +0 -19
  120. package/docs-dist/assets/guide_installation.md.k-KpAfxv.lean.js +0 -1
  121. package/docs-dist/assets/guide_quickstart.md.Bff_KFOD.lean.js +0 -1
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const module_1 = require("../../module");
4
- const controller = async (ctx, next) => {
4
+ const util_1 = require("../util");
5
+ const apiResponse_1 = require("../../util/apiResponse");
6
+ const getSongInfoController = (0, util_1.withErrorHandler)(async (ctx) => {
5
7
  const song_mid = ctx.query.songmid;
6
8
  const song_id = ctx.query.songid || '';
7
- const params = Object.assign({
9
+ const params = {
8
10
  format: 'json',
9
11
  inCharset: 'utf8',
10
12
  outCharset: 'utf-8',
@@ -26,22 +28,13 @@ const controller = async (ctx, next) => {
26
28
  module: 'music.pf_song_detail_svr'
27
29
  }
28
30
  }
29
- });
31
+ };
30
32
  const props = {
31
33
  method: 'get',
32
34
  params,
33
35
  option: {}
34
36
  };
35
- await (0, module_1.UCommon)(props)
36
- .then(res => {
37
- const response = res.data;
38
- ctx.status = 200;
39
- ctx.body = {
40
- response
41
- };
42
- })
43
- .catch(error => {
44
- console.log('error', error);
45
- });
46
- };
47
- exports.default = controller;
37
+ const response = await (0, module_1.UCommon)(props);
38
+ (0, util_1.setApiResponse)(ctx, (0, apiResponse_1.customResponse)({ response: response.data }, 200));
39
+ });
40
+ exports.default = getSongInfoController;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const module_1 = require("../../module");
4
+ const util_1 = require("../util");
4
5
  /**
5
6
  * @description: 歌单
6
7
  * 1 歌单类型
@@ -9,15 +10,13 @@ const module_1 = require("../../module");
9
10
  * 4 歌单详情
10
11
  *
11
12
  */
12
- exports.default = async (ctx, next) => {
13
+ const getSongListCategoriesController = (0, util_1.withErrorHandler)(async (ctx) => {
13
14
  const props = {
14
15
  method: 'get',
15
16
  params: {},
16
17
  option: {}
17
18
  };
18
- const { status, body } = await (0, module_1.songListCategories)(props);
19
- Object.assign(ctx, {
20
- status,
21
- body
22
- });
23
- };
19
+ const result = await (0, module_1.songListCategories)(props);
20
+ (0, util_1.setApiResponse)(ctx, result);
21
+ });
22
+ exports.default = getSongListCategoriesController;
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const module_1 = require("../../module");
4
- const controller = async (ctx, next) => {
4
+ const util_1 = require("../util");
5
+ const getSongListDetailController = (0, util_1.withErrorHandler)(async (ctx) => {
5
6
  const { disstid } = ctx.query;
6
7
  const props = {
7
8
  method: 'get',
@@ -10,10 +11,7 @@ const controller = async (ctx, next) => {
10
11
  },
11
12
  option: {}
12
13
  };
13
- const { status, body } = await (0, module_1.songListDetail)(props);
14
- Object.assign(ctx, {
15
- status,
16
- body
17
- });
18
- };
19
- exports.default = controller;
14
+ const result = await (0, module_1.songListDetail)(props);
15
+ (0, util_1.setApiResponse)(ctx, result);
16
+ });
17
+ exports.default = getSongListDetailController;
@@ -1,48 +1,35 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const module_1 = require("../../module");
4
+ const util_1 = require("../util");
5
+ const apiResponse_1 = require("../../util/apiResponse");
4
6
  // 获取 QQ 用户头像
5
- exports.default = async (ctx, next) => {
7
+ const getUserAvatarController = (0, util_1.withErrorHandler)(async (ctx) => {
6
8
  const rawK = Array.isArray(ctx.query.k) ? ctx.query.k[0] : ctx.query.k;
7
9
  const rawUin = Array.isArray(ctx.query.uin) ? ctx.query.uin[0] : ctx.query.uin;
8
10
  const rawSize = Array.isArray(ctx.query.size) ? ctx.query.size[0] : ctx.query.size;
9
11
  const parsedSize = rawSize ? Number(rawSize) : 140;
10
12
  if (!rawK && !rawUin) {
11
- ctx.status = 400;
12
- ctx.body = {
13
- error: '缺少 k 或 uin 参数'
14
- };
13
+ (0, util_1.setApiResponse)(ctx, (0, apiResponse_1.errorResponse)('缺少 k 或 uin 参数', 400));
15
14
  return;
16
15
  }
17
16
  if (!Number.isFinite(parsedSize) || parsedSize <= 0) {
18
- ctx.status = 400;
19
- ctx.body = {
20
- error: 'size 参数无效'
21
- };
17
+ (0, util_1.setApiResponse)(ctx, (0, apiResponse_1.errorResponse)('size 参数无效', 400));
22
18
  return;
23
19
  }
24
- try {
25
- const result = await (0, module_1.getUserAvatar)({
26
- k: rawK,
27
- uin: rawUin,
28
- size: parsedSize
29
- });
30
- ctx.status = 200;
31
- ctx.body = {
32
- response: {
33
- code: 0,
34
- data: {
35
- avatarUrl: result.avatarUrl,
36
- message: '获取头像成功'
37
- }
20
+ const result = await (0, module_1.getUserAvatar)({
21
+ k: rawK,
22
+ uin: rawUin,
23
+ size: parsedSize
24
+ });
25
+ (0, util_1.setApiResponse)(ctx, (0, apiResponse_1.customResponse)({
26
+ response: {
27
+ code: 0,
28
+ data: {
29
+ avatarUrl: result.avatarUrl,
30
+ message: '获取头像成功'
38
31
  }
39
- };
40
- }
41
- catch (error) {
42
- ctx.status = 502;
43
- ctx.body = {
44
- error: error.message
45
- };
46
- }
47
- await next();
48
- };
32
+ }
33
+ }, 200));
34
+ });
35
+ exports.default = getUserAvatarController;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const module_1 = require("../../module");
4
- // 获取用户创建的歌单
4
+ const cookieResolver_1 = require("../../util/cookieResolver");
5
5
  exports.default = async (ctx, next) => {
6
6
  const { uin, offset = 0, limit = 30 } = ctx.query;
7
7
  if (!uin) {
@@ -11,10 +11,13 @@ exports.default = async (ctx, next) => {
11
11
  };
12
12
  return;
13
13
  }
14
+ const normalizedUin = Array.isArray(uin) ? uin[0] : uin;
15
+ const { cookie } = (0, cookieResolver_1.resolveRequestCookie)(ctx);
14
16
  const { status, body } = await (0, module_1.getUserPlaylists)({
15
- uin: uin,
17
+ uin: String(normalizedUin),
16
18
  offset: Number(offset),
17
- limit: Number(limit)
19
+ limit: Number(limit),
20
+ cookie
18
21
  });
19
22
  Object.assign(ctx, {
20
23
  status,
@@ -1,107 +1,98 @@
1
1
  "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- // eslint-disable-next-line @typescript-eslint/no-var-requires
4
- const req = (id) => {
5
- const mod = require(id);
6
- return mod && mod.default ? mod.default : mod;
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
4
  };
8
- const getDownloadQQMusic = req('./getDownloadQQMusic');
9
- const getHotKey = req('./getHotkey');
10
- const getSearchByKey = req('./getSearchByKey');
11
- const getSmartbox = req('./getSmartbox');
12
- const getSongListCategories = req('./getSongListCategories');
13
- const getSongLists = req('./getSongLists');
14
- const batchGetSongLists = req('./batchGetSongLists');
15
- const getSongInfo = req('./getSongInfo');
16
- const batchGetSongInfo = req('./batchGetSongInfo');
17
- const getSongListDetail = req('./getSongListDetail');
18
- const getNewDisks = req('./getNewDisks');
19
- const getMvByTag = req('./getMvByTag');
20
- const getMv = req('./getMv');
21
- const getSingerList = req('./getSingerList');
22
- const getSimilarSinger = req('./getSimilarSinger');
23
- const getSingerAlbum = req('./getSingerAlbum');
24
- const getSingerHotsong = req('./getSingerHotsong');
25
- const getSingerMv = req('./getSingerMv');
26
- const getSingerDesc = req('./getSingerDesc');
27
- const getSingerStarNum = req('./getSingerStarNum');
28
- const getRadioLists = req('./getRadioLists');
29
- const getDigitalAlbumLists = req('./getDigitalAlbumLists');
30
- const getLyric = req('./getLyric');
31
- const getMusicPlay = req('./getMusicPlay');
32
- const getAlbumInfo = req('./getAlbumInfo');
33
- const getComments = req('./getComments');
34
- const getRecommend = req('./getRecommend');
35
- const getMvPlay = req('./getMvPlay');
36
- const getTopLists = req('./getTopLists');
37
- const getRanks = req('./getRanks');
38
- const getTicketInfo = req('./getTicketInfo');
39
- const getImageUrl = req('./getImageUrl');
40
- const getQQLoginQr = req('./getQQLoginQr');
41
- const checkQQLoginQr = req('./checkQQLoginQr');
42
- const { get: getCookie, set: setCookie } = req('./cookies');
43
- const getUserPlaylists = req('./getUserPlaylists');
44
- const getUserAvatar = req('./getUserAvatar');
45
- const getUserLikedSongs = req('./getUserLikedSongs');
46
- const dailyRecommendController = req('./getDailyRecommend');
47
- const personalRecommendController = req('./getPersonalRecommend');
48
- const extendController = req('./getPlaylistTags');
49
- const getDailyRecommend = dailyRecommendController.getDailyRecommend;
50
- const getPrivateFM = dailyRecommendController.getPrivateFM;
51
- const getNewSongs = dailyRecommendController.getNewSongs;
52
- const getPersonalRecommend = personalRecommendController.getPersonalRecommend;
53
- const getSimilarSongs = personalRecommendController.getSimilarSongs;
54
- const getPlaylistTags = extendController.getPlaylistTags;
55
- const getPlaylistsByTag = extendController.getPlaylistsByTag;
56
- const getHotComments = extendController.getHotComments;
57
- const getSingerListByArea = extendController.getSingerListByArea;
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ // Import refactored controllers
7
+ const getDownloadQQMusic_1 = __importDefault(require("./getDownloadQQMusic"));
8
+ const getHotkey_1 = __importDefault(require("./getHotkey"));
9
+ const getSearchByKey_1 = __importDefault(require("./getSearchByKey"));
10
+ const getSmartbox_1 = __importDefault(require("./getSmartbox"));
11
+ const getSongListCategories_1 = __importDefault(require("./getSongListCategories"));
12
+ const getSongLists_1 = __importDefault(require("./getSongLists"));
13
+ const batchGetSongLists_1 = __importDefault(require("./batchGetSongLists"));
14
+ const getSongInfo_1 = __importDefault(require("./getSongInfo"));
15
+ const batchGetSongInfo_1 = __importDefault(require("./batchGetSongInfo"));
16
+ const getSongListDetail_1 = __importDefault(require("./getSongListDetail"));
17
+ const getNewDisks_1 = __importDefault(require("./getNewDisks"));
18
+ const getMvByTag_1 = __importDefault(require("./getMvByTag"));
19
+ const getMv_1 = __importDefault(require("./getMv"));
20
+ const getSingerList_1 = __importDefault(require("./getSingerList"));
21
+ const getSimilarSinger_1 = __importDefault(require("./getSimilarSinger"));
22
+ const getSingerAlbum_1 = __importDefault(require("./getSingerAlbum"));
23
+ const getSingerHotsong_1 = __importDefault(require("./getSingerHotsong"));
24
+ const getSingerMv_1 = __importDefault(require("./getSingerMv"));
25
+ const getSingerDesc_1 = __importDefault(require("./getSingerDesc"));
26
+ const getSingerStarNum_1 = __importDefault(require("./getSingerStarNum"));
27
+ const getRadioLists_1 = __importDefault(require("./getRadioLists"));
28
+ const getDigitalAlbumLists_1 = __importDefault(require("./getDigitalAlbumLists"));
29
+ const getLyric_1 = __importDefault(require("./getLyric"));
30
+ const getMusicPlay_1 = __importDefault(require("./getMusicPlay"));
31
+ const getAlbumInfo_1 = __importDefault(require("./getAlbumInfo"));
32
+ const getComments_1 = __importDefault(require("./getComments"));
33
+ const getRecommend_1 = __importDefault(require("./getRecommend"));
34
+ const getMvPlay_1 = __importDefault(require("./getMvPlay"));
35
+ const getTopLists_1 = __importDefault(require("./getTopLists"));
36
+ const getRanks_1 = __importDefault(require("./getRanks"));
37
+ const getTicketInfo_1 = __importDefault(require("./getTicketInfo"));
38
+ const getImageUrl_1 = __importDefault(require("./getImageUrl"));
39
+ const getQQLoginQr_1 = __importDefault(require("./getQQLoginQr"));
40
+ const checkQQLoginQr_1 = __importDefault(require("./checkQQLoginQr"));
41
+ const cookies_1 = __importDefault(require("./cookies"));
42
+ const getUserPlaylists_1 = __importDefault(require("./getUserPlaylists"));
43
+ const getUserAvatar_1 = __importDefault(require("./getUserAvatar"));
44
+ const getUserLikedSongs_1 = __importDefault(require("./getUserLikedSongs"));
45
+ const getDailyRecommend_1 = require("./getDailyRecommend");
46
+ const getPersonalRecommend_1 = require("./getPersonalRecommend");
47
+ const getPlaylistTags_1 = require("./getPlaylistTags");
48
+ // Export all controllers with consistent naming
58
49
  exports.default = {
59
- getCookie,
60
- setCookie,
61
- getDownloadQQMusic,
62
- getHotKey,
63
- getSearchByKey,
64
- getSmartbox,
65
- getSongListCategories,
66
- getSongLists,
67
- batchGetSongLists,
68
- getSongInfo,
69
- batchGetSongInfo,
70
- getSongListDetail,
71
- getNewDisks,
72
- getMvByTag,
73
- getMv,
74
- getSingerList,
75
- getSimilarSinger,
76
- getSingerAlbum,
77
- getSingerHotsong,
78
- getSingerMv,
79
- getSingerDesc,
80
- getSingerStarNum,
81
- getRadioLists,
82
- getDigitalAlbumLists,
83
- getLyric,
84
- getMusicPlay,
85
- getAlbumInfo,
86
- getComments,
87
- getRecommend,
88
- getMvPlay,
89
- getTopLists,
90
- getRanks,
91
- getTicketInfo,
92
- getImageUrl,
93
- getQQLoginQr,
94
- checkQQLoginQr,
95
- getUserPlaylists,
96
- getUserAvatar,
97
- getUserLikedSongs,
98
- getDailyRecommend,
99
- getPrivateFM,
100
- getNewSongs,
101
- getPersonalRecommend,
102
- getSimilarSongs,
103
- getPlaylistTags,
104
- getPlaylistsByTag,
105
- getHotComments,
106
- getSingerListByArea
50
+ getCookie: cookies_1.default.get,
51
+ setCookie: cookies_1.default.set,
52
+ getDownloadQQMusic: getDownloadQQMusic_1.default,
53
+ getHotKey: getHotkey_1.default,
54
+ getSearchByKey: getSearchByKey_1.default,
55
+ getSmartbox: getSmartbox_1.default,
56
+ getSongListCategories: getSongListCategories_1.default,
57
+ getSongLists: getSongLists_1.default,
58
+ batchGetSongLists: batchGetSongLists_1.default,
59
+ getSongInfo: getSongInfo_1.default,
60
+ batchGetSongInfo: batchGetSongInfo_1.default,
61
+ getSongListDetail: getSongListDetail_1.default,
62
+ getNewDisks: getNewDisks_1.default,
63
+ getMvByTag: getMvByTag_1.default,
64
+ getMv: getMv_1.default,
65
+ getSingerList: getSingerList_1.default,
66
+ getSimilarSinger: getSimilarSinger_1.default,
67
+ getSingerAlbum: getSingerAlbum_1.default,
68
+ getSingerHotsong: getSingerHotsong_1.default,
69
+ getSingerMv: getSingerMv_1.default,
70
+ getSingerDesc: getSingerDesc_1.default,
71
+ getSingerStarNum: getSingerStarNum_1.default,
72
+ getRadioLists: getRadioLists_1.default,
73
+ getDigitalAlbumLists: getDigitalAlbumLists_1.default,
74
+ getLyric: getLyric_1.default,
75
+ getMusicPlay: getMusicPlay_1.default,
76
+ getAlbumInfo: getAlbumInfo_1.default,
77
+ getComments: getComments_1.default,
78
+ getRecommend: getRecommend_1.default,
79
+ getMvPlay: getMvPlay_1.default,
80
+ getTopLists: getTopLists_1.default,
81
+ getRanks: getRanks_1.default,
82
+ getTicketInfo: getTicketInfo_1.default,
83
+ getImageUrl: getImageUrl_1.default,
84
+ getQQLoginQr: getQQLoginQr_1.default,
85
+ checkQQLoginQr: checkQQLoginQr_1.default,
86
+ getUserPlaylists: getUserPlaylists_1.default,
87
+ getUserAvatar: getUserAvatar_1.default,
88
+ getUserLikedSongs: getUserLikedSongs_1.default,
89
+ getDailyRecommend: getDailyRecommend_1.getDailyRecommendController,
90
+ getPrivateFM: getDailyRecommend_1.getPrivateFMController,
91
+ getNewSongs: getDailyRecommend_1.getNewSongsController,
92
+ getPersonalRecommend: getPersonalRecommend_1.getPersonalRecommendController,
93
+ getSimilarSongs: getPersonalRecommend_1.getSimilarSongsController,
94
+ getPlaylistTags: getPlaylistTags_1.getPlaylistTagsController,
95
+ getPlaylistsByTag: getPlaylistTags_1.getPlaylistsByTagController,
96
+ getHotComments: getPlaylistTags_1.getHotCommentsController,
97
+ getSingerListByArea: getPlaylistTags_1.getSingerListByAreaController
107
98
  };
@@ -5,6 +5,8 @@ exports.createPostController = createPostController;
5
5
  exports.validateRequired = validateRequired;
6
6
  exports.handleControllerResponse = handleControllerResponse;
7
7
  exports.createCustomController = createCustomController;
8
+ exports.setApiResponse = setApiResponse;
9
+ exports.withErrorHandler = withErrorHandler;
8
10
  const INTERNAL_ERROR_MESSAGE = '服务器内部错误';
9
11
  const normalizeErrorMessage = (error) => {
10
12
  if (error instanceof Error && error.message) {
@@ -186,3 +188,32 @@ function createCustomController(handler, apiFunction) {
186
188
  }
187
189
  };
188
190
  }
191
+ /**
192
+ * 统一处理 API 响应并设置到 Koa 上下文
193
+ * @param ctx - Koa 上下文
194
+ * @param apiResponse - API 响应对象
195
+ */
196
+ function setApiResponse(ctx, apiResponse) {
197
+ ctx.status = apiResponse.status || 500;
198
+ ctx.body = apiResponse.body;
199
+ }
200
+ /**
201
+ * 包装异步控制器,自动处理错误
202
+ * @param handler - 控制器处理函数
203
+ * @returns 包装后的控制器
204
+ */
205
+ function withErrorHandler(handler) {
206
+ return async (ctx, next) => {
207
+ try {
208
+ await handler(ctx);
209
+ await next();
210
+ }
211
+ catch (error) {
212
+ console.error('Controller error:', error);
213
+ ctx.status = 502;
214
+ ctx.body = {
215
+ error: error.message || '服务器内部错误',
216
+ };
217
+ }
218
+ };
219
+ }
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ /**
3
+ * 运行测试并生成带 flags 的覆盖率报告
4
+ *
5
+ * 用法:
6
+ * - 运行所有测试:npm run test:flags
7
+ * - 只运行单元测试:npm run test:flags:unit
8
+ *
9
+ * 注意:此脚本通过 tsx 运行,不使用 ts-node
10
+ */
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || (function () {
28
+ var ownKeys = function(o) {
29
+ ownKeys = Object.getOwnPropertyNames || function (o) {
30
+ var ar = [];
31
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
+ return ar;
33
+ };
34
+ return ownKeys(o);
35
+ };
36
+ return function (mod) {
37
+ if (mod && mod.__esModule) return mod;
38
+ var result = {};
39
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
+ __setModuleDefault(result, mod);
41
+ return result;
42
+ };
43
+ })();
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ const child_process_1 = require("child_process");
46
+ const fs = __importStar(require("fs"));
47
+ const path = __importStar(require("path"));
48
+ const ROOT_DIR = path.resolve(__dirname, '..');
49
+ const COVERAGE_DIR = path.join(ROOT_DIR, 'coverage');
50
+ // 确保覆盖率目录存在
51
+ if (!fs.existsSync(COVERAGE_DIR)) {
52
+ fs.mkdirSync(COVERAGE_DIR, { recursive: true });
53
+ }
54
+ /**
55
+ * 运行命令
56
+ * 注意:command 参数必须是硬编码的命令字符串,不能包含用户输入
57
+ * @param command - 要执行的命令(必须是硬编码字符串)
58
+ * @param env - 环境变量
59
+ */
60
+ function runCommand(command, env = {}) {
61
+ try {
62
+ // 使用 execSync 执行命令,命令必须是固定的字符串
63
+ // 安全说明:此函数只能用于执行硬编码的命令,不接受外部输入
64
+ // 所有调用此函数的地方都必须使用字符串字面量
65
+ (0, child_process_1.execSync)(command, {
66
+ stdio: 'inherit',
67
+ env: { ...process.env, ...env },
68
+ cwd: ROOT_DIR
69
+ });
70
+ }
71
+ catch (error) {
72
+ console.error(`命令执行失败:${command}`);
73
+ throw error;
74
+ }
75
+ }
76
+ /**
77
+ * 运行 Jest 测试(安全版本)
78
+ * 使用参数化方式执行 Jest,避免命令注入风险
79
+ * @param args - Jest 命令行参数数组
80
+ * @param env - 环境变量
81
+ */
82
+ function runJest(args, env = {}) {
83
+ const command = `npx jest ${args.join(' ')}`;
84
+ return runCommand(command, env);
85
+ }
86
+ function runUnitTests() {
87
+ console.log('\n🧪 运行单元测试...\n');
88
+ // 运行单元测试 - 使用参数化方式
89
+ runJest(['--coverage', '--testPathPattern=tests/unit'], {
90
+ JEST_JUNIT_OUTPUT_NAME: 'unit-test-results.xml',
91
+ COVERAGE_FILE: 'coverage/unit-coverage.json'
92
+ });
93
+ // 移动覆盖率文件
94
+ const coverageFile = path.join(COVERAGE_DIR, 'coverage-final.json');
95
+ if (fs.existsSync(coverageFile)) {
96
+ const unitCoverageFile = path.join(COVERAGE_DIR, 'unit-coverage-final.json');
97
+ fs.copyFileSync(coverageFile, unitCoverageFile);
98
+ console.log(`✅ 单元测试覆盖率已保存到:${unitCoverageFile}`);
99
+ }
100
+ }
101
+ function runAllTests() {
102
+ console.log('\n🧪 运行所有测试...\n');
103
+ // 运行所有测试 - 使用参数化方式
104
+ runJest(['--coverage'], {
105
+ JEST_JUNIT_OUTPUT_NAME: 'test-results.xml',
106
+ COVERAGE_FILE: 'coverage/all-coverage.json'
107
+ });
108
+ // 移动覆盖率文件
109
+ const coverageFile = path.join(COVERAGE_DIR, 'coverage-final.json');
110
+ if (fs.existsSync(coverageFile)) {
111
+ const allCoverageFile = path.join(COVERAGE_DIR, 'all-coverage-final.json');
112
+ fs.copyFileSync(coverageFile, allCoverageFile);
113
+ console.log(`✅ 所有测试覆盖率已保存到:${allCoverageFile}`);
114
+ }
115
+ }
116
+ function main() {
117
+ const args = process.argv.slice(2);
118
+ const testType = args[0] || 'all';
119
+ console.log('🚀 开始运行测试...\n');
120
+ try {
121
+ if (testType === 'unit') {
122
+ runUnitTests();
123
+ }
124
+ else if (testType === 'all') {
125
+ runAllTests();
126
+ }
127
+ else {
128
+ console.error(`❌ 未知的测试类型:${testType}`);
129
+ console.error('可用选项:unit, all');
130
+ process.exit(1);
131
+ }
132
+ console.log('\n✅ 测试完成!\n');
133
+ }
134
+ catch (error) {
135
+ console.error('\n❌ 测试失败!\n');
136
+ process.exit(1);
137
+ }
138
+ }
139
+ main();
@@ -1,19 +1,27 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ const service_config_1 = __importDefault(require("../config/service-config"));
7
+ const cookieResolver_1 = require("./cookieResolver");
3
8
  const SAFE_COOKIE_NAMES = new Set(['qqmusic_key', 'qqmusic_uin']);
4
9
  const cookieMiddleware = () => async (ctx, next) => {
5
- if (global.userInfo?.cookie) {
6
- // Extend Request interface if needed, or just cast
7
- ctx.request.cookie = global.userInfo.cookie;
10
+ const { cookie } = (0, cookieResolver_1.resolveRequestCookie)(ctx, {
11
+ fallbackMode: service_config_1.default.fallbackMode,
12
+ useGlobalCookie: service_config_1.default.useGlobalCookie,
13
+ cookieParamName: service_config_1.default.cookieParamName
14
+ });
15
+ if (cookie) {
16
+ (0, cookieResolver_1.setRequestCookieContext)(ctx, cookie);
8
17
  }
9
- if (Array.isArray(global.userInfo?.cookieList)) {
10
- global.userInfo.cookieList.forEach((cookie) => {
11
- const [key, ...valueParts] = cookie.split('=');
18
+ if (service_config_1.default.useGlobalCookie && Array.isArray(global.userInfo?.cookieList)) {
19
+ global.userInfo.cookieList.forEach((cookieItem) => {
20
+ const [key, ...valueParts] = cookieItem.split('=');
12
21
  const normalizedKey = key?.trim();
13
22
  const value = valueParts.join('=').trim();
14
23
  if (normalizedKey && value && SAFE_COOKIE_NAMES.has(normalizedKey)) {
15
24
  ctx.cookies.set(normalizedKey, value, {
16
- // 仅同步前端业务必需且可公开的 Cookie,避免敏感登录态透传
17
25
  overwrite: true,
18
26
  httpOnly: false,
19
27
  sameSite: 'lax'