在电脑上将QQ音乐导入到网易云

被浏览

最近帮一位朋友把 QQ 音乐歌单里的歌曲导入到网易云音乐,虽然手机端有音乐导入的选项,但她似乎觉得不是很好用。

在网上也没有这类的教程,全是把网易云导入到 QQ 音乐的(笑),只好借助别人造好的轮子实现了一个。

链接:https://github.com/sxyugao/QQMusicToNetease

以下是实现过程,不感兴趣的朋友可以不看。

QQMusicApiNeteaseCloudMusicApi 克隆到本地,先熟悉一下接口。

节选一段通过 QQMusicApi 获得的 QQ 音乐歌单信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
{
"albumdesc": "",
"albumid": 1526209,
"albummid": "0007oL0R1hDyxV",
"albumname": "君の名は。 (《你的名字。》动画电影原声带)",
"alertid": 2,
"belongCD": 21,
"cdIdx": 0,
"interval": 243,
"isonly": 0,
"label": "4611686018431582240",
"msgid": 13,
"pay": {
"payalbum": 0,
"payalbumprice": 0,
"paydownload": 1,
"payinfo": 1,
"payplay": 1,
"paytrackmouth": 1,
"paytrackprice": 200,
"timefree": 0
},
"preview": { "trybegin": 0, "tryend": 0, "trysize": 960887 },
"rate": 0,
"singer": [
{
"id": 9962,
"mid": "000f1b6W1wzyRN",
"name": "RADWIMPS (ラッドウィンプス)"
}
],
"size128": 3893085,
"size320": 9732393,
"size5_1": 0,
"sizeape": 0,
"sizeflac": 38430893,
"sizeogg": 5040946,
"songid": 107762026,
"songmid": "000HHwBt3KESHr",
"songname": "三葉のテーマ (三叶的主题音乐)",
"songorig": "三葉のテーマ",
"songtype": 0,
"strMediaMid": "000rw7Do2ey9VI",
"stream": 0,
"switch": 17401089,
"type": 0,
"vid": ""
}

稍微分析一下,便会发现用 songorig 字段去搜索是最为靠谱的。

下面是通过 NeteaseCloudMusicApi 搜索到的歌曲信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
{
"result": {
"songs": [
{
"id": 1406638282,
"name": "三葉のテーマ",
"artists": [
{
"id": 33288488,
"name": "屈艳宇",
"picUrl": null,
"alias": [],
"albumSize": 0,
"picId": 0,
"img1v1Url": "https://p1.music.126.net/6y-UleORITEDbvrOLV0Q8A==/5639395138885805.jpg",
"img1v1": 0,
"trans": null
}
],
"album": {
"id": 81755365,
"name": "Vinky is a cat",
"artist": {
"id": 0,
"name": "",
"picUrl": null,
"alias": [],
"albumSize": 0,
"picId": 0,
"img1v1Url": "https://p1.music.126.net/6y-UleORITEDbvrOLV0Q8A==/5639395138885805.jpg",
"img1v1": 0,
"trans": null
},
"publishTime": 1569142910676,
"size": 7,
"copyrightId": 0,
"status": 0,
"picId": 109951164380589660,
"mark": 0
},
"duration": 240455,
"copyrightId": 0,
"status": 0,
"alias": [],
"rtype": 0,
"ftype": 0,
"mvid": 0,
"fee": 8,
"rUrl": null,
"mark": 64
}
],
"hasMore": true,
"songCount": 74
},
"code": 200
}

上面我传的参数是 limit=1,虽然可以发现排在第一位的并不是 QQ 音乐的原曲,但是如果去试听一下就会发现是差不多的,出现这个现象是因为原曲已经变成了付费歌曲。

说起来网易云真是贴心,搜出来的第一个就是穷人版的欸,所以就放心大胆地直接用第一个吧。

因为 NeteaseCloudMusicApi 向歌单添加歌曲的接口 /playlist/tracks 要求传入的是歌曲 id,所以我们到时候传的是 res.result.songs[0].id

熟悉好接口后我们就可以开始了。

实现思路非常 simple,就是先获取 QQ 音乐歌单里的歌曲,再在网易云音乐搜索相关歌曲,将关联度最高的导入网易云音乐。

说起来简单,可是实际操作起来还是碰上了问题。由于我的 JavaScript 只是半吊子水平,所以最开始碰到异步过程不按顺序执行头痛不已:每次在请求完成之前都会继续执行,完全摸不着头脑。

在我一筹莫展之际,突然想起来 swwind 学长曾带着我这个小萌新做的 user-scripts,他有一次在这个项目里使用了 Promise,还向我推销过这个特性。

那么为什么不试试 Promise 呢?这次我是独立操作,在上网查阅了基本资料后,不禁也和学长当时一样惊呼:“Promise 大法好!”

用了 Promise 后,代码变得简洁易懂多了。

贴一下核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const option = {
headers: {
'cookie': null
}
};
const NeteaseAPI = (url) => {
return new Promise((resolve, reject) => {
http.get(url, option, (req) => {
let s = "";
req.on('data', (data) => {
s += data;
});
req.on('end', () => {
resolve(JSON.parse(s));
})
})
})
}

使用的时候就可以:

1
2
3
4
NeteaseAPI(request).then((res) => {
// res 是返回的数据
// 一些对 res 进行处理的代码
})

实际操作过程中,会出现歌单歌曲数目不一致,但对应的歌曲可以被找到的情况。根据返回的数据看,是由于付费歌曲无法通过这个接口加入歌单。举个例子,登录后传入 http://localhost:3000/playlist/tracks?op=add&pid=803049038&tracks=451703096,返回的信息为:

1
2
3
4
5
6
7
{
"message":"未付费歌曲无法收藏",
"trackIds":"[451703096]",
"code":512,
"count":190,
"cloudCount":0
}

对这种情况稍加判断即可。(话说付费歌曲在客户端上是能收藏的,可能还有其他的接口吧)

最后实现的也比较简陋,只能说是勉强能用,就当是练手了。

P.S. 写代码的时候因为判断等于用了 = 调试了很久,学校教 VB 真是害人不浅啊!