最近帮一位朋友把 QQ 音乐歌单里的歌曲导入到网易云音乐,虽然手机端有音乐导入的选项,但她似乎觉得不是很好用。
在网上也没有这类的教程,全是把网易云导入到 QQ 音乐的(笑),只好借助别人造好的轮子实现了一个。
链接:https://github.com/sxyugao/QQMusicToNetease
以下是实现过程,不感兴趣的朋友可以不看。
将 QQMusicApi 和 NeteaseCloudMusicApi 克隆到本地,先熟悉一下接口。
节选一段通过 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) => { })
|
实际操作过程中,会出现歌单歌曲数目不一致,但对应的歌曲可以被找到的情况。根据返回的数据看,是由于付费歌曲无法通过这个接口加入歌单。举个例子,登录后传入 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 真是害人不浅啊!