@sansenjian/qq-music-api 1.0.6 → 2.0.0

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 (94) hide show
  1. package/.babelrc +2 -2
  2. package/.dockerignore +5 -5
  3. package/.editorconfig +31 -31
  4. package/.eslintrc.json +21 -17
  5. package/.github/FUNDING.yml +12 -12
  6. package/.github/ISSUE_TEMPLATE/bug_report.md +38 -38
  7. package/.github/ISSUE_TEMPLATE/custom.md +24 -24
  8. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -20
  9. package/.github/workflows/publish.yml +26 -0
  10. package/.husky/commit-msg +1 -0
  11. package/.husky/pre-commit +1 -0
  12. package/.prettierignore +1 -1
  13. package/.prettierrc +9 -9
  14. package/CHANGELOG.md +70 -70
  15. package/Dockerfile +18 -18
  16. package/LICENSE +21 -21
  17. package/README.md +218 -177
  18. package/app.js +75 -75
  19. package/commitlint.config.js +20 -20
  20. package/config/user-info.js +42 -42
  21. package/index.js +1 -1
  22. package/middlewares/koa-cors.js +97 -97
  23. package/module/apis/UCommon/UCommon.js +6 -6
  24. package/module/apis/album/getAlbumInfo.js +33 -33
  25. package/module/apis/comments/getComments.js +35 -35
  26. package/module/apis/digitalAlbum/getDigitalAlbumLists.js +34 -34
  27. package/module/apis/downloadQQMusic.js +41 -41
  28. package/module/apis/music/getLyric.js +42 -41
  29. package/module/apis/mv/getMvByTag.js +35 -35
  30. package/module/apis/radio/getRadioLists.js +38 -38
  31. package/module/apis/rank/getTopLists.js +44 -44
  32. package/module/apis/search/getHotKey.js +35 -35
  33. package/module/apis/search/getSearchByKey.js +45 -45
  34. package/module/apis/search/getSmartbox.js +34 -34
  35. package/module/apis/singers/getSimilarSinger.js +36 -36
  36. package/module/apis/singers/getSingerDesc.js +38 -38
  37. package/module/apis/singers/getSingerMv.js +35 -35
  38. package/module/apis/singers/getSingerStarNum.js +36 -36
  39. package/module/apis/songLists/songListCategories.js +33 -33
  40. package/module/apis/songLists/songListDetail.js +38 -38
  41. package/module/apis/songLists/songLists.js +41 -41
  42. package/module/apis/u_common.js +17 -16
  43. package/module/apis/user/checkQQLoginQr.js +125 -86
  44. package/module/apis/user/getQQLoginQr.js +17 -11
  45. package/module/apis/y_common.js +27 -14
  46. package/module/config.js +31 -31
  47. package/module/index.js +82 -82
  48. package/package.json +72 -83
  49. package/public/index.html +47 -47
  50. package/routers/context/batchGetSongInfo.js +59 -59
  51. package/routers/context/batchGetSongLists.js +50 -50
  52. package/routers/context/checkQQLoginQr.js +17 -15
  53. package/routers/context/cookies.js +36 -36
  54. package/routers/context/getAlbumInfo.js +27 -27
  55. package/routers/context/getComments.js +51 -51
  56. package/routers/context/getDigitalAlbumLists.js +14 -14
  57. package/routers/context/getDownloadQQMusic.js +14 -14
  58. package/routers/context/getHotkey.js +14 -14
  59. package/routers/context/getImageUrl.js +34 -34
  60. package/routers/context/getLyric.js +26 -26
  61. package/routers/context/getMusicPlay.js +116 -112
  62. package/routers/context/getMv.js +56 -56
  63. package/routers/context/getMvByTag.js +15 -15
  64. package/routers/context/getMvPlay.js +128 -118
  65. package/routers/context/getNewDisks.js +50 -51
  66. package/routers/context/getQQLoginQr.js +12 -12
  67. package/routers/context/getRadioLists.js +14 -14
  68. package/routers/context/getRanks.js +90 -86
  69. package/routers/context/getRecommend.js +86 -86
  70. package/routers/context/getSearchByKey.js +32 -32
  71. package/routers/context/getSimilarSinger.js +25 -25
  72. package/routers/context/getSingerAlbum.js +52 -52
  73. package/routers/context/getSingerDesc.js +25 -25
  74. package/routers/context/getSingerHotsong.js +52 -52
  75. package/routers/context/getSingerList.js +51 -52
  76. package/routers/context/getSingerMv.js +32 -32
  77. package/routers/context/getSingerStarNum.js +24 -24
  78. package/routers/context/getSmartbox.js +24 -24
  79. package/routers/context/getSongInfo.js +49 -49
  80. package/routers/context/getSongListCategories.js +22 -22
  81. package/routers/context/getSongListDetail.js +25 -25
  82. package/routers/context/getSongLists.js +32 -32
  83. package/routers/context/getTicketInfo.js +45 -45
  84. package/routers/context/getTopLists.js +15 -15
  85. package/routers/context/index.js +74 -74
  86. package/routers/router.js +116 -112
  87. package/scripts/build-images.js +36 -36
  88. package/scripts/commit-push.sh +103 -103
  89. package/util/colors.js +16 -16
  90. package/util/cookie.js +22 -22
  91. package/util/loginUtils.js +28 -23
  92. package/util/lyricParse.js +64 -64
  93. package/util/request.js +57 -57
  94. package/vercel.json +15 -15
@@ -1,112 +1,116 @@
1
- const { UCommon } = require('../../module');
2
- const { _guid } = require('../../module/config');
3
- const get = require('lodash.get');
4
-
5
- // songmid=003rJSwm3TechU
6
- // songmid=001yNIo41SJjuC,001wPuVc4ZiMhj
7
- module.exports = async (ctx, next) => {
8
- const uin = global.userInfo.uin || '0';
9
- const songmid = ctx.query.songmid + '';
10
- // response data only need play url value (all play)
11
- const justPlayUrl = (ctx.query.resType || 'play') === 'play';
12
- const guid = _guid ? _guid + '' : '1429839143';
13
- let {quality = 128, mediaId} = ctx.query;
14
- const fileType = {
15
- m4a: {
16
- s: 'C400',
17
- e: '.m4a',
18
- },
19
- 128: {
20
- s: 'M500',
21
- e: '.mp3',
22
- },
23
- 320: {
24
- s: 'M800',
25
- e: '.mp3',
26
- },
27
- ape: {
28
- s: 'A000',
29
- e: '.ape',
30
- },
31
- flac: {
32
- s: 'F000',
33
- e: '.flac',
34
- }
35
- };
36
- const songmidList = songmid.split(',');
37
- const fileInfo = fileType[quality];
38
- const file = songmidList.map(_ => `${fileInfo.s}${_}${mediaId || _}${fileInfo.e}`);
39
- const data = {
40
- // req: {
41
- // module: 'CDN.SrfCdnDispatchServer',
42
- // method: 'GetCdnDispatch',
43
- // param: {
44
- // guid,
45
- // calltype: 0,
46
- // userip: '',
47
- // },
48
- // },
49
- req_0: {
50
- module: 'vkey.GetVkeyServer',
51
- method: 'CgiGetVkey',
52
- param: {
53
- filename: file,
54
- guid,
55
- songmid: songmidList,
56
- songtype: [0],
57
- uin,
58
- loginflag: 1,
59
- platform: '20',
60
- },
61
- },
62
- loginUin: uin,
63
- comm: {
64
- uin,
65
- format: 'json',
66
- ct: 24,
67
- cv: 0,
68
- },
69
- };
70
- const params = Object.assign({
71
- format: 'json',
72
- sign: 'zzannc1o6o9b4i971602f3554385022046ab796512b7012',
73
- data: JSON.stringify(data),
74
- });
75
- const props = {
76
- method: 'get',
77
- params,
78
- option: {},
79
- };
80
-
81
- if (songmid) {
82
- await UCommon(props)
83
- .then(res => {
84
- const response = res.data;
85
- const domain = get(response, 'req_0.data.sip', [])
86
- .find(i => !i.startsWith('http://ws'))
87
- || get(response, 'req_0.data.sip[0]');
88
-
89
- let playUrl = {};
90
- get(response, 'req_0.data.midurlinfo', []).forEach((item) => {
91
- playUrl[item.songmid] = {
92
- url: item.purl ? `${domain}${item.purl}` : '',
93
- error: !item.purl && '暂无播放链接'
94
- };
95
- });
96
- response.playUrl = playUrl;
97
- ctx.body = {
98
- data: justPlayUrl ? {playUrl} : response,
99
- };
100
- })
101
- .catch(error => {
102
- console.log('error', error);
103
- });
104
- } else {
105
- ctx.status = 400;
106
- ctx.body = {
107
- data: {
108
- message: 'no songmid',
109
- }
110
- };
111
- }
112
- };
1
+ const { UCommon } = require('../../module');
2
+ const { _guid } = require('../../module/config');
3
+
4
+ const ALLOWED_QUALITIES = ['m4a', 128, 320, 'ape', 'flac'];
5
+ const DEFAULT_QUALITY = 128;
6
+
7
+ const parseQuality = quality => {
8
+ const parsed = parseInt(quality) || quality;
9
+ return ALLOWED_QUALITIES.includes(parsed) ? parsed : DEFAULT_QUALITY;
10
+ };
11
+
12
+ module.exports = async (ctx, next) => {
13
+ const uin = global.userInfo.uin || '0';
14
+ const songmid = ctx.query.songmid + '';
15
+ const justPlayUrl = (ctx.query.resType || 'play') === 'play';
16
+ const guid = _guid ? _guid + '' : '1429839143';
17
+ const { mediaId } = ctx.query;
18
+ const quality = parseQuality(ctx.query.quality);
19
+ const fileType = {
20
+ m4a: {
21
+ s: 'C400',
22
+ e: '.m4a',
23
+ },
24
+ 128: {
25
+ s: 'M500',
26
+ e: '.mp3',
27
+ },
28
+ 320: {
29
+ s: 'M800',
30
+ e: '.mp3',
31
+ },
32
+ ape: {
33
+ s: 'A000',
34
+ e: '.ape',
35
+ },
36
+ flac: {
37
+ s: 'F000',
38
+ e: '.flac',
39
+ },
40
+ };
41
+ const songmidList = songmid.split(',');
42
+ const fileInfo = fileType[quality];
43
+ const file = songmidList.map(_ => `${fileInfo.s}${_}${mediaId || _}${fileInfo.e}`);
44
+ const data = {
45
+ // req: {
46
+ // module: 'CDN.SrfCdnDispatchServer',
47
+ // method: 'GetCdnDispatch',
48
+ // param: {
49
+ // guid,
50
+ // calltype: 0,
51
+ // userip: '',
52
+ // },
53
+ // },
54
+ req_0: {
55
+ module: 'vkey.GetVkeyServer',
56
+ method: 'CgiGetVkey',
57
+ param: {
58
+ filename: file,
59
+ guid,
60
+ songmid: songmidList,
61
+ songtype: [0],
62
+ uin,
63
+ loginflag: 1,
64
+ platform: '20',
65
+ },
66
+ },
67
+ loginUin: uin,
68
+ comm: {
69
+ uin,
70
+ format: 'json',
71
+ ct: 24,
72
+ cv: 0,
73
+ },
74
+ };
75
+ const params = Object.assign({
76
+ format: 'json',
77
+ sign: 'zzannc1o6o9b4i971602f3554385022046ab796512b7012',
78
+ data: JSON.stringify(data),
79
+ });
80
+ const props = {
81
+ method: 'get',
82
+ params,
83
+ option: {},
84
+ };
85
+
86
+ if (songmid) {
87
+ await UCommon(props)
88
+ .then(res => {
89
+ const response = res.data;
90
+ const domain =
91
+ response?.req_0?.data?.sip?.filter?.(i => !i.startsWith('http://ws'))?.[0] || response?.req_0?.data?.sip?.[0];
92
+
93
+ const playUrl = {};
94
+ (response?.req_0?.data?.midurlinfo || []).forEach(item => {
95
+ playUrl[item.songmid] = {
96
+ url: item.purl ? `${domain}${item.purl}` : '',
97
+ error: !item.purl && '暂无播放链接',
98
+ };
99
+ });
100
+ response.playUrl = playUrl;
101
+ ctx.body = {
102
+ data: justPlayUrl ? { playUrl } : response,
103
+ };
104
+ })
105
+ .catch(error => {
106
+ console.log('error', error);
107
+ });
108
+ } else {
109
+ ctx.status = 400;
110
+ ctx.body = {
111
+ data: {
112
+ message: 'no songmid',
113
+ },
114
+ };
115
+ }
116
+ };
@@ -1,56 +1,56 @@
1
- const { UCommon } = require('../../module');
2
-
3
- // area_id=15&version_id=7
4
- module.exports = async (ctx, next) => {
5
- // BUGFIX: https://github.com/Rain120/qq-music-api/issues/16#issuecomment-638230301
6
- const { area_id = 15, version_id = 7, limit = 20, page = 0 } = ctx.query;
7
- const start = (+page ? +page - 1 : 0) * +limit;
8
- const data = {
9
- comm: {
10
- ct: 24,
11
- },
12
- mv_tag: {
13
- module: 'MvService.MvInfoProServer',
14
- method: 'GetAllocTag',
15
- param: {},
16
- },
17
- mv_list: {
18
- module: 'MvService.MvInfoProServer',
19
- method: 'GetAllocMvInfo',
20
- param: {
21
- start,
22
- limit: +limit,
23
- version_id,
24
- area_id,
25
- order: 1,
26
- },
27
- },
28
- };
29
- const params = Object.assign({
30
- format: 'json',
31
- data: JSON.stringify(data),
32
- });
33
- const props = {
34
- method: 'get',
35
- params,
36
- option: {},
37
- };
38
- if (version_id && area_id) {
39
- await UCommon(props)
40
- .then(res => {
41
- const response = res.data;
42
- ctx.status = 200;
43
- ctx.body = {
44
- response,
45
- };
46
- })
47
- .catch(error => {
48
- console.log('error', error);
49
- });
50
- } else {
51
- ctx.status = 400;
52
- ctx.body = {
53
- response: 'version_id or area_id is null',
54
- };
55
- }
56
- };
1
+ const { UCommon } = require('../../module');
2
+
3
+ // area_id=15&version_id=7
4
+ module.exports = async (ctx, next) => {
5
+ // BUGFIX: https://github.com/Rain120/qq-music-api/issues/16#issuecomment-638230301
6
+ const { area_id = 15, version_id = 7, limit = 20, page = 0 } = ctx.query;
7
+ const start = (+page ? +page - 1 : 0) * +limit;
8
+ const data = {
9
+ comm: {
10
+ ct: 24,
11
+ },
12
+ mv_tag: {
13
+ module: 'MvService.MvInfoProServer',
14
+ method: 'GetAllocTag',
15
+ param: {},
16
+ },
17
+ mv_list: {
18
+ module: 'MvService.MvInfoProServer',
19
+ method: 'GetAllocMvInfo',
20
+ param: {
21
+ start,
22
+ limit: +limit,
23
+ version_id,
24
+ area_id,
25
+ order: 1,
26
+ },
27
+ },
28
+ };
29
+ const params = Object.assign({
30
+ format: 'json',
31
+ data: JSON.stringify(data),
32
+ });
33
+ const props = {
34
+ method: 'get',
35
+ params,
36
+ option: {},
37
+ };
38
+ if (version_id && area_id) {
39
+ await UCommon(props)
40
+ .then(res => {
41
+ const response = res.data;
42
+ ctx.status = 200;
43
+ ctx.body = {
44
+ response,
45
+ };
46
+ })
47
+ .catch(error => {
48
+ console.log('error', error);
49
+ });
50
+ } else {
51
+ ctx.status = 400;
52
+ ctx.body = {
53
+ response: 'version_id or area_id is null',
54
+ };
55
+ }
56
+ };
@@ -1,15 +1,15 @@
1
- const { getMvByTag } = require('../../module');
2
-
3
- // songmid=001CLC7W2Gpz4J
4
- module.exports = async (ctx, next) => {
5
- const props = {
6
- method: 'get',
7
- params: {},
8
- option: {},
9
- };
10
- const { status, body } = await getMvByTag(props);
11
- Object.assign(ctx, {
12
- status,
13
- body,
14
- });
15
- };
1
+ const { getMvByTag } = require('../../module');
2
+
3
+ // songmid=001CLC7W2Gpz4J
4
+ module.exports = async (ctx, next) => {
5
+ const props = {
6
+ method: 'get',
7
+ params: {},
8
+ option: {},
9
+ };
10
+ const { status, body } = await getMvByTag(props);
11
+ Object.assign(ctx, {
12
+ status,
13
+ body,
14
+ });
15
+ };
@@ -1,118 +1,128 @@
1
- const { UCommon } = require('../../module');
2
-
3
- // vid=u00222le4ox
4
- module.exports = async (ctx, next) => {
5
- const { vid } = ctx.query;
6
- const data = {
7
- comm: {
8
- ct: 24,
9
- cv: 4747474,
10
- },
11
- getMVUrl: {
12
- module: 'gosrf.Stream.MvUrlProxy',
13
- method: 'GetMvUrls',
14
- param: {
15
- vids: [vid],
16
- request_typet: 10001,
17
- },
18
- },
19
- mvinfo: {
20
- module: 'video.VideoDataServer',
21
- method: 'get_video_info_batch',
22
- param: {
23
- vidlist: [vid],
24
- required: [
25
- 'vid',
26
- 'type',
27
- 'sid',
28
- 'cover_pic',
29
- 'duration',
30
- 'singers',
31
- 'video_switch',
32
- 'msg',
33
- 'name',
34
- 'desc',
35
- 'playcnt',
36
- 'pubdate',
37
- 'isfav',
38
- 'gmid',
39
- ],
40
- },
41
- },
42
- other: {
43
- module: 'video.VideoLogicServer',
44
- method: 'rec_video_byvid',
45
- param: {
46
- vid,
47
- required: [
48
- 'vid',
49
- 'type',
50
- 'sid',
51
- 'cover_pic',
52
- 'duration',
53
- 'singers',
54
- 'video_switch',
55
- 'msg',
56
- 'name',
57
- 'desc',
58
- 'playcnt',
59
- 'pubdate',
60
- 'isfav',
61
- 'gmid',
62
- 'uploader_headurl',
63
- 'uploader_nick',
64
- 'uploader_encuin',
65
- 'uploader_uin',
66
- 'uploader_hasfollow',
67
- 'uploader_follower_num',
68
- ],
69
- support: 1,
70
- },
71
- },
72
- };
73
- const params = Object.assign({
74
- format: 'json',
75
- data: JSON.stringify(data),
76
- });
77
- const props = {
78
- method: 'get',
79
- params,
80
- option: {},
81
- };
82
- if (vid) {
83
- await UCommon(props)
84
- .then(res => {
85
- const response = res.data;
86
- let mvurls = response.getMVUrl.data;
87
- let mvurlskey = Object.keys(mvurls)[0];
88
- let mp4_urls = mvurls[mvurlskey].mp4.map(item => item.freeflow_url);
89
- let hls_urls = mvurls[mvurlskey].hls.map(item => item.freeflow_url);
90
- let urls = [...mp4_urls, ...hls_urls];
91
- let play_urls = [];
92
- let playLists = {};
93
- urls.length &&
94
- urls.forEach(url => {
95
- play_urls = [...play_urls, ...url];
96
- });
97
- playLists = {
98
- f10: play_urls.filter(item => /\.f10\.mp4/.test(item)),
99
- f20: play_urls.filter(item => /\.f20\.mp4/.test(item)),
100
- f30: play_urls.filter(item => /\.f30\.mp4/.test(item)),
101
- f40: play_urls.filter(item => /\.f40\.mp4/.test(item)),
102
- };
103
- response.playLists = playLists;
104
- ctx.status = 200;
105
- ctx.body = {
106
- response,
107
- };
108
- })
109
- .catch(error => {
110
- console.log('error', error);
111
- });
112
- } else {
113
- ctx.status = 400;
114
- ctx.body = {
115
- response: 'vid is null',
116
- };
117
- }
118
- };
1
+ const { UCommon } = require('../../module');
2
+
3
+ // vid=u00222le4ox
4
+ module.exports = async (ctx, next) => {
5
+ const { vid } = ctx.query;
6
+ const data = {
7
+ comm: {
8
+ ct: 24,
9
+ cv: 4747474,
10
+ },
11
+ getMVUrl: {
12
+ module: 'gosrf.Stream.MvUrlProxy',
13
+ method: 'GetMvUrls',
14
+ param: {
15
+ vids: [vid],
16
+ request_typet: 10001,
17
+ },
18
+ },
19
+ mvinfo: {
20
+ module: 'video.VideoDataServer',
21
+ method: 'get_video_info_batch',
22
+ param: {
23
+ vidlist: [vid],
24
+ required: [
25
+ 'vid',
26
+ 'type',
27
+ 'sid',
28
+ 'cover_pic',
29
+ 'duration',
30
+ 'singers',
31
+ 'video_switch',
32
+ 'msg',
33
+ 'name',
34
+ 'desc',
35
+ 'playcnt',
36
+ 'pubdate',
37
+ 'isfav',
38
+ 'gmid',
39
+ ],
40
+ },
41
+ },
42
+ other: {
43
+ module: 'video.VideoLogicServer',
44
+ method: 'rec_video_byvid',
45
+ param: {
46
+ vid,
47
+ required: [
48
+ 'vid',
49
+ 'type',
50
+ 'sid',
51
+ 'cover_pic',
52
+ 'duration',
53
+ 'singers',
54
+ 'video_switch',
55
+ 'msg',
56
+ 'name',
57
+ 'desc',
58
+ 'playcnt',
59
+ 'pubdate',
60
+ 'isfav',
61
+ 'gmid',
62
+ 'uploader_headurl',
63
+ 'uploader_nick',
64
+ 'uploader_encuin',
65
+ 'uploader_uin',
66
+ 'uploader_hasfollow',
67
+ 'uploader_follower_num',
68
+ ],
69
+ support: 1,
70
+ },
71
+ },
72
+ };
73
+ const params = Object.assign({
74
+ format: 'json',
75
+ data: JSON.stringify(data),
76
+ });
77
+ const props = {
78
+ method: 'get',
79
+ params,
80
+ option: {},
81
+ };
82
+ if (vid) {
83
+ await UCommon(props)
84
+ .then(res => {
85
+ const response = res.data;
86
+ const mvurls = response?.getMVUrl?.data;
87
+ if (!mvurls || typeof mvurls !== 'object' || Object.keys(mvurls).length === 0) {
88
+ ctx.status = 502;
89
+ ctx.body = {
90
+ response: {
91
+ data: null,
92
+ error: 'Failed to get MV URL data',
93
+ },
94
+ };
95
+ return;
96
+ }
97
+ const mvurlskey = Object.keys(mvurls)[0];
98
+ const mp4_urls = mvurls[mvurlskey]?.mp4?.map(item => item.freeflow_url) || [];
99
+ const hls_urls = mvurls[mvurlskey]?.hls?.map(item => item.freeflow_url) || [];
100
+ const urls = [...mp4_urls, ...hls_urls];
101
+ let play_urls = [];
102
+ let playLists = {};
103
+ urls.length &&
104
+ urls.forEach(url => {
105
+ play_urls = [...play_urls, ...url];
106
+ });
107
+ playLists = {
108
+ f10: play_urls.filter(item => /\.f10\.mp4/.test(item)),
109
+ f20: play_urls.filter(item => /\.f20\.mp4/.test(item)),
110
+ f30: play_urls.filter(item => /\.f30\.mp4/.test(item)),
111
+ f40: play_urls.filter(item => /\.f40\.mp4/.test(item)),
112
+ };
113
+ response.playLists = playLists;
114
+ ctx.status = 200;
115
+ ctx.body = {
116
+ response,
117
+ };
118
+ })
119
+ .catch(error => {
120
+ console.log('error', error);
121
+ });
122
+ } else {
123
+ ctx.status = 400;
124
+ ctx.body = {
125
+ response: 'vid is null',
126
+ };
127
+ }
128
+ };