[\s\S]*?

[\s\S]*?
]*>([^<]+?)<\/a>[\s\S]*?]*>([^<]+?)<\/a>/g
+ let result,
+ playlists = []
+ while ((result = pattern.exec(response.body)) != null) {
+ playlists.push({
+ creator: {
+ userId: result[4].slice('/user/home?id='.length),
+ nickname: result[5],
+ },
+ coverImgUrl: result[1].slice(0, -'?param=50y50'.length),
+ name: result[3],
+ id: result[2].slice('/playlist?id='.length),
+ })
+ }
+ response.body = { code: 200, playlists: playlists }
+ return response
+ } catch (err) {
+ response.status = 500
+ response.body = { code: 500, msg: err.stack }
+ return Promise.reject(response)
+ }
+ })
+}
diff --git a/netease_api/module/resource_like.js b/netease_api/module/resource_like.js
new file mode 100644
index 0000000..de285b6
--- /dev/null
+++ b/netease_api/module/resource_like.js
@@ -0,0 +1,29 @@
+// 点赞与取消点赞资源
+
+module.exports = (query, request) => {
+ query.cookie.os = 'pc'
+ query.t = query.t == 1 ? 'like' : 'unlike'
+ query.type = {
+ 1: 'R_MV_5_', // MV
+ 4: 'A_DJ_1_', // 电台
+ 5: 'R_VI_62_', // 视频
+ 6: 'A_EV_2_',
+ }[query.type]
+ const data = {
+ threadId: query.type + query.id,
+ }
+ if (query.type === 'A_EV_2_') {
+ data.threadId = query.threadId
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/resource/${query.t}`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/scrobble.js b/netease_api/module/scrobble.js
new file mode 100644
index 0000000..ad542d5
--- /dev/null
+++ b/netease_api/module/scrobble.js
@@ -0,0 +1,27 @@
+// 听歌打卡
+
+module.exports = (query, request) => {
+ const data = {
+ logs: JSON.stringify([
+ {
+ action: 'play',
+ json: {
+ download: 0,
+ end: 'playend',
+ id: query.id,
+ sourceId: query.sourceid,
+ time: query.time,
+ type: 'song',
+ wifi: 0,
+ },
+ },
+ ]),
+ }
+
+ return request('POST', `https://music.163.com/weapi/feedback/weblog`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/search.js b/netease_api/module/search.js
new file mode 100644
index 0000000..b2e1ff9
--- /dev/null
+++ b/netease_api/module/search.js
@@ -0,0 +1,16 @@
+// 搜索
+
+module.exports = (query, request) => {
+ const data = {
+ s: query.keywords,
+ type: query.type || 1, // 1: 单曲, 10: 专辑, 100: 歌手, 1000: 歌单, 1002: 用户, 1004: MV, 1006: 歌词, 1009: 电台, 1014: 视频
+ limit: query.limit || 30,
+ offset: query.offset || 0,
+ }
+ return request('POST', `https://music.163.com/weapi/search/get`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/search_default.js b/netease_api/module/search_default.js
new file mode 100644
index 0000000..b573254
--- /dev/null
+++ b/netease_api/module/search_default.js
@@ -0,0 +1,16 @@
+// 默认搜索关键词
+
+module.exports = (query, request) => {
+ return request(
+ 'POST',
+ `https://interface3.music.163.com/eapi/search/defaultkeyword/get`,
+ {},
+ {
+ crypto: 'eapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ url: '/api/search/defaultkeyword/get',
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/search_hot.js b/netease_api/module/search_hot.js
new file mode 100644
index 0000000..75c95a6
--- /dev/null
+++ b/netease_api/module/search_hot.js
@@ -0,0 +1,14 @@
+// 热门搜索
+
+module.exports = (query, request) => {
+ const data = {
+ type: 1111,
+ }
+ return request('POST', `https://music.163.com/weapi/search/hot`, data, {
+ crypto: 'weapi',
+ ua: 'mobile',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/search_hot_detail.js b/netease_api/module/search_hot_detail.js
new file mode 100644
index 0000000..aae7c7e
--- /dev/null
+++ b/netease_api/module/search_hot_detail.js
@@ -0,0 +1,15 @@
+// 热搜列表
+module.exports = (query, request) => {
+ const data = {}
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/hotsearchlist/get`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/search_multimatch.js b/netease_api/module/search_multimatch.js
new file mode 100644
index 0000000..6e4c0e8
--- /dev/null
+++ b/netease_api/module/search_multimatch.js
@@ -0,0 +1,19 @@
+// 多类型搜索
+
+module.exports = (query, request) => {
+ const data = {
+ type: query.type || 1,
+ s: query.keywords || '',
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/search/suggest/multimatch`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/search_suggest.js b/netease_api/module/search_suggest.js
new file mode 100644
index 0000000..e78b255
--- /dev/null
+++ b/netease_api/module/search_suggest.js
@@ -0,0 +1,19 @@
+// 搜索建议
+
+module.exports = (query, request) => {
+ const data = {
+ s: query.keywords || '',
+ }
+ let type = query.type == 'mobile' ? 'keyword' : 'web'
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/search/suggest/` + type,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/send_album.js b/netease_api/module/send_album.js
new file mode 100644
index 0000000..8af5673
--- /dev/null
+++ b/netease_api/module/send_album.js
@@ -0,0 +1,18 @@
+// 私信专辑
+
+module.exports = (query, request) => {
+ query.cookie.os = 'ios'
+ query.cookie.appver = '8.1.20'
+ const data = {
+ id: query.id,
+ msg: query.msg || '',
+ type: 'album',
+ userIds: '[' + query.user_ids + ']',
+ }
+ return request('POST', `https://music.163.com/api/msg/private/send`, data, {
+ crypto: 'api',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/send_playlist.js b/netease_api/module/send_playlist.js
new file mode 100644
index 0000000..a1d9bd4
--- /dev/null
+++ b/netease_api/module/send_playlist.js
@@ -0,0 +1,17 @@
+// 私信歌单
+
+module.exports = (query, request) => {
+ query.cookie.os = 'pc'
+ const data = {
+ id: query.playlist,
+ type: 'playlist',
+ msg: query.msg,
+ userIds: '[' + query.user_ids + ']',
+ }
+ return request('POST', `https://music.163.com/weapi/msg/private/send`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/send_song.js b/netease_api/module/send_song.js
new file mode 100644
index 0000000..932cde1
--- /dev/null
+++ b/netease_api/module/send_song.js
@@ -0,0 +1,18 @@
+// 私信歌曲
+
+module.exports = (query, request) => {
+ query.cookie.os = 'ios'
+ query.cookie.appver = '8.1.20'
+ const data = {
+ id: query.id,
+ msg: query.msg || '',
+ type: 'song',
+ userIds: '[' + query.user_ids + ']',
+ }
+ return request('POST', `https://music.163.com/api/msg/private/send`, data, {
+ crypto: 'api',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/send_text.js b/netease_api/module/send_text.js
new file mode 100644
index 0000000..a13ad35
--- /dev/null
+++ b/netease_api/module/send_text.js
@@ -0,0 +1,16 @@
+// 私信
+
+module.exports = (query, request) => {
+ query.cookie.os = 'pc'
+ const data = {
+ type: 'text',
+ msg: query.msg,
+ userIds: '[' + query.user_ids + ']',
+ }
+ return request('POST', `https://music.163.com/weapi/msg/private/send`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/setting.js b/netease_api/module/setting.js
new file mode 100644
index 0000000..7dd8279
--- /dev/null
+++ b/netease_api/module/setting.js
@@ -0,0 +1,11 @@
+// 设置
+
+module.exports = (query, request) => {
+ const data = {}
+ return request('POST', `https://music.163.com/api/user/setting`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/share_resource.js b/netease_api/module/share_resource.js
new file mode 100644
index 0000000..64c016a
--- /dev/null
+++ b/netease_api/module/share_resource.js
@@ -0,0 +1,20 @@
+// 分享歌曲到动态
+
+module.exports = (query, request) => {
+ const data = {
+ type: query.type || 'song', // song,playlist,mv,djprogram,djradio
+ msg: query.msg || '',
+ id: query.id || '',
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/share/friends/resource`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/simi_artist.js b/netease_api/module/simi_artist.js
new file mode 100644
index 0000000..36d2572
--- /dev/null
+++ b/netease_api/module/simi_artist.js
@@ -0,0 +1,20 @@
+// 相似歌手
+const config = require('../util/config.json')
+module.exports = (query, request) => {
+ if (!('MUSIC_U' in query.cookie))
+ query.cookie.MUSIC_A = config.anonymous_token
+ const data = {
+ artistid: query.id,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/discovery/simiArtist`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/simi_mv.js b/netease_api/module/simi_mv.js
new file mode 100644
index 0000000..6dd1c5f
--- /dev/null
+++ b/netease_api/module/simi_mv.js
@@ -0,0 +1,13 @@
+// 相似MV
+
+module.exports = (query, request) => {
+ const data = {
+ mvid: query.mvid,
+ }
+ return request('POST', `https://music.163.com/weapi/discovery/simiMV`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/simi_playlist.js b/netease_api/module/simi_playlist.js
new file mode 100644
index 0000000..11052df
--- /dev/null
+++ b/netease_api/module/simi_playlist.js
@@ -0,0 +1,20 @@
+// 相似歌单
+
+module.exports = (query, request) => {
+ const data = {
+ songid: query.id,
+ limit: query.limit || 50,
+ offset: query.offset || 0,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/discovery/simiPlaylist`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/simi_song.js b/netease_api/module/simi_song.js
new file mode 100644
index 0000000..58b3be9
--- /dev/null
+++ b/netease_api/module/simi_song.js
@@ -0,0 +1,20 @@
+// 相似歌曲
+
+module.exports = (query, request) => {
+ const data = {
+ songid: query.id,
+ limit: query.limit || 50,
+ offset: query.offset || 0,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/v1/discovery/simiSong`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/simi_user.js b/netease_api/module/simi_user.js
new file mode 100644
index 0000000..65a96d1
--- /dev/null
+++ b/netease_api/module/simi_user.js
@@ -0,0 +1,20 @@
+// 相似用户
+
+module.exports = (query, request) => {
+ const data = {
+ songid: query.id,
+ limit: query.limit || 50,
+ offset: query.offset || 0,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/discovery/simiUser`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/song_detail.js b/netease_api/module/song_detail.js
new file mode 100644
index 0000000..338fddc
--- /dev/null
+++ b/netease_api/module/song_detail.js
@@ -0,0 +1,14 @@
+// 歌曲详情
+
+module.exports = (query, request) => {
+ query.ids = query.ids.split(/\s*,\s*/)
+ const data = {
+ c: '[' + query.ids.map((id) => '{"id":' + id + '}').join(',') + ']',
+ }
+ return request('POST', `https://music.163.com/api/v3/song/detail`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/song_order_update.js b/netease_api/module/song_order_update.js
new file mode 100644
index 0000000..0dfb416
--- /dev/null
+++ b/netease_api/module/song_order_update.js
@@ -0,0 +1,22 @@
+// 更新歌曲顺序
+
+module.exports = (query, request) => {
+ const data = {
+ pid: query.pid,
+ trackIds: query.ids,
+ op: 'update',
+ }
+
+ return request(
+ 'POST',
+ `http://interface.music.163.com/api/playlist/manipulate/tracks`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ url: '/api/playlist/desc/update',
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/song_purchased.js b/netease_api/module/song_purchased.js
new file mode 100644
index 0000000..c86dfa1
--- /dev/null
+++ b/netease_api/module/song_purchased.js
@@ -0,0 +1,19 @@
+// 已购单曲
+
+module.exports = (query, request) => {
+ const data = {
+ limit: query.limit || 20,
+ offset: query.offset || 0,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/single/mybought/song/list`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/song_url.js b/netease_api/module/song_url.js
new file mode 100644
index 0000000..46e6bf1
--- /dev/null
+++ b/netease_api/module/song_url.js
@@ -0,0 +1,24 @@
+// 歌曲链接
+
+const crypto = require('crypto')
+module.exports = (query, request) => {
+ if (!('MUSIC_U' in query.cookie))
+ query.cookie._ntes_nuid = crypto.randomBytes(16).toString('hex')
+ query.cookie.os = 'pc'
+ const data = {
+ ids: '[' + query.id + ']',
+ br: parseInt(query.br || 999000),
+ }
+ return request(
+ 'POST',
+ `https://interface3.music.163.com/eapi/song/enhance/player/url`,
+ data,
+ {
+ crypto: 'eapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ url: '/api/song/enhance/player/url',
+ },
+ )
+}
diff --git a/netease_api/module/top_album.js b/netease_api/module/top_album.js
new file mode 100644
index 0000000..d220297
--- /dev/null
+++ b/netease_api/module/top_album.js
@@ -0,0 +1,27 @@
+// 新碟上架
+
+module.exports = (query, request) => {
+ const date = new Date()
+
+ const data = {
+ area: query.area || 'ALL', // //ALL:全部,ZH:华语,EA:欧美,KR:韩国,JP:日本
+ limit: query.limit || 50,
+ offset: query.offset || 0,
+ type: query.type || 'new',
+ year: query.year || date.getFullYear(),
+ month: query.month || date.getMonth() + 1,
+ total: false,
+ rcmd: true,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/api/discovery/new/albums/area`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/top_artists.js b/netease_api/module/top_artists.js
new file mode 100644
index 0000000..a1a40b6
--- /dev/null
+++ b/netease_api/module/top_artists.js
@@ -0,0 +1,15 @@
+// 热门歌手
+
+module.exports = (query, request) => {
+ const data = {
+ limit: query.limit || 50,
+ offset: query.offset || 0,
+ total: true,
+ }
+ return request('POST', `https://music.163.com/weapi/artist/top`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/top_list.js b/netease_api/module/top_list.js
new file mode 100644
index 0000000..c33b251
--- /dev/null
+++ b/netease_api/module/top_list.js
@@ -0,0 +1,30 @@
+// 排行榜
+module.exports = (query, request) => {
+ query.cookie.os = 'pc'
+ if (query.idx) {
+ return Promise.resolve({
+ status: 500,
+ body: {
+ code: 500,
+ msg: '不支持此方式调用,只支持id调用',
+ },
+ })
+ }
+
+ const data = {
+ id: query.id,
+ n: '500',
+ s: '0',
+ }
+ return request(
+ 'POST',
+ `https://interface3.music.163.com/api/playlist/v4/detail`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/top_mv.js b/netease_api/module/top_mv.js
new file mode 100644
index 0000000..2dc7c22
--- /dev/null
+++ b/netease_api/module/top_mv.js
@@ -0,0 +1,16 @@
+// MV排行榜
+
+module.exports = (query, request) => {
+ const data = {
+ area: query.area || '',
+ limit: query.limit || 30,
+ offset: query.offset || 0,
+ total: true,
+ }
+ return request('POST', `https://music.163.com/weapi/mv/toplist`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/top_playlist.js b/netease_api/module/top_playlist.js
new file mode 100644
index 0000000..4f41edb
--- /dev/null
+++ b/netease_api/module/top_playlist.js
@@ -0,0 +1,17 @@
+// 分类歌单
+
+module.exports = (query, request) => {
+ const data = {
+ cat: query.cat || '全部', // 全部,华语,欧美,日语,韩语,粤语,小语种,流行,摇滚,民谣,电子,舞曲,说唱,轻音乐,爵士,乡村,R&B/Soul,古典,民族,英伦,金属,朋克,蓝调,雷鬼,世界音乐,拉丁,另类/独立,New Age,古风,后摇,Bossa Nova,清晨,夜晚,学习,工作,午休,下午茶,地铁,驾车,运动,旅行,散步,酒吧,怀旧,清新,浪漫,性感,伤感,治愈,放松,孤独,感动,兴奋,快乐,安静,思念,影视原声,ACG,儿童,校园,游戏,70后,80后,90后,网络歌曲,KTV,经典,翻唱,吉他,钢琴,器乐,榜单,00后
+ order: query.order || 'hot', // hot,new
+ limit: query.limit || 50,
+ offset: query.offset || 0,
+ total: true,
+ }
+ return request('POST', `https://music.163.com/weapi/playlist/list`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/top_playlist_highquality.js b/netease_api/module/top_playlist_highquality.js
new file mode 100644
index 0000000..a704652
--- /dev/null
+++ b/netease_api/module/top_playlist_highquality.js
@@ -0,0 +1,21 @@
+// 精品歌单
+
+module.exports = (query, request) => {
+ const data = {
+ cat: query.cat || '全部', // 全部,华语,欧美,韩语,日语,粤语,小语种,运动,ACG,影视原声,流行,摇滚,后摇,古风,民谣,轻音乐,电子,器乐,说唱,古典,爵士
+ limit: query.limit || 50,
+ lasttime: query.before || 0, // 歌单updateTime
+ total: true,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/api/playlist/highquality/list`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/top_song.js b/netease_api/module/top_song.js
new file mode 100644
index 0000000..4b37d38
--- /dev/null
+++ b/netease_api/module/top_song.js
@@ -0,0 +1,21 @@
+// 新歌速递
+
+module.exports = (query, request) => {
+ const data = {
+ areaId: query.type || 0, // 全部:0 华语:7 欧美:96 日本:8 韩国:16
+ // limit: query.limit || 100,
+ // offset: query.offset || 0,
+ total: true,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/v1/discovery/new/songs`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/topic_detail.js b/netease_api/module/topic_detail.js
new file mode 100644
index 0000000..e0dd006
--- /dev/null
+++ b/netease_api/module/topic_detail.js
@@ -0,0 +1,11 @@
+module.exports = (query, request) => {
+ const data = {
+ actid: query.actid,
+ }
+ return request('POST', `https://music.163.com/api/act/detail`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/topic_detail_event_hot.js b/netease_api/module/topic_detail_event_hot.js
new file mode 100644
index 0000000..a979b6f
--- /dev/null
+++ b/netease_api/module/topic_detail_event_hot.js
@@ -0,0 +1,11 @@
+module.exports = (query, request) => {
+ const data = {
+ actid: query.actid,
+ }
+ return request('POST', `https://music.163.com/api/act/event/hot`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/topic_sublist.js b/netease_api/module/topic_sublist.js
new file mode 100644
index 0000000..153b298
--- /dev/null
+++ b/netease_api/module/topic_sublist.js
@@ -0,0 +1,15 @@
+// 收藏的专栏
+
+module.exports = (query, request) => {
+ const data = {
+ limit: query.limit || 50,
+ offset: query.offset || 0,
+ total: true,
+ }
+ return request('POST', `https://music.163.com/api/topic/sublist`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/toplist.js b/netease_api/module/toplist.js
new file mode 100644
index 0000000..c690241
--- /dev/null
+++ b/netease_api/module/toplist.js
@@ -0,0 +1,15 @@
+// 所有榜单介绍
+
+module.exports = (query, request) => {
+ return request(
+ 'POST',
+ `https://music.163.com/api/toplist`,
+ {},
+ {
+ crypto: 'api',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/toplist_artist.js b/netease_api/module/toplist_artist.js
new file mode 100644
index 0000000..825a649
--- /dev/null
+++ b/netease_api/module/toplist_artist.js
@@ -0,0 +1,16 @@
+// 歌手榜
+
+module.exports = (query, request) => {
+ const data = {
+ type: query.type || 1,
+ limit: 100,
+ offset: 0,
+ total: true,
+ }
+ return request('POST', `https://music.163.com/weapi/toplist/artist`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/toplist_detail.js b/netease_api/module/toplist_detail.js
new file mode 100644
index 0000000..e194e03
--- /dev/null
+++ b/netease_api/module/toplist_detail.js
@@ -0,0 +1,15 @@
+// 所有榜单内容摘要
+
+module.exports = (query, request) => {
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/toplist/detail`,
+ {},
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/user_account.js b/netease_api/module/user_account.js
new file mode 100644
index 0000000..0eff002
--- /dev/null
+++ b/netease_api/module/user_account.js
@@ -0,0 +1,9 @@
+module.exports = (query, request) => {
+ const data = {}
+ return request('POST', `https://music.163.com/api/nuser/account/get`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/user_audio.js b/netease_api/module/user_audio.js
new file mode 100644
index 0000000..b63e700
--- /dev/null
+++ b/netease_api/module/user_audio.js
@@ -0,0 +1,18 @@
+// 用户创建的电台
+
+module.exports = (query, request) => {
+ const data = {
+ userId: query.uid,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/djradio/get/byuser`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/user_binding.js b/netease_api/module/user_binding.js
new file mode 100644
index 0000000..559b4b5
--- /dev/null
+++ b/netease_api/module/user_binding.js
@@ -0,0 +1,14 @@
+module.exports = (query, request) => {
+ const data = {}
+ return request(
+ 'POST',
+ `https://music.163.com/api/v1/user/bindings/${query.uid}`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/user_bindingcellphone.js b/netease_api/module/user_bindingcellphone.js
new file mode 100644
index 0000000..abe1c98
--- /dev/null
+++ b/netease_api/module/user_bindingcellphone.js
@@ -0,0 +1,21 @@
+module.exports = (query, request) => {
+ const data = {
+ phone: query.phone,
+ countrycode: query.countrycode || '86',
+ captcha: query.captcha,
+ password: query.password
+ ? crypto.createHash('md5').update(query.password).digest('hex')
+ : '',
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/api/user/bindingCellphone`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/user_cloud.js b/netease_api/module/user_cloud.js
new file mode 100644
index 0000000..3134960
--- /dev/null
+++ b/netease_api/module/user_cloud.js
@@ -0,0 +1,14 @@
+// 云盘数据
+
+module.exports = (query, request) => {
+ const data = {
+ limit: query.limit || 30,
+ offset: query.offset || 0,
+ }
+ return request('POST', `https://music.163.com/api/v1/cloud/get`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/user_cloud_del.js b/netease_api/module/user_cloud_del.js
new file mode 100644
index 0000000..7a5577b
--- /dev/null
+++ b/netease_api/module/user_cloud_del.js
@@ -0,0 +1,13 @@
+// 云盘歌曲删除
+
+module.exports = (query, request) => {
+ const data = {
+ songIds: [query.id],
+ }
+ return request('POST', `https://music.163.com/weapi/cloud/del`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/user_cloud_detail.js b/netease_api/module/user_cloud_detail.js
new file mode 100644
index 0000000..45f1b5a
--- /dev/null
+++ b/netease_api/module/user_cloud_detail.js
@@ -0,0 +1,19 @@
+// 云盘数据详情
+
+module.exports = (query, request) => {
+ const id = query.id.replace(/\s/g, '').split(',')
+ const data = {
+ songIds: id,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/v1/cloud/get/byids`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/user_comment_history.js b/netease_api/module/user_comment_history.js
new file mode 100644
index 0000000..bb98221
--- /dev/null
+++ b/netease_api/module/user_comment_history.js
@@ -0,0 +1,22 @@
+module.exports = (query, request) => {
+ query.cookie.os = 'ios'
+ query.cookie.appver = '8.1.20'
+ const data = {
+ compose_reminder: 'true',
+ compose_hot_comment: 'true',
+ limit: query.limit || 10,
+ user_id: query.uid,
+ time: query.time || 0,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/api/comment/user/comment/history`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/user_detail.js b/netease_api/module/user_detail.js
new file mode 100644
index 0000000..b3da340
--- /dev/null
+++ b/netease_api/module/user_detail.js
@@ -0,0 +1,15 @@
+// 用户详情
+
+module.exports = (query, request) => {
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/v1/user/detail/${query.uid}`,
+ {},
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/user_dj.js b/netease_api/module/user_dj.js
new file mode 100644
index 0000000..45a6a3a
--- /dev/null
+++ b/netease_api/module/user_dj.js
@@ -0,0 +1,19 @@
+// 用户电台节目
+
+module.exports = (query, request) => {
+ const data = {
+ limit: query.limit || 30,
+ offset: query.offset || 0,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/dj/program/${query.uid}`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/user_event.js b/netease_api/module/user_event.js
new file mode 100644
index 0000000..0c642ae
--- /dev/null
+++ b/netease_api/module/user_event.js
@@ -0,0 +1,23 @@
+// 用户动态
+
+module.exports = (query, request) => {
+ query.cookie.os = 'ios'
+ query.cookie.appver = '8.1.20'
+ const data = {
+ getcounts: true,
+ time: query.lasttime || -1,
+ limit: query.limit || 30,
+ total: false,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/api/event/get/${query.uid}`,
+ data,
+ {
+ crypto: 'api',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/user_followeds.js b/netease_api/module/user_followeds.js
new file mode 100644
index 0000000..678477a
--- /dev/null
+++ b/netease_api/module/user_followeds.js
@@ -0,0 +1,23 @@
+// 关注TA的人(粉丝)
+
+module.exports = (query, request) => {
+ const data = {
+ userId: query.uid,
+ time: '0',
+ limit: query.limit || 30,
+ offset: query.offset || 0,
+ getcounts: 'true',
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/eapi/user/getfolloweds/${query.uid}`,
+ data,
+ {
+ crypto: 'eapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ url: '/api/user/getfolloweds',
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/user_follows.js b/netease_api/module/user_follows.js
new file mode 100644
index 0000000..cff742f
--- /dev/null
+++ b/netease_api/module/user_follows.js
@@ -0,0 +1,20 @@
+// TA关注的人(关注)
+
+module.exports = (query, request) => {
+ const data = {
+ offset: query.offset || 0,
+ limit: query.limit || 30,
+ order: true,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/user/getfollows/${query.uid}`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/user_level.js b/netease_api/module/user_level.js
new file mode 100644
index 0000000..107a45f
--- /dev/null
+++ b/netease_api/module/user_level.js
@@ -0,0 +1,11 @@
+// 类别热门电台
+
+module.exports = (query, request) => {
+ const data = {}
+ return request('POST', `https://music.163.com/weapi/user/level`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/user_playlist.js b/netease_api/module/user_playlist.js
new file mode 100644
index 0000000..51a7c45
--- /dev/null
+++ b/netease_api/module/user_playlist.js
@@ -0,0 +1,16 @@
+// 用户歌单
+
+module.exports = (query, request) => {
+ const data = {
+ uid: query.uid,
+ limit: query.limit || 30,
+ offset: query.offset || 0,
+ includeVideo: true,
+ }
+ return request('POST', `https://music.163.com/api/user/playlist`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/user_record.js b/netease_api/module/user_record.js
new file mode 100644
index 0000000..8f5f2cc
--- /dev/null
+++ b/netease_api/module/user_record.js
@@ -0,0 +1,14 @@
+// 听歌排行
+
+module.exports = (query, request) => {
+ const data = {
+ uid: query.uid,
+ type: query.type || 0, // 1: 最近一周, 0: 所有时间
+ }
+ return request('POST', `https://music.163.com/weapi/v1/play/record`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/user_replacephone.js b/netease_api/module/user_replacephone.js
new file mode 100644
index 0000000..feed2fe
--- /dev/null
+++ b/netease_api/module/user_replacephone.js
@@ -0,0 +1,19 @@
+module.exports = (query, request) => {
+ const data = {
+ phone: query.phone,
+ captcha: query.captcha,
+ oldcaptcha: query.oldcaptcha,
+ countrycode: query.countrycode || '86',
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/api/user/replaceCellphone`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/user_subcount.js b/netease_api/module/user_subcount.js
new file mode 100644
index 0000000..cfa53ab
--- /dev/null
+++ b/netease_api/module/user_subcount.js
@@ -0,0 +1,15 @@
+// 收藏计数
+
+module.exports = (query, request) => {
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/subcount`,
+ {},
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/user_update.js b/netease_api/module/user_update.js
new file mode 100644
index 0000000..96c7af1
--- /dev/null
+++ b/netease_api/module/user_update.js
@@ -0,0 +1,24 @@
+// 编辑用户信息
+
+module.exports = (query, request) => {
+ const data = {
+ avatarImgId: '0',
+ birthday: query.birthday,
+ city: query.city,
+ gender: query.gender,
+ nickname: query.nickname,
+ province: query.province,
+ signature: query.signature,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/user/profile/update`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/video_category_list.js b/netease_api/module/video_category_list.js
new file mode 100644
index 0000000..88c13c7
--- /dev/null
+++ b/netease_api/module/video_category_list.js
@@ -0,0 +1,20 @@
+// 视频分类列表
+
+module.exports = (query, request) => {
+ const data = {
+ offset: query.offset || 0,
+ total: 'true',
+ limit: query.limit || 99,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/api/cloudvideo/category/list`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/video_detail.js b/netease_api/module/video_detail.js
new file mode 100644
index 0000000..63507ae
--- /dev/null
+++ b/netease_api/module/video_detail.js
@@ -0,0 +1,18 @@
+// 视频详情
+
+module.exports = (query, request) => {
+ const data = {
+ id: query.id,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/cloudvideo/v1/video/detail`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/video_detail_info.js b/netease_api/module/video_detail_info.js
new file mode 100644
index 0000000..4a163ae
--- /dev/null
+++ b/netease_api/module/video_detail_info.js
@@ -0,0 +1,19 @@
+// 视频点赞转发评论数数据
+
+module.exports = (query, request) => {
+ const data = {
+ threadid: `R_VI_62_${query.vid}`,
+ composeliked: true,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/api/comment/commentthread/info`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/video_group.js b/netease_api/module/video_group.js
new file mode 100644
index 0000000..9c39129
--- /dev/null
+++ b/netease_api/module/video_group.js
@@ -0,0 +1,21 @@
+// 视频标签/分类下的视频
+
+module.exports = (query, request) => {
+ const data = {
+ groupId: query.id,
+ offset: query.offset || 0,
+ need_preview_url: 'true',
+ total: true,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/api/videotimeline/videogroup/otherclient/get`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/video_group_list.js b/netease_api/module/video_group_list.js
new file mode 100644
index 0000000..22acdc7
--- /dev/null
+++ b/netease_api/module/video_group_list.js
@@ -0,0 +1,16 @@
+// 视频标签列表
+
+module.exports = (query, request) => {
+ const data = {}
+ return request(
+ 'POST',
+ `https://music.163.com/api/cloudvideo/group/list`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/video_sub.js b/netease_api/module/video_sub.js
new file mode 100644
index 0000000..562a7c2
--- /dev/null
+++ b/netease_api/module/video_sub.js
@@ -0,0 +1,19 @@
+// 收藏与取消收藏视频
+
+module.exports = (query, request) => {
+ query.t = query.t == 1 ? 'sub' : 'unsub'
+ const data = {
+ id: query.id,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/cloudvideo/video/${query.t}`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/video_timeline_all.js b/netease_api/module/video_timeline_all.js
new file mode 100644
index 0000000..b05a46c
--- /dev/null
+++ b/netease_api/module/video_timeline_all.js
@@ -0,0 +1,22 @@
+// 全部视频列表
+
+module.exports = (query, request) => {
+ const data = {
+ groupId: 0,
+ offset: query.offset || 0,
+ need_preview_url: 'true',
+ total: true,
+ }
+ // /api/videotimeline/otherclient/get
+ return request(
+ 'POST',
+ `https://music.163.com/api/videotimeline/otherclient/get`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/video_timeline_recommend.js b/netease_api/module/video_timeline_recommend.js
new file mode 100644
index 0000000..1ca218a
--- /dev/null
+++ b/netease_api/module/video_timeline_recommend.js
@@ -0,0 +1,17 @@
+// 推荐视频
+
+module.exports = (query, request) => {
+ const data = {
+ offset: query.offset || 0,
+ filterLives: '[]',
+ withProgramInfo: 'true',
+ needUrl: '1',
+ resolution: '480',
+ }
+ return request('POST', `https://music.163.com/api/videotimeline/get`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/video_url.js b/netease_api/module/video_url.js
new file mode 100644
index 0000000..b564f8a
--- /dev/null
+++ b/netease_api/module/video_url.js
@@ -0,0 +1,19 @@
+// 视频链接
+
+module.exports = (query, request) => {
+ const data = {
+ ids: '["' + query.id + '"]',
+ resolution: query.res || 1080,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/cloudvideo/playurl`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/vip_growthpoint.js b/netease_api/module/vip_growthpoint.js
new file mode 100644
index 0000000..e035c5a
--- /dev/null
+++ b/netease_api/module/vip_growthpoint.js
@@ -0,0 +1,16 @@
+// 会员成长值
+
+module.exports = (query, request) => {
+ const data = {}
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/vipnewcenter/app/level/growhpoint/basic`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/vip_growthpoint_details.js b/netease_api/module/vip_growthpoint_details.js
new file mode 100644
index 0000000..be9c927
--- /dev/null
+++ b/netease_api/module/vip_growthpoint_details.js
@@ -0,0 +1,19 @@
+// 会员成长值领取记录
+
+module.exports = (query, request) => {
+ const data = {
+ limit: query.limit || 20,
+ offset: query.offset || 0,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/vipnewcenter/app/level/growth/details`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/vip_growthpoint_get.js b/netease_api/module/vip_growthpoint_get.js
new file mode 100644
index 0000000..69ae94b
--- /dev/null
+++ b/netease_api/module/vip_growthpoint_get.js
@@ -0,0 +1,18 @@
+// 领取会员成长值
+
+module.exports = (query, request) => {
+ const data = {
+ taskIds: query.ids,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/vipnewcenter/app/level/task/reward/get`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/vip_info.js b/netease_api/module/vip_info.js
new file mode 100644
index 0000000..30cba78
--- /dev/null
+++ b/netease_api/module/vip_info.js
@@ -0,0 +1,15 @@
+// 获取 VIP 信息
+
+module.exports = (query, request) => {
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/music-vip-membership/front/vip/info`,
+ {},
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/vip_tasks.js b/netease_api/module/vip_tasks.js
new file mode 100644
index 0000000..256e67a
--- /dev/null
+++ b/netease_api/module/vip_tasks.js
@@ -0,0 +1,16 @@
+// 会员任务
+
+module.exports = (query, request) => {
+ const data = {}
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/vipnewcenter/app/level/task/list`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/weblog.js b/netease_api/module/weblog.js
new file mode 100644
index 0000000..1b593e3
--- /dev/null
+++ b/netease_api/module/weblog.js
@@ -0,0 +1,15 @@
+// 操作记录
+
+module.exports = (query, request) => {
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/feedback/weblog`,
+ query.data || {},
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/yunbei.js b/netease_api/module/yunbei.js
new file mode 100644
index 0000000..b2bee9a
--- /dev/null
+++ b/netease_api/module/yunbei.js
@@ -0,0 +1,10 @@
+module.exports = (query, request) => {
+ const data = {}
+ // /api/point/today/get
+ return request('POST', `https://music.163.com/api/point/signed/get`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/yunbei_expense.js b/netease_api/module/yunbei_expense.js
new file mode 100644
index 0000000..50b6f95
--- /dev/null
+++ b/netease_api/module/yunbei_expense.js
@@ -0,0 +1,17 @@
+module.exports = (query, request) => {
+ const data = {
+ limit: query.limit || 10,
+ offset: query.offset || 0,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/store/api/point/expense`,
+ data,
+ {
+ crypto: 'api',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/yunbei_info.js b/netease_api/module/yunbei_info.js
new file mode 100644
index 0000000..68ea2bf
--- /dev/null
+++ b/netease_api/module/yunbei_info.js
@@ -0,0 +1,9 @@
+module.exports = (query, request) => {
+ const data = {}
+ return request('POST', `https://music.163.com/api/v1/user/info`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/yunbei_rcmd_song.js b/netease_api/module/yunbei_rcmd_song.js
new file mode 100644
index 0000000..94ddeaa
--- /dev/null
+++ b/netease_api/module/yunbei_rcmd_song.js
@@ -0,0 +1,21 @@
+// 云贝推歌
+
+module.exports = (query, request) => {
+ const data = {
+ songId: query.id,
+ reason: query.reason || '好歌献给你',
+ scene: '',
+ fromUserId: -1,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/yunbei/rcmd/song/submit`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/yunbei_rcmd_song_history.js b/netease_api/module/yunbei_rcmd_song_history.js
new file mode 100644
index 0000000..224a4f8
--- /dev/null
+++ b/netease_api/module/yunbei_rcmd_song_history.js
@@ -0,0 +1,21 @@
+// 云贝推歌历史记录
+
+module.exports = (query, request) => {
+ const data = {
+ page: JSON.stringify({
+ size: query.size || 20,
+ cursor: query.cursor || '',
+ }),
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/weapi/yunbei/rcmd/song/history/list`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/yunbei_receipt.js b/netease_api/module/yunbei_receipt.js
new file mode 100644
index 0000000..5eb04ca
--- /dev/null
+++ b/netease_api/module/yunbei_receipt.js
@@ -0,0 +1,17 @@
+module.exports = (query, request) => {
+ const data = {
+ limit: query.limit || 10,
+ offset: query.offset || 0,
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/store/api/point/receipt`,
+ data,
+ {
+ crypto: 'api',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/yunbei_sign.js b/netease_api/module/yunbei_sign.js
new file mode 100644
index 0000000..9765f6d
--- /dev/null
+++ b/netease_api/module/yunbei_sign.js
@@ -0,0 +1,11 @@
+module.exports = (query, request) => {
+ const data = {
+ type: '0',
+ }
+ return request('POST', `https://music.163.com/api/point/dailyTask`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module/yunbei_task_finish.js b/netease_api/module/yunbei_task_finish.js
new file mode 100644
index 0000000..0988ae9
--- /dev/null
+++ b/netease_api/module/yunbei_task_finish.js
@@ -0,0 +1,17 @@
+module.exports = (query, request) => {
+ const data = {
+ userTaskId: query.userTaskId,
+ depositCode: query.depositCode || '0',
+ }
+ return request(
+ 'POST',
+ `https://music.163.com/api/usertool/task/point/receive`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/yunbei_tasks.js b/netease_api/module/yunbei_tasks.js
new file mode 100644
index 0000000..fdc2d43
--- /dev/null
+++ b/netease_api/module/yunbei_tasks.js
@@ -0,0 +1,14 @@
+module.exports = (query, request) => {
+ const data = {}
+ return request(
+ 'POST',
+ `https://music.163.com/api/usertool/task/list/all`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/yunbei_tasks_todo.js b/netease_api/module/yunbei_tasks_todo.js
new file mode 100644
index 0000000..a294484
--- /dev/null
+++ b/netease_api/module/yunbei_tasks_todo.js
@@ -0,0 +1,14 @@
+module.exports = (query, request) => {
+ const data = {}
+ return request(
+ 'POST',
+ `https://music.163.com/api/usertool/task/todo/query`,
+ data,
+ {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ },
+ )
+}
diff --git a/netease_api/module/yunbei_today.js b/netease_api/module/yunbei_today.js
new file mode 100644
index 0000000..5b542bf
--- /dev/null
+++ b/netease_api/module/yunbei_today.js
@@ -0,0 +1,9 @@
+module.exports = (query, request) => {
+ const data = {}
+ return request('POST', `https://music.163.com/api/point/today/get`, data, {
+ crypto: 'weapi',
+ cookie: query.cookie,
+ proxy: query.proxy,
+ realIP: query.realIP,
+ })
+}
diff --git a/netease_api/module_example/avatar_upload.js b/netease_api/module_example/avatar_upload.js
new file mode 100644
index 0000000..39ea5e5
--- /dev/null
+++ b/netease_api/module_example/avatar_upload.js
@@ -0,0 +1,20 @@
+const { avatar_upload, login_cellphone } = require('../main')
+const fs = require('fs')
+const path = require('path')
+
+async function main() {
+ const result = await login_cellphone({
+ phone: '手机号',
+ password: '密码',
+ })
+ const filePath = './test.jpg'
+ await avatar_upload({
+ imgFile: {
+ name: path.basename(filePath),
+ data: fs.readFileSync(filePath),
+ },
+ imgSize: 1012, //图片尺寸,需要正方形图片
+ cookie: result.body.cookie,
+ })
+}
+main()
diff --git a/netease_api/module_example/song_upload.js b/netease_api/module_example/song_upload.js
new file mode 100644
index 0000000..6973301
--- /dev/null
+++ b/netease_api/module_example/song_upload.js
@@ -0,0 +1,23 @@
+const { cloud, login_cellphone } = require('../main')
+const fs = require('fs')
+const path = require('path')
+
+async function main() {
+ const result = await login_cellphone({
+ phone: '手机号',
+ password: '密码',
+ })
+ const filePath = './test.mp3'
+ try {
+ await cloud({
+ songFile: {
+ name: path.basename(filePath),
+ data: fs.readFileSync(filePath),
+ },
+ cookie: result.body.cookie,
+ })
+ } catch (error) {
+ console.log(error, 'error')
+ }
+}
+main()
diff --git a/netease_api/module_example/test.jpg b/netease_api/module_example/test.jpg
new file mode 100644
index 0000000..790c2e7
Binary files /dev/null and b/netease_api/module_example/test.jpg differ
diff --git a/netease_api/module_example/test.js b/netease_api/module_example/test.js
new file mode 100644
index 0000000..1a019d7
--- /dev/null
+++ b/netease_api/module_example/test.js
@@ -0,0 +1,31 @@
+const {
+ login_cellphone,
+ user_cloud,
+ album_sublist,
+ song_url,
+} = require('../main')
+async function test() {
+ try {
+ const result = await login_cellphone({
+ phone: '手机号',
+ password: '密码',
+ })
+ console.log(result)
+ const result2 = await user_cloud({
+ cookie: result.body.cookie,
+ })
+ console.log(result2.body)
+ const result3 = await album_sublist({
+ cookie: result.body.cookie,
+ })
+ console.log(result3.body)
+ const result4 = await song_url({
+ cookie: result.body.cookie,
+ id: 33894312,
+ })
+ console.log(result4.body)
+ } catch (error) {
+ console.log(error)
+ }
+}
+test()
diff --git a/netease_api/module_example/test.mp3 b/netease_api/module_example/test.mp3
new file mode 100644
index 0000000..e85b76e
Binary files /dev/null and b/netease_api/module_example/test.mp3 differ
diff --git a/netease_api/module_example/test.ts b/netease_api/module_example/test.ts
new file mode 100644
index 0000000..c5c1751
--- /dev/null
+++ b/netease_api/module_example/test.ts
@@ -0,0 +1,9 @@
+import { banner, lyric } from 'NeteaseCloudMusicApi'
+banner({ type: 0 }).then((res) => {
+ console.log(res)
+})
+lyric({
+ id: '33894312',
+}).then((res) => {
+ console.log(res)
+})
diff --git a/netease_api/package-lock.json b/netease_api/package-lock.json
new file mode 100644
index 0000000..d9dfd5d
--- /dev/null
+++ b/netease_api/package-lock.json
@@ -0,0 +1,4439 @@
+{
+ "name": "NeteaseCloudMusicApi",
+ "version": "4.0.8",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.12.13",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz",
+ "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==",
+ "dev": true,
+ "requires": {
+ "@babel/highlight": "^7.12.13"
+ },
+ "dependencies": {
+ "@babel/helper-validator-identifier": {
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz",
+ "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==",
+ "dev": true
+ },
+ "@babel/highlight": {
+ "version": "7.13.8",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz",
+ "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.12.11",
+ "chalk": "^2.0.0",
+ "js-tokens": "^4.0.0"
+ }
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
+ }
+ },
+ "@babel/helper-validator-identifier": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npm.taobao.org/@babel/helper-validator-identifier/download/@babel/helper-validator-identifier-7.10.4.tgz?cache=0&sync_timestamp=1593521083613&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-validator-identifier%2Fdownload%2F%40babel%2Fhelper-validator-identifier-7.10.4.tgz",
+ "integrity": "sha1-p4x6clHgH2FlEtMbEK3PUq2l4NI=",
+ "dev": true
+ },
+ "@babel/highlight": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npm.taobao.org/@babel/highlight/download/@babel/highlight-7.10.4.tgz?cache=0&sync_timestamp=1593521095576&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhighlight%2Fdownload%2F%40babel%2Fhighlight-7.10.4.tgz",
+ "integrity": "sha1-fRvf1ldTU4+r5sOFls23bZrGAUM=",
+ "dev": true,
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.10.4",
+ "chalk": "^2.0.0",
+ "js-tokens": "^4.0.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-2.4.2.tgz?cache=0&sync_timestamp=1591687076871&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchalk%2Fdownload%2Fchalk-2.4.2.tgz",
+ "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
+ }
+ },
+ "@eslint/eslintrc": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz",
+ "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.12.4",
+ "debug": "^4.1.1",
+ "espree": "^7.3.0",
+ "globals": "^12.1.0",
+ "ignore": "^4.0.6",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^3.13.1",
+ "minimatch": "^3.0.4",
+ "strip-json-comments": "^3.1.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+ "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "dev": true,
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "ignore": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+ "dev": true
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ }
+ }
+ },
+ "@nodelib/fs.scandir": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npm.taobao.org/@nodelib/fs.scandir/download/@nodelib/fs.scandir-2.1.3.tgz",
+ "integrity": "sha1-Olgr21OATGum0UZXnEblITDPSjs=",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.stat": "2.0.3",
+ "run-parallel": "^1.1.9"
+ }
+ },
+ "@nodelib/fs.stat": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npm.taobao.org/@nodelib/fs.stat/download/@nodelib/fs.stat-2.0.3.tgz",
+ "integrity": "sha1-NNxfTKu8cg9OYPdadH5+zWwXW9M=",
+ "dev": true
+ },
+ "@nodelib/fs.walk": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npm.taobao.org/@nodelib/fs.walk/download/@nodelib/fs.walk-1.2.4.tgz",
+ "integrity": "sha1-ARuSAqcKY2bkNspcBlhEUoqwSXY=",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.scandir": "2.1.3",
+ "fastq": "^1.6.0"
+ }
+ },
+ "@tokenizer/token": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.1.1.tgz",
+ "integrity": "sha512-XO6INPbZCxdprl+9qa/AAbFFOMzzwqYxpjPgLICrMD6C2FCw6qfJOPcBk6JqqPLSaZ/Qx87qn4rpPmPMwaAK6w=="
+ },
+ "@tootallnate/once": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npm.taobao.org/@tootallnate/once/download/@tootallnate/once-1.1.2.tgz",
+ "integrity": "sha1-zLkURTYBeaBOf+av94wA/8Hur4I="
+ },
+ "@types/debug": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz",
+ "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ=="
+ },
+ "@types/json-schema": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npm.taobao.org/@types/json-schema/download/@types/json-schema-7.0.6.tgz?cache=0&sync_timestamp=1598910403749&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fjson-schema%2Fdownload%2F%40types%2Fjson-schema-7.0.6.tgz",
+ "integrity": "sha1-9MfsQ+gbMZqYFRFQMXCfJph4kfA=",
+ "dev": true
+ },
+ "@types/node": {
+ "version": "14.14.31",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.31.tgz",
+ "integrity": "sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g=="
+ },
+ "@types/parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
+ "dev": true
+ },
+ "@types/readable-stream": {
+ "version": "2.3.9",
+ "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.9.tgz",
+ "integrity": "sha512-sqsgQqFT7HmQz/V5jH1O0fvQQnXAJO46Gg9LRO/JPfjmVmGUlcx831TZZO3Y3HtWhIkzf3kTsNT0Z0kzIhIvZw==",
+ "requires": {
+ "@types/node": "*",
+ "safe-buffer": "*"
+ }
+ },
+ "@typescript-eslint/eslint-plugin": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npm.taobao.org/@typescript-eslint/eslint-plugin/download/@typescript-eslint/eslint-plugin-4.4.1.tgz?cache=0&sync_timestamp=1603565073344&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40typescript-eslint%2Feslint-plugin%2Fdownload%2F%40typescript-eslint%2Feslint-plugin-4.4.1.tgz",
+ "integrity": "sha1-uKzqA3O9KjiKxH30RlLwC/izaPU=",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/experimental-utils": "4.4.1",
+ "@typescript-eslint/scope-manager": "4.4.1",
+ "debug": "^4.1.1",
+ "functional-red-black-tree": "^1.0.1",
+ "regexpp": "^3.0.0",
+ "semver": "^7.3.2",
+ "tsutils": "^3.17.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.2.0.tgz?cache=0&sync_timestamp=1600502894812&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-4.2.0.tgz",
+ "integrity": "sha1-fxUPk5IOlMWPVXTC/QGjEQ7/5/E=",
+ "dev": true,
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz",
+ "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=",
+ "dev": true
+ }
+ }
+ },
+ "@typescript-eslint/experimental-utils": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npm.taobao.org/@typescript-eslint/experimental-utils/download/@typescript-eslint/experimental-utils-4.4.1.tgz?cache=0&sync_timestamp=1603563239927&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40typescript-eslint%2Fexperimental-utils%2Fdownload%2F%40typescript-eslint%2Fexperimental-utils-4.4.1.tgz",
+ "integrity": "sha1-QGE7l1f6AXDePgBDJU27B3yvrAw=",
+ "dev": true,
+ "requires": {
+ "@types/json-schema": "^7.0.3",
+ "@typescript-eslint/scope-manager": "4.4.1",
+ "@typescript-eslint/types": "4.4.1",
+ "@typescript-eslint/typescript-estree": "4.4.1",
+ "eslint-scope": "^5.0.0",
+ "eslint-utils": "^2.0.0"
+ }
+ },
+ "@typescript-eslint/parser": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npm.taobao.org/@typescript-eslint/parser/download/@typescript-eslint/parser-4.4.1.tgz?cache=0&sync_timestamp=1603563241160&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40typescript-eslint%2Fparser%2Fdownload%2F%40typescript-eslint%2Fparser-4.4.1.tgz",
+ "integrity": "sha1-Jf3pwIBhHzA/LzPO2xRdLFmRW4A=",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/scope-manager": "4.4.1",
+ "@typescript-eslint/types": "4.4.1",
+ "@typescript-eslint/typescript-estree": "4.4.1",
+ "debug": "^4.1.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.2.0.tgz?cache=0&sync_timestamp=1600502894812&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-4.2.0.tgz",
+ "integrity": "sha1-fxUPk5IOlMWPVXTC/QGjEQ7/5/E=",
+ "dev": true,
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz",
+ "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=",
+ "dev": true
+ }
+ }
+ },
+ "@typescript-eslint/scope-manager": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npm.taobao.org/@typescript-eslint/scope-manager/download/@typescript-eslint/scope-manager-4.4.1.tgz",
+ "integrity": "sha1-0ZRH5g2yzpxCWJjWL6A7LM6Oo/k=",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "4.4.1",
+ "@typescript-eslint/visitor-keys": "4.4.1"
+ }
+ },
+ "@typescript-eslint/types": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npm.taobao.org/@typescript-eslint/types/download/@typescript-eslint/types-4.4.1.tgz",
+ "integrity": "sha1-xQezXPUjvHugCq5fde6bgQzau8E=",
+ "dev": true
+ },
+ "@typescript-eslint/typescript-estree": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npm.taobao.org/@typescript-eslint/typescript-estree/download/@typescript-eslint/typescript-estree-4.4.1.tgz?cache=0&sync_timestamp=1603563238913&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40typescript-eslint%2Ftypescript-estree%2Fdownload%2F%40typescript-eslint%2Ftypescript-estree-4.4.1.tgz",
+ "integrity": "sha1-WY9t5IgQbCWH1HyiRixg9uJ5fLg=",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "4.4.1",
+ "@typescript-eslint/visitor-keys": "4.4.1",
+ "debug": "^4.1.1",
+ "globby": "^11.0.1",
+ "is-glob": "^4.0.1",
+ "lodash": "^4.17.15",
+ "semver": "^7.3.2",
+ "tsutils": "^3.17.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.2.0.tgz?cache=0&sync_timestamp=1600502894812&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-4.2.0.tgz",
+ "integrity": "sha1-fxUPk5IOlMWPVXTC/QGjEQ7/5/E=",
+ "dev": true,
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz",
+ "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=",
+ "dev": true
+ }
+ }
+ },
+ "@typescript-eslint/visitor-keys": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npm.taobao.org/@typescript-eslint/visitor-keys/download/@typescript-eslint/visitor-keys-4.4.1.tgz",
+ "integrity": "sha1-F2ncep4tfSz9Mxi3ftgkkYeu1cM=",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "4.4.1",
+ "eslint-visitor-keys": "^2.0.0"
+ }
+ },
+ "@ungap/promise-all-settled": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
+ "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==",
+ "dev": true
+ },
+ "accepts": {
+ "version": "1.3.7",
+ "resolved": "https://registry.npm.taobao.org/accepts/download/accepts-1.3.7.tgz",
+ "integrity": "sha1-UxvHJlF6OytB+FACHGzBXqq1B80=",
+ "requires": {
+ "mime-types": "~2.1.24",
+ "negotiator": "0.6.2"
+ }
+ },
+ "acorn": {
+ "version": "7.4.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
+ "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+ "dev": true
+ },
+ "acorn-es7-plugin": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npm.taobao.org/acorn-es7-plugin/download/acorn-es7-plugin-1.1.7.tgz",
+ "integrity": "sha1-8u4fMiipDurRJF+asZIusucdM2s=",
+ "dev": true
+ },
+ "acorn-jsx": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
+ "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
+ "dev": true
+ },
+ "agent-base": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npm.taobao.org/agent-base/download/agent-base-6.0.2.tgz?cache=0&sync_timestamp=1603480100923&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fagent-base%2Fdownload%2Fagent-base-6.0.2.tgz",
+ "integrity": "sha1-Sf/1hXfP7j83F2/qtMIuAPhtf3c=",
+ "requires": {
+ "debug": "4"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.2.0.tgz?cache=0&sync_timestamp=1600502894812&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-4.2.0.tgz",
+ "integrity": "sha1-fxUPk5IOlMWPVXTC/QGjEQ7/5/E=",
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz",
+ "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk="
+ }
+ }
+ },
+ "aggregate-error": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
+ "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
+ "dev": true,
+ "requires": {
+ "clean-stack": "^2.0.0",
+ "indent-string": "^4.0.0"
+ }
+ },
+ "ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "amdefine": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npm.taobao.org/amdefine/download/amdefine-1.0.1.tgz",
+ "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
+ "dev": true
+ },
+ "ansi-colors": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npm.taobao.org/ansi-colors/download/ansi-colors-4.1.1.tgz",
+ "integrity": "sha1-y7muJWv3UK8eqzRPIpqif+lLo0g=",
+ "dev": true
+ },
+ "ansi-escapes": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz",
+ "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==",
+ "dev": true,
+ "requires": {
+ "type-fest": "^0.11.0"
+ },
+ "dependencies": {
+ "type-fest": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz",
+ "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==",
+ "dev": true
+ }
+ }
+ },
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-5.0.0.tgz",
+ "integrity": "sha1-OIU59VF5vzkznIGvMKZU1p+Hy3U=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-3.2.1.tgz?cache=0&sync_timestamp=1601839122515&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-3.2.1.tgz",
+ "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=",
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "anymatch": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
+ "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
+ "dev": true,
+ "requires": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ }
+ },
+ "argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "requires": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "array-filter": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npm.taobao.org/array-filter/download/array-filter-1.0.0.tgz",
+ "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=",
+ "dev": true
+ },
+ "array-find": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npm.taobao.org/array-find/download/array-find-1.0.0.tgz",
+ "integrity": "sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg=",
+ "dev": true
+ },
+ "array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npm.taobao.org/array-flatten/download/array-flatten-1.1.1.tgz?cache=0&sync_timestamp=1574313384951&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Farray-flatten%2Fdownload%2Farray-flatten-1.1.1.tgz",
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+ },
+ "array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npm.taobao.org/array-union/download/array-union-2.1.0.tgz",
+ "integrity": "sha1-t5hCCtvrHego2ErNii4j0+/oXo0=",
+ "dev": true
+ },
+ "ast-types": {
+ "version": "0.13.4",
+ "resolved": "https://registry.npm.taobao.org/ast-types/download/ast-types-0.13.4.tgz?cache=0&sync_timestamp=1599935985242&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fast-types%2Fdownload%2Fast-types-0.13.4.tgz",
+ "integrity": "sha1-7g13s0MmOWXsw/ti2hbnIisrZ4I=",
+ "requires": {
+ "tslib": "^2.0.1"
+ }
+ },
+ "astral-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+ "dev": true
+ },
+ "axios": {
+ "version": "0.21.1",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
+ "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
+ "requires": {
+ "follow-redirects": "^1.10.0"
+ }
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+ "dev": true
+ },
+ "base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
+ },
+ "binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "dev": true
+ },
+ "body-parser": {
+ "version": "1.19.0",
+ "resolved": "https://registry.npm.taobao.org/body-parser/download/body-parser-1.19.0.tgz",
+ "integrity": "sha1-lrJwnlfJxOCab9Zqj9l5hE9p8Io=",
+ "requires": {
+ "bytes": "3.1.0",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "on-finished": "~2.3.0",
+ "qs": "6.7.0",
+ "raw-body": "2.4.0",
+ "type-is": "~1.6.17"
+ }
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npm.taobao.org/brace-expansion/download/brace-expansion-1.1.11.tgz?cache=0&sync_timestamp=1601898189928&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbrace-expansion%2Fdownload%2Fbrace-expansion-1.1.11.tgz",
+ "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npm.taobao.org/braces/download/braces-3.0.2.tgz",
+ "integrity": "sha1-NFThpGLujVmeI23zNs2epPiv4Qc=",
+ "dev": true,
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
+ "browser-stdout": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
+ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
+ "dev": true
+ },
+ "buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "requires": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "buffer-alloc": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
+ "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
+ "requires": {
+ "buffer-alloc-unsafe": "^1.1.0",
+ "buffer-fill": "^1.0.0"
+ }
+ },
+ "buffer-alloc-unsafe": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
+ "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg=="
+ },
+ "buffer-fill": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
+ "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw="
+ },
+ "buffer-from": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
+ },
+ "busboy": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npm.taobao.org/busboy/download/busboy-0.3.1.tgz",
+ "integrity": "sha1-FwiZJ0xb84quJ9XGK3EmjNWF/Rs=",
+ "requires": {
+ "dicer": "0.3.0"
+ }
+ },
+ "bytes": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npm.taobao.org/bytes/download/bytes-3.1.0.tgz",
+ "integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY="
+ },
+ "call-matcher": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npm.taobao.org/call-matcher/download/call-matcher-1.1.0.tgz",
+ "integrity": "sha1-I7LBvHqDlMi+KGCdd929V4ZoBDI=",
+ "dev": true,
+ "requires": {
+ "core-js": "^2.0.0",
+ "deep-equal": "^1.0.0",
+ "espurify": "^1.6.0",
+ "estraverse": "^4.0.0"
+ }
+ },
+ "call-signature": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npm.taobao.org/call-signature/download/call-signature-0.0.2.tgz",
+ "integrity": "sha1-qEq8glpV70yysCi9dOIFpluaSZY=",
+ "dev": true
+ },
+ "callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npm.taobao.org/callsites/download/callsites-3.1.0.tgz",
+ "integrity": "sha1-s2MKvYlDQy9Us/BRkjjjPNffL3M=",
+ "dev": true
+ },
+ "camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npm.taobao.org/camelcase/download/camelcase-5.3.1.tgz?cache=0&sync_timestamp=1602350083472&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcamelcase%2Fdownload%2Fcamelcase-5.3.1.tgz",
+ "integrity": "sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA="
+ },
+ "chalk": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-4.1.0.tgz?cache=0&sync_timestamp=1591687076871&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchalk%2Fdownload%2Fchalk-4.1.0.tgz",
+ "integrity": "sha1-ThSHCmGNni7dl92DRf2dncMVZGo=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-4.3.0.tgz?cache=0&sync_timestamp=1601839122515&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-4.3.0.tgz",
+ "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz",
+ "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz",
+ "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-4.0.0.tgz",
+ "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-7.2.0.tgz?cache=0&sync_timestamp=1598611709087&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-7.2.0.tgz",
+ "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "charenc": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
+ "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc="
+ },
+ "chokidar": {
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz",
+ "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==",
+ "dev": true,
+ "requires": {
+ "anymatch": "~3.1.1",
+ "braces": "~3.0.2",
+ "fsevents": "~2.3.1",
+ "glob-parent": "~5.1.0",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.5.0"
+ }
+ },
+ "clean-stack": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
+ "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
+ "dev": true
+ },
+ "cli-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+ "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
+ "dev": true,
+ "requires": {
+ "restore-cursor": "^3.1.0"
+ }
+ },
+ "cli-truncate": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz",
+ "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==",
+ "dev": true,
+ "requires": {
+ "slice-ansi": "^3.0.0",
+ "string-width": "^4.2.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "slice-ansi": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
+ "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
+ }
+ },
+ "string-width": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
+ "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ }
+ }
+ }
+ },
+ "cliui": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npm.taobao.org/cliui/download/cliui-5.0.0.tgz?cache=0&sync_timestamp=1602861367442&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcliui%2Fdownload%2Fcliui-5.0.0.tgz",
+ "integrity": "sha1-3u/P2y6AB4SqNPRvoI4GhRx7u8U=",
+ "requires": {
+ "string-width": "^3.1.0",
+ "strip-ansi": "^5.2.0",
+ "wrap-ansi": "^5.1.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-4.1.0.tgz",
+ "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc="
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz?cache=0&sync_timestamp=1573280518303&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-5.2.0.tgz",
+ "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=",
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ }
+ },
+ "wrap-ansi": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-5.1.0.tgz",
+ "integrity": "sha1-H9H2cjXVttD+54EFYAG/tpTAOwk=",
+ "requires": {
+ "ansi-styles": "^3.2.0",
+ "string-width": "^3.0.0",
+ "strip-ansi": "^5.0.0"
+ }
+ }
+ }
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-1.9.3.tgz",
+ "integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=",
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
+ },
+ "commander": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+ "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
+ "dev": true
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "dev": true
+ },
+ "content-disposition": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npm.taobao.org/content-disposition/download/content-disposition-0.5.3.tgz",
+ "integrity": "sha1-4TDK9+cnkIfFYWwgB9BIVpiYT70=",
+ "requires": {
+ "safe-buffer": "5.1.2"
+ }
+ },
+ "content-type": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npm.taobao.org/content-type/download/content-type-1.0.4.tgz",
+ "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js="
+ },
+ "convert-source-map": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npm.taobao.org/convert-source-map/download/convert-source-map-1.7.0.tgz?cache=0&sync_timestamp=1573003637425&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fconvert-source-map%2Fdownload%2Fconvert-source-map-1.7.0.tgz",
+ "integrity": "sha1-F6LLiC1/d9NJBYXizmxSRCSjpEI=",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.1"
+ }
+ },
+ "cookie": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npm.taobao.org/cookie/download/cookie-0.4.0.tgz?cache=0&sync_timestamp=1587525865178&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcookie%2Fdownload%2Fcookie-0.4.0.tgz",
+ "integrity": "sha1-vrQ35wIrO21JAZ0IhmUwPr6cFLo="
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npm.taobao.org/cookie-signature/download/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+ },
+ "core-js": {
+ "version": "2.6.11",
+ "resolved": "https://registry.npm.taobao.org/core-js/download/core-js-2.6.11.tgz?cache=0&sync_timestamp=1586450269267&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcore-js%2Fdownload%2Fcore-js-2.6.11.tgz",
+ "integrity": "sha1-OIMUafmSK97Y7iHJ3EaYXgOZMIw=",
+ "dev": true
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+ },
+ "cosmiconfig": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz",
+ "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==",
+ "dev": true,
+ "requires": {
+ "@types/parse-json": "^4.0.0",
+ "import-fresh": "^3.2.1",
+ "parse-json": "^5.0.0",
+ "path-type": "^4.0.0",
+ "yaml": "^1.10.0"
+ }
+ },
+ "cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npm.taobao.org/cross-spawn/download/cross-spawn-7.0.3.tgz",
+ "integrity": "sha1-9zqFudXUHQRVUcF34ogtSshXKKY=",
+ "dev": true,
+ "requires": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ }
+ },
+ "crypt": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
+ "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs="
+ },
+ "d": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npm.taobao.org/d/download/d-1.0.1.tgz",
+ "integrity": "sha1-hpgJU3LVjb7jRv/Qxwk/mfj561o=",
+ "dev": true,
+ "requires": {
+ "es5-ext": "^0.10.50",
+ "type": "^1.0.1"
+ }
+ },
+ "data-uri-to-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npm.taobao.org/data-uri-to-buffer/download/data-uri-to-buffer-3.0.1.tgz?cache=0&sync_timestamp=1590800007667&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdata-uri-to-buffer%2Fdownload%2Fdata-uri-to-buffer-3.0.1.tgz",
+ "integrity": "sha1-WUuJc5OMW8LDMEZTV4U0GrxPNjY="
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1600502894812&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz",
+ "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npm.taobao.org/decamelize/download/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
+ },
+ "dedent": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
+ "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=",
+ "dev": true
+ },
+ "deep-equal": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npm.taobao.org/deep-equal/download/deep-equal-1.1.1.tgz",
+ "integrity": "sha1-tcmMlCzv+vfLBR4k4UNKJaLmB2o=",
+ "dev": true,
+ "requires": {
+ "is-arguments": "^1.0.4",
+ "is-date-object": "^1.0.1",
+ "is-regex": "^1.0.4",
+ "object-is": "^1.0.1",
+ "object-keys": "^1.1.1",
+ "regexp.prototype.flags": "^1.2.0"
+ }
+ },
+ "deep-is": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npm.taobao.org/deep-is/download/deep-is-0.1.3.tgz",
+ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
+ },
+ "define-properties": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npm.taobao.org/define-properties/download/define-properties-1.1.3.tgz",
+ "integrity": "sha1-z4jabL7ib+bbcJT2HYcMvYTO6fE=",
+ "dev": true,
+ "requires": {
+ "object-keys": "^1.0.12"
+ }
+ },
+ "degenerator": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npm.taobao.org/degenerator/download/degenerator-2.2.0.tgz",
+ "integrity": "sha1-SemMEfoCk8Wybt+7UvFXKa/NslQ=",
+ "requires": {
+ "ast-types": "^0.13.2",
+ "escodegen": "^1.8.1",
+ "esprima": "^4.0.0"
+ }
+ },
+ "depd": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz",
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
+ },
+ "destroy": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npm.taobao.org/destroy/download/destroy-1.0.4.tgz",
+ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
+ },
+ "dicer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npm.taobao.org/dicer/download/dicer-0.3.0.tgz",
+ "integrity": "sha1-6s2Ys7+/kuirXC/bcaqsRLsGuHI=",
+ "requires": {
+ "streamsearch": "0.1.2"
+ }
+ },
+ "diff": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
+ "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
+ "dev": true
+ },
+ "diff-match-patch": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npm.taobao.org/diff-match-patch/download/diff-match-patch-1.0.5.tgz",
+ "integrity": "sha1-q7WE1fEM0Rlt/FWqA3AVkq4/ezc=",
+ "dev": true
+ },
+ "dijkstrajs": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.1.tgz",
+ "integrity": "sha1-082BIh4+pAdCz83lVtTpnpjdxxs="
+ },
+ "dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npm.taobao.org/dir-glob/download/dir-glob-3.0.1.tgz",
+ "integrity": "sha1-Vtv3PZkqSpO6FYT0U0Bj/S5BcX8=",
+ "dev": true,
+ "requires": {
+ "path-type": "^4.0.0"
+ }
+ },
+ "doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "requires": {
+ "esutils": "^2.0.2"
+ }
+ },
+ "dom-serializer": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz",
+ "integrity": "sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "^2.0.1",
+ "domhandler": "^4.0.0",
+ "entities": "^2.0.0"
+ },
+ "dependencies": {
+ "domhandler": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz",
+ "integrity": "sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "^2.1.0"
+ }
+ }
+ }
+ },
+ "domelementtype": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz",
+ "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==",
+ "dev": true
+ },
+ "domhandler": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz",
+ "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "^2.0.1"
+ }
+ },
+ "domutils": {
+ "version": "2.4.4",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.4.4.tgz",
+ "integrity": "sha512-jBC0vOsECI4OMdD0GC9mGn7NXPLb+Qt6KW1YDQzeQYRUFKmNG8lh7mO5HiELfr+lLQE7loDVI4QcAxV80HS+RA==",
+ "dev": true,
+ "requires": {
+ "dom-serializer": "^1.0.1",
+ "domelementtype": "^2.0.1",
+ "domhandler": "^4.0.0"
+ },
+ "dependencies": {
+ "domhandler": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz",
+ "integrity": "sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "^2.1.0"
+ }
+ }
+ }
+ },
+ "eastasianwidth": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npm.taobao.org/eastasianwidth/download/eastasianwidth-0.2.0.tgz",
+ "integrity": "sha1-aWzi7Aqg5uqTo5f/zySqeEDIJ8s=",
+ "dev": true
+ },
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+ },
+ "emoji-regex": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npm.taobao.org/emoji-regex/download/emoji-regex-7.0.3.tgz?cache=0&sync_timestamp=1603212180491&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Femoji-regex%2Fdownload%2Femoji-regex-7.0.3.tgz",
+ "integrity": "sha1-kzoEBShgyF6DwSJHnEdIqOTHIVY="
+ },
+ "empower": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npm.taobao.org/empower/download/empower-1.3.1.tgz",
+ "integrity": "sha1-dol5y7s21x2PXtqrZj3qy52rkWw=",
+ "dev": true,
+ "requires": {
+ "core-js": "^2.0.0",
+ "empower-core": "^1.2.0"
+ }
+ },
+ "empower-assert": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npm.taobao.org/empower-assert/download/empower-assert-1.1.0.tgz",
+ "integrity": "sha1-jTJ/vmmoivkN2pjRv8mCnSok/WI=",
+ "dev": true,
+ "requires": {
+ "estraverse": "^4.2.0"
+ }
+ },
+ "empower-core": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npm.taobao.org/empower-core/download/empower-core-1.2.0.tgz",
+ "integrity": "sha1-zj+ySE1Rh/opwj+6g0Swsv31YBw=",
+ "dev": true,
+ "requires": {
+ "call-signature": "0.0.2",
+ "core-js": "^2.0.0"
+ }
+ },
+ "encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npm.taobao.org/encodeurl/download/encodeurl-1.0.2.tgz",
+ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
+ },
+ "end-of-stream": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+ "dev": true,
+ "requires": {
+ "once": "^1.4.0"
+ }
+ },
+ "enquirer": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npm.taobao.org/enquirer/download/enquirer-2.3.6.tgz?cache=0&sync_timestamp=1593693291943&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fenquirer%2Fdownload%2Fenquirer-2.3.6.tgz",
+ "integrity": "sha1-Kn/l3WNKHkElqXXsmU/1RW3Dc00=",
+ "dev": true,
+ "requires": {
+ "ansi-colors": "^4.1.1"
+ }
+ },
+ "entities": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
+ "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
+ "dev": true
+ },
+ "error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "dev": true,
+ "requires": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "es-abstract": {
+ "version": "1.18.0-next.1",
+ "resolved": "https://registry.npm.taobao.org/es-abstract/download/es-abstract-1.18.0-next.1.tgz?cache=0&sync_timestamp=1601502719982&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fes-abstract%2Fdownload%2Fes-abstract-1.18.0-next.1.tgz",
+ "integrity": "sha1-bjoKS9pxflAjqzuOkL7DYQjSLGg=",
+ "dev": true,
+ "requires": {
+ "es-to-primitive": "^1.2.1",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1",
+ "is-callable": "^1.2.2",
+ "is-negative-zero": "^2.0.0",
+ "is-regex": "^1.1.1",
+ "object-inspect": "^1.8.0",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.1",
+ "string.prototype.trimend": "^1.0.1",
+ "string.prototype.trimstart": "^1.0.1"
+ }
+ },
+ "es-to-primitive": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npm.taobao.org/es-to-primitive/download/es-to-primitive-1.2.1.tgz",
+ "integrity": "sha1-5VzUyc3BiLzvsDs2bHNjI/xciYo=",
+ "dev": true,
+ "requires": {
+ "is-callable": "^1.1.4",
+ "is-date-object": "^1.0.1",
+ "is-symbol": "^1.0.2"
+ }
+ },
+ "es5-ext": {
+ "version": "0.10.53",
+ "resolved": "https://registry.npm.taobao.org/es5-ext/download/es5-ext-0.10.53.tgz",
+ "integrity": "sha1-k8WjrP2+8nUiCtcmRK0C7hg2jeE=",
+ "dev": true,
+ "requires": {
+ "es6-iterator": "~2.0.3",
+ "es6-symbol": "~3.1.3",
+ "next-tick": "~1.0.0"
+ }
+ },
+ "es6-iterator": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npm.taobao.org/es6-iterator/download/es6-iterator-2.0.3.tgz",
+ "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
+ "dev": true,
+ "requires": {
+ "d": "1",
+ "es5-ext": "^0.10.35",
+ "es6-symbol": "^3.1.1"
+ }
+ },
+ "es6-map": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npm.taobao.org/es6-map/download/es6-map-0.1.5.tgz",
+ "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=",
+ "dev": true,
+ "requires": {
+ "d": "1",
+ "es5-ext": "~0.10.14",
+ "es6-iterator": "~2.0.1",
+ "es6-set": "~0.1.5",
+ "es6-symbol": "~3.1.1",
+ "event-emitter": "~0.3.5"
+ }
+ },
+ "es6-set": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npm.taobao.org/es6-set/download/es6-set-0.1.5.tgz",
+ "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=",
+ "dev": true,
+ "requires": {
+ "d": "1",
+ "es5-ext": "~0.10.14",
+ "es6-iterator": "~2.0.1",
+ "es6-symbol": "3.1.1",
+ "event-emitter": "~0.3.5"
+ },
+ "dependencies": {
+ "es6-symbol": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npm.taobao.org/es6-symbol/download/es6-symbol-3.1.1.tgz",
+ "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",
+ "dev": true,
+ "requires": {
+ "d": "1",
+ "es5-ext": "~0.10.14"
+ }
+ }
+ }
+ },
+ "es6-symbol": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npm.taobao.org/es6-symbol/download/es6-symbol-3.1.3.tgz",
+ "integrity": "sha1-utXTwbzawoJp9MszHkMceKxwXRg=",
+ "dev": true,
+ "requires": {
+ "d": "^1.0.1",
+ "ext": "^1.1.2"
+ }
+ },
+ "es6-weak-map": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npm.taobao.org/es6-weak-map/download/es6-weak-map-2.0.3.tgz",
+ "integrity": "sha1-ttofFswswNm+Q+a9v8Xn383zHVM=",
+ "dev": true,
+ "requires": {
+ "d": "1",
+ "es5-ext": "^0.10.46",
+ "es6-iterator": "^2.0.3",
+ "es6-symbol": "^3.1.1"
+ }
+ },
+ "escalade": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+ "dev": true
+ },
+ "escallmatch": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npm.taobao.org/escallmatch/download/escallmatch-1.5.0.tgz",
+ "integrity": "sha1-UAmdhugJGwkt+N37w/mm+wWgJNA=",
+ "dev": true,
+ "requires": {
+ "call-matcher": "^1.0.0",
+ "esprima": "^2.0.0"
+ },
+ "dependencies": {
+ "esprima": {
+ "version": "2.7.3",
+ "resolved": "https://registry.npm.taobao.org/esprima/download/esprima-2.7.3.tgz",
+ "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=",
+ "dev": true
+ }
+ }
+ },
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+ "dev": true
+ },
+ "escodegen": {
+ "version": "1.14.3",
+ "resolved": "https://registry.npm.taobao.org/escodegen/download/escodegen-1.14.3.tgz?cache=0&sync_timestamp=1596669832613&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fescodegen%2Fdownload%2Fescodegen-1.14.3.tgz",
+ "integrity": "sha1-TnuB+6YVgdyXWC7XjKt/Do1j9QM=",
+ "requires": {
+ "esprima": "^4.0.1",
+ "estraverse": "^4.2.0",
+ "esutils": "^2.0.2",
+ "optionator": "^0.8.1",
+ "source-map": "~0.6.1"
+ }
+ },
+ "escope": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npm.taobao.org/escope/download/escope-3.6.0.tgz",
+ "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=",
+ "dev": true,
+ "requires": {
+ "es6-map": "^0.1.3",
+ "es6-weak-map": "^2.0.1",
+ "esrecurse": "^4.1.0",
+ "estraverse": "^4.1.1"
+ }
+ },
+ "eslint": {
+ "version": "7.21.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.21.0.tgz",
+ "integrity": "sha512-W2aJbXpMNofUp0ztQaF40fveSsJBjlSCSWpy//gzfTvwC+USs/nceBrKmlJOiM8r1bLwP2EuYkCqArn/6QTIgg==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "7.12.11",
+ "@eslint/eslintrc": "^0.4.0",
+ "ajv": "^6.10.0",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.0.1",
+ "doctrine": "^3.0.0",
+ "enquirer": "^2.3.5",
+ "eslint-scope": "^5.1.1",
+ "eslint-utils": "^2.1.0",
+ "eslint-visitor-keys": "^2.0.0",
+ "espree": "^7.3.1",
+ "esquery": "^1.4.0",
+ "esutils": "^2.0.2",
+ "file-entry-cache": "^6.0.1",
+ "functional-red-black-tree": "^1.0.1",
+ "glob-parent": "^5.0.0",
+ "globals": "^12.1.0",
+ "ignore": "^4.0.6",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "js-yaml": "^3.13.1",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash": "^4.17.20",
+ "minimatch": "^3.0.4",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.1",
+ "progress": "^2.0.0",
+ "regexpp": "^3.1.0",
+ "semver": "^7.2.1",
+ "strip-ansi": "^6.0.0",
+ "strip-json-comments": "^3.1.0",
+ "table": "^6.0.4",
+ "text-table": "^0.2.0",
+ "v8-compile-cache": "^2.0.3"
+ },
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
+ "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
+ "dev": true,
+ "requires": {
+ "@babel/highlight": "^7.10.4"
+ }
+ },
+ "debug": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+ "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "dev": true,
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "ignore": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+ "dev": true
+ },
+ "levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "optionator": {
+ "version": "0.9.1",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
+ "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+ "dev": true,
+ "requires": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.3"
+ }
+ },
+ "prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true
+ },
+ "type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "^1.2.1"
+ }
+ }
+ }
+ },
+ "eslint-config-prettier": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.1.0.tgz",
+ "integrity": "sha512-9sm5/PxaFG7qNJvJzTROMM1Bk1ozXVTKI0buKOyb0Bsr1hrwi0H/TzxF/COtf1uxikIK8SwhX7K6zg78jAzbeA==",
+ "dev": true
+ },
+ "eslint-plugin-html": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-6.1.1.tgz",
+ "integrity": "sha512-JSe3ZDb7feKMnQM27XWGeoIjvP4oWQMJD9GZ6wW67J7/plVL87NK72RBwlvfc3tTZiYUchHhxAwtgEd1GdofDA==",
+ "dev": true,
+ "requires": {
+ "htmlparser2": "^5.0.1"
+ }
+ },
+ "eslint-plugin-prettier": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz",
+ "integrity": "sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ==",
+ "dev": true,
+ "requires": {
+ "prettier-linter-helpers": "^1.0.0"
+ }
+ },
+ "eslint-scope": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npm.taobao.org/eslint-scope/download/eslint-scope-5.1.1.tgz?cache=0&sync_timestamp=1599933651660&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feslint-scope%2Fdownload%2Feslint-scope-5.1.1.tgz",
+ "integrity": "sha1-54blmmbLkrP2wfsNUIqrF0hI9Iw=",
+ "dev": true,
+ "requires": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^4.1.1"
+ }
+ },
+ "eslint-utils": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npm.taobao.org/eslint-utils/download/eslint-utils-2.1.0.tgz?cache=0&sync_timestamp=1592222145079&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feslint-utils%2Fdownload%2Feslint-utils-2.1.0.tgz",
+ "integrity": "sha1-0t5eA0JOcH3BDHQGjd7a5wh0Gyc=",
+ "dev": true,
+ "requires": {
+ "eslint-visitor-keys": "^1.1.0"
+ },
+ "dependencies": {
+ "eslint-visitor-keys": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npm.taobao.org/eslint-visitor-keys/download/eslint-visitor-keys-1.3.0.tgz?cache=0&sync_timestamp=1597435068105&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feslint-visitor-keys%2Fdownload%2Feslint-visitor-keys-1.3.0.tgz",
+ "integrity": "sha1-MOvR73wv3/AcOk8VEESvJfqwUj4=",
+ "dev": true
+ }
+ }
+ },
+ "eslint-visitor-keys": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npm.taobao.org/eslint-visitor-keys/download/eslint-visitor-keys-2.0.0.tgz?cache=0&sync_timestamp=1597435068105&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feslint-visitor-keys%2Fdownload%2Feslint-visitor-keys-2.0.0.tgz",
+ "integrity": "sha1-If3I+82ceVzAMh8FY3AglXUVEag=",
+ "dev": true
+ },
+ "espower": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npm.taobao.org/espower/download/espower-2.1.2.tgz",
+ "integrity": "sha1-gk+IeI+f7fTPD5KPXhG7kHzpuRg=",
+ "dev": true,
+ "requires": {
+ "array-find": "^1.0.0",
+ "escallmatch": "^1.5.0",
+ "escodegen": "^1.7.0",
+ "escope": "^3.3.0",
+ "espower-location-detector": "^1.0.0",
+ "espurify": "^1.3.0",
+ "estraverse": "^4.1.0",
+ "source-map": "^0.5.0",
+ "type-name": "^2.0.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz?cache=0&sync_timestamp=1571657176668&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ }
+ }
+ },
+ "espower-loader": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npm.taobao.org/espower-loader/download/espower-loader-1.2.2.tgz",
+ "integrity": "sha1-7bRsPFmga6yOpzppXIblxaC8gto=",
+ "dev": true,
+ "requires": {
+ "convert-source-map": "^1.1.0",
+ "espower-source": "^2.0.0",
+ "minimatch": "^3.0.0",
+ "source-map-support": "^0.4.0",
+ "xtend": "^4.0.0"
+ }
+ },
+ "espower-location-detector": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npm.taobao.org/espower-location-detector/download/espower-location-detector-1.0.0.tgz",
+ "integrity": "sha1-oXt+zFnTDheeK+9z+0E3cEyzMbU=",
+ "dev": true,
+ "requires": {
+ "is-url": "^1.2.1",
+ "path-is-absolute": "^1.0.0",
+ "source-map": "^0.5.0",
+ "xtend": "^4.0.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz?cache=0&sync_timestamp=1571657176668&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ }
+ }
+ },
+ "espower-source": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npm.taobao.org/espower-source/download/espower-source-2.3.0.tgz",
+ "integrity": "sha1-Q+k7LBivUAGL2xvqehJx9KHBJfQ=",
+ "dev": true,
+ "requires": {
+ "acorn": "^5.0.0",
+ "acorn-es7-plugin": "^1.0.10",
+ "convert-source-map": "^1.1.1",
+ "empower-assert": "^1.0.0",
+ "escodegen": "^1.10.0",
+ "espower": "^2.1.1",
+ "estraverse": "^4.0.0",
+ "merge-estraverse-visitors": "^1.0.0",
+ "multi-stage-sourcemap": "^0.2.1",
+ "path-is-absolute": "^1.0.0",
+ "xtend": "^4.0.0"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "5.7.4",
+ "resolved": "https://registry.npm.taobao.org/acorn/download/acorn-5.7.4.tgz",
+ "integrity": "sha1-Po2KmUfQWZoXltECJddDL0pKz14=",
+ "dev": true
+ }
+ }
+ },
+ "espree": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz",
+ "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==",
+ "dev": true,
+ "requires": {
+ "acorn": "^7.4.0",
+ "acorn-jsx": "^5.3.1",
+ "eslint-visitor-keys": "^1.3.0"
+ },
+ "dependencies": {
+ "eslint-visitor-keys": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+ "dev": true
+ }
+ }
+ },
+ "esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npm.taobao.org/esprima/download/esprima-4.0.1.tgz",
+ "integrity": "sha1-E7BM2z5sXRnfkatph6hpVhmwqnE="
+ },
+ "espurify": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npm.taobao.org/espurify/download/espurify-1.8.1.tgz",
+ "integrity": "sha1-V0bGwatC0wLeEL0dW/fw6MBRUFY=",
+ "dev": true,
+ "requires": {
+ "core-js": "^2.0.0"
+ }
+ },
+ "esquery": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
+ "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
+ "dev": true,
+ "requires": {
+ "estraverse": "^5.1.0"
+ },
+ "dependencies": {
+ "estraverse": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+ "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+ "dev": true
+ }
+ }
+ },
+ "esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npm.taobao.org/esrecurse/download/esrecurse-4.3.0.tgz?cache=0&sync_timestamp=1598898255610&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fesrecurse%2Fdownload%2Fesrecurse-4.3.0.tgz",
+ "integrity": "sha1-eteWTWeauyi+5yzsY3WLHF0smSE=",
+ "dev": true,
+ "requires": {
+ "estraverse": "^5.2.0"
+ },
+ "dependencies": {
+ "estraverse": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npm.taobao.org/estraverse/download/estraverse-5.2.0.tgz?cache=0&sync_timestamp=1596642998635&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Festraverse%2Fdownload%2Festraverse-5.2.0.tgz",
+ "integrity": "sha1-MH30JUfmzHMk088DwVXVzbjFOIA=",
+ "dev": true
+ }
+ }
+ },
+ "estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npm.taobao.org/estraverse/download/estraverse-4.3.0.tgz?cache=0&sync_timestamp=1596642998635&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Festraverse%2Fdownload%2Festraverse-4.3.0.tgz",
+ "integrity": "sha1-OYrT88WiSUi+dyXoPRGn3ijNvR0="
+ },
+ "esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npm.taobao.org/esutils/download/esutils-2.0.3.tgz",
+ "integrity": "sha1-dNLrTeC42hKTcRkQ1Qd1ubcQ72Q="
+ },
+ "etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npm.taobao.org/etag/download/etag-1.8.1.tgz",
+ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
+ },
+ "event-emitter": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npm.taobao.org/event-emitter/download/event-emitter-0.3.5.tgz",
+ "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
+ "dev": true,
+ "requires": {
+ "d": "1",
+ "es5-ext": "~0.10.14"
+ }
+ },
+ "execa": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
+ "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
+ "dev": true,
+ "requires": {
+ "cross-spawn": "^7.0.0",
+ "get-stream": "^5.0.0",
+ "human-signals": "^1.1.1",
+ "is-stream": "^2.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^4.0.0",
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2",
+ "strip-final-newline": "^2.0.0"
+ }
+ },
+ "express": {
+ "version": "4.17.1",
+ "resolved": "https://registry.npm.taobao.org/express/download/express-4.17.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fexpress%2Fdownload%2Fexpress-4.17.1.tgz",
+ "integrity": "sha1-RJH8OGBc9R+GKdOcK10Cb5ikwTQ=",
+ "requires": {
+ "accepts": "~1.3.7",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.19.0",
+ "content-disposition": "0.5.3",
+ "content-type": "~1.0.4",
+ "cookie": "0.4.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "~1.1.2",
+ "fresh": "0.5.2",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.5",
+ "qs": "6.7.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.1.2",
+ "send": "0.17.1",
+ "serve-static": "1.14.1",
+ "setprototypeof": "1.1.1",
+ "statuses": "~1.5.0",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ }
+ },
+ "express-fileupload": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npm.taobao.org/express-fileupload/download/express-fileupload-1.2.0.tgz",
+ "integrity": "sha1-NWxN/WRb5xq5+y9ObYTusA0keXk=",
+ "requires": {
+ "busboy": "^0.3.1"
+ }
+ },
+ "ext": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npm.taobao.org/ext/download/ext-1.4.0.tgz",
+ "integrity": "sha1-ia56BxWPedNVF4gpBDJAd+Q3kkQ=",
+ "dev": true,
+ "requires": {
+ "type": "^2.0.0"
+ },
+ "dependencies": {
+ "type": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npm.taobao.org/type/download/type-2.1.0.tgz?cache=0&sync_timestamp=1598016585110&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftype%2Fdownload%2Ftype-2.1.0.tgz",
+ "integrity": "sha1-m9wixkjPjPht0j0yM2pBz7ZHXj8=",
+ "dev": true
+ }
+ }
+ },
+ "fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true
+ },
+ "fast-diff": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
+ "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
+ "dev": true
+ },
+ "fast-glob": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npm.taobao.org/fast-glob/download/fast-glob-3.2.4.tgz?cache=0&sync_timestamp=1592291968616&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffast-glob%2Fdownload%2Ffast-glob-3.2.4.tgz",
+ "integrity": "sha1-0grvv5lXk4Pn88xmUpFYybmFVNM=",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.0",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.2",
+ "picomatch": "^2.2.1"
+ }
+ },
+ "fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
+ },
+ "fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npm.taobao.org/fast-levenshtein/download/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
+ },
+ "fastq": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npm.taobao.org/fastq/download/fastq-1.8.0.tgz?cache=0&sync_timestamp=1589280329638&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffastq%2Fdownload%2Ffastq-1.8.0.tgz",
+ "integrity": "sha1-VQ4fn1m7xl/hhctqm02VNXEH9IE=",
+ "dev": true,
+ "requires": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "figures": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
+ "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.5"
+ }
+ },
+ "file-entry-cache": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "dev": true,
+ "requires": {
+ "flat-cache": "^3.0.4"
+ }
+ },
+ "file-type": {
+ "version": "16.1.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.1.0.tgz",
+ "integrity": "sha512-G4Klqf6tuprtG0pC4r9kni4Wv8XhAAsfHphVqsQGA+YiOlPAO40BZduDqKfv0RFsu9q9ZbFObWfwszY/NqhEZw==",
+ "requires": {
+ "readable-web-to-node-stream": "^3.0.0",
+ "strtok3": "^6.0.3",
+ "token-types": "^2.0.0",
+ "typedarray-to-buffer": "^3.1.5"
+ }
+ },
+ "file-uri-to-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npm.taobao.org/file-uri-to-path/download/file-uri-to-path-2.0.0.tgz",
+ "integrity": "sha1-e0Fa66In1XWFHgpbDGQNdlZAP7o="
+ },
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npm.taobao.org/fill-range/download/fill-range-7.0.1.tgz",
+ "integrity": "sha1-GRmmp8df44ssfHflGYU12prN2kA=",
+ "dev": true,
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "finalhandler": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npm.taobao.org/finalhandler/download/finalhandler-1.1.2.tgz",
+ "integrity": "sha1-t+fQAP/RGTjQ/bBTUG9uur6fWH0=",
+ "requires": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "statuses": "~1.5.0",
+ "unpipe": "~1.0.0"
+ }
+ },
+ "find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "flat": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
+ "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
+ "dev": true
+ },
+ "flat-cache": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+ "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+ "dev": true,
+ "requires": {
+ "flatted": "^3.1.0",
+ "rimraf": "^3.0.2"
+ }
+ },
+ "flatted": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz",
+ "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==",
+ "dev": true
+ },
+ "follow-redirects": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz",
+ "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg=="
+ },
+ "forwarded": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npm.taobao.org/forwarded/download/forwarded-0.1.2.tgz",
+ "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
+ },
+ "fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npm.taobao.org/fresh/download/fresh-0.5.2.tgz",
+ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
+ },
+ "fs-extra": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npm.taobao.org/fs-extra/download/fs-extra-8.1.0.tgz",
+ "integrity": "sha1-SdQ8RaiM2Wd2aMt74bRu/bjS4cA=",
+ "requires": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npm.taobao.org/fs.realpath/download/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "dev": true
+ },
+ "fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "optional": true
+ },
+ "ftp": {
+ "version": "0.3.10",
+ "resolved": "https://registry.npm.taobao.org/ftp/download/ftp-0.3.10.tgz",
+ "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=",
+ "requires": {
+ "readable-stream": "1.1.x",
+ "xregexp": "2.0.0"
+ }
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npm.taobao.org/function-bind/download/function-bind-1.1.1.tgz",
+ "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=",
+ "dev": true
+ },
+ "functional-red-black-tree": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npm.taobao.org/functional-red-black-tree/download/functional-red-black-tree-1.0.1.tgz",
+ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
+ "dev": true
+ },
+ "get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npm.taobao.org/get-caller-file/download/get-caller-file-2.0.5.tgz",
+ "integrity": "sha1-T5RBKoLbMvNuOwuXQfipf+sDH34="
+ },
+ "get-own-enumerable-property-symbols": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz",
+ "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==",
+ "dev": true
+ },
+ "get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "dev": true,
+ "requires": {
+ "pump": "^3.0.0"
+ }
+ },
+ "get-uri": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npm.taobao.org/get-uri/download/get-uri-3.0.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fget-uri%2Fdownload%2Fget-uri-3.0.2.tgz",
+ "integrity": "sha1-8O8TVvqrxw4flAT6O2ayupv8clw=",
+ "requires": {
+ "@tootallnate/once": "1",
+ "data-uri-to-buffer": "3",
+ "debug": "4",
+ "file-uri-to-path": "2",
+ "fs-extra": "^8.1.0",
+ "ftp": "^0.3.10"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.2.0.tgz?cache=0&sync_timestamp=1600502894812&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-4.2.0.tgz",
+ "integrity": "sha1-fxUPk5IOlMWPVXTC/QGjEQ7/5/E=",
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz",
+ "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk="
+ }
+ }
+ },
+ "glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npm.taobao.org/glob/download/glob-7.1.6.tgz?cache=0&sync_timestamp=1573078121947&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fglob%2Fdownload%2Fglob-7.1.6.tgz",
+ "integrity": "sha1-FB8zuBp8JJLhJVlDB0gMRmeSeKY=",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "glob-parent": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npm.taobao.org/glob-parent/download/glob-parent-5.1.1.tgz",
+ "integrity": "sha1-tsHvQXxOVmPqSY8cRa+saRa7wik=",
+ "dev": true,
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ },
+ "globals": {
+ "version": "12.4.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
+ "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
+ "dev": true,
+ "requires": {
+ "type-fest": "^0.8.1"
+ }
+ },
+ "globby": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npm.taobao.org/globby/download/globby-11.0.1.tgz?cache=0&sync_timestamp=1591083783605&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fglobby%2Fdownload%2Fglobby-11.0.1.tgz",
+ "integrity": "sha1-mivxB6Bo8//qvEmtcCx57ejP01c=",
+ "dev": true,
+ "requires": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.1.1",
+ "ignore": "^5.1.4",
+ "merge2": "^1.3.0",
+ "slash": "^3.0.0"
+ }
+ },
+ "graceful-fs": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npm.taobao.org/graceful-fs/download/graceful-fs-4.2.4.tgz",
+ "integrity": "sha1-Ila94U02MpWMRl68ltxGfKB6Kfs="
+ },
+ "growl": {
+ "version": "1.10.5",
+ "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
+ "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
+ "dev": true
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npm.taobao.org/has/download/has-1.0.3.tgz",
+ "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "dev": true
+ },
+ "has-symbols": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npm.taobao.org/has-symbols/download/has-symbols-1.0.1.tgz",
+ "integrity": "sha1-n1IUdYpEGWxAbZvXbOv4HsLdMeg=",
+ "dev": true
+ },
+ "he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "dev": true
+ },
+ "htmlparser2": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-5.0.1.tgz",
+ "integrity": "sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "^2.0.1",
+ "domhandler": "^3.3.0",
+ "domutils": "^2.4.2",
+ "entities": "^2.0.0"
+ }
+ },
+ "http-errors": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.7.2.tgz?cache=0&sync_timestamp=1593407858306&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttp-errors%2Fdownload%2Fhttp-errors-1.7.2.tgz",
+ "integrity": "sha1-T1ApzxMjnzEDblsuVSkrz7zIXI8=",
+ "requires": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.1.1",
+ "statuses": ">= 1.5.0 < 2",
+ "toidentifier": "1.0.0"
+ }
+ },
+ "http-proxy-agent": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npm.taobao.org/http-proxy-agent/download/http-proxy-agent-4.0.1.tgz",
+ "integrity": "sha1-ioyO9/WTLM+VPClsqCkblap0qjo=",
+ "requires": {
+ "@tootallnate/once": "1",
+ "agent-base": "6",
+ "debug": "4"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.2.0.tgz?cache=0&sync_timestamp=1600502894812&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-4.2.0.tgz",
+ "integrity": "sha1-fxUPk5IOlMWPVXTC/QGjEQ7/5/E=",
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz",
+ "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk="
+ }
+ }
+ },
+ "https-proxy-agent": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npm.taobao.org/https-proxy-agent/download/https-proxy-agent-5.0.0.tgz?cache=0&sync_timestamp=1581106803611&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttps-proxy-agent%2Fdownload%2Fhttps-proxy-agent-5.0.0.tgz",
+ "integrity": "sha1-4qkFQqu2inYuCghQ9sntrf2FBrI=",
+ "requires": {
+ "agent-base": "6",
+ "debug": "4"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.2.0.tgz?cache=0&sync_timestamp=1600502894812&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-4.2.0.tgz",
+ "integrity": "sha1-fxUPk5IOlMWPVXTC/QGjEQ7/5/E=",
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz",
+ "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk="
+ }
+ }
+ },
+ "human-signals": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
+ "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==",
+ "dev": true
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.24.tgz?cache=0&sync_timestamp=1594184264130&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ficonv-lite%2Fdownload%2Ficonv-lite-0.4.24.tgz",
+ "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=",
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
+ },
+ "ignore": {
+ "version": "5.1.8",
+ "resolved": "https://registry.npm.taobao.org/ignore/download/ignore-5.1.8.tgz?cache=0&sync_timestamp=1590809289115&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fignore%2Fdownload%2Fignore-5.1.8.tgz",
+ "integrity": "sha1-8VCotQo0KJsz4i9YiavU2AFvDlc=",
+ "dev": true
+ },
+ "import-fresh": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npm.taobao.org/import-fresh/download/import-fresh-3.2.1.tgz",
+ "integrity": "sha1-Yz/2GFBueTr1rJG/SLcmd+FcvmY=",
+ "dev": true,
+ "requires": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ }
+ },
+ "imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+ "dev": true
+ },
+ "indent-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+ "dev": true
+ },
+ "indexof": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npm.taobao.org/indexof/download/indexof-0.0.1.tgz",
+ "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=",
+ "dev": true
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npm.taobao.org/inflight/download/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "dev": true,
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ },
+ "intelli-espower-loader": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npm.taobao.org/intelli-espower-loader/download/intelli-espower-loader-1.0.1.tgz",
+ "integrity": "sha1-LHsDFGvB1GvyENCgOXxckatMorA=",
+ "dev": true,
+ "requires": {
+ "espower-loader": "^1.0.0"
+ }
+ },
+ "ip": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npm.taobao.org/ip/download/ip-1.1.5.tgz",
+ "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
+ },
+ "ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npm.taobao.org/ipaddr.js/download/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha1-v/OFQ+64mEglB5/zoqjmy9RngbM="
+ },
+ "is-arguments": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npm.taobao.org/is-arguments/download/is-arguments-1.0.4.tgz",
+ "integrity": "sha1-P6+WbHy6D/Q3+zH2JQCC/PBEjPM=",
+ "dev": true
+ },
+ "is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
+ "dev": true
+ },
+ "is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "requires": {
+ "binary-extensions": "^2.0.0"
+ }
+ },
+ "is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
+ },
+ "is-callable": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npm.taobao.org/is-callable/download/is-callable-1.2.2.tgz?cache=0&sync_timestamp=1600719276620&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-callable%2Fdownload%2Fis-callable-1.2.2.tgz",
+ "integrity": "sha1-x8ZxXNItTdtI0+GZcCI6zquwgNk=",
+ "dev": true
+ },
+ "is-date-object": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npm.taobao.org/is-date-object/download/is-date-object-1.0.2.tgz?cache=0&sync_timestamp=1576729165697&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-date-object%2Fdownload%2Fis-date-object-1.0.2.tgz",
+ "integrity": "sha1-vac28s2P0G0yhE53Q7+nSUw7/X4=",
+ "dev": true
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npm.taobao.org/is-extglob/download/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-2.0.0.tgz",
+ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+ },
+ "is-glob": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npm.taobao.org/is-glob/download/is-glob-4.0.1.tgz",
+ "integrity": "sha1-dWfb6fL14kZ7x3q4PEopSCQHpdw=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-negative-zero": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npm.taobao.org/is-negative-zero/download/is-negative-zero-2.0.0.tgz",
+ "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=",
+ "dev": true
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npm.taobao.org/is-number/download/is-number-7.0.0.tgz",
+ "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=",
+ "dev": true
+ },
+ "is-obj": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
+ "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
+ "dev": true
+ },
+ "is-plain-obj": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+ "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+ "dev": true
+ },
+ "is-regex": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npm.taobao.org/is-regex/download/is-regex-1.1.1.tgz?cache=0&sync_timestamp=1596555762356&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-regex%2Fdownload%2Fis-regex-1.1.1.tgz",
+ "integrity": "sha1-xvmKrMVG9s7FRooHt7FTq1ZKV7k=",
+ "dev": true,
+ "requires": {
+ "has-symbols": "^1.0.1"
+ }
+ },
+ "is-regexp": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz",
+ "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=",
+ "dev": true
+ },
+ "is-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
+ "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
+ "dev": true
+ },
+ "is-symbol": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npm.taobao.org/is-symbol/download/is-symbol-1.0.3.tgz",
+ "integrity": "sha1-OOEBS55jKb4N6dJKQU/XRB7GGTc=",
+ "dev": true,
+ "requires": {
+ "has-symbols": "^1.0.1"
+ }
+ },
+ "is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
+ },
+ "is-url": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npm.taobao.org/is-url/download/is-url-1.2.4.tgz",
+ "integrity": "sha1-BKTfRtKMTP89c9Af8Gq+sxihqlI=",
+ "dev": true
+ },
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npm.taobao.org/isarray/download/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+ },
+ "isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npm.taobao.org/isexe/download/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+ "dev": true
+ },
+ "js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npm.taobao.org/js-tokens/download/js-tokens-4.0.0.tgz?cache=0&sync_timestamp=1586796260005&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjs-tokens%2Fdownload%2Fjs-tokens-4.0.0.tgz",
+ "integrity": "sha1-GSA/tZmR35jjoocFDUZHzerzJJk=",
+ "dev": true
+ },
+ "js-yaml": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "dev": true,
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
+ "json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "dev": true
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+ "dev": true
+ },
+ "jsonfile": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npm.taobao.org/jsonfile/download/jsonfile-4.0.0.tgz",
+ "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
+ "requires": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "levn": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npm.taobao.org/levn/download/levn-0.3.0.tgz",
+ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+ "requires": {
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2"
+ }
+ },
+ "lines-and-columns": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz",
+ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=",
+ "dev": true
+ },
+ "lint-staged": {
+ "version": "10.5.4",
+ "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.5.4.tgz",
+ "integrity": "sha512-EechC3DdFic/TdOPgj/RB3FicqE6932LTHCUm0Y2fsD9KGlLB+RwJl2q1IYBIvEsKzDOgn0D4gll+YxG5RsrKg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^4.1.0",
+ "cli-truncate": "^2.1.0",
+ "commander": "^6.2.0",
+ "cosmiconfig": "^7.0.0",
+ "debug": "^4.2.0",
+ "dedent": "^0.7.0",
+ "enquirer": "^2.3.6",
+ "execa": "^4.1.0",
+ "listr2": "^3.2.2",
+ "log-symbols": "^4.0.0",
+ "micromatch": "^4.0.2",
+ "normalize-path": "^3.0.0",
+ "please-upgrade-node": "^3.2.0",
+ "string-argv": "0.3.1",
+ "stringify-object": "^3.3.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+ "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "dev": true,
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ }
+ }
+ },
+ "listr2": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.4.1.tgz",
+ "integrity": "sha512-TYim70Kml0vISlYH7mWHqeiBytkfDwWtp4Z+HmxEXWkXCRz6sCxHisOM3b1w+OYfhLlwB7ADblC0cdZhZIriPA==",
+ "dev": true,
+ "requires": {
+ "chalk": "^4.1.0",
+ "cli-truncate": "^2.1.0",
+ "figures": "^3.2.0",
+ "indent-string": "^4.0.0",
+ "log-update": "^4.0.0",
+ "p-map": "^4.0.0",
+ "rxjs": "^6.6.6",
+ "through": "^2.3.8",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^5.0.0"
+ }
+ },
+ "lodash": {
+ "version": "4.17.20",
+ "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.20.tgz?cache=0&sync_timestamp=1597335994883&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.20.tgz",
+ "integrity": "sha1-tEqbYpe8tpjxxRo1RaKzs2jVnFI=",
+ "dev": true
+ },
+ "log-symbols": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npm.taobao.org/log-symbols/download/log-symbols-4.0.0.tgz?cache=0&sync_timestamp=1587898912367&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flog-symbols%2Fdownload%2Flog-symbols-4.0.0.tgz",
+ "integrity": "sha1-abPMRtIPRI7M23XqH6cz2eghySA=",
+ "dev": true,
+ "requires": {
+ "chalk": "^4.0.0"
+ }
+ },
+ "log-update": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz",
+ "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==",
+ "dev": true,
+ "requires": {
+ "ansi-escapes": "^4.3.0",
+ "cli-cursor": "^3.1.0",
+ "slice-ansi": "^4.0.0",
+ "wrap-ansi": "^6.2.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
+ "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ }
+ }
+ }
+ },
+ "md5": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
+ "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
+ "requires": {
+ "charenc": "0.0.2",
+ "crypt": "0.0.2",
+ "is-buffer": "~1.1.6"
+ }
+ },
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npm.taobao.org/media-typer/download/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+ },
+ "merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npm.taobao.org/merge-descriptors/download/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+ },
+ "merge-estraverse-visitors": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npm.taobao.org/merge-estraverse-visitors/download/merge-estraverse-visitors-1.0.0.tgz",
+ "integrity": "sha1-65aDOLXe1c7tgs7AMH3sui2OqZQ=",
+ "dev": true,
+ "requires": {
+ "estraverse": "^4.0.0"
+ }
+ },
+ "merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+ "dev": true
+ },
+ "merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npm.taobao.org/merge2/download/merge2-1.4.1.tgz?cache=0&sync_timestamp=1591170027156&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmerge2%2Fdownload%2Fmerge2-1.4.1.tgz",
+ "integrity": "sha1-Q2iJL4hekHRVpv19xVwMnUBJkK4=",
+ "dev": true
+ },
+ "methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npm.taobao.org/methods/download/methods-1.1.2.tgz",
+ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
+ },
+ "micromatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npm.taobao.org/micromatch/download/micromatch-4.0.2.tgz",
+ "integrity": "sha1-T8sJmb+fvC/L3SEvbWKbmlbDklk=",
+ "dev": true,
+ "requires": {
+ "braces": "^3.0.1",
+ "picomatch": "^2.0.5"
+ }
+ },
+ "mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npm.taobao.org/mime/download/mime-1.6.0.tgz?cache=0&sync_timestamp=1590596706367&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmime%2Fdownload%2Fmime-1.6.0.tgz",
+ "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE="
+ },
+ "mime-db": {
+ "version": "1.44.0",
+ "resolved": "https://registry.npm.taobao.org/mime-db/download/mime-db-1.44.0.tgz?cache=0&sync_timestamp=1600831210195&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmime-db%2Fdownload%2Fmime-db-1.44.0.tgz",
+ "integrity": "sha1-+hHF6wrKEzS0Izy01S8QxaYnL5I="
+ },
+ "mime-types": {
+ "version": "2.1.27",
+ "resolved": "https://registry.npm.taobao.org/mime-types/download/mime-types-2.1.27.tgz",
+ "integrity": "sha1-R5SfmOJ56lMRn1ci4PNOUpvsAJ8=",
+ "requires": {
+ "mime-db": "1.44.0"
+ }
+ },
+ "mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "dev": true
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz",
+ "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "mocha": {
+ "version": "8.3.1",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.3.1.tgz",
+ "integrity": "sha512-5SBMxANWqOv5bw3Hx+HVgaWlcWcFEQDUdaUAr1AUU+qwtx6cowhn7gEDT/DwQP7uYxnvShdUOVLbTYAHOEGfDQ==",
+ "dev": true,
+ "requires": {
+ "@ungap/promise-all-settled": "1.1.2",
+ "ansi-colors": "4.1.1",
+ "browser-stdout": "1.3.1",
+ "chokidar": "3.5.1",
+ "debug": "4.3.1",
+ "diff": "5.0.0",
+ "escape-string-regexp": "4.0.0",
+ "find-up": "5.0.0",
+ "glob": "7.1.6",
+ "growl": "1.10.5",
+ "he": "1.2.0",
+ "js-yaml": "4.0.0",
+ "log-symbols": "4.0.0",
+ "minimatch": "3.0.4",
+ "ms": "2.1.3",
+ "nanoid": "3.1.20",
+ "serialize-javascript": "5.0.1",
+ "strip-json-comments": "3.1.1",
+ "supports-color": "8.1.1",
+ "which": "2.0.2",
+ "wide-align": "1.1.3",
+ "workerpool": "6.1.0",
+ "yargs": "16.2.0",
+ "yargs-parser": "20.2.4",
+ "yargs-unparser": "2.0.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
+ "cliui": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+ "dev": true,
+ "requires": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "debug": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+ "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "dev": true,
+ "requires": {
+ "ms": "2.1.2"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ }
+ }
+ },
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "js-yaml": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz",
+ "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==",
+ "dev": true,
+ "requires": {
+ "argparse": "^2.0.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
+ "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ },
+ "wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "y18n": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz",
+ "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==",
+ "dev": true
+ },
+ "yargs": {
+ "version": "16.2.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+ "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+ "dev": true,
+ "requires": {
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.0",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^20.2.2"
+ }
+ },
+ "yargs-parser": {
+ "version": "20.2.4",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
+ "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
+ "dev": true
+ }
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "multi-stage-sourcemap": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npm.taobao.org/multi-stage-sourcemap/download/multi-stage-sourcemap-0.2.1.tgz",
+ "integrity": "sha1-sJ/IWG6qF/gdV1xK0C4Pej9rEQU=",
+ "dev": true,
+ "requires": {
+ "source-map": "^0.1.34"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.1.43",
+ "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.1.43.tgz?cache=0&sync_timestamp=1571657176668&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.1.43.tgz",
+ "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=",
+ "dev": true,
+ "requires": {
+ "amdefine": ">=0.0.4"
+ }
+ }
+ }
+ },
+ "music-metadata": {
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/music-metadata/-/music-metadata-7.6.0.tgz",
+ "integrity": "sha512-XSBNmv+4JwithIharDmqwEVGLqEQ62nvrpSJAc5OQcgciSlTjjZLxmAQRic1AofiMB4t45D4MS4mwGk/5PeVeQ==",
+ "requires": {
+ "content-type": "^1.0.4",
+ "debug": "^4.3.1",
+ "file-type": "^16.1.0",
+ "media-typer": "^1.1.0",
+ "strtok3": "^6.0.4",
+ "token-types": "^2.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+ "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "media-typer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
+ "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ }
+ }
+ },
+ "nanoid": {
+ "version": "3.1.20",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz",
+ "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==",
+ "dev": true
+ },
+ "natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+ "dev": true
+ },
+ "negotiator": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npm.taobao.org/negotiator/download/negotiator-0.6.2.tgz",
+ "integrity": "sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs="
+ },
+ "netmask": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npm.taobao.org/netmask/download/netmask-1.0.6.tgz",
+ "integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU="
+ },
+ "next-tick": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npm.taobao.org/next-tick/download/next-tick-1.0.0.tgz",
+ "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
+ "dev": true
+ },
+ "normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npm.taobao.org/normalize-path/download/normalize-path-3.0.0.tgz",
+ "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=",
+ "dev": true
+ },
+ "npm-run-path": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+ "dev": true,
+ "requires": {
+ "path-key": "^3.0.0"
+ }
+ },
+ "object-inspect": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npm.taobao.org/object-inspect/download/object-inspect-1.8.0.tgz?cache=0&sync_timestamp=1592545231350&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fobject-inspect%2Fdownload%2Fobject-inspect-1.8.0.tgz",
+ "integrity": "sha1-34B+Xs9TpgnMa/6T6sPMe+WzqdA=",
+ "dev": true
+ },
+ "object-is": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npm.taobao.org/object-is/download/object-is-1.1.3.tgz?cache=0&sync_timestamp=1601502788762&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fobject-is%2Fdownload%2Fobject-is-1.1.3.tgz",
+ "integrity": "sha1-LjueZVYBN0Ve471irsTZCi6hzIE=",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.1"
+ }
+ },
+ "object-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npm.taobao.org/object-keys/download/object-keys-1.1.1.tgz",
+ "integrity": "sha1-HEfyct8nfzsdrwYWd9nILiMixg4=",
+ "dev": true
+ },
+ "object.assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npm.taobao.org/object.assign/download/object.assign-4.1.1.tgz?cache=0&sync_timestamp=1599844927493&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fobject.assign%2Fdownload%2Fobject.assign-4.1.1.tgz",
+ "integrity": "sha1-MDhnpmbN1Bk27N7fsfjz4ypHjN0=",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.0",
+ "has-symbols": "^1.0.1",
+ "object-keys": "^1.1.1"
+ }
+ },
+ "on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npm.taobao.org/on-finished/download/on-finished-2.3.0.tgz",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npm.taobao.org/once/download/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "dev": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "onetime": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "dev": true,
+ "requires": {
+ "mimic-fn": "^2.1.0"
+ }
+ },
+ "optionator": {
+ "version": "0.8.3",
+ "resolved": "https://registry.npm.taobao.org/optionator/download/optionator-0.8.3.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Foptionator%2Fdownload%2Foptionator-0.8.3.tgz",
+ "integrity": "sha1-hPodA2/p08fiHZmIS2ARZ+yPtJU=",
+ "requires": {
+ "deep-is": "~0.1.3",
+ "fast-levenshtein": "~2.0.6",
+ "levn": "~0.3.0",
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2",
+ "word-wrap": "~1.2.3"
+ }
+ },
+ "p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npm.taobao.org/p-limit/download/p-limit-2.3.0.tgz?cache=0&sync_timestamp=1594559734248&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fp-limit%2Fdownload%2Fp-limit-2.3.0.tgz",
+ "integrity": "sha1-PdM8ZHohT9//2DWTPrCG2g3CHbE=",
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^3.0.2"
+ },
+ "dependencies": {
+ "p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "requires": {
+ "yocto-queue": "^0.1.0"
+ }
+ }
+ }
+ },
+ "p-map": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
+ "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
+ "dev": true,
+ "requires": {
+ "aggregate-error": "^3.0.0"
+ }
+ },
+ "p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npm.taobao.org/p-try/download/p-try-2.2.0.tgz",
+ "integrity": "sha1-yyhoVA4xPWHeWPr741zpAE1VQOY="
+ },
+ "pac-proxy-agent": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npm.taobao.org/pac-proxy-agent/download/pac-proxy-agent-4.1.0.tgz",
+ "integrity": "sha1-Zog+6rrckV/F6VRXMkyw8Kx43vs=",
+ "requires": {
+ "@tootallnate/once": "1",
+ "agent-base": "6",
+ "debug": "4",
+ "get-uri": "3",
+ "http-proxy-agent": "^4.0.1",
+ "https-proxy-agent": "5",
+ "pac-resolver": "^4.1.0",
+ "raw-body": "^2.2.0",
+ "socks-proxy-agent": "5"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.2.0.tgz?cache=0&sync_timestamp=1600502894812&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-4.2.0.tgz",
+ "integrity": "sha1-fxUPk5IOlMWPVXTC/QGjEQ7/5/E=",
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz",
+ "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk="
+ }
+ }
+ },
+ "pac-resolver": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npm.taobao.org/pac-resolver/download/pac-resolver-4.1.0.tgz?cache=0&sync_timestamp=1581134452130&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpac-resolver%2Fdownload%2Fpac-resolver-4.1.0.tgz",
+ "integrity": "sha1-SxLn0JayVaO4TlP2gx8y6cfl/pU=",
+ "requires": {
+ "degenerator": "^2.2.0",
+ "ip": "^1.1.5",
+ "netmask": "^1.0.6"
+ }
+ },
+ "parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npm.taobao.org/parent-module/download/parent-module-1.0.1.tgz",
+ "integrity": "sha1-aR0nCeeMefrjoVZiJFLQB2LKqqI=",
+ "dev": true,
+ "requires": {
+ "callsites": "^3.0.0"
+ }
+ },
+ "parse-json": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+ "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-even-better-errors": "^2.3.0",
+ "lines-and-columns": "^1.1.6"
+ }
+ },
+ "parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npm.taobao.org/parseurl/download/parseurl-1.3.3.tgz",
+ "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ="
+ },
+ "path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "dev": true
+ },
+ "path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npm.taobao.org/path-key/download/path-key-3.1.1.tgz",
+ "integrity": "sha1-WB9q3mWMu6ZaDTOA3ndTKVBU83U=",
+ "dev": true
+ },
+ "path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npm.taobao.org/path-to-regexp/download/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+ },
+ "path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npm.taobao.org/path-type/download/path-type-4.0.0.tgz",
+ "integrity": "sha1-hO0BwKe6OAr+CdkKjBgNzZ0DBDs=",
+ "dev": true
+ },
+ "peek-readable": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-3.1.0.tgz",
+ "integrity": "sha512-KGuODSTV6hcgdZvDrIDBUkN0utcAVj1LL7FfGbM0viKTtCHmtZcuEJ+lGqsp0fTFkGqesdtemV2yUSMeyy3ddA=="
+ },
+ "picomatch": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npm.taobao.org/picomatch/download/picomatch-2.2.2.tgz?cache=0&sync_timestamp=1584790434095&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpicomatch%2Fdownload%2Fpicomatch-2.2.2.tgz",
+ "integrity": "sha1-IfMz6ba46v8CRo9RRupAbTRfTa0=",
+ "dev": true
+ },
+ "please-upgrade-node": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz",
+ "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==",
+ "dev": true,
+ "requires": {
+ "semver-compare": "^1.0.0"
+ }
+ },
+ "pngjs": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz",
+ "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w=="
+ },
+ "power-assert": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npm.taobao.org/power-assert/download/power-assert-1.6.1.tgz",
+ "integrity": "sha1-soy8Aq6Aiv0UMdDNUJOjmsWlsf4=",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.2",
+ "empower": "^1.3.1",
+ "power-assert-formatter": "^1.4.1",
+ "universal-deep-strict-equal": "^1.2.1",
+ "xtend": "^4.0.0"
+ }
+ },
+ "power-assert-context-formatter": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npm.taobao.org/power-assert-context-formatter/download/power-assert-context-formatter-1.2.0.tgz",
+ "integrity": "sha1-j75yaSKI7FpyA83yFci4OKYGHSo=",
+ "dev": true,
+ "requires": {
+ "core-js": "^2.0.0",
+ "power-assert-context-traversal": "^1.2.0"
+ }
+ },
+ "power-assert-context-reducer-ast": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npm.taobao.org/power-assert-context-reducer-ast/download/power-assert-context-reducer-ast-1.2.0.tgz",
+ "integrity": "sha1-x8ocnjmm+3F/esX+nnbhkr9SXfM=",
+ "dev": true,
+ "requires": {
+ "acorn": "^5.0.0",
+ "acorn-es7-plugin": "^1.0.12",
+ "core-js": "^2.0.0",
+ "espurify": "^1.6.0",
+ "estraverse": "^4.2.0"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "5.7.4",
+ "resolved": "https://registry.npm.taobao.org/acorn/download/acorn-5.7.4.tgz",
+ "integrity": "sha1-Po2KmUfQWZoXltECJddDL0pKz14=",
+ "dev": true
+ }
+ }
+ },
+ "power-assert-context-traversal": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npm.taobao.org/power-assert-context-traversal/download/power-assert-context-traversal-1.2.0.tgz",
+ "integrity": "sha1-9ucUVLr2QN5cHJwnA0n1yasLLpQ=",
+ "dev": true,
+ "requires": {
+ "core-js": "^2.0.0",
+ "estraverse": "^4.1.0"
+ }
+ },
+ "power-assert-formatter": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npm.taobao.org/power-assert-formatter/download/power-assert-formatter-1.4.1.tgz",
+ "integrity": "sha1-XcEl7VCj37HdomwZNH879Y7CiEo=",
+ "dev": true,
+ "requires": {
+ "core-js": "^2.0.0",
+ "power-assert-context-formatter": "^1.0.7",
+ "power-assert-context-reducer-ast": "^1.0.7",
+ "power-assert-renderer-assertion": "^1.0.7",
+ "power-assert-renderer-comparison": "^1.0.7",
+ "power-assert-renderer-diagram": "^1.0.7",
+ "power-assert-renderer-file": "^1.0.7"
+ }
+ },
+ "power-assert-renderer-assertion": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npm.taobao.org/power-assert-renderer-assertion/download/power-assert-renderer-assertion-1.2.0.tgz",
+ "integrity": "sha1-Pbb/zaEGs3vB4GQyrQ10imgrFHo=",
+ "dev": true,
+ "requires": {
+ "power-assert-renderer-base": "^1.1.1",
+ "power-assert-util-string-width": "^1.2.0"
+ }
+ },
+ "power-assert-renderer-base": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npm.taobao.org/power-assert-renderer-base/download/power-assert-renderer-base-1.1.1.tgz",
+ "integrity": "sha1-lqZQxv0F7hvB9mtUrWFELIs/Y+s=",
+ "dev": true
+ },
+ "power-assert-renderer-comparison": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npm.taobao.org/power-assert-renderer-comparison/download/power-assert-renderer-comparison-1.2.0.tgz",
+ "integrity": "sha1-5PiBEyJaab6KpYbq0FrvmUYsBJU=",
+ "dev": true,
+ "requires": {
+ "core-js": "^2.0.0",
+ "diff-match-patch": "^1.0.0",
+ "power-assert-renderer-base": "^1.1.1",
+ "stringifier": "^1.3.0",
+ "type-name": "^2.0.1"
+ }
+ },
+ "power-assert-renderer-diagram": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npm.taobao.org/power-assert-renderer-diagram/download/power-assert-renderer-diagram-1.2.0.tgz",
+ "integrity": "sha1-N/ZuhULlZ3xbWObXKwHA2aMOIhk=",
+ "dev": true,
+ "requires": {
+ "core-js": "^2.0.0",
+ "power-assert-renderer-base": "^1.1.1",
+ "power-assert-util-string-width": "^1.2.0",
+ "stringifier": "^1.3.0"
+ }
+ },
+ "power-assert-renderer-file": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npm.taobao.org/power-assert-renderer-file/download/power-assert-renderer-file-1.2.0.tgz",
+ "integrity": "sha1-P0vr2eFFXXXPKsVB57tRWofUzks=",
+ "dev": true,
+ "requires": {
+ "power-assert-renderer-base": "^1.1.1"
+ }
+ },
+ "power-assert-util-string-width": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npm.taobao.org/power-assert-util-string-width/download/power-assert-util-string-width-1.2.0.tgz",
+ "integrity": "sha1-bgbV41gbuHbF03fFMQn/+pW9kaA=",
+ "dev": true,
+ "requires": {
+ "eastasianwidth": "^0.2.0"
+ }
+ },
+ "prelude-ls": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npm.taobao.org/prelude-ls/download/prelude-ls-1.1.2.tgz",
+ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
+ },
+ "prettier": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz",
+ "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==",
+ "dev": true
+ },
+ "prettier-linter-helpers": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
+ "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
+ "dev": true,
+ "requires": {
+ "fast-diff": "^1.1.2"
+ }
+ },
+ "progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "dev": true
+ },
+ "proxy-addr": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npm.taobao.org/proxy-addr/download/proxy-addr-2.0.6.tgz",
+ "integrity": "sha1-/cIzZQVEfT8vLGOO0nLK9hS7sr8=",
+ "requires": {
+ "forwarded": "~0.1.2",
+ "ipaddr.js": "1.9.1"
+ }
+ },
+ "pump": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+ "dev": true,
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "dev": true
+ },
+ "qrcode": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.4.4.tgz",
+ "integrity": "sha512-oLzEC5+NKFou9P0bMj5+v6Z40evexeE29Z9cummZXZ9QXyMr3lphkURzxjXgPJC5azpxcshoDWV1xE46z+/c3Q==",
+ "requires": {
+ "buffer": "^5.4.3",
+ "buffer-alloc": "^1.2.0",
+ "buffer-from": "^1.1.1",
+ "dijkstrajs": "^1.0.1",
+ "isarray": "^2.0.1",
+ "pngjs": "^3.3.0",
+ "yargs": "^13.2.4"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+ "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="
+ }
+ }
+ },
+ "qs": {
+ "version": "6.7.0",
+ "resolved": "https://registry.npm.taobao.org/qs/download/qs-6.7.0.tgz",
+ "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw="
+ },
+ "randombytes": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+ "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npm.taobao.org/range-parser/download/range-parser-1.2.1.tgz",
+ "integrity": "sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE="
+ },
+ "raw-body": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npm.taobao.org/raw-body/download/raw-body-2.4.0.tgz",
+ "integrity": "sha1-oc5vucm8NWylLoklarWQWeE9AzI=",
+ "requires": {
+ "bytes": "3.1.0",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ }
+ },
+ "readable-stream": {
+ "version": "1.1.14",
+ "resolved": "https://registry.npm.taobao.org/readable-stream/download/readable-stream-1.1.14.tgz?cache=0&sync_timestamp=1581624324274&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freadable-stream%2Fdownload%2Freadable-stream-1.1.14.tgz",
+ "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "~0.10.x"
+ }
+ },
+ "readable-web-to-node-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.0.tgz",
+ "integrity": "sha512-HNmLb3n0SteGAs8HQlErYPGeO+y7cvL/mVUKtXeUkl0iCZ/2GIgKGrCFHyS7UXFnO8uc9U+0y3pYIzAPsjFfvA==",
+ "requires": {
+ "@types/readable-stream": "^2.3.9",
+ "readable-stream": "^3.6.0"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
+ },
+ "string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "requires": {
+ "safe-buffer": "~5.2.0"
+ }
+ }
+ }
+ },
+ "readdirp": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
+ "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
+ "dev": true,
+ "requires": {
+ "picomatch": "^2.2.1"
+ }
+ },
+ "regexp.prototype.flags": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npm.taobao.org/regexp.prototype.flags/download/regexp.prototype.flags-1.3.0.tgz?cache=0&sync_timestamp=1576388141321&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fregexp.prototype.flags%2Fdownload%2Fregexp.prototype.flags-1.3.0.tgz",
+ "integrity": "sha1-erqJs8E6ZFCdq888qNn7ub31y3U=",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.17.0-next.1"
+ },
+ "dependencies": {
+ "es-abstract": {
+ "version": "1.17.7",
+ "resolved": "https://registry.npm.taobao.org/es-abstract/download/es-abstract-1.17.7.tgz?cache=0&sync_timestamp=1601502719982&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fes-abstract%2Fdownload%2Fes-abstract-1.17.7.tgz",
+ "integrity": "sha1-pN5hsvZpifx0IWdsHLl4dXOs5Uw=",
+ "dev": true,
+ "requires": {
+ "es-to-primitive": "^1.2.1",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1",
+ "is-callable": "^1.2.2",
+ "is-regex": "^1.1.1",
+ "object-inspect": "^1.8.0",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.1",
+ "string.prototype.trimend": "^1.0.1",
+ "string.prototype.trimstart": "^1.0.1"
+ }
+ }
+ }
+ },
+ "regexpp": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npm.taobao.org/regexpp/download/regexpp-3.1.0.tgz",
+ "integrity": "sha1-IG0K0KVkjP+9uK5GQ489xRyfeOI=",
+ "dev": true
+ },
+ "require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npm.taobao.org/require-directory/download/require-directory-2.1.1.tgz",
+ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
+ },
+ "require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "dev": true
+ },
+ "require-main-filename": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npm.taobao.org/require-main-filename/download/require-main-filename-2.0.0.tgz",
+ "integrity": "sha1-0LMp7MfMD2Fkn2IhW+aa9UqomJs="
+ },
+ "resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npm.taobao.org/resolve-from/download/resolve-from-4.0.0.tgz",
+ "integrity": "sha1-SrzYUq0y3Xuqv+m0DgCjbbXzkuY=",
+ "dev": true
+ },
+ "restore-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
+ "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
+ "dev": true,
+ "requires": {
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2"
+ }
+ },
+ "reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npm.taobao.org/reusify/download/reusify-1.0.4.tgz",
+ "integrity": "sha1-kNo4Kx4SbvwCFG6QhFqI2xKSXXY=",
+ "dev": true
+ },
+ "rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "run-parallel": {
+ "version": "1.1.9",
+ "resolved": "https://registry.npm.taobao.org/run-parallel/download/run-parallel-1.1.9.tgz",
+ "integrity": "sha1-yd06fPn0ssS2JE4XOm7YZuYd1nk=",
+ "dev": true
+ },
+ "rxjs": {
+ "version": "6.6.6",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.6.tgz",
+ "integrity": "sha512-/oTwee4N4iWzAMAL9xdGKjkEHmIwupR3oXbQjCKywF1BeFohswF3vZdogbmEF6pZkOsXTzWkrZszrWpQTByYVg==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.9.0"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "dev": true
+ }
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz",
+ "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0="
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npm.taobao.org/safer-buffer/download/safer-buffer-2.1.2.tgz",
+ "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo="
+ },
+ "semver": {
+ "version": "7.3.2",
+ "resolved": "https://registry.npm.taobao.org/semver/download/semver-7.3.2.tgz",
+ "integrity": "sha1-YElisFK4HtB4aq6EOJ/7pw/9OTg=",
+ "dev": true
+ },
+ "semver-compare": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
+ "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=",
+ "dev": true
+ },
+ "send": {
+ "version": "0.17.1",
+ "resolved": "https://registry.npm.taobao.org/send/download/send-0.17.1.tgz",
+ "integrity": "sha1-wdiwWfeQD3Rm3Uk4vcROEd2zdsg=",
+ "requires": {
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "destroy": "~1.0.4",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "~1.7.2",
+ "mime": "1.6.0",
+ "ms": "2.1.1",
+ "on-finished": "~2.3.0",
+ "range-parser": "~1.2.1",
+ "statuses": "~1.5.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.1.tgz",
+ "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo="
+ }
+ }
+ },
+ "serialize-javascript": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz",
+ "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==",
+ "dev": true,
+ "requires": {
+ "randombytes": "^2.1.0"
+ }
+ },
+ "serve-static": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npm.taobao.org/serve-static/download/serve-static-1.14.1.tgz",
+ "integrity": "sha1-Zm5jbcTwEPfvKZcKiKZ0MgiYsvk=",
+ "requires": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.17.1"
+ }
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npm.taobao.org/set-blocking/download/set-blocking-2.0.0.tgz",
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
+ },
+ "setprototypeof": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.1.1.tgz",
+ "integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM="
+ },
+ "shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npm.taobao.org/shebang-command/download/shebang-command-2.0.0.tgz",
+ "integrity": "sha1-zNCvT4g1+9wmW4JGGq8MNmY/NOo=",
+ "dev": true,
+ "requires": {
+ "shebang-regex": "^3.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npm.taobao.org/shebang-regex/download/shebang-regex-3.0.0.tgz",
+ "integrity": "sha1-rhbxZE2HPsrYQ7AwexQzYtTEIXI=",
+ "dev": true
+ },
+ "signal-exit": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
+ "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
+ "dev": true
+ },
+ "slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npm.taobao.org/slash/download/slash-3.0.0.tgz",
+ "integrity": "sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ=",
+ "dev": true
+ },
+ "slice-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+ "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ }
+ }
+ },
+ "smart-buffer": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npm.taobao.org/smart-buffer/download/smart-buffer-4.1.0.tgz",
+ "integrity": "sha1-kWBcJdkWUvRmHqacz0XxszHKIbo="
+ },
+ "socks": {
+ "version": "2.4.4",
+ "resolved": "https://registry.npm.taobao.org/socks/download/socks-2.4.4.tgz?cache=0&sync_timestamp=1599605506578&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsocks%2Fdownload%2Fsocks-2.4.4.tgz",
+ "integrity": "sha1-8aM4LngUrijJe7gqOLwawkshzKI=",
+ "requires": {
+ "ip": "^1.1.5",
+ "smart-buffer": "^4.1.0"
+ }
+ },
+ "socks-proxy-agent": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npm.taobao.org/socks-proxy-agent/download/socks-proxy-agent-5.0.0.tgz?cache=0&sync_timestamp=1580845554635&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsocks-proxy-agent%2Fdownload%2Fsocks-proxy-agent-5.0.0.tgz",
+ "integrity": "sha1-fA82Tnsc9KekN+cSU77XLpAEvmA=",
+ "requires": {
+ "agent-base": "6",
+ "debug": "4",
+ "socks": "^2.3.3"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.2.0.tgz?cache=0&sync_timestamp=1600502894812&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-4.2.0.tgz",
+ "integrity": "sha1-fxUPk5IOlMWPVXTC/QGjEQ7/5/E=",
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz",
+ "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk="
+ }
+ }
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz?cache=0&sync_timestamp=1571657176668&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.6.1.tgz",
+ "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=",
+ "optional": true
+ },
+ "source-map-support": {
+ "version": "0.4.18",
+ "resolved": "https://registry.npm.taobao.org/source-map-support/download/source-map-support-0.4.18.tgz?cache=0&sync_timestamp=1587719289626&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map-support%2Fdownload%2Fsource-map-support-0.4.18.tgz",
+ "integrity": "sha1-Aoam3ovkJkEzhZTpfM6nXwosWF8=",
+ "dev": true,
+ "requires": {
+ "source-map": "^0.5.6"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz?cache=0&sync_timestamp=1571657176668&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ }
+ }
+ },
+ "sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+ "dev": true
+ },
+ "statuses": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npm.taobao.org/statuses/download/statuses-1.5.0.tgz?cache=0&sync_timestamp=1587327902535&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstatuses%2Fdownload%2Fstatuses-1.5.0.tgz",
+ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
+ },
+ "streamsearch": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npm.taobao.org/streamsearch/download/streamsearch-0.1.2.tgz",
+ "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
+ },
+ "string-argv": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz",
+ "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npm.taobao.org/string-width/download/string-width-3.1.0.tgz",
+ "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=",
+ "requires": {
+ "emoji-regex": "^7.0.1",
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^5.1.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-4.1.0.tgz",
+ "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc="
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz?cache=0&sync_timestamp=1573280518303&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-5.2.0.tgz",
+ "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=",
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ }
+ }
+ }
+ },
+ "string.prototype.trimend": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npm.taobao.org/string.prototype.trimend/download/string.prototype.trimend-1.0.2.tgz?cache=0&sync_timestamp=1603219618123&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstring.prototype.trimend%2Fdownload%2Fstring.prototype.trimend-1.0.2.tgz",
+ "integrity": "sha1-bd2ah5a8cUtImjriIkaiCPN7+kY=",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.1"
+ }
+ },
+ "string.prototype.trimstart": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npm.taobao.org/string.prototype.trimstart/download/string.prototype.trimstart-1.0.2.tgz?cache=0&sync_timestamp=1603219618047&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstring.prototype.trimstart%2Fdownload%2Fstring.prototype.trimstart-1.0.2.tgz",
+ "integrity": "sha1-ItRdqBAVMJzQzdeXh+iRn8XGE+c=",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.1"
+ }
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npm.taobao.org/string_decoder/download/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+ },
+ "stringifier": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npm.taobao.org/stringifier/download/stringifier-1.4.0.tgz",
+ "integrity": "sha1-1wRYFWf0UmJl0A7Y7LNUoCw/7Cg=",
+ "dev": true,
+ "requires": {
+ "core-js": "^2.0.0",
+ "traverse": "^0.6.6",
+ "type-name": "^2.0.1"
+ }
+ },
+ "stringify-object": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz",
+ "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==",
+ "dev": true,
+ "requires": {
+ "get-own-enumerable-property-symbols": "^3.0.0",
+ "is-obj": "^1.0.1",
+ "is-regexp": "^1.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-6.0.0.tgz?cache=0&sync_timestamp=1573280518303&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-6.0.0.tgz",
+ "integrity": "sha1-CxVx3XZpzNTz4G4U7x7tJiJa5TI=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ },
+ "strip-final-newline": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+ "dev": true
+ },
+ "strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npm.taobao.org/strip-json-comments/download/strip-json-comments-3.1.1.tgz?cache=0&sync_timestamp=1594567532500&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-json-comments%2Fdownload%2Fstrip-json-comments-3.1.1.tgz",
+ "integrity": "sha1-MfEoGzgyYwQ0gxwxDAHMzajL4AY=",
+ "dev": true
+ },
+ "strtok3": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.0.5.tgz",
+ "integrity": "sha512-enqQyimC8HLT3w18MQb3qcWl53QDxQ+eo9OPucprMsfLGBIlMlSId4GjK/xWvNOUowp/s4woyKvPBzcIbm59FA==",
+ "requires": {
+ "@tokenizer/token": "^0.1.1",
+ "@types/debug": "^4.1.5",
+ "peek-readable": "^3.1.0"
+ }
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-5.5.0.tgz?cache=0&sync_timestamp=1598611709087&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-5.5.0.tgz",
+ "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ },
+ "table": {
+ "version": "6.0.7",
+ "resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz",
+ "integrity": "sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g==",
+ "dev": true,
+ "requires": {
+ "ajv": "^7.0.2",
+ "lodash": "^4.17.20",
+ "slice-ansi": "^4.0.0",
+ "string-width": "^4.2.0"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.1.1.tgz",
+ "integrity": "sha512-ga/aqDYnUy/o7vbsRTFhhTsNeXiYb5JWDIcRIeZfwRNCefwjNTVYCGdGSUrEmiu3yDK3vFvNbgJxvrQW4JXrYQ==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.1.tgz",
+ "integrity": "sha512-LL0OLyN6AnfV9xqGQpDBwedT2Rt63737LxvsRxbcwpa2aIeynBApG2Sm//F3TaLHIR1aJBN52DWklc06b94o5Q==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ }
+ }
+ }
+ },
+ "text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+ "dev": true
+ },
+ "through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+ "dev": true
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npm.taobao.org/to-regex-range/download/to-regex-range-5.0.1.tgz",
+ "integrity": "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ=",
+ "dev": true,
+ "requires": {
+ "is-number": "^7.0.0"
+ }
+ },
+ "toidentifier": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npm.taobao.org/toidentifier/download/toidentifier-1.0.0.tgz",
+ "integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM="
+ },
+ "token-types": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/token-types/-/token-types-2.0.0.tgz",
+ "integrity": "sha512-WWvu8sGK8/ZmGusekZJJ5NM6rRVTTDO7/bahz4NGiSDb/XsmdYBn6a1N/bymUHuWYTWeuLUg98wUzvE4jPdCZw==",
+ "requires": {
+ "@tokenizer/token": "^0.1.0",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "traverse": {
+ "version": "0.6.6",
+ "resolved": "https://registry.npm.taobao.org/traverse/download/traverse-0.6.6.tgz",
+ "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=",
+ "dev": true
+ },
+ "tslib": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npm.taobao.org/tslib/download/tslib-2.0.3.tgz",
+ "integrity": "sha1-jgdBrEX8DCJuWKF7/D5kubxsphw="
+ },
+ "tsutils": {
+ "version": "3.17.1",
+ "resolved": "https://registry.npm.taobao.org/tsutils/download/tsutils-3.17.1.tgz",
+ "integrity": "sha1-7XGZF/EcoN7lhicrKsSeAVot11k=",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.8.1"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npm.taobao.org/tslib/download/tslib-1.14.1.tgz",
+ "integrity": "sha1-zy04vcNKE0vK8QkcQfZhni9nLQA=",
+ "dev": true
+ }
+ }
+ },
+ "tunnel": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npm.taobao.org/tunnel/download/tunnel-0.0.6.tgz",
+ "integrity": "sha1-cvExSzSlsZLbASMk3yzFh8pH+Sw="
+ },
+ "type": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npm.taobao.org/type/download/type-1.2.0.tgz?cache=0&sync_timestamp=1598016585110&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftype%2Fdownload%2Ftype-1.2.0.tgz",
+ "integrity": "sha1-hI3XaY2vo+VKbEeedZxLw/GIR6A=",
+ "dev": true
+ },
+ "type-check": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npm.taobao.org/type-check/download/type-check-0.3.2.tgz",
+ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "requires": {
+ "prelude-ls": "~1.1.2"
+ }
+ },
+ "type-fest": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+ "dev": true
+ },
+ "type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npm.taobao.org/type-is/download/type-is-1.6.18.tgz",
+ "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=",
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ }
+ },
+ "type-name": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npm.taobao.org/type-name/download/type-name-2.0.2.tgz",
+ "integrity": "sha1-7+fUEj2KxSr/9/QMfk3sUmYAj7Q=",
+ "dev": true
+ },
+ "typedarray-to-buffer": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
+ "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
+ "requires": {
+ "is-typedarray": "^1.0.0"
+ }
+ },
+ "typescript": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz",
+ "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==",
+ "dev": true
+ },
+ "universal-deep-strict-equal": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npm.taobao.org/universal-deep-strict-equal/download/universal-deep-strict-equal-1.2.2.tgz",
+ "integrity": "sha1-DaSsL3PP95JMgfpN4BjKViyisKc=",
+ "dev": true,
+ "requires": {
+ "array-filter": "^1.0.0",
+ "indexof": "0.0.1",
+ "object-keys": "^1.0.0"
+ }
+ },
+ "universalify": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npm.taobao.org/universalify/download/universalify-0.1.2.tgz?cache=0&sync_timestamp=1603179967633&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Funiversalify%2Fdownload%2Funiversalify-0.1.2.tgz",
+ "integrity": "sha1-tkb2m+OULavOzJ1mOcgNwQXvqmY="
+ },
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npm.taobao.org/unpipe/download/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+ },
+ "uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "requires": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+ },
+ "utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npm.taobao.org/utils-merge/download/utils-merge-1.0.1.tgz",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
+ },
+ "v8-compile-cache": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz",
+ "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==",
+ "dev": true
+ },
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npm.taobao.org/vary/download/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+ },
+ "which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npm.taobao.org/which/download/which-2.0.2.tgz?cache=0&sync_timestamp=1574116720213&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwhich%2Fdownload%2Fwhich-2.0.2.tgz",
+ "integrity": "sha1-fGqN0KY2oDJ+ELWckobu6T8/UbE=",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ },
+ "which-module": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npm.taobao.org/which-module/download/which-module-2.0.0.tgz",
+ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
+ },
+ "wide-align": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+ "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
+ "dev": true,
+ "requires": {
+ "string-width": "^1.0.2 || 2"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "dev": true
+ },
+ "string-width": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "dev": true,
+ "requires": {
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^4.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ }
+ }
+ },
+ "word-wrap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npm.taobao.org/word-wrap/download/word-wrap-1.2.3.tgz",
+ "integrity": "sha1-YQY29rH3A4kb00dxzLF/uTtHB5w="
+ },
+ "workerpool": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz",
+ "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==",
+ "dev": true
+ },
+ "wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
+ "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ }
+ }
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npm.taobao.org/wrappy/download/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "dev": true
+ },
+ "xregexp": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npm.taobao.org/xregexp/download/xregexp-2.0.0.tgz?cache=0&sync_timestamp=1581429204252&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fxregexp%2Fdownload%2Fxregexp-2.0.0.tgz",
+ "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM="
+ },
+ "xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npm.taobao.org/xtend/download/xtend-4.0.2.tgz",
+ "integrity": "sha1-u3J3n1+kZRhrH0OPZ0+jR/2121Q=",
+ "dev": true
+ },
+ "y18n": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npm.taobao.org/y18n/download/y18n-4.0.0.tgz",
+ "integrity": "sha1-le+U+F7MgdAHwmThkKEg8KPIVms="
+ },
+ "yaml": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz",
+ "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==",
+ "dev": true
+ },
+ "yargs": {
+ "version": "13.3.2",
+ "resolved": "https://registry.npm.taobao.org/yargs/download/yargs-13.3.2.tgz?cache=0&sync_timestamp=1602805561021&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs%2Fdownload%2Fyargs-13.3.2.tgz",
+ "integrity": "sha1-rX/+/sGqWVZayRX4Lcyzipwxot0=",
+ "requires": {
+ "cliui": "^5.0.0",
+ "find-up": "^3.0.0",
+ "get-caller-file": "^2.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^3.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^13.1.2"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npm.taobao.org/find-up/download/find-up-3.0.0.tgz?cache=0&sync_timestamp=1597169842138&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffind-up%2Fdownload%2Ffind-up-3.0.0.tgz",
+ "integrity": "sha1-SRafHXmTQwZG2mHsxa41XCHJe3M=",
+ "requires": {
+ "locate-path": "^3.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npm.taobao.org/locate-path/download/locate-path-3.0.0.tgz",
+ "integrity": "sha1-2+w7OrdZdYBxtY/ln8QYca8hQA4=",
+ "requires": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npm.taobao.org/p-locate/download/p-locate-3.0.0.tgz",
+ "integrity": "sha1-Mi1poFwCZLJZl9n0DNiokasAZKQ=",
+ "requires": {
+ "p-limit": "^2.0.0"
+ }
+ },
+ "path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npm.taobao.org/path-exists/download/path-exists-3.0.0.tgz",
+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
+ }
+ }
+ },
+ "yargs-parser": {
+ "version": "13.1.2",
+ "resolved": "https://registry.npm.taobao.org/yargs-parser/download/yargs-parser-13.1.2.tgz?cache=0&sync_timestamp=1602861397132&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs-parser%2Fdownload%2Fyargs-parser-13.1.2.tgz",
+ "integrity": "sha1-Ew8JcC667vJlDVTObj5XBvek+zg=",
+ "requires": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ }
+ },
+ "yargs-unparser": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
+ "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^6.0.0",
+ "decamelize": "^4.0.0",
+ "flat": "^5.0.2",
+ "is-plain-obj": "^2.1.0"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz",
+ "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==",
+ "dev": true
+ },
+ "decamelize": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
+ "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
+ "dev": true
+ }
+ }
+ },
+ "yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true
+ }
+ }
+}
diff --git a/netease_api/package.json b/netease_api/package.json
new file mode 100644
index 0000000..3990157
--- /dev/null
+++ b/netease_api/package.json
@@ -0,0 +1,63 @@
+{
+ "name": "NeteaseCloudMusicApi",
+ "version": "4.0.8",
+ "description": "网易云音乐 NodeJS 版 API",
+ "scripts": {
+ "start": "node app.js",
+ "test": "mocha -r intelli-espower-loader -t 20000 app.test.js --exit",
+ "lint": "eslint **/*.{js,ts}",
+ "lint-fix": "eslint --fix **/*.{js,ts}"
+ },
+ "keywords": [
+ "网易云音乐",
+ "网易云",
+ "音乐",
+ "网易云音乐nodejs"
+ ],
+ "main": "main.js",
+ "types": "./interface.d.ts",
+ "engines": {
+ "node": ">=12"
+ },
+ "lint-staged": {
+ "*.js": [
+ "eslint --fix",
+ "git add"
+ ]
+ },
+ "author": "binaryify",
+ "license": "MIT",
+ "files": [
+ "module",
+ "util",
+ "plugins",
+ "main.d.ts",
+ "interface.d.ts",
+ "module_types"
+ ],
+ "dependencies": {
+ "axios": "^0.21.1",
+ "express": "^4.17.1",
+ "express-fileupload": "^1.1.9",
+ "md5": "^2.3.0",
+ "music-metadata": "^7.5.3",
+ "pac-proxy-agent": "^4.0.0",
+ "qrcode": "^1.4.4",
+ "tunnel": "^0.0.6"
+ },
+ "devDependencies": {
+ "@types/node": "14.14.31",
+ "@typescript-eslint/eslint-plugin": "4.4.1",
+ "@typescript-eslint/parser": "4.4.1",
+ "eslint": "7.21.0",
+ "eslint-config-prettier": "7.1.0",
+ "eslint-plugin-html": "6.1.1",
+ "eslint-plugin-prettier": "3.3.1",
+ "intelli-espower-loader": "1.0.1",
+ "lint-staged": "10.5.4",
+ "mocha": "8.3.1",
+ "power-assert": "1.6.1",
+ "prettier": "2.2.1",
+ "typescript": "4.2.3"
+ }
+}
diff --git a/netease_api/plugins/songUpload.js b/netease_api/plugins/songUpload.js
new file mode 100644
index 0000000..89d85fc
--- /dev/null
+++ b/netease_api/plugins/songUpload.js
@@ -0,0 +1,42 @@
+const axios = require('axios')
+module.exports = async (query, request) => {
+ // 获取key和token
+ const tokenRes = await request(
+ 'POST',
+ `https://music.163.com/weapi/nos/token/alloc`,
+ {
+ bucket: 'jd-musicrep-privatecloud-audio-public',
+ ext: 'mp3',
+ filename: query.songFile.name.replace('.mp3', ''),
+ local: false,
+ nos_product: 3,
+ type: 'audio',
+ md5: query.songFile.md5,
+ },
+ { crypto: 'weapi', cookie: query.cookie, proxy: query.proxy },
+ )
+
+ // 上传
+ const objectKey = tokenRes.body.result.objectKey.replace('/', '%2F')
+ try {
+ await axios({
+ method: 'post',
+ url: `http://45.127.129.8/jd-musicrep-privatecloud-audio-public/${objectKey}?offset=0&complete=true&version=1.0`,
+ headers: {
+ 'x-nos-token': tokenRes.body.result.token,
+ 'Content-MD5': query.songFile.md5,
+ 'Content-Type': 'audio/mpeg',
+ 'Content-Length': String(query.songFile.size),
+ },
+ data: query.songFile.data,
+ maxContentLength: Infinity,
+ maxBodyLength: Infinity,
+ })
+ } catch (error) {
+ console.log('error', error.response)
+ throw error.response
+ }
+ return {
+ ...tokenRes,
+ }
+}
diff --git a/netease_api/plugins/upload.js b/netease_api/plugins/upload.js
new file mode 100644
index 0000000..cddb52b
--- /dev/null
+++ b/netease_api/plugins/upload.js
@@ -0,0 +1,48 @@
+const axios = require('axios')
+module.exports = async (query, request) => {
+ const data = {
+ bucket: 'yyimgs',
+ ext: 'jpg',
+ filename: query.imgFile.name,
+ local: false,
+ nos_product: 0,
+ return_body: `{"code":200,"size":"$(ObjectSize)"}`,
+ type: 'other',
+ }
+ // 获取key和token
+ const res = await request(
+ 'POST',
+ `https://music.163.com/weapi/nos/token/alloc`,
+ data,
+ { crypto: 'weapi', cookie: query.cookie, proxy: query.proxy },
+ )
+ // 上传图片
+ const res2 = await axios({
+ method: 'post',
+ url: `https://nosup-hz1.127.net/yyimgs/${res.body.result.objectKey}?offset=0&complete=true&version=1.0`,
+ headers: {
+ 'x-nos-token': res.body.result.token,
+ 'Content-Type': 'image/jpeg',
+ },
+ data: query.imgFile.data,
+ })
+ // 获取裁剪后图片的id
+ const imgSize = query.imgSize || 300
+ const imgX = query.imgX || 0
+ const imgY = query.imgY || 0
+ const res3 = await request(
+ 'POST',
+ `https://music.163.com/upload/img/op?id=${res.body.result.docId}&op=${imgX}y${imgY}y${imgSize}y${imgSize}`,
+ {},
+ { crypto: 'weapi', cookie: query.cookie, proxy: query.proxy },
+ )
+
+ return {
+ // ...res.body.result,
+ // ...res2.data,
+ // ...res3.body,
+ url_pre: 'https://p1.music.126.net/' + res.body.result.objectKey,
+ url: res3.body.url,
+ imgId: res3.body.id,
+ }
+}
diff --git a/netease_api/public/avatar_update.html b/netease_api/public/avatar_update.html
new file mode 100644
index 0000000..7b0817f
--- /dev/null
+++ b/netease_api/public/avatar_update.html
@@ -0,0 +1,82 @@
+
+
+
+
+
+ 更新头像
+
+
+
+
+
+
+
+
+
diff --git a/netease_api/public/cloud.html b/netease_api/public/cloud.html
new file mode 100644
index 0000000..746b9b2
--- /dev/null
+++ b/netease_api/public/cloud.html
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+ 云盘上传
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/netease_api/public/index.html b/netease_api/public/index.html
new file mode 100644
index 0000000..ff4c0fa
--- /dev/null
+++ b/netease_api/public/index.html
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+ 网易云音乐 API
+
+
+
+ 网易云音乐 API
+ 当你看到这个页面时,这个服务已经成功跑起来了~
+ 查看文档
+
例子:
+
+
+
+
+
diff --git a/netease_api/public/playlist_cover_update.html b/netease_api/public/playlist_cover_update.html
new file mode 100644
index 0000000..75e0fe6
--- /dev/null
+++ b/netease_api/public/playlist_cover_update.html
@@ -0,0 +1,89 @@
+
+
+
+
+
+
歌单封面上传
+
+
+
+
+
![]()
+
+
+
+
diff --git a/netease_api/public/qrlogin.html b/netease_api/public/qrlogin.html
new file mode 100644
index 0000000..a6beb3e
--- /dev/null
+++ b/netease_api/public/qrlogin.html
@@ -0,0 +1,66 @@
+
+
+
+
+
+
二维码登录
+
+
+
+
![]()
+
+
+
+
+
+
diff --git a/netease_api/public/test.html b/netease_api/public/test.html
new file mode 100644
index 0000000..fccca52
--- /dev/null
+++ b/netease_api/public/test.html
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
test
+
+
+
+
请在控制台看结果
+
+
+
+
+
+
diff --git a/netease_api/renovate.json b/netease_api/renovate.json
new file mode 100644
index 0000000..f45d8f1
--- /dev/null
+++ b/netease_api/renovate.json
@@ -0,0 +1,5 @@
+{
+ "extends": [
+ "config:base"
+ ]
+}
diff --git a/netease_api/routes/index.js b/netease_api/routes/index.js
new file mode 100644
index 0000000..816ff3a
--- /dev/null
+++ b/netease_api/routes/index.js
@@ -0,0 +1,101 @@
+const {
+ cookieToJson
+} = require('../util/index');
+const request = require('../util/request');
+const clc = require('cli-color');
+
+const table = {
+ // 注意 /album 这样的路由必须放在 /album/new 这样的路由后面
+ '/top/playlist/highquality': require('../module/top_playlist_highquality'),
+ '/album/detail/dynamic': require('../module/album_detail_dynamic'),
+ '/recommend/resource': require('../module/recommend_resource'),
+ '/playlist/subscribe': require('../module/playlist_subscribe'),
+ '/user/cloud/detail': require('../module/user_cloud_detail'),
+ '/playlist/catlist': require('../module/playlist_catlist'),
+ '/playlist/detail': require('../module/playlist_detail'),
+ '/login/cellphone': require('../module/login_cellphone'),
+ '/playlist/delete': require('../module/playlist_delete'),
+ '/playlist/create': require('../module/playlist_create'),
+ '/playlist/tracks': require('../module/playlist_tracks'),
+ '/recommend/songs': require('../module/recommend_songs'),
+ '/login/qr/create': require('../module/login_qr_create'),
+ '/login/qr/check': require('../module/login_qr_check'),
+ '/user/cloud/del': require('../module/user_cloud_del'),
+ '/toplist/artist': require('../module/toplist_artist'),
+ '/artist/sublist': require('../module/artist_sublist'),
+ '/login/refresh': require('../module/login_refresh'),
+ '/user/playlist': require('../module/user_playlist'),
+ '/album/sublist': require('../module/album_sublist'),
+ '/artist/album': require('../module/artist_album'),
+ '/personalized': require('../module/personalized'),
+ '/top/playlist': require('../module/top_playlist'),
+ '/user/account': require('../module/user_account'),
+ '/login/qr/key': require('../module/login_qr_key'),
+ '/daily_signin': require('../module/daily_signin'),
+ '/simi/artist': require('../module/simi_artist'),
+ '/song/detail': require('../module/song_detail'),
+ '/user/detail': require('../module/user_detail'),
+ '/personal_fm': require('../module/personal_fm'),
+ '/artist/sub': require('../module/artist_sub'),
+ '/mv/sublist': require('../module/mv_sublist'),
+ '/user/cloud': require('../module/user_cloud'),
+ '/album/new': require('../module/album_new'),
+ '/album/sub': require('../module/album_sub'),
+ '/mv/detail': require('../module/mv_detail'),
+ '/artist/mv': require('../module/artist_mv'),
+ '/song/url': require('../module/song_url'),
+ '/top/song': require('../module/top_song'),
+ '/scrobble': require('../module/scrobble'),
+ '/likelist': require('../module/likelist'),
+ '/fm_trash': require('../module/fm_trash'),
+ '/artists': require('../module/artists'),
+ '/simi/mv': require('../module/simi_mv'),
+ '/toplist': require('../module/toplist'),
+ '/logout': require('../module/logout'),
+ '/mv/url': require('../module/mv_url'),
+ '/mv/sub': require('../module/mv_sub'),
+ '/search': require('../module/search'),
+ '/lyric': require('../module/lyric'),
+ '/cloud': require('../module/cloud'),
+ '/album': require('../module/album'),
+ '/login': require('../module/login'),
+ '/like': require('../module/like'),
+}
+
+const handleRequest = (req, res, func) => {
+ if (typeof req.query.cookie === 'string') {
+ req.query.cookie = cookieToJson(req.query.cookie);
+ }
+ let query = Object.assign(
+ {},
+ { cookie: req.cookies },
+ req.query,
+ req.body,
+ req.files,
+ )
+ return func(query, request)
+ .then((answer) => {
+ console.log(`${clc.redBright('[NetEase API]')} OK, ${decodeURIComponent(req.originalUrl)}`);
+ res.append('Set-Cookie', answer.cookie);
+ res.status(answer.status).send(answer.body);
+ })
+ .catch((answer) => {
+ console.log(`${clc.redBright('[NetEase API]')} ERROR 🚫 `, decodeURIComponent(req.originalUrl), {
+ status: answer.status,
+ body: answer.body,
+ });
+ if (answer.body.code == '301') answer.body.msg = '需要登录';
+ res.append('Set-Cookie', answer.cookie);
+ res.status(answer.status).send(answer.body);
+ });
+}
+
+let defaultExport = {};
+
+for (const [route, func] of Object.entries(table)) {
+ defaultExport[route] = (req, res) => {
+ return handleRequest(req, res, func);
+ };
+};
+
+export default defaultExport;
diff --git a/netease_api/static/artist_album.png b/netease_api/static/artist_album.png
new file mode 100644
index 0000000..7188755
Binary files /dev/null and b/netease_api/static/artist_album.png differ
diff --git a/netease_api/static/artists.png b/netease_api/static/artists.png
new file mode 100644
index 0000000..dfe4422
Binary files /dev/null and b/netease_api/static/artists.png differ
diff --git a/netease_api/static/banner.png b/netease_api/static/banner.png
new file mode 100644
index 0000000..fac182a
Binary files /dev/null and b/netease_api/static/banner.png differ
diff --git a/netease_api/static/comment.png b/netease_api/static/comment.png
new file mode 100644
index 0000000..6631f62
Binary files /dev/null and b/netease_api/static/comment.png differ
diff --git a/netease_api/static/docs.png b/netease_api/static/docs.png
new file mode 100644
index 0000000..1f1794a
Binary files /dev/null and b/netease_api/static/docs.png differ
diff --git a/netease_api/static/fm_trash.png b/netease_api/static/fm_trash.png
new file mode 100644
index 0000000..4c85539
Binary files /dev/null and b/netease_api/static/fm_trash.png differ
diff --git a/netease_api/static/like.png b/netease_api/static/like.png
new file mode 100644
index 0000000..85acf19
Binary files /dev/null and b/netease_api/static/like.png differ
diff --git a/netease_api/static/likeSuccess.png b/netease_api/static/likeSuccess.png
new file mode 100644
index 0000000..d882a6b
Binary files /dev/null and b/netease_api/static/likeSuccess.png differ
diff --git a/netease_api/static/mv.png b/netease_api/static/mv.png
new file mode 100644
index 0000000..dbb9b16
Binary files /dev/null and b/netease_api/static/mv.png differ
diff --git a/netease_api/static/new_albums.png b/netease_api/static/new_albums.png
new file mode 100644
index 0000000..b5ceaa4
Binary files /dev/null and b/netease_api/static/new_albums.png differ
diff --git a/netease_api/static/personal_fm.png b/netease_api/static/personal_fm.png
new file mode 100644
index 0000000..ba0d297
Binary files /dev/null and b/netease_api/static/personal_fm.png differ
diff --git a/netease_api/static/play_mv.png b/netease_api/static/play_mv.png
new file mode 100644
index 0000000..de23951
Binary files /dev/null and b/netease_api/static/play_mv.png differ
diff --git a/netease_api/static/screenshot1.png b/netease_api/static/screenshot1.png
new file mode 100644
index 0000000..eb20062
Binary files /dev/null and b/netease_api/static/screenshot1.png differ
diff --git a/netease_api/static/screenshot2.png b/netease_api/static/screenshot2.png
new file mode 100644
index 0000000..1d8418d
Binary files /dev/null and b/netease_api/static/screenshot2.png differ
diff --git a/netease_api/static/signinError.png b/netease_api/static/signinError.png
new file mode 100644
index 0000000..e5815dc
Binary files /dev/null and b/netease_api/static/signinError.png differ
diff --git a/netease_api/static/signinSuccess.png b/netease_api/static/signinSuccess.png
new file mode 100644
index 0000000..7778a57
Binary files /dev/null and b/netease_api/static/signinSuccess.png differ
diff --git a/netease_api/static/songDetail.png b/netease_api/static/songDetail.png
new file mode 100644
index 0000000..808d0b1
Binary files /dev/null and b/netease_api/static/songDetail.png differ
diff --git a/netease_api/static/top_artists.png b/netease_api/static/top_artists.png
new file mode 100644
index 0000000..4105876
Binary files /dev/null and b/netease_api/static/top_artists.png differ
diff --git a/netease_api/static/top_list.png b/netease_api/static/top_list.png
new file mode 100644
index 0000000..d1fbe02
Binary files /dev/null and b/netease_api/static/top_list.png differ
diff --git a/netease_api/static/top_playlist.png b/netease_api/static/top_playlist.png
new file mode 100644
index 0000000..51715d6
Binary files /dev/null and b/netease_api/static/top_playlist.png differ
diff --git a/netease_api/static/专辑.png b/netease_api/static/专辑.png
new file mode 100644
index 0000000..251f6a8
Binary files /dev/null and b/netease_api/static/专辑.png differ
diff --git a/netease_api/static/推荐歌单.png b/netease_api/static/推荐歌单.png
new file mode 100644
index 0000000..05a425a
Binary files /dev/null and b/netease_api/static/推荐歌单.png differ
diff --git a/netease_api/static/推荐歌曲.png b/netease_api/static/推荐歌曲.png
new file mode 100644
index 0000000..fdd8f9e
Binary files /dev/null and b/netease_api/static/推荐歌曲.png differ
diff --git a/netease_api/static/搜索.png b/netease_api/static/搜索.png
new file mode 100644
index 0000000..c787181
Binary files /dev/null and b/netease_api/static/搜索.png differ
diff --git a/netease_api/static/歌单详情.png b/netease_api/static/歌单详情.png
new file mode 100644
index 0000000..9300715
Binary files /dev/null and b/netease_api/static/歌单详情.png differ
diff --git a/netease_api/static/歌词.png b/netease_api/static/歌词.png
new file mode 100644
index 0000000..e886906
Binary files /dev/null and b/netease_api/static/歌词.png differ
diff --git a/netease_api/static/用户歌单.png b/netease_api/static/用户歌单.png
new file mode 100644
index 0000000..5c1835f
Binary files /dev/null and b/netease_api/static/用户歌单.png differ
diff --git a/netease_api/static/登录.png b/netease_api/static/登录.png
new file mode 100644
index 0000000..fdf6c80
Binary files /dev/null and b/netease_api/static/登录.png differ
diff --git a/netease_api/static/音乐 url.png b/netease_api/static/音乐 url.png
new file mode 100644
index 0000000..14599c6
Binary files /dev/null and b/netease_api/static/音乐 url.png differ
diff --git a/netease_api/test/album.test.js b/netease_api/test/album.test.js
new file mode 100644
index 0000000..2a6a1b9
--- /dev/null
+++ b/netease_api/test/album.test.js
@@ -0,0 +1,25 @@
+const assert = require('assert')
+const axios = require('axios')
+const host = global.host || 'http://localhost:3000'
+
+describe('测试获取歌手专辑列表是否正常', () => {
+ it('数据的 code 应该为200', (done) => {
+ const qs = {
+ id: 32311,
+ }
+
+ axios
+ .get(`${host}/album`, {
+ params: qs,
+ })
+ .then(({ status, data }) => {
+ if (status == 200) {
+ assert(data.code === 200)
+ }
+ done()
+ })
+ .catch((err) => {
+ done(err)
+ })
+ })
+})
diff --git a/netease_api/test/comment.test.js b/netease_api/test/comment.test.js
new file mode 100644
index 0000000..612f670
--- /dev/null
+++ b/netease_api/test/comment.test.js
@@ -0,0 +1,25 @@
+const assert = require('assert')
+const axios = require('axios')
+const host = global.host || 'http://localhost:3000'
+
+describe('测试获取评论是否正常', () => {
+ it('数据的 code 应该为200', (done) => {
+ const qs = {
+ id: 32311,
+ }
+
+ axios
+ .get(`${host}/comment/album`, {
+ params: qs,
+ })
+ .then(({ status, data }) => {
+ if (status == 200) {
+ assert(data.code === 200)
+ }
+ done()
+ })
+ .catch((err) => {
+ done(err)
+ })
+ })
+})
diff --git a/netease_api/test/login.test.js b/netease_api/test/login.test.js
new file mode 100644
index 0000000..d10da4b
--- /dev/null
+++ b/netease_api/test/login.test.js
@@ -0,0 +1,32 @@
+const assert = require('assert')
+const axios = require('axios')
+const host = global.host || 'http://localhost:3000'
+
+console.log('注意: 测试登录需在 test/login.test.js 中填写账号密码!!!')
+const phone = ''
+const password = ''
+describe('测试登录是否正常', () => {
+ it('手机登录 code 应该等于200', (done) => {
+ const qs = {
+ phone: process.env.NCM_API_TEST_LOGIN_PHONE || phone || '',
+ password: process.env.NCM_API_TEST_LOGIN_PASSWORD || password || '',
+ }
+
+ axios
+ .get(`${host}/login/cellphone`, {
+ params: qs,
+ })
+ .then(({ status, data }) => {
+ if (status == 200) {
+ console.log('昵称:' + data.profile.nickname)
+ assert(data.code === 200)
+ done()
+ } else {
+ done('登录错误')
+ }
+ })
+ .catch((err) => {
+ done(err)
+ })
+ })
+})
diff --git a/netease_api/test/lyric.test.js b/netease_api/test/lyric.test.js
new file mode 100644
index 0000000..41886e4
--- /dev/null
+++ b/netease_api/test/lyric.test.js
@@ -0,0 +1,25 @@
+const assert = require('assert')
+const axios = require('axios')
+const host = global.host || 'http://localhost:3000'
+
+describe('测试获取歌词是否正常', () => {
+ it('数据应该有 lrc 字段', (done) => {
+ const qs = {
+ id: 347230,
+ }
+
+ axios
+ .get(`${host}/lyric`, {
+ params: qs,
+ })
+ .then(({ status, data }) => {
+ if (status == 200) {
+ assert(typeof data.lrc !== 'undefined')
+ }
+ done()
+ })
+ .catch((err) => {
+ done(err)
+ })
+ })
+})
diff --git a/netease_api/test/music_url.test.js b/netease_api/test/music_url.test.js
new file mode 100644
index 0000000..cf7777c
--- /dev/null
+++ b/netease_api/test/music_url.test.js
@@ -0,0 +1,26 @@
+const assert = require('assert')
+const axios = require('axios')
+const host = global.host || 'http://localhost:3000'
+
+describe('测试获取歌曲是否正常', () => {
+ it('歌曲的 url 不应该为空', (done) => {
+ const qs = {
+ id: 462791935,
+ br: 999000,
+ }
+
+ axios
+ .get(`${host}/song/url`, {
+ params: qs,
+ })
+ .then(({ status, data }) => {
+ if (status == 200) {
+ assert(!!data.data[0].url)
+ }
+ done()
+ })
+ .catch((err) => {
+ done(err)
+ })
+ })
+})
diff --git a/netease_api/test/search.test.js b/netease_api/test/search.test.js
new file mode 100644
index 0000000..e80dea5
--- /dev/null
+++ b/netease_api/test/search.test.js
@@ -0,0 +1,25 @@
+const assert = require('assert')
+const axios = require('axios')
+const host = global.host || 'http://localhost:3000'
+
+describe('测试搜索是否正常', () => {
+ it('获取到的数据的 name 应该和搜索关键词一致', (done) => {
+ const qs = {
+ keywords: '海阔天空',
+ type: 1,
+ }
+ axios
+ .get(`${host}/search`, {
+ params: qs,
+ })
+ .then(({ status, data }) => {
+ if (status == 200) {
+ assert(data.result.songs[0].name === '海阔天空')
+ }
+ done()
+ })
+ .catch((err) => {
+ done(err)
+ })
+ })
+})
diff --git a/netease_api/tsconfig.json b/netease_api/tsconfig.json
new file mode 100644
index 0000000..9656c53
--- /dev/null
+++ b/netease_api/tsconfig.json
@@ -0,0 +1,30 @@
+{
+ "compilerOptions": {
+ "target": "ES2015",
+ "module": "commonjs",
+ "experimentalDecorators": true,
+ "moduleResolution": "node",
+ "lib": [
+ "esnext",
+ "esnext.asynciterable",
+ "dom"
+ ],
+ "esModuleInterop": true,
+ "allowJs": true,
+ "sourceMap": true,
+ "strict": true,
+ "noEmit": true,
+ "baseUrl": ".",
+ "paths": {
+ "~/*": [
+ "./*"
+ ],
+ "@/*": [
+ "./*"
+ ]
+ },
+ },
+ "exclude": [
+ "node_modules"
+ ]
+ }
\ No newline at end of file
diff --git a/netease_api/util/apicache.js b/netease_api/util/apicache.js
new file mode 100644
index 0000000..a71c998
--- /dev/null
+++ b/netease_api/util/apicache.js
@@ -0,0 +1,830 @@
+var url = require('url')
+var MemoryCache = require('./memory-cache')
+
+var t = {
+ ms: 1,
+ second: 1000,
+ minute: 60000,
+ hour: 3600000,
+ day: 3600000 * 24,
+ week: 3600000 * 24 * 7,
+ month: 3600000 * 24 * 30,
+}
+
+var instances = []
+
+var matches = function (a) {
+ return function (b) {
+ return a === b
+ }
+}
+
+var doesntMatch = function (a) {
+ return function (b) {
+ return !matches(a)(b)
+ }
+}
+
+var logDuration = function (d, prefix) {
+ var str = d > 1000 ? (d / 1000).toFixed(2) + 'sec' : d + 'ms'
+ return '\x1b[33m- ' + (prefix ? prefix + ' ' : '') + str + '\x1b[0m'
+}
+
+function getSafeHeaders(res) {
+ return res.getHeaders ? res.getHeaders() : res._headers
+}
+
+function ApiCache() {
+ var memCache = new MemoryCache()
+
+ var globalOptions = {
+ debug: false,
+ defaultDuration: 3600000,
+ enabled: true,
+ appendKey: [],
+ jsonp: false,
+ redisClient: false,
+ headerBlacklist: [],
+ statusCodes: {
+ include: [],
+ exclude: [],
+ },
+ events: {
+ expire: undefined,
+ },
+ headers: {
+ // 'cache-control': 'no-cache' // example of header overwrite
+ },
+ trackPerformance: false,
+ }
+
+ var middlewareOptions = []
+ var instance = this
+ var index = null
+ var timers = {}
+ var performanceArray = [] // for tracking cache hit rate
+
+ instances.push(this)
+ this.id = instances.length
+
+ function debug(a, b, c, d) {
+ var arr = ['\x1b[36m[apicache]\x1b[0m', a, b, c, d].filter(function (arg) {
+ return arg !== undefined
+ })
+ var debugEnv =
+ process.env.DEBUG &&
+ process.env.DEBUG.split(',').indexOf('apicache') !== -1
+
+ return (globalOptions.debug || debugEnv) && console.log.apply(null, arr)
+ }
+
+ function shouldCacheResponse(request, response, toggle) {
+ var opt = globalOptions
+ var codes = opt.statusCodes
+
+ if (!response) return false
+
+ if (toggle && !toggle(request, response)) {
+ return false
+ }
+
+ if (
+ codes.exclude &&
+ codes.exclude.length &&
+ codes.exclude.indexOf(response.statusCode) !== -1
+ )
+ return false
+ if (
+ codes.include &&
+ codes.include.length &&
+ codes.include.indexOf(response.statusCode) === -1
+ )
+ return false
+
+ return true
+ }
+
+ function addIndexEntries(key, req) {
+ var groupName = req.apicacheGroup
+
+ if (groupName) {
+ debug('group detected "' + groupName + '"')
+ var group = (index.groups[groupName] = index.groups[groupName] || [])
+ group.unshift(key)
+ }
+
+ index.all.unshift(key)
+ }
+
+ function filterBlacklistedHeaders(headers) {
+ return Object.keys(headers)
+ .filter(function (key) {
+ return globalOptions.headerBlacklist.indexOf(key) === -1
+ })
+ .reduce(function (acc, header) {
+ acc[header] = headers[header]
+ return acc
+ }, {})
+ }
+
+ function createCacheObject(status, headers, data, encoding) {
+ return {
+ status: status,
+ headers: filterBlacklistedHeaders(headers),
+ data: data,
+ encoding: encoding,
+ timestamp: new Date().getTime() / 1000, // seconds since epoch. This is used to properly decrement max-age headers in cached responses.
+ }
+ }
+
+ function cacheResponse(key, value, duration) {
+ var redis = globalOptions.redisClient
+ var expireCallback = globalOptions.events.expire
+
+ if (redis && redis.connected) {
+ try {
+ redis.hset(key, 'response', JSON.stringify(value))
+ redis.hset(key, 'duration', duration)
+ redis.expire(key, duration / 1000, expireCallback || function () {})
+ } catch (err) {
+ debug('[apicache] error in redis.hset()')
+ }
+ } else {
+ memCache.add(key, value, duration, expireCallback)
+ }
+
+ // add automatic cache clearing from duration, includes max limit on setTimeout
+ timers[key] = setTimeout(function () {
+ instance.clear(key, true)
+ }, Math.min(duration, 2147483647))
+ }
+
+ function accumulateContent(res, content) {
+ if (content) {
+ if (typeof content == 'string') {
+ res._apicache.content = (res._apicache.content || '') + content
+ } else if (Buffer.isBuffer(content)) {
+ var oldContent = res._apicache.content
+
+ if (typeof oldContent === 'string') {
+ oldContent = !Buffer.from
+ ? new Buffer(oldContent)
+ : Buffer.from(oldContent)
+ }
+
+ if (!oldContent) {
+ oldContent = !Buffer.alloc ? new Buffer(0) : Buffer.alloc(0)
+ }
+
+ res._apicache.content = Buffer.concat(
+ [oldContent, content],
+ oldContent.length + content.length,
+ )
+ } else {
+ res._apicache.content = content
+ }
+ }
+ }
+
+ function makeResponseCacheable(
+ req,
+ res,
+ next,
+ key,
+ duration,
+ strDuration,
+ toggle,
+ ) {
+ // monkeypatch res.end to create cache object
+ res._apicache = {
+ write: res.write,
+ writeHead: res.writeHead,
+ end: res.end,
+ cacheable: true,
+ content: undefined,
+ }
+
+ // append header overwrites if applicable
+ Object.keys(globalOptions.headers).forEach(function (name) {
+ res.setHeader(name, globalOptions.headers[name])
+ })
+
+ res.writeHead = function () {
+ // add cache control headers
+ if (!globalOptions.headers['cache-control']) {
+ if (shouldCacheResponse(req, res, toggle)) {
+ res.setHeader(
+ 'cache-control',
+ 'max-age=' + (duration / 1000).toFixed(0),
+ )
+ } else {
+ res.setHeader('cache-control', 'no-cache, no-store, must-revalidate')
+ }
+ }
+
+ res._apicache.headers = Object.assign({}, getSafeHeaders(res))
+ return res._apicache.writeHead.apply(this, arguments)
+ }
+
+ // patch res.write
+ res.write = function (content) {
+ accumulateContent(res, content)
+ return res._apicache.write.apply(this, arguments)
+ }
+
+ // patch res.end
+ res.end = function (content, encoding) {
+ if (shouldCacheResponse(req, res, toggle)) {
+ accumulateContent(res, content)
+
+ if (res._apicache.cacheable && res._apicache.content) {
+ addIndexEntries(key, req)
+ var headers = res._apicache.headers || getSafeHeaders(res)
+ var cacheObject = createCacheObject(
+ res.statusCode,
+ headers,
+ res._apicache.content,
+ encoding,
+ )
+ cacheResponse(key, cacheObject, duration)
+
+ // display log entry
+ var elapsed = new Date() - req.apicacheTimer
+ debug(
+ 'adding cache entry for "' + key + '" @ ' + strDuration,
+ logDuration(elapsed),
+ )
+ debug('_apicache.headers: ', res._apicache.headers)
+ debug('res.getHeaders(): ', getSafeHeaders(res))
+ debug('cacheObject: ', cacheObject)
+ }
+ }
+
+ return res._apicache.end.apply(this, arguments)
+ }
+
+ next()
+ }
+
+ function sendCachedResponse(
+ request,
+ response,
+ cacheObject,
+ toggle,
+ next,
+ duration,
+ ) {
+ if (toggle && !toggle(request, response)) {
+ return next()
+ }
+
+ var headers = getSafeHeaders(response)
+
+ Object.assign(
+ headers,
+ filterBlacklistedHeaders(cacheObject.headers || {}),
+ {
+ // set properly-decremented max-age header. This ensures that max-age is in sync with the cache expiration.
+ 'cache-control':
+ 'max-age=' +
+ Math.max(
+ 0,
+ (
+ duration / 1000 -
+ (new Date().getTime() / 1000 - cacheObject.timestamp)
+ ).toFixed(0),
+ ),
+ },
+ )
+
+ // only embed apicache headers when not in production environment
+
+ // unstringify buffers
+ var data = cacheObject.data
+ if (data && data.type === 'Buffer') {
+ data =
+ typeof data.data === 'number'
+ ? new Buffer.alloc(data.data)
+ : new Buffer.from(data.data)
+ }
+
+ // test Etag against If-None-Match for 304
+ var cachedEtag = cacheObject.headers.etag
+ var requestEtag = request.headers['if-none-match']
+
+ if (requestEtag && cachedEtag === requestEtag) {
+ response.writeHead(304, headers)
+ return response.end()
+ }
+
+ response.writeHead(cacheObject.status || 200, headers)
+
+ return response.end(data, cacheObject.encoding)
+ }
+
+ function syncOptions() {
+ for (var i in middlewareOptions) {
+ Object.assign(
+ middlewareOptions[i].options,
+ globalOptions,
+ middlewareOptions[i].localOptions,
+ )
+ }
+ }
+
+ this.clear = function (target, isAutomatic) {
+ var group = index.groups[target]
+ var redis = globalOptions.redisClient
+
+ if (group) {
+ debug('clearing group "' + target + '"')
+
+ group.forEach(function (key) {
+ debug('clearing cached entry for "' + key + '"')
+ clearTimeout(timers[key])
+ delete timers[key]
+ if (!globalOptions.redisClient) {
+ memCache.delete(key)
+ } else {
+ try {
+ redis.del(key)
+ } catch (err) {
+ console.log('[apicache] error in redis.del("' + key + '")')
+ }
+ }
+ index.all = index.all.filter(doesntMatch(key))
+ })
+
+ delete index.groups[target]
+ } else if (target) {
+ debug(
+ 'clearing ' +
+ (isAutomatic ? 'expired' : 'cached') +
+ ' entry for "' +
+ target +
+ '"',
+ )
+ clearTimeout(timers[target])
+ delete timers[target]
+ // clear actual cached entry
+ if (!redis) {
+ memCache.delete(target)
+ } else {
+ try {
+ redis.del(target)
+ } catch (err) {
+ console.log('[apicache] error in redis.del("' + target + '")')
+ }
+ }
+
+ // remove from global index
+ index.all = index.all.filter(doesntMatch(target))
+
+ // remove target from each group that it may exist in
+ Object.keys(index.groups).forEach(function (groupName) {
+ index.groups[groupName] = index.groups[groupName].filter(
+ doesntMatch(target),
+ )
+
+ // delete group if now empty
+ if (!index.groups[groupName].length) {
+ delete index.groups[groupName]
+ }
+ })
+ } else {
+ debug('clearing entire index')
+
+ if (!redis) {
+ memCache.clear()
+ } else {
+ // clear redis keys one by one from internal index to prevent clearing non-apicache entries
+ index.all.forEach(function (key) {
+ clearTimeout(timers[key])
+ delete timers[key]
+ try {
+ redis.del(key)
+ } catch (err) {
+ console.log('[apicache] error in redis.del("' + key + '")')
+ }
+ })
+ }
+ this.resetIndex()
+ }
+
+ return this.getIndex()
+ }
+
+ function parseDuration(duration, defaultDuration) {
+ if (typeof duration === 'number') return duration
+
+ if (typeof duration === 'string') {
+ var split = duration.match(/^([\d\.,]+)\s?(\w+)$/)
+
+ if (split.length === 3) {
+ var len = parseFloat(split[1])
+ var unit = split[2].replace(/s$/i, '').toLowerCase()
+ if (unit === 'm') {
+ unit = 'ms'
+ }
+
+ return (len || 1) * (t[unit] || 0)
+ }
+ }
+
+ return defaultDuration
+ }
+
+ this.getDuration = function (duration) {
+ return parseDuration(duration, globalOptions.defaultDuration)
+ }
+
+ /**
+ * Return cache performance statistics (hit rate). Suitable for putting into a route:
+ *
+ * app.get('/api/cache/performance', (req, res) => {
+ * res.json(apicache.getPerformance())
+ * })
+ *
+ */
+ this.getPerformance = function () {
+ return performanceArray.map(function (p) {
+ return p.report()
+ })
+ }
+
+ this.getIndex = function (group) {
+ if (group) {
+ return index.groups[group]
+ } else {
+ return index
+ }
+ }
+
+ this.middleware = function cache(
+ strDuration,
+ middlewareToggle,
+ localOptions,
+ ) {
+ var duration = instance.getDuration(strDuration)
+ var opt = {}
+
+ middlewareOptions.push({
+ options: opt,
+ })
+
+ var options = function (localOptions) {
+ if (localOptions) {
+ middlewareOptions.find(function (middleware) {
+ return middleware.options === opt
+ }).localOptions = localOptions
+ }
+
+ syncOptions()
+
+ return opt
+ }
+
+ options(localOptions)
+
+ /**
+ * A Function for non tracking performance
+ */
+ function NOOPCachePerformance() {
+ this.report = this.hit = this.miss = function () {} // noop;
+ }
+
+ /**
+ * A function for tracking and reporting hit rate. These statistics are returned by the getPerformance() call above.
+ */
+ function CachePerformance() {
+ /**
+ * Tracks the hit rate for the last 100 requests.
+ * If there have been fewer than 100 requests, the hit rate just considers the requests that have happened.
+ */
+ this.hitsLast100 = new Uint8Array(100 / 4) // each hit is 2 bits
+
+ /**
+ * Tracks the hit rate for the last 1000 requests.
+ * If there have been fewer than 1000 requests, the hit rate just considers the requests that have happened.
+ */
+ this.hitsLast1000 = new Uint8Array(1000 / 4) // each hit is 2 bits
+
+ /**
+ * Tracks the hit rate for the last 10000 requests.
+ * If there have been fewer than 10000 requests, the hit rate just considers the requests that have happened.
+ */
+ this.hitsLast10000 = new Uint8Array(10000 / 4) // each hit is 2 bits
+
+ /**
+ * Tracks the hit rate for the last 100000 requests.
+ * If there have been fewer than 100000 requests, the hit rate just considers the requests that have happened.
+ */
+ this.hitsLast100000 = new Uint8Array(100000 / 4) // each hit is 2 bits
+
+ /**
+ * The number of calls that have passed through the middleware since the server started.
+ */
+ this.callCount = 0
+
+ /**
+ * The total number of hits since the server started
+ */
+ this.hitCount = 0
+
+ /**
+ * The key from the last cache hit. This is useful in identifying which route these statistics apply to.
+ */
+ this.lastCacheHit = null
+
+ /**
+ * The key from the last cache miss. This is useful in identifying which route these statistics apply to.
+ */
+ this.lastCacheMiss = null
+
+ /**
+ * Return performance statistics
+ */
+ this.report = function () {
+ return {
+ lastCacheHit: this.lastCacheHit,
+ lastCacheMiss: this.lastCacheMiss,
+ callCount: this.callCount,
+ hitCount: this.hitCount,
+ missCount: this.callCount - this.hitCount,
+ hitRate: this.callCount == 0 ? null : this.hitCount / this.callCount,
+ hitRateLast100: this.hitRate(this.hitsLast100),
+ hitRateLast1000: this.hitRate(this.hitsLast1000),
+ hitRateLast10000: this.hitRate(this.hitsLast10000),
+ hitRateLast100000: this.hitRate(this.hitsLast100000),
+ }
+ }
+
+ /**
+ * Computes a cache hit rate from an array of hits and misses.
+ * @param {Uint8Array} array An array representing hits and misses.
+ * @returns a number between 0 and 1, or null if the array has no hits or misses
+ */
+ this.hitRate = function (array) {
+ var hits = 0
+ var misses = 0
+ for (var i = 0; i < array.length; i++) {
+ var n8 = array[i]
+ for (j = 0; j < 4; j++) {
+ switch (n8 & 3) {
+ case 1:
+ hits++
+ break
+ case 2:
+ misses++
+ break
+ }
+ n8 >>= 2
+ }
+ }
+ var total = hits + misses
+ if (total == 0) return null
+ return hits / total
+ }
+
+ /**
+ * Record a hit or miss in the given array. It will be recorded at a position determined
+ * by the current value of the callCount variable.
+ * @param {Uint8Array} array An array representing hits and misses.
+ * @param {boolean} hit true for a hit, false for a miss
+ * Each element in the array is 8 bits, and encodes 4 hit/miss records.
+ * Each hit or miss is encoded as to bits as follows:
+ * 00 means no hit or miss has been recorded in these bits
+ * 01 encodes a hit
+ * 10 encodes a miss
+ */
+ this.recordHitInArray = function (array, hit) {
+ var arrayIndex = ~~(this.callCount / 4) % array.length
+ var bitOffset = (this.callCount % 4) * 2 // 2 bits per record, 4 records per uint8 array element
+ var clearMask = ~(3 << bitOffset)
+ var record = (hit ? 1 : 2) << bitOffset
+ array[arrayIndex] = (array[arrayIndex] & clearMask) | record
+ }
+
+ /**
+ * Records the hit or miss in the tracking arrays and increments the call count.
+ * @param {boolean} hit true records a hit, false records a miss
+ */
+ this.recordHit = function (hit) {
+ this.recordHitInArray(this.hitsLast100, hit)
+ this.recordHitInArray(this.hitsLast1000, hit)
+ this.recordHitInArray(this.hitsLast10000, hit)
+ this.recordHitInArray(this.hitsLast100000, hit)
+ if (hit) this.hitCount++
+ this.callCount++
+ }
+
+ /**
+ * Records a hit event, setting lastCacheMiss to the given key
+ * @param {string} key The key that had the cache hit
+ */
+ this.hit = function (key) {
+ this.recordHit(true)
+ this.lastCacheHit = key
+ }
+
+ /**
+ * Records a miss event, setting lastCacheMiss to the given key
+ * @param {string} key The key that had the cache miss
+ */
+ this.miss = function (key) {
+ this.recordHit(false)
+ this.lastCacheMiss = key
+ }
+ }
+
+ var perf = globalOptions.trackPerformance
+ ? new CachePerformance()
+ : new NOOPCachePerformance()
+
+ performanceArray.push(perf)
+
+ var cache = function (req, res, next) {
+ function bypass() {
+ debug('bypass detected, skipping cache.')
+ return next()
+ }
+
+ // initial bypass chances
+ if (!opt.enabled) return bypass()
+ if (
+ req.headers['x-apicache-bypass'] ||
+ req.headers['x-apicache-force-fetch']
+ )
+ return bypass()
+
+ // REMOVED IN 0.11.1 TO CORRECT MIDDLEWARE TOGGLE EXECUTE ORDER
+ // if (typeof middlewareToggle === 'function') {
+ // if (!middlewareToggle(req, res)) return bypass()
+ // } else if (middlewareToggle !== undefined && !middlewareToggle) {
+ // return bypass()
+ // }
+
+ // embed timer
+ req.apicacheTimer = new Date()
+
+ // In Express 4.x the url is ambigious based on where a router is mounted. originalUrl will give the full Url
+ var key = req.originalUrl || req.url
+
+ // Remove querystring from key if jsonp option is enabled
+ if (opt.jsonp) {
+ key = url.parse(key).pathname
+ }
+
+ // add appendKey (either custom function or response path)
+ if (typeof opt.appendKey === 'function') {
+ key += '$$appendKey=' + opt.appendKey(req, res)
+ } else if (opt.appendKey.length > 0) {
+ var appendKey = req
+
+ for (var i = 0; i < opt.appendKey.length; i++) {
+ appendKey = appendKey[opt.appendKey[i]]
+ }
+ key += '$$appendKey=' + appendKey
+ }
+
+ // attempt cache hit
+ var redis = opt.redisClient
+ var cached = !redis ? memCache.getValue(key) : null
+
+ // send if cache hit from memory-cache
+ if (cached) {
+ var elapsed = new Date() - req.apicacheTimer
+ debug(
+ 'sending cached (memory-cache) version of',
+ key,
+ logDuration(elapsed),
+ )
+
+ perf.hit(key)
+ return sendCachedResponse(
+ req,
+ res,
+ cached,
+ middlewareToggle,
+ next,
+ duration,
+ )
+ }
+
+ // send if cache hit from redis
+ if (redis && redis.connected) {
+ try {
+ redis.hgetall(key, function (err, obj) {
+ if (!err && obj && obj.response) {
+ var elapsed = new Date() - req.apicacheTimer
+ debug(
+ 'sending cached (redis) version of',
+ key,
+ logDuration(elapsed),
+ )
+
+ perf.hit(key)
+ return sendCachedResponse(
+ req,
+ res,
+ JSON.parse(obj.response),
+ middlewareToggle,
+ next,
+ duration,
+ )
+ } else {
+ perf.miss(key)
+ return makeResponseCacheable(
+ req,
+ res,
+ next,
+ key,
+ duration,
+ strDuration,
+ middlewareToggle,
+ )
+ }
+ })
+ } catch (err) {
+ // bypass redis on error
+ perf.miss(key)
+ return makeResponseCacheable(
+ req,
+ res,
+ next,
+ key,
+ duration,
+ strDuration,
+ middlewareToggle,
+ )
+ }
+ } else {
+ perf.miss(key)
+ return makeResponseCacheable(
+ req,
+ res,
+ next,
+ key,
+ duration,
+ strDuration,
+ middlewareToggle,
+ )
+ }
+ }
+
+ cache.options = options
+
+ return cache
+ }
+
+ this.options = function (options) {
+ if (options) {
+ Object.assign(globalOptions, options)
+ syncOptions()
+
+ if ('defaultDuration' in options) {
+ // Convert the default duration to a number in milliseconds (if needed)
+ globalOptions.defaultDuration = parseDuration(
+ globalOptions.defaultDuration,
+ 3600000,
+ )
+ }
+
+ if (globalOptions.trackPerformance) {
+ debug(
+ 'WARNING: using trackPerformance flag can cause high memory usage!',
+ )
+ }
+
+ return this
+ } else {
+ return globalOptions
+ }
+ }
+
+ this.resetIndex = function () {
+ index = {
+ all: [],
+ groups: {},
+ }
+ }
+
+ this.newInstance = function (config) {
+ var instance = new ApiCache()
+
+ if (config) {
+ instance.options(config)
+ }
+
+ return instance
+ }
+
+ this.clone = function () {
+ return this.newInstance(this.options())
+ }
+
+ // initialize index
+ this.resetIndex()
+}
+
+module.exports = new ApiCache()
diff --git a/netease_api/util/config.json b/netease_api/util/config.json
new file mode 100644
index 0000000..dbfda36
--- /dev/null
+++ b/netease_api/util/config.json
@@ -0,0 +1,12 @@
+{
+ "anonymous_token": "8aae43f148f990410b9a2af38324af24e87ab9227c9265627ddd10145db744295fcd8701dc45b1ab8985e142f491516295dd965bae848761274a577a62b0fdc54a50284d1e434dcc04ca6d1a52333c9a",
+ "resourceTypeMap": {
+ "0": "R_SO_4_",
+ "1": "R_MV_5_",
+ "2": "A_PL_0_",
+ "3": "R_AL_3_",
+ "4": "A_DJ_1_",
+ "5": "R_VI_62_",
+ "6": "A_EV_2_"
+ }
+}
diff --git a/netease_api/util/crypto.js b/netease_api/util/crypto.js
new file mode 100644
index 0000000..3f99e85
--- /dev/null
+++ b/netease_api/util/crypto.js
@@ -0,0 +1,67 @@
+const crypto = require('crypto')
+const iv = Buffer.from('0102030405060708')
+const presetKey = Buffer.from('0CoJUm6Qyw8W8jud')
+const linuxapiKey = Buffer.from('rFgB&h#%2?^eDg:Q')
+const base62 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
+const publicKey =
+ '-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgtQn2JZ34ZC28NWYpAUd98iZ37BUrX/aKzmFbt7clFSs6sXqHauqKWqdtLkF2KexO40H1YTX8z2lSgBBOAxLsvaklV8k4cBFK9snQXE9/DDaFt6Rr7iVZMldczhC0JNgTz+SHXT6CBHuX3e9SdB1Ua44oncaTWz7OBGLbCiK45wIDAQAB\n-----END PUBLIC KEY-----'
+const eapiKey = 'e82ckenh8dichen8'
+
+const aesEncrypt = (buffer, mode, key, iv) => {
+ const cipher = crypto.createCipheriv('aes-128-' + mode, key, iv)
+ return Buffer.concat([cipher.update(buffer), cipher.final()])
+}
+
+const rsaEncrypt = (buffer, key) => {
+ buffer = Buffer.concat([Buffer.alloc(128 - buffer.length), buffer])
+ return crypto.publicEncrypt(
+ { key: key, padding: crypto.constants.RSA_NO_PADDING },
+ buffer,
+ )
+}
+
+const weapi = (object) => {
+ const text = JSON.stringify(object)
+ const secretKey = crypto
+ .randomBytes(16)
+ .map((n) => base62.charAt(n % 62).charCodeAt())
+ return {
+ params: aesEncrypt(
+ Buffer.from(
+ aesEncrypt(Buffer.from(text), 'cbc', presetKey, iv).toString('base64'),
+ ),
+ 'cbc',
+ secretKey,
+ iv,
+ ).toString('base64'),
+ encSecKey: rsaEncrypt(secretKey.reverse(), publicKey).toString('hex'),
+ }
+}
+
+const linuxapi = (object) => {
+ const text = JSON.stringify(object)
+ return {
+ eparams: aesEncrypt(Buffer.from(text), 'ecb', linuxapiKey, '')
+ .toString('hex')
+ .toUpperCase(),
+ }
+}
+
+const eapi = (url, object) => {
+ const text = typeof object === 'object' ? JSON.stringify(object) : object
+ const message = `nobody${url}use${text}md5forencrypt`
+ const digest = crypto.createHash('md5').update(message).digest('hex')
+ const data = `${url}-36cd479b6b5-${text}-36cd479b6b5-${digest}`
+ return {
+ params: aesEncrypt(Buffer.from(data), 'ecb', eapiKey, '')
+ .toString('hex')
+ .toUpperCase(),
+ }
+}
+
+const decrypt = (cipherBuffer) => {
+ const decipher = crypto.createDecipheriv('aes-128-ecb', eapiKey, '')
+ return Buffer.concat([decipher.update(cipherBuffer), decipher.final()])
+}
+
+module.exports = { weapi, linuxapi, eapi, decrypt }
diff --git a/netease_api/util/index.js b/netease_api/util/index.js
new file mode 100644
index 0000000..06aade5
--- /dev/null
+++ b/netease_api/util/index.js
@@ -0,0 +1,17 @@
+module.exports = {
+ toBoolean(val) {
+ if (typeof val === 'boolean') return val
+ if (val === '') return val
+ return val === 'true' || val == '1'
+ },
+ cookieToJson(cookie) {
+ if (!cookie) return {}
+ let cookieArr = cookie.split(';')
+ let obj = {}
+ cookieArr.forEach((i) => {
+ let arr = i.split('=')
+ obj[arr[0]] = arr[1]
+ })
+ return obj
+ },
+}
diff --git a/netease_api/util/memory-cache.js b/netease_api/util/memory-cache.js
new file mode 100644
index 0000000..6b6deaa
--- /dev/null
+++ b/netease_api/util/memory-cache.js
@@ -0,0 +1,63 @@
+function MemoryCache() {
+ this.cache = {}
+ this.size = 0
+}
+
+MemoryCache.prototype.add = function (key, value, time, timeoutCallback) {
+ var old = this.cache[key]
+ var instance = this
+
+ var entry = {
+ value: value,
+ expire: time + Date.now(),
+ timeout: setTimeout(function () {
+ instance.delete(key)
+ return (
+ timeoutCallback &&
+ typeof timeoutCallback === 'function' &&
+ timeoutCallback(value, key)
+ )
+ }, time),
+ }
+
+ this.cache[key] = entry
+ this.size = Object.keys(this.cache).length
+
+ return entry
+}
+
+MemoryCache.prototype.delete = function (key) {
+ var entry = this.cache[key]
+
+ if (entry) {
+ clearTimeout(entry.timeout)
+ }
+
+ delete this.cache[key]
+
+ this.size = Object.keys(this.cache).length
+
+ return null
+}
+
+MemoryCache.prototype.get = function (key) {
+ var entry = this.cache[key]
+
+ return entry
+}
+
+MemoryCache.prototype.getValue = function (key) {
+ var entry = this.get(key)
+
+ return entry && entry.value
+}
+
+MemoryCache.prototype.clear = function () {
+ Object.keys(this.cache).forEach(function (key) {
+ this.delete(key)
+ }, this)
+
+ return true
+}
+
+module.exports = MemoryCache
diff --git a/netease_api/util/request.js b/netease_api/util/request.js
new file mode 100644
index 0000000..7b4f45a
--- /dev/null
+++ b/netease_api/util/request.js
@@ -0,0 +1,192 @@
+const encrypt = require('./crypto')
+const axios = require('axios')
+const queryString = require('querystring')
+const PacProxyAgent = require('pac-proxy-agent')
+const http = require('http')
+const https = require('https')
+const tunnel = require('tunnel')
+const qs = require('url')
+// request.debug = true // 开启可看到更详细信息
+
+const chooseUserAgent = (ua = false) => {
+ const userAgentList = {
+ mobile: [
+ // iOS 13.5.1 14.0 beta with safari
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Mobile/15E148 Safari/604.1',
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.',
+ // iOS with qq micromsg
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_5_1 like Mac OS X) AppleWebKit/602.1.50 (KHTML like Gecko) Mobile/14A456 QQ/6.5.7.408 V1_IPH_SQ_6.5.7_1_APP_A Pixel/750 Core/UIWebView NetType/4G Mem/103',
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/7.0.15(0x17000f27) NetType/WIFI Language/zh',
+ // Android -> Huawei Xiaomi
+ 'Mozilla/5.0 (Linux; Android 9; PCT-AL10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 HuaweiBrowser/10.0.3.311 Mobile Safari/537.36',
+ 'Mozilla/5.0 (Linux; U; Android 9; zh-cn; Redmi Note 8 Build/PKQ1.190616.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.141 Mobile Safari/537.36 XiaoMi/MiuiBrowser/12.5.22',
+ // Android + qq micromsg
+ 'Mozilla/5.0 (Linux; Android 10; YAL-AL00 Build/HUAWEIYAL-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/78.0.3904.62 XWEB/2581 MMWEBSDK/200801 Mobile Safari/537.36 MMWEBID/3027 MicroMessenger/7.0.18.1740(0x27001235) Process/toolsmp WeChat/arm64 NetType/WIFI Language/zh_CN ABI/arm64',
+ 'Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; BKK-AL10 Build/HONORBKK-AL10) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/10.6 Mobile Safari/537.36',
+ ],
+ pc: [
+ // macOS 10.15.6 Firefox / Chrome / Safari
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:80.0) Gecko/20100101 Firefox/80.0',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.30 Safari/537.36',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.2 Safari/605.1.15',
+ // Windows 10 Firefox / Chrome / Edge
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.30 Safari/537.36',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/13.10586',
+ // Linux 就算了
+ ],
+ }
+ let realUserAgentList =
+ userAgentList[ua] || userAgentList.mobile.concat(userAgentList.pc)
+ return ['mobile', 'pc', false].indexOf(ua) > -1
+ ? realUserAgentList[Math.floor(Math.random() * realUserAgentList.length)]
+ : ua
+}
+const createRequest = (method, url, data, options) => {
+ return new Promise((resolve, reject) => {
+ let headers = { 'User-Agent': chooseUserAgent(options.ua) }
+ if (method.toUpperCase() === 'POST')
+ headers['Content-Type'] = 'application/x-www-form-urlencoded'
+ if (url.includes('music.163.com'))
+ headers['Referer'] = 'https://music.163.com'
+ if (options.realIP) headers['X-Real-IP'] = options.realIP
+ // headers['X-Real-IP'] = '118.88.88.88'
+ if (typeof options.cookie === 'object')
+ headers['Cookie'] = Object.keys(options.cookie)
+ .map(
+ (key) =>
+ encodeURIComponent(key) +
+ '=' +
+ encodeURIComponent(options.cookie[key]),
+ )
+ .join('; ')
+ else if (options.cookie) headers['Cookie'] = options.cookie
+
+ if (!headers['Cookie']) {
+ headers['Cookie'] = options.token || ''
+ }
+ if (options.crypto === 'weapi') {
+ let csrfToken = (headers['Cookie'] || '').match(/_csrf=([^(;|$)]+)/)
+ data.csrf_token = csrfToken ? csrfToken[1] : ''
+ data = encrypt.weapi(data)
+ url = url.replace(/\w*api/, 'weapi')
+ } else if (options.crypto === 'linuxapi') {
+ data = encrypt.linuxapi({
+ method: method,
+ url: url.replace(/\w*api/, 'api'),
+ params: data,
+ })
+ headers['User-Agent'] =
+ 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36'
+ url = 'https://music.163.com/api/linux/forward'
+ } else if (options.crypto === 'eapi') {
+ const cookie = options.cookie || {}
+ const csrfToken = cookie['__csrf'] || ''
+ const header = {
+ osver: cookie.osver, //系统版本
+ deviceId: cookie.deviceId, //encrypt.base64.encode(imei + '\t02:00:00:00:00:00\t5106025eb79a5247\t70ffbaac7')
+ appver: cookie.appver || '8.0.0', // app版本
+ versioncode: cookie.versioncode || '140', //版本号
+ mobilename: cookie.mobilename, //设备model
+ buildver: cookie.buildver || Date.now().toString().substr(0, 10),
+ resolution: cookie.resolution || '1920x1080', //设备分辨率
+ __csrf: csrfToken,
+ os: cookie.os || 'android',
+ channel: cookie.channel,
+ requestId: `${Date.now()}_${Math.floor(Math.random() * 1000)
+ .toString()
+ .padStart(4, '0')}`,
+ }
+ if (cookie.MUSIC_U) header['MUSIC_U'] = cookie.MUSIC_U
+ if (cookie.MUSIC_A) header['MUSIC_A'] = cookie.MUSIC_A
+ headers['Cookie'] = Object.keys(header)
+ .map(
+ (key) =>
+ encodeURIComponent(key) + '=' + encodeURIComponent(header[key]),
+ )
+ .join('; ')
+ data.header = header
+ data = encrypt.eapi(options.url, data)
+ url = url.replace(/\w*api/, 'eapi')
+ }
+
+ const answer = { status: 500, body: {}, cookie: [] }
+ let settings = {
+ method: method,
+ url: url,
+ headers: headers,
+ data: queryString.stringify(data),
+ httpAgent: new http.Agent({ keepAlive: true }),
+ httpsAgent: new https.Agent({ keepAlive: true, rejectUnauthorized: false }),
+ }
+
+ if (options.crypto === 'eapi') settings.encoding = null
+
+ if (options.proxy) {
+ if (options.proxy.indexOf('pac') > -1) {
+ settings.httpAgent = new PacProxyAgent(options.proxy)
+ settings.httpsAgent = new PacProxyAgent(options.proxy)
+ } else {
+ var purl = qs.parse(options.proxy)
+ if (purl.hostname) {
+ const agent = tunnel.httpsOverHttp({
+ proxy: {
+ host: purl.hostname,
+ port: purl.port || 80,
+ },
+ })
+ settings.httpsAgent = agent
+ settings.httpAgent = agent
+ settings.proxy = false
+ } else {
+ console.error('代理配置无效,不使用代理')
+ }
+ }
+ }
+ if (options.crypto === 'eapi') {
+ settings = {
+ ...settings,
+ responseType: 'arraybuffer',
+ }
+ }
+ axios(settings)
+ .then((res) => {
+ const body = res.data
+ answer.cookie = (res.headers['set-cookie'] || []).map((x) =>
+ x.replace(/\s*Domain=[^(;|$)]+;*/, ''),
+ )
+ try {
+ if (options.crypto === 'eapi') {
+ answer.body = JSON.parse(encrypt.decrypt(body).toString())
+ } else {
+ answer.body = body
+ }
+
+ answer.status = answer.body.code || res.status
+ if (
+ [201, 302, 400, 502, 800, 801, 802, 803].indexOf(answer.body.code) >
+ -1
+ ) {
+ // 特殊状态码
+ answer.status = 200
+ }
+ } catch (e) {
+ // console.log(e)
+ answer.body = body
+ answer.status = res.status
+ }
+
+ answer.status =
+ 100 < answer.status && answer.status < 600 ? answer.status : 400
+ if (answer.status == 200) resolve(answer)
+ else reject(answer)
+ })
+ .catch((err) => {
+ answer.status = 502
+ answer.body = { code: 502, msg: err }
+ reject(answer)
+ })
+ })
+}
+
+module.exports = createRequest
diff --git a/netease_api/vercel.json b/netease_api/vercel.json
new file mode 100644
index 0000000..e8eaad7
--- /dev/null
+++ b/netease_api/vercel.json
@@ -0,0 +1,15 @@
+{
+ "version": 2,
+ "builds": [
+ {
+ "src": "./index.js",
+ "use": "@vercel/node"
+ }
+ ],
+ "routes": [
+ {
+ "src": "/(.*)",
+ "dest": "/"
+ }
+ ]
+}
diff --git a/package.json b/package.json
index bb87fdd..5258849 100644
--- a/package.json
+++ b/package.json
@@ -1,9 +1,9 @@
{
"name": "yesplaymusic",
- "version": "0.4.9",
+ "version": "0.4.2",
"private": true,
"description": "A third party music player for Netease Music",
- "author": "qier222
",
+ "author": "hawtim",
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
@@ -18,68 +18,62 @@
"electron:publish": "vue-cli-service electron:build -mwl -p always",
"postinstall": "electron-builder install-app-deps",
"postuninstall": "electron-builder install-app-deps",
- "prettier": "npx prettier --write ./src",
- "netease_api:run": "npx NeteaseCloudMusicApi"
+ "prettier": "npx prettier --write ./src ./script",
+ "netease_api:run": "cd ./netease_api && npm run start",
+ "netease_api:pull": "node script/pull.js",
+ "netease_api:install": "cd ./netease_api && npm install",
+ "netease_api:setup": "npm run netease_api:pull && npm run netease_api:install"
},
"main": "background.js",
- "engines": {
- "node": "14 || 16"
- },
"dependencies": {
- "@unblockneteasemusic/rust-napi": "^0.4.0",
- "NeteaseCloudMusicApi": "^4.23.3",
- "axios": "^0.26.1",
+ "@revincx/unblockneteasemusic": "^0.25.7",
+ "axios": "^0.21.0",
"change-case": "^4.1.2",
"cli-color": "^2.0.0",
- "color": "^4.2.3",
+ "color": "^3.1.3",
"core-js": "^3.6.5",
"crypto-js": "^4.0.0",
"dayjs": "^1.8.36",
"dexie": "^3.0.3",
"discord-rich-presence": "^0.0.8",
- "electron": "^13.6.7",
- "electron-builder": "^23.0.0",
- "electron-context-menu": "^3.1.2",
+ "electron": "^13.0.1",
+ "electron-builder": "^22.10.5",
+ "electron-context-menu": "^2.3.0",
"electron-debug": "^3.1.0",
"electron-devtools-installer": "^3.2",
- "electron-icon-builder": "^2.0.1",
- "electron-is-dev": "^2.0.0",
+ "electron-icon-builder": "^1.0.2",
+ "electron-is-dev": "^1.2.0",
"electron-log": "^4.3.0",
- "electron-store": "^8.0.1",
- "electron-updater": "^5.0.1",
- "esbuild": "^0.20.1",
- "esbuild-loader": "^4.0.3",
+ "electron-store": "^6.0.1",
+ "electron-updater": "^4.3.5",
"express": "^4.17.1",
+ "md5": "^2.3.0",
+ "music-metadata": "^7.5.3",
"express-fileupload": "^1.2.0",
"express-http-proxy": "^1.6.2",
"extract-zip": "^2.0.1",
"howler": "^2.2.3",
"js-cookie": "^2.2.1",
- "jsbi": "^4.1.0",
"lodash": "^4.17.20",
- "md5": "^2.3.0",
- "mpris-service": "^2.1.2",
- "music-metadata": "^7.5.3",
- "node-vibrant": "^3.2.1-alpha.1",
+ "node-vibrant": "^3.1.6",
"nprogress": "^0.2.0",
"pac-proxy-agent": "^4.1.0",
"plyr": "^3.6.2",
+ "prettier": "2.1.2",
"qrcode": "^1.4.4",
"register-service-worker": "^1.7.1",
- "svg-sprite-loader": "^6.0.11",
+ "svg-sprite-loader": "^5.0.0",
"tunnel": "^0.0.6",
- "vscode-codicons": "^0.0.17",
+ "vscode-codicons": "^0.0.14",
"vue": "^2.6.11",
+ "vue-analytics": "^5.22.1",
"vue-clipboard2": "^0.3.1",
- "vue-gtag": "1",
"vue-i18n": "^8.22.0",
"vue-router": "^3.4.3",
"vue-slider-component": "^3.2.5",
- "vuex": "^3.4.0",
- "x11": "^2.3.0"
+ "vuex": "^3.4.0"
},
"devDependencies": {
- "@types/node": "^17.0.0",
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-pwa": "~4.5.0",
@@ -91,17 +85,11 @@
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-vue": "^7.9.0",
"husky": "^4.3.0",
- "prettier": "2.5.1",
"sass": "^1.26.11",
"sass-loader": "^10.0.2",
- "vue-cli-plugin-electron-builder": "~2.1.1",
+ "vue-cli-plugin-electron-builder": "~2.0.0-rc.4",
"vue-template-compiler": "^2.6.11"
},
- "resolutions": {
- "icon-gen": "3.0.0",
- "degenerator": "2.2.0",
- "electron-builder": "^23.0.0"
- },
"eslintConfig": {
"root": true,
"env": {
diff --git a/public/img/icons/menu-dark@88.png b/public/img/icons/menu-dark@88.png
deleted file mode 100644
index a2feb00..0000000
Binary files a/public/img/icons/menu-dark@88.png and /dev/null differ
diff --git a/public/img/icons/menu-light@88.png b/public/img/icons/menu@88.png
similarity index 100%
rename from public/img/icons/menu-light@88.png
rename to public/img/icons/menu@88.png
diff --git a/public/img/icons/pause.png b/public/img/icons/pause.png
deleted file mode 100644
index 509d738..0000000
Binary files a/public/img/icons/pause.png and /dev/null differ
diff --git a/public/img/icons/unlike.png b/public/img/icons/unlike.png
deleted file mode 100644
index a0afa24..0000000
Binary files a/public/img/icons/unlike.png and /dev/null differ
diff --git a/public/img/logos/yesplaymusic-white24x24.png b/public/img/logos/yesplaymusic-white24x24.png
deleted file mode 100644
index d8e4715..0000000
Binary files a/public/img/logos/yesplaymusic-white24x24.png and /dev/null differ
diff --git a/public/robots.txt b/public/robots.txt
index 1f53798..eb05362 100644
--- a/public/robots.txt
+++ b/public/robots.txt
@@ -1,2 +1,2 @@
User-agent: *
-Disallow: /
+Disallow:
diff --git a/restyled.yml b/restyled.yml
deleted file mode 100644
index c31d3e8..0000000
--- a/restyled.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-commit_template: 'style: with ${restyler.name}'
-restylers:
- - prettier
- - prettier-json
- - prettier-markdown
- - prettier-yaml
- - whitespace
diff --git a/script/pull.js b/script/pull.js
new file mode 100644
index 0000000..30ac9b2
--- /dev/null
+++ b/script/pull.js
@@ -0,0 +1,103 @@
+// node module
+const fs = require('fs');
+const https = require('https');
+const resolve = require('path').resolve;
+const join = require('path').resolve;
+const extract = require('extract-zip');
+
+// 函数参数
+const dest = resolve(__dirname, '../');
+const fileName = 'NeteaseCloudMusicApi-master.zip';
+const options = {
+ hostname: 'github.91chifun.workers.dev',
+ path: `//https://github.com/Binaryify/NeteaseCloudMusicApi/archive/master.zip`,
+};
+
+// 完整的流程控制
+/**
+ * 1. 检查本地文件是否已有
+ * 2. 下载默认/指定版本的 zip 压缩包,等待下载
+ * 3. 解压缩
+ * 4. 进入目录安装依赖 npm install
+ */
+
+function fix2(number) {
+ return number.toFixed(2);
+}
+
+async function download(options, fileName, callback) {
+ return await new Promise((resolve, reject) => {
+ const destPath = join(__dirname, '../' + fileName);
+ // Check if exist
+ if (fs.existsSync(destPath)) return resolve(destPath);
+
+ const file = fs.createWriteStream(destPath);
+ const request = https.get(options, res => {
+ let len = res.headers && parseInt(res.headers['content-length'], 10);
+ let cur = 0;
+ // 1048576 - bytes in 1Megabyte
+ const MEGA = 1048576;
+ let total = 0;
+ if (len) {
+ total = len / MEGA;
+ }
+ if (!len) {
+ console.log(
+ 'Downloading, but can not get content-length, please be patient.'
+ );
+ }
+ res.on('data', chunk => {
+ if (len) {
+ cur += chunk.length;
+ console.log(
+ `Downloading ${fix2((100.0 * cur) / len)}% ${fix2(
+ cur / MEGA
+ )}/${fix2(total)}mb`
+ );
+ }
+ });
+ res.on('end', () => {
+ callback('Downloading complete!');
+ });
+ res.pipe(file);
+ file.on('finish', () => {
+ file.close(() => {
+ callback('File wrote complete!');
+ resolve(destPath);
+ });
+ });
+ file.on('error', err => {
+ fs.unlink(destPath);
+ reject(err);
+ });
+ request.on('error', err => {
+ console.log('Error: ' + err.message);
+ });
+ });
+ });
+}
+
+async function unzip(source, target) {
+ try {
+ await extract(source, {
+ dir: target,
+ });
+ console.log('Extraction complete');
+ return true;
+ } catch (err) {
+ // handle any errors
+ if (err.message === 'end of central directory record signature not found') {
+ console.log('Not a full_downloaded zip file, removed!');
+ fs.unlinkSync(source);
+ }
+ return false;
+ }
+}
+// Download process
+download(options, fileName, text => {
+ console.log(text);
+}).then(path => {
+ console.log(path);
+ // Unzip process
+ return unzip(path, dest);
+});
diff --git a/src/App.vue b/src/App.vue
index 59392be..b9d7d41 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -124,7 +124,6 @@ main {
overflow: auto;
padding: 64px 10vw 96px 10vw;
box-sizing: border-box;
- scrollbar-width: none; // firefox
}
@media (max-width: 1336px) {
diff --git a/src/api/artist.js b/src/api/artist.js
index 925df45..462f707 100644
--- a/src/api/artist.js
+++ b/src/api/artist.js
@@ -1,7 +1,5 @@
import request from '@/utils/request';
import { mapTrackPlayableStatus } from '@/utils/common';
-import { isAccountLoggedIn } from '@/utils/auth';
-import { getTrackDetail } from '@/api/track';
/**
* 获取歌手单曲
@@ -16,13 +14,7 @@ export function getArtist(id) {
id,
timestamp: new Date().getTime(),
},
- }).then(async data => {
- if (!isAccountLoggedIn()) {
- const trackIDs = data.hotSongs.map(t => t.id);
- const tracks = await getTrackDetail(trackIDs.join(','));
- data.hotSongs = tracks.songs;
- return data;
- }
+ }).then(data => {
data.hotSongs = mapTrackPlayableStatus(data.hotSongs);
return data;
});
diff --git a/src/api/playlist.js b/src/api/playlist.js
index 08177ea..b1b9a84 100644
--- a/src/api/playlist.js
+++ b/src/api/playlist.js
@@ -26,10 +26,7 @@ export function dailyRecommendPlaylist(params) {
return request({
url: '/recommend/resource',
method: 'get',
- params: {
- params,
- timestamp: Date.now(),
- },
+ params,
});
}
/**
@@ -209,21 +206,3 @@ export function dailyRecommendTracks() {
return result;
});
}
-
-/**
- * 心动模式/智能播放
- * 说明 : 登录后调用此接口 , 可获取心动模式/智能播放列表 必选参数 : id : 歌曲 id
- * - id : 歌曲 id
- * - pid : 歌单 id
- * - sid : 要开始播放的歌曲的 id (可选参数)
- * @param {Object} params
- * @param {number=} params.id
- * @param {number=} params.pid
- */
-export function intelligencePlaylist(params) {
- return request({
- url: '/playmode/intelligence/list',
- method: 'get',
- params,
- });
-}
diff --git a/src/api/track.js b/src/api/track.js
index 490c91c..472dc6a 100644
--- a/src/api/track.js
+++ b/src/api/track.js
@@ -15,18 +15,16 @@ import {
* @param {string} id - 音乐的 id,例如 id=405998841,33894312
*/
export function getMP3(id) {
- const getBr = () => {
- // 当返回的 quality >= 400000时,就会优先返回 hi-res
- const quality = store.state.settings?.musicQuality ?? '320000';
- return quality === 'flac' ? '350000' : quality;
- };
-
+ let br =
+ store.state.settings?.musicQuality !== undefined
+ ? store.state.settings.musicQuality
+ : 320000;
return request({
url: '/song/url',
method: 'get',
params: {
id,
- br: getBr(),
+ br,
},
});
}
diff --git a/src/api/user.js b/src/api/user.js
index ec02014..8269297 100644
--- a/src/api/user.js
+++ b/src/api/user.js
@@ -50,23 +50,6 @@ export function userPlaylist(params) {
});
}
-/**
- * 获取用户播放记录
- * 说明 : 登录后调用此接口 , 传入用户 id, 可获取用户播放记录
- * - uid : 用户 id
- * - type : type=1 时只返回 weekData, type=0 时返回 allData
- * @param {Object} params
- * @param {number} params.uid
- * @param {number} params.type
- */
-export function userPlayHistory(params) {
- return request({
- url: '/user/record',
- method: 'get',
- params,
- });
-}
-
/**
* 喜欢音乐列表(需要登录)
* 说明 : 调用此接口 , 传入用户 id, 可获取已喜欢音乐id列表(id数组)
diff --git a/src/assets/icons/fullscreen-exit.svg b/src/assets/icons/fullscreen-exit.svg
deleted file mode 100644
index f76f601..0000000
--- a/src/assets/icons/fullscreen-exit.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
\ No newline at end of file
diff --git a/src/assets/icons/fullscreen.svg b/src/assets/icons/fullscreen.svg
deleted file mode 100644
index e6128c0..0000000
--- a/src/assets/icons/fullscreen.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
\ No newline at end of file
diff --git a/src/assets/icons/sort-up.svg b/src/assets/icons/sort-up.svg
deleted file mode 100644
index 3efe4cf..0000000
--- a/src/assets/icons/sort-up.svg
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
\ No newline at end of file
diff --git a/src/background.js b/src/background.js
index 94dbbc0..5efde71 100644
--- a/src/background.js
+++ b/src/background.js
@@ -7,16 +7,7 @@ import {
dialog,
globalShortcut,
nativeTheme,
- screen,
} from 'electron';
-import {
- isWindows,
- isMac,
- isLinux,
- isDevelopment,
- isCreateTray,
- isCreateMpris,
-} from '@/utils/platform';
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib';
import { startNeteaseMusicApi } from './electron/services';
import { initIpcMain } from './electron/ipcMain.js';
@@ -27,12 +18,9 @@ import { createDockMenu } from './electron/dockMenu';
import { registerGlobalShortcut } from './electron/globalShortcut';
import { autoUpdater } from 'electron-updater';
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer';
-import { EventEmitter } from 'events';
import express from 'express';
import expressProxy from 'express-http-proxy';
import Store from 'electron-store';
-import { createMpris, createDbus } from '@/electron/mpris';
-import { spawn } from 'child_process';
const clc = require('cli-color');
const log = text => {
console.log(`${clc.blueBright('[background.js]')} ${text}`);
@@ -81,10 +69,15 @@ const closeOnLinux = (e, win, store) => {
}
};
+const isWindows = process.platform === 'win32';
+const isMac = process.platform === 'darwin';
+const isLinux = process.platform === 'linux';
+const isDevelopment = process.env.NODE_ENV === 'development';
+
class Background {
constructor() {
this.window = null;
- this.ypmTrayImpl = null;
+ this.tray = null;
this.store = new Store({
windowWidth: {
width: { type: 'number', default: 1440 },
@@ -117,14 +110,6 @@ class Background {
// handle app events
this.handleAppEvents();
-
- // disable chromium mpris
- if (isCreateMpris) {
- app.commandLine.appendSwitch(
- 'disable-features',
- 'HardwareMediaKeyHandling,MediaSessionService'
- );
- }
}
async initDevtools() {
@@ -182,10 +167,7 @@ class Background {
minWidth: 1080,
minHeight: 720,
titleBarStyle: 'hiddenInset',
- frame: !(
- isWindows ||
- (isLinux && this.store.get('settings.linuxEnableCustomTitlebar'))
- ),
+ frame: !isWindows,
title: 'YesPlayMusic',
show: false,
webPreferences: {
@@ -203,42 +185,8 @@ class Background {
};
if (this.store.get('window.x') && this.store.get('window.y')) {
- let x = this.store.get('window.x');
- let y = this.store.get('window.y');
-
- let displays = screen.getAllDisplays();
- let isResetWindiw = false;
- if (displays.length === 1) {
- let { bounds } = displays[0];
- if (
- x < bounds.x ||
- x > bounds.x + bounds.width - 50 ||
- y < bounds.y ||
- y > bounds.y + bounds.height - 50
- ) {
- isResetWindiw = true;
- }
- } else {
- isResetWindiw = true;
- for (let i = 0; i < displays.length; i++) {
- let { bounds } = displays[i];
- if (
- x > bounds.x &&
- x < bounds.x + bounds.width &&
- y > bounds.y &&
- y < bounds.y - bounds.height
- ) {
- // 检测到APP窗口当前处于一个可用的屏幕里,break
- isResetWindiw = false;
- break;
- }
- }
- }
-
- if (!isResetWindiw) {
- options.x = x;
- options.y = y;
- }
+ options.x = this.store.get('window.x');
+ options.y = this.store.get('window.y');
}
this.window = new BrowserWindow(options);
@@ -297,7 +245,6 @@ class Background {
this.window.once('ready-to-show', () => {
log('window ready-to-show event');
this.window.show();
- this.store.set('window', this.window.getBounds());
});
this.window.on('close', e => {
@@ -333,14 +280,6 @@ class Background {
this.store.set('window', this.window.getBounds());
});
- this.window.on('maximize', () => {
- this.window.webContents.send('isMaximized', true);
- });
-
- this.window.on('unmaximize', () => {
- this.window.webContents.send('isMaximized', false);
- });
-
this.window.webContents.on('new-window', function (e, url) {
e.preventDefault();
log('open url');
@@ -385,14 +324,8 @@ class Background {
});
this.handleWindowEvents();
- // create tray
- if (isCreateTray) {
- this.trayEventEmitter = new EventEmitter();
- this.ypmTrayImpl = createTray(this.window, this.trayEventEmitter);
- }
-
// init ipcMain
- initIpcMain(this.window, this.store, this.trayEventEmitter);
+ initIpcMain(this.window, this.store);
// set proxy
const proxyRules = this.store.get('proxy');
@@ -408,38 +341,21 @@ class Background {
// create menu
createMenu(this.window, this.store);
+ // create tray
+ if (isWindows || isLinux || isDevelopment) {
+ this.tray = createTray(this.window);
+ }
+
// create dock menu for macOS
- const createdDockMenu = createDockMenu(this.window);
- if (createDockMenu && app.dock) app.dock.setMenu(createdDockMenu);
+ app.dock.setMenu(createDockMenu(this.window));
// create touch bar
- const createdTouchBar = createTouchBar(this.window);
- if (createdTouchBar) this.window.setTouchBar(createdTouchBar);
+ this.window.setTouchBar(createTouchBar(this.window));
// register global shortcuts
if (this.store.get('settings.enableGlobalShortcut') !== false) {
registerGlobalShortcut(this.window, this.store);
}
-
- // try to start osdlyrics process on start
- if (this.store.get('settings.enableOsdlyricsSupport')) {
- await createDbus(this.window);
- log('try to start osdlyrics process');
- const osdlyricsProcess = spawn('osdlyrics');
-
- osdlyricsProcess.on('error', err => {
- log(`failed to start osdlyrics: ${err.message}`);
- });
-
- osdlyricsProcess.on('exit', (code, signal) => {
- log(`osdlyrics process exited with code ${code}, signal ${signal}`);
- });
- }
-
- // create mpris
- if (isCreateMpris) {
- createMpris(this.window);
- }
});
app.on('activate', () => {
diff --git a/src/components/ArtistsInLine.vue b/src/components/ArtistsInLine.vue
index e2c619d..cc13384 100644
--- a/src/components/ArtistsInLine.vue
+++ b/src/components/ArtistsInLine.vue
@@ -2,13 +2,11 @@
{{ computedPrefix }}
- {{
- ar.name
- }}
+
+ {{ ar.name }}
+
{{ ar.name }}
- ,
+ ,
@@ -42,12 +40,4 @@ export default {
};
-
+
diff --git a/src/components/ContextMenu.vue b/src/components/ContextMenu.vue
index 186448f..dd6365b 100644
--- a/src/components/ContextMenu.vue
+++ b/src/components/ContextMenu.vue
@@ -15,8 +15,6 @@
-
-
diff --git a/src/components/Modal.vue b/src/components/Modal.vue
index 6657369..4ddc909 100644
--- a/src/components/Modal.vue
+++ b/src/components/Modal.vue
@@ -39,16 +39,11 @@ export default {
type: Boolean,
default: false,
},
- minWidth: {
- type: String,
- default: 'calc(min(23rem, 100vw))',
- },
},
computed: {
modalStyles() {
return {
width: this.width,
- minWidth: this.minWidth,
};
},
},
diff --git a/src/components/ModalAddTrackToPlaylist.vue b/src/components/ModalAddTrackToPlaylist.vue
index e6c94dd..193bcd4 100644
--- a/src/components/ModalAddTrackToPlaylist.vue
+++ b/src/components/ModalAddTrackToPlaylist.vue
@@ -17,7 +17,7 @@
class="playlist"
@click="addTrackToPlaylist(playlist.id)"
>
-
+
{{ playlist.name }}
{{ playlist.trackCount }} 首
diff --git a/src/components/ModalNewPlaylist.vue b/src/components/ModalNewPlaylist.vue
index 0bbc8f4..29e997e 100644
--- a/src/components/ModalNewPlaylist.vue
+++ b/src/components/ModalNewPlaylist.vue
@@ -147,7 +147,6 @@ export default {
label {
font-size: 12px;
}
- user-select: none;
}
}
}
diff --git a/src/components/MvRow.vue b/src/components/MvRow.vue
index a06fa6a..a5d4d7a 100644
--- a/src/components/MvRow.vue
+++ b/src/components/MvRow.vue
@@ -7,7 +7,7 @@
@mouseleave="hoverVideoID = 0"
@click="goToMv(getID(mv))"
>
-
![]()
+
${artistName}`;
+ return `
${artistName}`;
} else if (this.subtitle === 'publishTime') {
return mv.publishTime;
}
diff --git a/src/components/Navbar.vue b/src/components/Navbar.vue
index dce629b..372fca0 100644
--- a/src/components/Navbar.vue
+++ b/src/components/Navbar.vue
@@ -1,8 +1,27 @@
-
+
@@ -82,16 +95,17 @@ import { isLooseLoggedIn, doLogout } from '@/utils/auth';
// icons by https://github.com/microsoft/vscode-codicons
import 'vscode-codicons/dist/codicon.css';
-import Win32Titlebar from '@/components/Win32Titlebar.vue';
-import LinuxTitlebar from '@/components/LinuxTitlebar.vue';
import ContextMenu from '@/components/ContextMenu.vue';
import ButtonIcon from '@/components/ButtonIcon.vue';
+const electron =
+ process.env.IS_ELECTRON === true ? window.require('electron') : null;
+const ipcRenderer =
+ process.env.IS_ELECTRON === true ? electron.ipcRenderer : null;
+
export default {
name: 'Navbar',
components: {
- Win32Titlebar,
- LinuxTitlebar,
ButtonIcon,
ContextMenu,
},
@@ -100,8 +114,7 @@ export default {
inputFocus: false,
langs: ['zh-CN', 'zh-TW', 'en', 'tr'],
keywords: '',
- enableWin32Titlebar: false,
- enableLinuxTitlebar: false,
+ isWindowMaximized: false,
};
},
computed: {
@@ -114,18 +127,12 @@ export default {
? `${this.data?.user?.avatarUrl}?param=512y512`
: 'http://s4.music.126.net/style/web2/img/default/default_avatar.jpg?param=60y60';
},
- hasCustomTitlebar() {
- return this.enableWin32Titlebar || this.enableLinuxTitlebar;
- },
},
created() {
- if (process.platform === 'win32') {
- this.enableWin32Titlebar = true;
- } else if (
- process.platform === 'linux' &&
- this.settings.linuxEnableCustomTitlebar
- ) {
- this.enableLinuxTitlebar = true;
+ if (process.env.IS_ELECTRON === true) {
+ ipcRenderer.on('isMaximized', (event, value) => {
+ this.isWindowMaximized = value;
+ });
}
},
methods: {
@@ -167,6 +174,15 @@ export default {
this.$router.push({ name: 'login' });
}
},
+ windowMinimize() {
+ ipcRenderer.send('minimize');
+ },
+ windowMaxRestore() {
+ ipcRenderer.send('maximizeOrUnmaximize');
+ },
+ windowClose() {
+ ipcRenderer.send('close');
+ },
},
};
@@ -194,7 +210,7 @@ nav {
@media (max-width: 1336px) {
nav {
- padding: 0 max(5vw, 90px);
+ padding: 0 5vw;
}
}
@@ -204,9 +220,68 @@ nav {
}
}
-nav.has-custom-titlebar {
- padding-top: 20px;
- -webkit-app-region: no-drag;
+.win32-titlebar {
+ display: none;
+}
+
+[data-electron-os='win32'] {
+ nav {
+ padding-top: 20px;
+ -webkit-app-region: no-drag;
+ }
+ .win32-titlebar {
+ color: var(--color-text);
+ position: fixed;
+ left: 0;
+ top: 0;
+ right: 0;
+ -webkit-app-region: drag;
+ display: flex;
+ align-items: center;
+ --hover: #e6e6e6;
+ --active: #cccccc;
+
+ .title {
+ padding: 8px;
+ font-size: 12px;
+ font-family: 'Segoe UI', 'Microsoft YaHei UI', 'Microsoft YaHei',
+ sans-serif;
+ }
+ .controls {
+ height: 32px;
+ margin-left: auto;
+ justify-content: flex-end;
+ display: flex;
+ .button {
+ height: 100%;
+ width: 46px;
+ font-size: 16px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ -webkit-app-region: no-drag;
+ &:hover {
+ background: var(--hover);
+ }
+ &:active {
+ background: var(--active);
+ }
+ &.close {
+ &:hover {
+ background: rgba(232, 17, 35, 0.9);
+ }
+ &:active {
+ background: #f1707a;
+ color: #000;
+ }
+ }
+ }
+ }
+ }
+ &[data-theme='dark'] .win32-titlebar {
+ --hover: #191919;
+ --active: #333333;
+ }
}
.navigation-buttons {
diff --git a/src/components/Player.vue b/src/components/Player.vue
index 0b98ab6..9789a67 100644
--- a/src/components/Player.vue
+++ b/src/components/Player.vue
@@ -27,34 +27,26 @@
-
+
{{ currentTrack.name }}
- {{ ar.name }} {{ ar.name }} ,
-
@@ -120,7 +114,7 @@
? $t('player.repeatTrack')
: $t('player.repeat')
"
- @click.native="switchRepeatMode"
+ @click.native="player.switchRepeatMode"
>
-
-
+
@@ -348,14 +319,12 @@ export default {
opacity: 0.88;
color: var(--color-text);
margin-bottom: 4px;
+ cursor: pointer;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
word-break: break-all;
- }
- .has-list {
- cursor: pointer;
&:hover {
text-decoration: underline;
}
diff --git a/src/components/Toast.vue b/src/components/Toast.vue
index d5b5eb8..93af55a 100644
--- a/src/components/Toast.vue
+++ b/src/components/Toast.vue
@@ -30,7 +30,7 @@ export default {
border-radius: 8px;
box-sizing: border-box;
padding: 6px 12px;
- z-index: 1010;
+ z-index: 100;
}
[data-theme='dark'] {
diff --git a/src/components/TrackList.vue b/src/components/TrackList.vue
index ebb5046..a37eb18 100644
--- a/src/components/TrackList.vue
+++ b/src/components/TrackList.vue
@@ -2,10 +2,7 @@
-
![]()
+
{{ rightClickedTrackComputed.name }}
{{ rightClickedTrackComputed.ar[0].name }}
@@ -49,9 +46,6 @@
@click="addTrackToPlaylist"
>{{ $t('contextMenu.addToPlaylist') }}
-
{{
- $t('contextMenu.copyUrl')
- }}
{
- this.showToast(locale.t('toast.copied'));
- })
- .catch(err => {
- this.showToast(`${locale.t('toast.copyFailed')}${err}`);
- });
- },
removeTrackFromQueue() {
this.$store.state.player.removeTrackFromQueue(
this.rightClickedTrackIndex
diff --git a/src/components/TrackListItem.vue b/src/components/TrackListItem.vue
index a3a6238..302be50 100644
--- a/src/components/TrackListItem.vue
+++ b/src/components/TrackListItem.vue
@@ -10,18 +10,19 @@
-
@@ -90,7 +85,6 @@
import ArtistsInLine from '@/components/ArtistsInLine.vue';
import ExplicitSymbol from '@/components/ExplicitSymbol.vue';
import { mapState } from 'vuex';
-import { isNil } from 'lodash';
export default {
name: 'TrackListItem',
@@ -98,7 +92,6 @@ export default {
props: {
trackProp: Object,
- trackNo: Number,
highlightPlayingTrack: {
type: Boolean,
default: true,
@@ -116,9 +109,6 @@ export default {
? this.trackProp.simpleSong
: this.trackProp;
},
- playable() {
- return this.track?.privilege?.pl > 0 || this.track?.playable;
- },
imgUrl() {
let image =
this.track?.al?.picUrl ??
@@ -127,9 +117,8 @@ export default {
return image + '?param=224y224';
},
artists() {
- const { ar, artists } = this.track;
- if (!isNil(ar)) return ar;
- if (!isNil(artists)) return artists;
+ if (this.track.ar !== undefined) return this.track.ar;
+ if (this.track.artists !== undefined) return this.track.artists;
return [];
},
album() {
@@ -175,7 +164,7 @@ export default {
},
trackClass() {
let trackClass = [this.type];
- if (!this.playable && this.showUnavailableSongInGreyStyle)
+ if (!this.track.playable && this.showUnavailableSongInGreyStyle)
trackClass.push('disable');
if (this.isPlaying && this.highlightPlayingTrack)
trackClass.push('playing');
@@ -212,7 +201,6 @@ export default {
methods: {
goToAlbum() {
- if (this.track.al.id === 0) return;
this.$router.push({ path: '/album/' + this.track.al.id });
},
playTrack() {
@@ -277,6 +265,7 @@ button {
}
.explicit-symbol.before-artist {
+ margin-right: 2px;
.svg-icon {
margin-bottom: -3px;
}
@@ -319,9 +308,8 @@ button {
font-size: 14px;
opacity: 0.72;
}
- .sub-title {
- color: #7a7a7a;
- opacity: 0.7;
+ .subTitle {
+ color: #aeaeae;
margin-left: 4px;
}
}
@@ -357,8 +345,7 @@ button {
-webkit-line-clamp: 2;
overflow: hidden;
}
- .time,
- .count {
+ .time {
font-size: 16px;
width: 50px;
cursor: default;
@@ -369,11 +356,6 @@ button {
opacity: 0.88;
color: var(--color-text);
}
- .count {
- font-weight: bold;
- font-size: 22px;
- line-height: 22px;
- }
}
.track.focus {
@@ -430,13 +412,12 @@ button {
.title,
.album,
.time,
- .title-and-artist .sub-title {
+ .title-and-artist .subTitle {
color: var(--color-primary);
}
.title .featured,
.artist,
- .explicit-symbol,
- .count {
+ .explicit-symbol {
color: var(--color-primary);
opacity: 0.88;
}
diff --git a/src/components/Win32Titlebar.vue b/src/components/Win32Titlebar.vue
deleted file mode 100644
index 67386b3..0000000
--- a/src/components/Win32Titlebar.vue
+++ /dev/null
@@ -1,121 +0,0 @@
-
-
-
-
-
-
-
diff --git a/src/electron/ipcMain.js b/src/electron/ipcMain.js
index aa0e3d7..839c34c 100644
--- a/src/electron/ipcMain.js
+++ b/src/electron/ipcMain.js
@@ -1,207 +1,45 @@
import { app, dialog, globalShortcut, ipcMain } from 'electron';
-import UNM from '@unblockneteasemusic/rust-napi';
+import match from '@revincx/unblockneteasemusic';
import { registerGlobalShortcut } from '@/electron/globalShortcut';
import cloneDeep from 'lodash/cloneDeep';
import shortcuts from '@/utils/shortcuts';
import { createMenu } from './menu';
-import { isCreateTray, isMac } from '@/utils/platform';
const clc = require('cli-color');
const log = text => {
console.log(`${clc.blueBright('[ipcMain.js]')} ${text}`);
};
-const exitAsk = (e, win) => {
- e.preventDefault(); //阻止默认行为
- dialog
- .showMessageBox({
- type: 'info',
- title: 'Information',
- cancelId: 2,
- defaultId: 0,
- message: '确定要关闭吗?',
- buttons: ['最小化', '直接退出'],
- })
- .then(result => {
- if (result.response == 0) {
- e.preventDefault(); //阻止默认行为
- win.minimize(); //调用 最小化实例方法
- } else if (result.response == 1) {
- win = null;
- //app.quit();
- app.exit(); //exit()直接关闭客户端,不会执行quit();
- }
- })
- .catch(err => {
- log(err);
- });
-};
-
-const exitAskWithoutMac = (e, win) => {
- e.preventDefault(); //阻止默认行为
- dialog
- .showMessageBox({
- type: 'info',
- title: 'Information',
- cancelId: 2,
- defaultId: 0,
- message: '确定要关闭吗?',
- buttons: ['最小化到托盘', '直接退出'],
- checkboxLabel: '记住我的选择',
- })
- .then(result => {
- if (result.checkboxChecked && result.response !== 2) {
- win.webContents.send(
- 'rememberCloseAppOption',
- result.response === 0 ? 'minimizeToTray' : 'exit'
- );
- }
-
- if (result.response === 0) {
- e.preventDefault(); //阻止默认行为
- win.hide(); //调用 最小化实例方法
- } else if (result.response === 1) {
- win = null;
- //app.quit();
- app.exit(); //exit()直接关闭客户端,不会执行quit();
- }
- })
- .catch(err => {
- log(err);
- });
-};
-
const client = require('discord-rich-presence')('818936529484906596');
-/**
- * Make data a Buffer.
- *
- * @param {?} data The data to convert.
- * @returns {import("buffer").Buffer} The converted data.
- */
-function toBuffer(data) {
- if (data instanceof Buffer) {
- return data;
- } else {
- return Buffer.from(data);
- }
-}
+export function initIpcMain(win, store) {
+ ipcMain.on('unblock-music', (event, track) => {
+ // 兼容 unblockneteasemusic 所使用的 api 字段
+ track.alias = track.alia || [];
+ track.duration = track.dt || 0;
+ track.album = track.al || [];
+ track.artists = track.ar || [];
-/**
- * Get the file base64 data from bilivideo.
- *
- * @param {string} url The URL to fetch.
- * @returns {Promise
} The file base64 data.
- */
-async function getBiliVideoFile(url) {
- const axios = await import('axios').then(m => m.default);
- const response = await axios.get(url, {
- headers: {
- Referer: 'https://www.bilibili.com/',
- 'User-Agent': 'okhttp/3.4.1',
- },
- responseType: 'arraybuffer',
+ const matchPromise = match(track.id, ['qq', 'kuwo', 'migu'], track);
+ const timeoutPromise = new Promise((_, reject) => {
+ setTimeout(() => {
+ reject('timeout');
+ }, 3000);
+ });
+ Promise.race([matchPromise, timeoutPromise])
+ .then(res => {
+ event.returnValue = res;
+ })
+ .catch(err => {
+ log('unblock music error: ', err);
+ event.returnValue = null;
+ });
});
- const buffer = toBuffer(response.data);
- const encodedData = buffer.toString('base64');
-
- return encodedData;
-}
-
-/**
- * Parse the source string (`a, b`) to source list `['a', 'b']`.
- *
- * @param {import("@unblockneteasemusic/rust-napi").Executor} executor
- * @param {string} sourceString The source string.
- * @returns {string[]} The source list.
- */
-function parseSourceStringToList(executor, sourceString) {
- const availableSource = executor.list();
-
- return sourceString
- .split(',')
- .map(s => s.trim().toLowerCase())
- .filter(s => {
- const isAvailable = availableSource.includes(s);
-
- if (!isAvailable) {
- log(`This source is not one of the supported source: ${s}`);
- }
-
- return isAvailable;
- });
-}
-
-export function initIpcMain(win, store, trayEventEmitter) {
- // WIP: Do not enable logging as it has some issues in non-blocking I/O environment.
- // UNM.enableLogging(UNM.LoggingType.ConsoleEnv);
- const unmExecutor = new UNM.Executor();
-
- ipcMain.handle(
- 'unblock-music',
- /**
- *
- * @param {*} _
- * @param {string | null} sourceListString
- * @param {Record} ncmTrack
- * @param {UNM.Context} context
- */
- async (_, sourceListString, ncmTrack, context) => {
- // Formt the track input
- // FIXME: Figure out the structure of Track
- const song = {
- id: ncmTrack.id && ncmTrack.id.toString(),
- name: ncmTrack.name,
- duration: ncmTrack.dt,
- album: ncmTrack.al && {
- id: ncmTrack.al.id && ncmTrack.al.id.toString(),
- name: ncmTrack.al.name,
- },
- artists: ncmTrack.ar
- ? ncmTrack.ar.map(({ id, name }) => ({
- id: id && id.toString(),
- name,
- }))
- : [],
- };
-
- const sourceList =
- typeof sourceListString === 'string'
- ? parseSourceStringToList(unmExecutor, sourceListString)
- : ['ytdl', 'bilibili', 'pyncm', 'kugou'];
- log(`[UNM] using source: ${sourceList.join(', ')}`);
- log(`[UNM] using configuration: ${JSON.stringify(context)}`);
-
- try {
- // TODO: tell users to install yt-dlp.
- const matchedAudio = await unmExecutor.search(
- sourceList,
- song,
- context
- );
- const retrievedSong = await unmExecutor.retrieve(matchedAudio, context);
-
- // bilibili's audio file needs some special treatment
- if (retrievedSong.url.includes('bilivideo.com')) {
- retrievedSong.url = await getBiliVideoFile(retrievedSong.url);
- }
-
- log(`respond with retrieve song…`);
- log(JSON.stringify(matchedAudio));
- return retrievedSong;
- } catch (err) {
- const errorMessage = err instanceof Error ? `${err.message}` : `${err}`;
- log(`UnblockNeteaseMusic failed: ${errorMessage}`);
- return null;
- }
- }
- );
-
ipcMain.on('close', e => {
- if (isMac) {
+ if (process.platform === 'darwin') {
win.hide();
- exitAsk(e, win);
+ exitAsk(e);
} else {
let closeOpt = store.get('settings.closeAppOption');
if (closeOpt === 'exit') {
@@ -212,7 +50,7 @@ export function initIpcMain(win, store, trayEventEmitter) {
e.preventDefault();
win.hide();
} else {
- exitAskWithoutMac(e, win);
+ exitAskWithoutMac(e);
}
}
});
@@ -222,7 +60,9 @@ export function initIpcMain(win, store, trayEventEmitter) {
});
ipcMain.on('maximizeOrUnmaximize', () => {
- win.isMaximized() ? win.unmaximize() : win.maximize();
+ const isMaximized = win.isMaximized();
+ isMaximized ? win.unmaximize() : win.maximize();
+ win.webContents.send('isMaximized', isMaximized);
});
ipcMain.on('settings', (event, options) => {
@@ -240,7 +80,7 @@ export function initIpcMain(win, store, trayEventEmitter) {
details: track.name + ' - ' + track.ar.map(ar => ar.name).join(','),
state: track.al.name,
endTimestamp: Date.now() + track.dt,
- largeImageKey: track.al.picUrl,
+ largeImageKey: 'logo',
largeImageText: 'Listening ' + track.name,
smallImageKey: 'play',
smallImageText: 'Playing',
@@ -252,7 +92,7 @@ export function initIpcMain(win, store, trayEventEmitter) {
client.updatePresence({
details: track.name + ' - ' + track.ar.map(ar => ar.name).join(','),
state: track.al.name,
- largeImageKey: track.al.picUrl,
+ largeImageKey: 'logo',
largeImageText: 'YesPlayMusic',
smallImageKey: 'pause',
smallImageText: 'Pause',
@@ -309,15 +149,63 @@ export function initIpcMain(win, store, trayEventEmitter) {
registerGlobalShortcut(win, store);
});
- if (isCreateTray) {
- ipcMain.on('updateTrayTooltip', (_, title) => {
- trayEventEmitter.emit('updateTooltip', title);
- });
- ipcMain.on('updateTrayPlayState', (_, isPlaying) => {
- trayEventEmitter.emit('updatePlayState', isPlaying);
- });
- ipcMain.on('updateTrayLikeState', (_, isLiked) => {
- trayEventEmitter.emit('updateLikeState', isLiked);
- });
- }
+ const exitAsk = e => {
+ e.preventDefault(); //阻止默认行为
+ dialog
+ .showMessageBox({
+ type: 'info',
+ title: 'Information',
+ cancelId: 2,
+ defaultId: 0,
+ message: '确定要关闭吗?',
+ buttons: ['最小化', '直接退出'],
+ })
+ .then(result => {
+ if (result.response == 0) {
+ e.preventDefault(); //阻止默认行为
+ win.minimize(); //调用 最小化实例方法
+ } else if (result.response == 1) {
+ win = null;
+ //app.quit();
+ app.exit(); //exit()直接关闭客户端,不会执行quit();
+ }
+ })
+ .catch(err => {
+ log(err);
+ });
+ };
+
+ const exitAskWithoutMac = e => {
+ e.preventDefault(); //阻止默认行为
+ dialog
+ .showMessageBox({
+ type: 'info',
+ title: 'Information',
+ cancelId: 2,
+ defaultId: 0,
+ message: '确定要关闭吗?',
+ buttons: ['最小化到托盘', '直接退出'],
+ checkboxLabel: '记住我的选择',
+ })
+ .then(result => {
+ if (result.checkboxChecked && result.response !== 2) {
+ win.webContents.send(
+ 'rememberCloseAppOption',
+ result.response === 0 ? 'minimizeToTray' : 'exit'
+ );
+ }
+
+ if (result.response === 0) {
+ e.preventDefault(); //阻止默认行为
+ win.hide(); //调用 最小化实例方法
+ } else if (result.response === 1) {
+ win = null;
+ //app.quit();
+ app.exit(); //exit()直接关闭客户端,不会执行quit();
+ }
+ })
+ .catch(err => {
+ log(err);
+ });
+ };
}
diff --git a/src/electron/ipcRenderer.js b/src/electron/ipcRenderer.js
index ea8faf9..0222658 100644
--- a/src/electron/ipcRenderer.js
+++ b/src/electron/ipcRenderer.js
@@ -36,11 +36,7 @@ export function ipcRenderer(vueInstance) {
});
ipcRenderer.on('next', () => {
- if (player.isPersonalFM) {
- player.playNextFMTrack();
- } else {
- player.playNextTrack();
- }
+ player.playNextTrack();
});
ipcRenderer.on('previous', () => {
@@ -87,8 +83,4 @@ export function ipcRenderer(vueInstance) {
value,
});
});
-
- ipcRenderer.on('setPosition', (event, position) => {
- player._howler.seek(position);
- });
}
diff --git a/src/electron/mpris.js b/src/electron/mpris.js
deleted file mode 100644
index c6cfeee..0000000
--- a/src/electron/mpris.js
+++ /dev/null
@@ -1,94 +0,0 @@
-import dbus from 'dbus-next';
-import { ipcMain, app } from 'electron';
-
-export function createMpris(window) {
- const Player = require('mpris-service');
- const renderer = window.webContents;
-
- const player = Player({
- name: 'yesplaymusic',
- identity: 'YesPlayMusic',
- });
-
- player.on('next', () => renderer.send('next'));
- player.on('previous', () => renderer.send('previous'));
- player.on('playpause', () => renderer.send('play'));
- player.on('play', () => renderer.send('play'));
- player.on('pause', () => renderer.send('play'));
- player.on('quit', () => app.exit());
- player.on('position', args =>
- renderer.send('setPosition', args.position / 1000 / 1000)
- );
- player.on('loopStatus', () => renderer.send('repeat'));
- player.on('shuffle', () => renderer.send('shuffle'));
-
- ipcMain.on('player', (e, { playing }) => {
- player.playbackStatus = playing
- ? Player.PLAYBACK_STATUS_PLAYING
- : Player.PLAYBACK_STATUS_PAUSED;
- });
-
- ipcMain.on('metadata', (e, metadata) => {
- // 更新 Mpris 状态前将位置设为0, 否则 OSDLyrics 获取到的进度是上首音乐切换时的进度
- player.getPosition = () => 0;
- player.metadata = {
- 'mpris:trackid': player.objectPath('track/' + metadata.trackId),
- 'mpris:artUrl': metadata.artwork[0].src,
- 'mpris:length': metadata.length * 1000 * 1000,
- 'xesam:title': metadata.title,
- 'xesam:album': metadata.album,
- 'xesam:artist': metadata.artist.split(','),
- 'xesam:url': metadata.url,
- };
- });
-
- ipcMain.on('playerCurrentTrackTime', (e, position) => {
- player.getPosition = () => position * 1000 * 1000;
- player.seeked(position * 1000 * 1000);
- });
-
- ipcMain.on('seeked', (e, position) => {
- player.seeked(position * 1000 * 1000);
- });
-
- ipcMain.on('switchRepeatMode', (e, mode) => {
- switch (mode) {
- case 'off':
- player.loopStatus = Player.LOOP_STATUS_NONE;
- break;
- case 'one':
- player.loopStatus = Player.LOOP_STATUS_TRACK;
- break;
- case 'on':
- player.loopStatus = Player.LOOP_STATUS_PLAYLIST;
- break;
- }
- });
-
- ipcMain.on('switchShuffle', (e, shuffle) => {
- player.shuffle = shuffle;
- });
-}
-
-export async function createDbus(window) {
- const bus = dbus.sessionBus();
- const Variant = dbus.Variant;
-
- const osdService = await bus.getProxyObject(
- 'org.osdlyrics.Daemon',
- '/org/osdlyrics/Lyrics'
- );
-
- const osdInterface = osdService.getInterface('org.osdlyrics.Lyrics');
-
- ipcMain.on('sendLyrics', async (e, { track, lyrics }) => {
- const metadata = {
- title: new Variant('s', track.name),
- artist: new Variant('s', track.ar.map(ar => ar.name).join(', ')),
- };
-
- await osdInterface.SetLyricContent(metadata, Buffer.from(lyrics));
-
- window.webContents.send('saveLyricFinished');
- });
-}
diff --git a/src/electron/services.js b/src/electron/services.js
index 3a1106f..fe611b3 100644
--- a/src/electron/services.js
+++ b/src/electron/services.js
@@ -1,14 +1,63 @@
-import clc from 'cli-color';
-import checkAuthToken from '../utils/checkAuthToken';
-import server from 'NeteaseCloudMusicApi/server';
+const express = require('express');
+const bodyParser = require('body-parser');
+const cache = require('../../netease_api/util/apicache').middleware;
+const fileUpload = require('express-fileupload');
+import routes from '../../netease_api/routes';
+const clc = require('cli-color');
-export async function startNeteaseMusicApi() {
- // Let user know that the service is starting
- console.log(`${clc.redBright('[NetEase API]')} initiating NCM API`);
+export function startNeteaseMusicApi() {
+ // Integrate API
+ const app = express();
- // Load the NCM API.
- await server.serveNcmApi({
- port: 10754,
- moduleDefs: require('../ncmModDef'),
+ // CORS & Preflight request
+ app.use((req, res, next) => {
+ if (req.path !== '/' && !req.path.includes('.')) {
+ res.set({
+ 'Access-Control-Allow-Credentials': true,
+ 'Access-Control-Allow-Origin': req.headers.origin || '*',
+ 'Access-Control-Allow-Headers': 'X-Requested-With,Content-Type',
+ 'Access-Control-Allow-Methods': 'PUT,POST,GET,DELETE,OPTIONS',
+ 'Content-Type': 'application/json; charset=utf-8',
+ });
+ }
+ req.method === 'OPTIONS' ? res.status(204).end() : next();
+ });
+
+ // cookie parser
+ app.use((req, res, next) => {
+ req.cookies = {};
+ (req.headers.cookie || '').split(/\s*;\s*/).forEach(pair => {
+ let crack = pair.indexOf('=');
+ if (crack < 1 || crack == pair.length - 1) return;
+ req.cookies[
+ decodeURIComponent(pair.slice(0, crack)).trim()
+ ] = decodeURIComponent(pair.slice(crack + 1)).trim();
+ });
+ next();
+ });
+
+ // body parser
+ app.use(bodyParser.json());
+ app.use(bodyParser.urlencoded({ extended: false }));
+
+ app.use(fileUpload());
+
+ // cache
+ app.use(cache('2 minutes', (req, res) => res.statusCode === 200));
+ // router
+
+ Object.keys(routes).forEach(route => {
+ app.use(route, routes[route]);
+ });
+
+ const port = process.env.PORT || 10754;
+ const host = process.env.HOST || '127.0.0.1';
+
+ app.server = app.listen(port, host, () => {
+ console.log(
+ `${clc.redBright('[NetEase API]')} server running @ http://${
+ host ? host : 'localhost'
+ }:${port}`
+ );
});
}
diff --git a/src/electron/tray.js b/src/electron/tray.js
index ed314f2..b0ec291 100644
--- a/src/electron/tray.js
+++ b/src/electron/tray.js
@@ -1,30 +1,40 @@
/* global __static */
import path from 'path';
-import { app, nativeImage, Tray, Menu, nativeTheme } from 'electron';
-import { isLinux } from '@/utils/platform';
+import { app, nativeImage, Tray, Menu } from 'electron';
-function createMenuTemplate(win) {
- return [
+export function createTray(win) {
+ let icon = nativeImage
+ .createFromPath(path.join(__static, 'img/icons/menu@88.png'))
+ .resize({
+ height: 20,
+ width: 20,
+ });
+
+ let contextMenu = Menu.buildFromTemplate([
+ //setContextMenu破坏了预期的click行为
+ //在linux下,鼠标左右键都会呼出contextMenu
+ //所以此处单独为linux添加一个 显示主面板 选项
+ ...(process.platform === 'linux'
+ ? [
+ {
+ label: '显示主面板',
+ click: () => {
+ win.show();
+ },
+ },
+ {
+ type: 'separator',
+ },
+ ]
+ : []),
{
- label: '播放',
+ label: '播放/暂停',
icon: nativeImage.createFromPath(
path.join(__static, 'img/icons/play.png')
),
click: () => {
win.webContents.send('play');
},
- id: 'play',
- },
- {
- label: '暂停',
- icon: nativeImage.createFromPath(
- path.join(__static, 'img/icons/pause.png')
- ),
- click: () => {
- win.webContents.send('play');
- },
- id: 'pause',
- visible: false,
},
{
label: '上一首',
@@ -65,19 +75,6 @@ function createMenuTemplate(win) {
click: () => {
win.webContents.send('like');
},
- id: 'like',
- },
- {
- label: '取消喜欢',
- icon: nativeImage.createFromPath(
- path.join(__static, 'img/icons/unlike.png')
- ),
- accelerator: 'CmdOrCtrl+L',
- click: () => {
- win.webContents.send('like');
- },
- id: 'unlike',
- visible: false,
},
{
label: '退出',
@@ -89,128 +86,28 @@ function createMenuTemplate(win) {
app.exit();
},
},
- ];
-}
-
-// linux下托盘的实现方式比较迷惑
-// right-click无法在linux下使用
-// click在默认行为下会弹出一个contextMenu,里面的唯一选项才会调用click事件
-// setContextMenu应该是目前唯一能在linux下使用托盘菜单api
-// 但是无法区分鼠标左右键
-
-// 发现openSUSE KDE环境可以区分鼠标左右键
-// 添加左键支持
-// 2022.05.17
-class YPMTrayLinuxImpl {
- constructor(tray, win, emitter) {
- this.tray = tray;
- this.win = win;
- this.emitter = emitter;
- this.template = undefined;
- this.initTemplate();
- this.contextMenu = Menu.buildFromTemplate(this.template);
-
- this.tray.setContextMenu(this.contextMenu);
- this.handleEvents();
- }
-
- initTemplate() {
- //在linux下,鼠标左右键都会呼出contextMenu
- //所以此处单独为linux添加一个 显示主面板 选项
- this.template = [
- {
- label: '显示主面板',
- click: () => {
- this.win.show();
- },
- },
- {
- type: 'separator',
- },
- ].concat(createMenuTemplate(this.win));
- }
-
- handleEvents() {
- this.tray.on('click', () => {
- this.win.show();
- });
-
- this.emitter.on('updateTooltip', title => this.tray.setToolTip(title));
- this.emitter.on('updatePlayState', isPlaying => {
- this.contextMenu.getMenuItemById('play').visible = !isPlaying;
- this.contextMenu.getMenuItemById('pause').visible = isPlaying;
- this.tray.setContextMenu(this.contextMenu);
- });
- this.emitter.on('updateLikeState', isLiked => {
- this.contextMenu.getMenuItemById('like').visible = !isLiked;
- this.contextMenu.getMenuItemById('unlike').visible = isLiked;
- this.tray.setContextMenu(this.contextMenu);
- });
- }
-}
-
-class YPMTrayWindowsImpl {
- constructor(tray, win, emitter) {
- this.tray = tray;
- this.win = win;
- this.emitter = emitter;
- this.template = createMenuTemplate(win);
- this.contextMenu = Menu.buildFromTemplate(this.template);
-
- this.isPlaying = false;
- this.curDisplayPlaying = false;
-
- this.isLiked = false;
- this.curDisplayLiked = false;
-
- this.handleEvents();
- }
-
- handleEvents() {
- this.tray.on('click', () => {
- this.win.show();
- });
-
- this.tray.on('right-click', () => {
- if (this.isPlaying !== this.curDisplayPlaying) {
- this.curDisplayPlaying = this.isPlaying;
- this.contextMenu.getMenuItemById('play').visible = !this.isPlaying;
- this.contextMenu.getMenuItemById('pause').visible = this.isPlaying;
- }
-
- if (this.isLiked !== this.curDisplayLiked) {
- this.curDisplayLiked = this.isLiked;
- this.contextMenu.getMenuItemById('like').visible = !this.isLiked;
- this.contextMenu.getMenuItemById('unlike').visible = this.isLiked;
- }
-
- this.tray.popUpContextMenu(this.contextMenu);
- });
-
- this.emitter.on('updateTooltip', title => this.tray.setToolTip(title));
- this.emitter.on(
- 'updatePlayState',
- isPlaying => (this.isPlaying = isPlaying)
- );
- this.emitter.on('updateLikeState', isLiked => (this.isLiked = isLiked));
- }
-}
-
-export function createTray(win, eventEmitter) {
- // 感觉图标颜色应该不属于界面主题范畴,只需要跟随系统主题
- let iconTheme = nativeTheme.shouldUseDarkColors ? 'light' : 'dark';
-
- let icon = nativeImage
- .createFromPath(path.join(__static, `img/icons/menu-${iconTheme}@88.png`))
- .resize({
- height: 20,
- width: 20,
- });
-
+ ]);
let tray = new Tray(icon);
tray.setToolTip('YesPlayMusic');
- return isLinux
- ? new YPMTrayLinuxImpl(tray, win, eventEmitter)
- : new YPMTrayWindowsImpl(tray, win, eventEmitter);
+ if (process.platform === 'linux') {
+ //linux下托盘的实现方式比较迷惑
+ //right-click无法在linux下使用
+ //click在默认行为下会弹出一个contextMenu,里面的唯一选项才会调用click事件
+ //setContextMenu应该是目前唯一能在linux下使用托盘菜单api
+ //但是无法区分鼠标左右键
+
+ tray.setContextMenu(contextMenu);
+ } else {
+ //windows and macos
+ tray.on('click', () => {
+ win.show();
+ });
+
+ tray.on('right-click', () => {
+ tray.popUpContextMenu(contextMenu);
+ });
+ }
+
+ return tray;
}
diff --git a/src/locale/lang/en.js b/src/locale/lang/en.js
index d880e32..4065e98 100644
--- a/src/locale/lang/en.js
+++ b/src/locale/lang/en.js
@@ -28,14 +28,7 @@ export default {
albums: 'Albums',
artists: 'Artists',
mvs: 'MVs',
- cloudDisk: 'Cloud Disk',
newPlayList: 'New Playlist',
- uploadSongs: 'Upload Songs',
- playHistory: {
- title: 'Play History',
- week: 'Latest Week',
- all: 'All Time',
- },
userProfileMenu: {
settings: 'Settings',
logout: 'Logout',
@@ -102,19 +95,15 @@ export default {
},
player: {
like: 'Like',
- unlike: 'Unlike',
previous: 'Previous Song',
next: 'Next Song',
repeat: 'Repeat',
repeatTrack: 'Repeat Track',
shuffle: 'Shuffle',
- reversed: 'Reversed',
play: 'Play',
pause: 'Pause',
mute: 'Mute',
nextUp: 'Next Up',
- translationLyric: 'lyric (trans)',
- PronunciationLyric: 'lyric (pronounce)',
},
modal: {
close: 'Close',
@@ -132,17 +121,6 @@ export default {
settings: 'Settings',
logout: 'LOGOUT',
language: 'Languages',
- lyric: 'Lyric',
- others: 'Others',
- customization: 'Customization',
- MusicGenrePreference: {
- text: 'Music Language Preference',
- none: 'No preferences',
- mandarin: 'Mandarin',
- western: 'Europe & America',
- korean: 'Korean',
- japanese: 'Japanese',
- },
musicQuality: {
text: 'Music Quality',
low: 'Low',
@@ -176,11 +154,8 @@ export default {
showPlaylistsByAppleMusic: 'Show playlists by Apple Music',
enableDiscordRichPresence: 'Enable Discord Rich Presence',
enableGlobalShortcut: 'Enable Global Shortcut',
- showLibraryDefault: 'Show Library after App Launched',
- subTitleDefault: 'Show Alias for Subtitle by default',
- enableReversedMode: 'Enable Reversed Mode (Experimental)',
- enableCustomTitlebar: 'Enable custom title bar (Need restart)',
- showLyricsTime: 'Display current time',
+ showLibraryDefault: 'Show library default',
+ subTitleDefault: 'Sub title alia default',
lyricsBackground: {
text: 'Show Lyrics Background',
off: 'Off',
@@ -193,41 +168,6 @@ export default {
exit: 'Exit',
minimizeToTray: 'Minimize to tray',
},
- enableOsdlyricsSupport: {
- title: 'desktop lyrics support',
- desc1:
- 'Only takes effect under Linux. After enabled, it downloads the lyrics file to the local, and tries to launch OSDLyrics at startup.',
- desc2:
- 'Please ensure that you have installed OSDLyrics before turning on this.',
- },
- unm: {
- enable: 'Enable',
- audioSource: {
- title: 'Audio Sources',
- },
- enableFlac: {
- title: 'Enable FLAC Sources',
- desc: 'To take effect, it may be required to clear the cache after enabling this function.',
- },
- searchMode: {
- title: 'Audio Search Mode',
- fast: 'Speed Priority',
- order: 'Order Priority',
- },
- cookie: {
- joox: 'Cookie for Joox use',
- qq: 'Cookie for QQ use',
- desc1: 'Click here for the configuration instruction. ',
- desc2: 'Leave empty to pick up the default value',
- },
- ytdl: 'The youtube-dl Executable File for YtDl',
- proxy: {
- title: 'Proxy Server for UNM',
- desc1:
- 'The proxy server to use for requesting services such as YouTube',
- desc2: 'Leave empty to pick up the default value',
- },
- },
},
contextMenu: {
play: 'Play',
@@ -239,13 +179,9 @@ export default {
addToPlaylist: 'Add to playlist',
searchInPlaylist: 'Search in playlist',
copyUrl: 'Copy URL',
- openInBrowser: 'Open in Browser',
allPlaylists: 'All Playlists',
minePlaylists: 'My Playlists',
likedPlaylists: 'Liked Playlists',
- cardiacMode: 'Cardiac Mode',
- copyLyric: 'Copy Lyric',
- copyLyricWithTranslation: 'Copy Lyric With Translation',
},
toast: {
savedToPlaylist: 'Saved to playlist',
diff --git a/src/locale/lang/tr.js b/src/locale/lang/tr.js
index fda2939..56d5e4d 100644
--- a/src/locale/lang/tr.js
+++ b/src/locale/lang/tr.js
@@ -28,14 +28,7 @@ export default {
albums: 'Albümler',
artists: 'Sanatçılar',
mvs: 'MVs',
- cloudDisk: 'Cloud Disk',
newPlayList: 'Yeni Çalma Listesi',
- uploadSongs: 'Upload Songs',
- playHistory: {
- title: 'Play History',
- week: 'Latest Week',
- all: 'All Time',
- },
userProfileMenu: {
settings: 'Ayarlar',
logout: 'Çıkış Yap',
@@ -98,7 +91,6 @@ export default {
},
player: {
like: 'Beğen',
- unlike: 'Aksine',
previous: 'Önceki Müzik',
next: 'Sonraki Müzik',
repeat: 'Tekrarla',
@@ -108,8 +100,6 @@ export default {
pause: 'Durdur',
mute: 'Sesi kapat',
nextUp: 'Sıradaki',
- translationLyric: 'şarkı sözleri (çeviri)',
- PronunciationLyric: 'şarkı sözleri (çeviri)',
},
modal: {
close: 'Kapat',
@@ -127,17 +117,6 @@ export default {
settings: 'Ayarlar',
logout: 'ÇIKIŞ YAP',
language: 'Diller',
- lyric: 'Şarkı Sözleri',
- others: 'Diğerleri',
- customization: 'Özelleştirme',
- MusicGenrePreference: {
- text: 'Müzik Dili Tercihi',
- none: 'Tercih yok',
- mandarin: 'Çince dili',
- western: 'Avrupa ve Amerika',
- korean: 'Korece',
- japanese: 'Japonca',
- },
musicQuality: {
text: 'Müzik Kalitesi',
low: 'Düşük',
@@ -171,9 +150,7 @@ export default {
showPlaylistsByAppleMusic: "Apple Music'in Çalma Listelerini Göster",
enableDiscordRichPresence: 'Discord gösterimini aktifleştir',
showLibraryDefault: 'Kitaplık Varsayılanını göster',
- subTitleDefault: 'Show Alias for Subtitle by default',
- enableReversedMode: 'Enable Reversed Mode (Experimental)',
- enableCustomTitlebar: 'Enable custom title bar (Need restart)',
+ subTitleDefault: 'Sub title alia default',
lyricsBackground: {
text: 'Şarkı Sözleri Arka Planını Göster',
off: 'kapalı',
@@ -186,52 +163,12 @@ export default {
exit: 'Exit',
minimizeToTray: 'Küçült',
},
- unm: {
- enable: 'Enable',
- audioSource: {
- title: 'Audio Sources',
- },
- enableFlac: {
- title: 'Enable FLAC Sources',
- desc: 'To take effect, it may be required to clear the cache after enabling this function.',
- },
- searchMode: {
- title: 'Audio Search Mode',
- fast: 'Speed Priority',
- order: 'Order Priority',
- },
- cookie: {
- joox: 'Cookie for Joox use',
- qq: 'Cookie for QQ use',
- desc1: 'Click here for the configuration instruction. ',
- desc2: 'Leave empty to pick up the default value',
- },
- ytdl: 'The youtube-dl Executable File for YtDl',
- proxy: {
- title: 'Proxy Server for UNM',
- desc1:
- 'The proxy server to use for requesting services such as YouTube',
- desc2: 'Leave empty to pick up the default value',
- },
- },
},
contextMenu: {
play: 'Oynat',
addToQueue: 'Sonrakini Oynat',
saveToMyLikedSongs: 'Beğendiğim Müziklere Kaydet',
removeFromMyLikedMüzikler: 'Beğendiğim Müziklerden Kaldır',
- saveToLibrary: 'Save to library',
- removeFromLibrary: 'Remove from library',
- addToPlaylist: 'Add to playlist',
- searchInPlaylist: 'Search in playlist',
- copyUrl: 'Copy URL',
- openInBrowser: 'Open in Browser',
- allPlaylists: 'All Playlists',
- minePlaylists: 'My Playlists',
- likedPlaylists: 'Liked Playlists',
- cardiacMode: 'Cardiac Mode',
- copyLyric: 'Copy Lyric',
- copyLyricWithTranslation: 'Copy Lyric With Translation',
},
toast: {
savedToMyLikedSongs: 'Beğendiğim Müziklere Kaydet',
diff --git a/src/locale/lang/zh-CN.js b/src/locale/lang/zh-CN.js
index 543132a..99c0029 100644
--- a/src/locale/lang/zh-CN.js
+++ b/src/locale/lang/zh-CN.js
@@ -25,14 +25,7 @@ export default {
albums: '专辑',
artists: '艺人',
mvs: 'MV',
- cloudDisk: '云盘',
newPlayList: '新建歌单',
- uploadSongs: '上传歌曲',
- playHistory: {
- title: '听歌排行',
- week: '最近一周',
- all: '所有时间',
- },
userProfileMenu: {
settings: '设置',
logout: '登出',
@@ -103,19 +96,15 @@ export default {
},
player: {
like: '喜欢',
- unlike: '取消喜欢',
previous: '上一首',
next: '下一首',
repeat: '循环播放',
repeatTrack: '单曲循环',
shuffle: '随机播放',
- reversed: '倒序播放',
play: '播放',
pause: '暂停',
mute: '静音',
nextUp: '播放列表',
- translationLyric: '歌词(译)',
- PronunciationLyric: '歌词(音)',
},
modal: {
close: '关闭',
@@ -133,17 +122,6 @@ export default {
settings: '设置',
logout: '登出',
language: '语言',
- lyric: '歌词',
- others: '其他',
- customization: '自定义',
- MusicGenrePreference: {
- text: '音乐语种偏好',
- none: '无偏好',
- mandarin: '华语',
- western: '欧美',
- korean: '韩语',
- japanese: '日语',
- },
musicQuality: {
text: '音质选择',
low: '普通',
@@ -179,54 +157,18 @@ export default {
enableGlobalShortcut: '启用全局快捷键',
showLibraryDefault: '启动后显示音乐库',
subTitleDefault: '副标题使用别名',
- enableReversedMode: '启用倒序播放功能 (实验性功能)',
- enableCustomTitlebar: '启用自定义标题栏 (重启后生效)',
lyricsBackground: {
text: '显示歌词背景',
off: '关闭',
on: '打开',
dynamic: '动态(GPU 占用较高)',
},
- showLyricsTime: '显示当前时间',
closeAppOption: {
text: '关闭主面板时...',
ask: '询问',
exit: '退出',
minimizeToTray: '最小化到托盘',
},
- enableOsdlyricsSupport: {
- title: '桌面歌词支持',
- desc1:
- '仅 Linux 下生效。启用后会将歌词文件下载到本地,并在开启播放器时尝试拉起 OSDLyrics。',
- desc2: '请在开启之前确保您已经正确安装了 OSDLyrics。',
- },
- unm: {
- enable: '启用',
- audioSource: {
- title: '备选音源',
- },
- enableFlac: {
- title: '启用 FLAC',
- desc: '启用后需要清除歌曲缓存才能生效',
- },
- searchMode: {
- title: '音源搜索模式',
- fast: '速度优先',
- order: '顺序优先',
- },
- cookie: {
- joox: 'Joox 引擎的 Cookie',
- qq: 'QQ 引擎的 Cookie',
- desc1: '设置说明请参见此处',
- desc2: ',留空则不进行相关设置',
- },
- ytdl: 'YtDl 引擎要使用的 youtube-dl 可执行文件',
- proxy: {
- title: '用于 UNM 的代理服务器',
- desc1: '请求如 YouTube 音源服务时要使用的代理服务器',
- desc2: '留空则不进行相关设置',
- },
- },
},
contextMenu: {
play: '播放',
@@ -238,13 +180,9 @@ export default {
addToPlaylist: '添加到歌单',
searchInPlaylist: '歌单内搜索',
copyUrl: '复制链接',
- openInBrowser: '在浏览器中打开',
allPlaylists: '全部歌单',
minePlaylists: '创建的歌单',
likedPlaylists: '收藏的歌单',
- cardiacMode: '心动模式',
- copyLyric: '复制歌词',
- copyLyricWithTranslation: '复制歌词(含翻译)',
},
toast: {
savedToPlaylist: '已添加到歌单',
diff --git a/src/locale/lang/zh-TW.js b/src/locale/lang/zh-TW.js
index 384a0cf..5e66d07 100644
--- a/src/locale/lang/zh-TW.js
+++ b/src/locale/lang/zh-TW.js
@@ -25,14 +25,7 @@ export default {
albums: '專輯',
artists: '藝人',
mvs: 'MV',
- cloudDisk: '雲端硬碟',
newPlayList: '新增歌單',
- uploadSongs: '上傳音樂',
- playHistory: {
- title: '聽歌排行',
- week: '最近一周',
- all: '所有時間',
- },
userProfileMenu: {
settings: '設定',
logout: '登出',
@@ -64,14 +57,14 @@ export default {
search: '搜尋歌單內音樂',
},
login: {
- accessToAll: '可存取全部資料',
- loginText: '登入網易雲帳戶',
- search: '搜尋網易雲帳戶',
- readonly: '只能讀取帳戶公開資料',
+ accessToAll: '可存取全部數據',
+ loginText: '登入網易雲帳號',
+ search: '搜尋網易雲帳號',
+ readonly: '只能讀取帳號公開數據',
usernameLogin: '使用者名稱登入',
searchHolder: '請輸入您的網易雲使用者名稱',
enterTip: '按 Enter 搜尋',
- choose: '在選單中選擇你的帳戶',
+ choose: '在選單中選擇你的帳號',
confirm: '確認',
countryCode: '國際區碼',
phone: '手機號碼',
@@ -80,15 +73,15 @@ export default {
login: '登入',
loginWithEmail: '信箱登入',
loginWithPhone: '手機號碼登入',
- notice: `YesPlayMusic 承諾不會保存您的任何帳戶資訊到雲端。
+ notice: `YesPlayMusic 承諾不會保存您的任何帳號資訊到雲端。
您的密碼會在本地進行 MD5 加密後再傳輸到網易雲 API。
- YesPlayMusic 並非網易雲官方網站,輸入帳戶資訊前請慎重考慮。 您也可以前往
+ YesPlayMusic 並非網易雲官方網站,輸入帳號資訊前請慎重考慮。 您也可以前往
YesPlayMusic 的 GitHub 原始碼 Repo
自行編譯並使用自託管的網易雲 API。`,
noticeElectron: `您的密碼會在本地進行 MD5 加密後再傳輸到網易雲 API。
- YesPlayMusic 不會傳輸你的帳戶資料到任何非網易雲音樂官方的伺服器。
`,
+ YesPlayMusic 不會傳輸你的帳號數據到任何非網易雲音樂官方的伺服器。
`,
},
mv: {
moreVideo: '更多影片',
@@ -99,19 +92,15 @@ export default {
},
player: {
like: '喜歡',
- unlike: '取消喜歡',
previous: '上一首',
next: '下一首',
repeat: '循環播放',
repeatTrack: '單曲循環',
shuffle: '隨機播放',
- reversed: '倒序播放',
play: '播放',
pause: '暫停',
mute: '靜音',
nextUp: '播放清單',
- translationLyric: '歌詞(譯)',
- PronunciationLyric: '歌詞(音)',
},
modal: {
close: '關閉',
@@ -129,17 +118,6 @@ export default {
settings: '設定',
logout: '登出',
language: '語言',
- lyric: '歌詞',
- others: '其他',
- customization: '自訂',
- MusicGenrePreference: {
- text: '音樂語種偏好',
- none: '無偏好',
- mandarin: '華語',
- western: '歐美',
- korean: '韓語',
- japanese: '日語',
- },
musicQuality: {
text: '音質選擇',
low: '普通',
@@ -170,15 +148,12 @@ export default {
clearSongsCache: '清除歌曲快取',
cacheCount: '已快取 {song} 首 ({size})',
showLyricsTranslation: '顯示歌詞翻譯',
- minimizeToTray: '最小化到工作列角落',
+ minimizeToTray: '最小化到系統列',
showPlaylistsByAppleMusic: '首頁顯示來自 Apple Music 的歌單',
enableDiscordRichPresence: '啟用 Discord Rich Presence',
enableGlobalShortcut: '啟用全域快捷鍵',
showLibraryDefault: '啟動後顯示音樂庫',
subTitleDefault: '副標題使用別名',
- enableReversedMode: '啟用倒序播放功能 (實驗性功能)',
- enableCustomTitlebar: '啟用自訂標題列(重新啟動後生效)',
- showLyricsTime: '顯示目前時間',
lyricsBackground: {
text: '顯示歌詞背景',
off: '關閉',
@@ -189,40 +164,7 @@ export default {
text: '關閉主面板時...',
ask: '詢問',
exit: '退出',
- minimizeToTray: '最小化到工作列角落',
- },
- enableOsdlyricsSupport: {
- title: '桌面歌詞支援',
- desc1:
- '只在 Linux 環境下生效。啟用後會將歌詞檔案下載至本機位置,並在開啟播放器時嘗試連帶啟動 OSDLyrics。',
- desc2: '請在開啟之前確保您已經正確安裝了 OSDLyrics。',
- },
- unm: {
- enable: '啟用',
- audioSource: {
- title: '備選音源',
- },
- enableFlac: {
- title: '啟用 FLAC',
- desc: '啟用後需要清除歌曲快取才能生效',
- },
- searchMode: {
- title: '音源搜尋模式',
- fast: '速度優先',
- order: '順序優先',
- },
- cookie: {
- joox: 'Joox 引擎的 Cookie',
- qq: 'QQ 引擎的 Cookie',
- desc1: '設定說明請參見此處',
- desc2: ',留空則不進行相關設定',
- },
- ytdl: 'YtDl 引擎要使用的 youtube-dl 執行檔',
- proxy: {
- title: '用於 UNM 的 Proxy 伺服器',
- desc1: '請求如 YouTube 音源服務時要使用的 Proxy 伺服器',
- desc2: '留空則不進行相關設定',
- },
+ minimizeToTray: '最小化到系統列',
},
},
contextMenu: {
@@ -234,14 +176,10 @@ export default {
removeFromLibrary: '從音樂庫刪除',
addToPlaylist: '新增至歌單',
searchInPlaylist: '歌單內搜尋',
- openInBrowser: '在瀏覽器中打開',
- copyUrl: '複製連結',
+ copyUrl: '複製超連結',
allPlaylists: '全部歌單',
minePlaylists: '我建立的歌單',
likedPlaylists: '收藏的歌單',
- cardiacMode: '心動模式',
- copyLyric: '複製歌詞',
- copyLyricWithTranslation: '複製歌詞(含翻譯)',
},
toast: {
savedToPlaylist: '已新增至歌單',
@@ -250,6 +188,6 @@ export default {
removedFromMyLikedSongs: '已從喜歡的音樂中刪除',
copied: '已複製',
copyFailed: '複製失敗:',
- needToLogin: '此動作需要登入網易雲帳戶',
+ needToLogin: '此動作需要登入網易雲帳號',
},
};
diff --git a/src/main.js b/src/main.js
index 50d73a2..3903764 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,5 +1,5 @@
import Vue from 'vue';
-import VueGtag from 'vue-gtag';
+import VueAnalytics from 'vue-analytics';
import App from './App.vue';
import router from './router';
import store from './store';
@@ -7,6 +7,7 @@ import i18n from '@/locale';
import '@/assets/icons';
import '@/utils/filters';
import './registerServiceWorker';
+import { dailyTask } from '@/utils/common';
import '@/assets/css/global.scss';
import NProgress from 'nprogress';
import '@/assets/css/nprogress.css';
@@ -27,16 +28,14 @@ console.log(
'background:unset;color:unset;'
);
-Vue.use(
- VueGtag,
- {
- config: { id: 'G-KMJJCFZDKF' },
- },
- router
-);
+Vue.use(VueAnalytics, {
+ id: 'UA-180189423-1',
+ router,
+});
Vue.config.productionTip = false;
NProgress.configure({ showSpinner: false, trickleSpeed: 100 });
+dailyTask();
new Vue({
i18n,
diff --git a/src/ncmModDef.js b/src/ncmModDef.js
deleted file mode 100644
index 043ce28..0000000
--- a/src/ncmModDef.js
+++ /dev/null
@@ -1,617 +0,0 @@
-module.exports = [
- {
- identifier: 'user_update',
- route: '/user/update',
- module: require('NeteaseCloudMusicApi/module/user_update'),
- },
- {
- identifier: 'user_subcount',
- route: '/user/subcount',
- module: require('NeteaseCloudMusicApi/module/user_subcount'),
- },
- {
- identifier: 'user_replacephone',
- route: '/user/replacephone',
- module: require('NeteaseCloudMusicApi/module/user_replacephone'),
- },
- {
- identifier: 'user_record',
- route: '/user/record',
- module: require('NeteaseCloudMusicApi/module/user_record'),
- },
- {
- identifier: 'user_playlist',
- route: '/user/playlist',
- module: require('NeteaseCloudMusicApi/module/user_playlist'),
- },
- {
- identifier: 'user_level',
- route: '/user/level',
- module: require('NeteaseCloudMusicApi/module/user_level'),
- },
- {
- identifier: 'user_follows',
- route: '/user/follows',
- module: require('NeteaseCloudMusicApi/module/user_follows'),
- },
- {
- identifier: 'user_followeds',
- route: '/user/followeds',
- module: require('NeteaseCloudMusicApi/module/user_followeds'),
- },
- {
- identifier: 'user_event',
- route: '/user/event',
- module: require('NeteaseCloudMusicApi/module/user_event'),
- },
- {
- identifier: 'user_dj',
- route: '/user/dj',
- module: require('NeteaseCloudMusicApi/module/user_dj'),
- },
- {
- identifier: 'user_detail',
- route: '/user/detail',
- module: require('NeteaseCloudMusicApi/module/user_detail'),
- },
- {
- identifier: 'user_cloud_detail',
- route: '/user/cloud/detail',
- module: require('NeteaseCloudMusicApi/module/user_cloud_detail'),
- },
- {
- identifier: 'user_cloud_del',
- route: '/user/cloud/del',
- module: require('NeteaseCloudMusicApi/module/user_cloud_del'),
- },
- {
- identifier: 'user_cloud',
- route: '/user/cloud',
- module: require('NeteaseCloudMusicApi/module/user_cloud'),
- },
- {
- identifier: 'user_bindingcellphone',
- route: '/user/bindingcellphone',
- module: require('NeteaseCloudMusicApi/module/user_bindingcellphone'),
- },
- {
- identifier: 'user_binding',
- route: '/user/binding',
- module: require('NeteaseCloudMusicApi/module/user_binding'),
- },
- {
- identifier: 'user_audio',
- route: '/user/audio',
- module: require('NeteaseCloudMusicApi/module/user_audio'),
- },
- {
- identifier: 'user_account',
- route: '/user/account',
- module: require('NeteaseCloudMusicApi/module/user_account'),
- },
- {
- identifier: 'toplist_detail',
- route: '/toplist/detail',
- module: require('NeteaseCloudMusicApi/module/toplist_detail'),
- },
- {
- identifier: 'toplist_artist',
- route: '/toplist/artist',
- module: require('NeteaseCloudMusicApi/module/toplist_artist'),
- },
- {
- identifier: 'toplist',
- route: '/toplist',
- module: require('NeteaseCloudMusicApi/module/toplist'),
- },
- {
- identifier: 'topic_sublist',
- route: '/topic/sublist',
- module: require('NeteaseCloudMusicApi/module/topic_sublist'),
- },
- {
- identifier: 'topic_detail_event_hot',
- route: '/topic/detail/event/hot',
- module: require('NeteaseCloudMusicApi/module/topic_detail_event_hot'),
- },
- {
- identifier: 'topic_detail',
- route: '/topic/detail',
- module: require('NeteaseCloudMusicApi/module/topic_detail'),
- },
- {
- identifier: 'top_song',
- route: '/top/song',
- module: require('NeteaseCloudMusicApi/module/top_song'),
- },
- {
- identifier: 'top_playlist_highquality',
- route: '/top/playlist/highquality',
- module: require('NeteaseCloudMusicApi/module/top_playlist_highquality'),
- },
- {
- identifier: 'top_playlist',
- route: '/top/playlist',
- module: require('NeteaseCloudMusicApi/module/top_playlist'),
- },
- {
- identifier: 'top_mv',
- route: '/top/mv',
- module: require('NeteaseCloudMusicApi/module/top_mv'),
- },
- {
- identifier: 'top_list',
- route: '/top/list',
- module: require('NeteaseCloudMusicApi/module/top_list'),
- },
- {
- identifier: 'top_artists',
- route: '/top/artists',
- module: require('NeteaseCloudMusicApi/module/top_artists'),
- },
- {
- identifier: 'top_album',
- route: '/top/album',
- module: require('NeteaseCloudMusicApi/module/top_album'),
- },
- {
- identifier: 'song_url',
- route: '/song/url',
- module: require('NeteaseCloudMusicApi/module/song_url'),
- },
- {
- identifier: 'song_download_url',
- route: '/song/download/url',
- module: require('NeteaseCloudMusicApi/module/song_download_url'),
- },
- {
- identifier: 'song_detail',
- route: '/song/detail',
- module: require('NeteaseCloudMusicApi/module/song_detail'),
- },
- {
- identifier: 'simi_mv',
- route: '/simi/mv',
- module: require('NeteaseCloudMusicApi/module/simi_mv'),
- },
- {
- identifier: 'simi_artist',
- route: '/simi/artist',
- module: require('NeteaseCloudMusicApi/module/simi_artist'),
- },
- {
- identifier: 'search',
- route: '/search',
- module: require('NeteaseCloudMusicApi/module/search'),
- },
- {
- identifier: 'scrobble',
- route: '/scrobble',
- module: require('NeteaseCloudMusicApi/module/scrobble'),
- },
- {
- identifier: 'recommend_songs',
- route: '/recommend/songs',
- module: require('NeteaseCloudMusicApi/module/recommend_songs'),
- },
- {
- identifier: 'recommend_resource',
- route: '/recommend/resource',
- module: require('NeteaseCloudMusicApi/module/recommend_resource'),
- },
- {
- identifier: 'playmode_intelligence_list',
- route: '/playmode/intelligence/list',
- module: require('NeteaseCloudMusicApi/module/playmode_intelligence_list'),
- },
- {
- identifier: 'playlist_video_recent',
- route: '/playlist/video/recent',
- module: require('NeteaseCloudMusicApi/module/playlist_video_recent'),
- },
- {
- identifier: 'playlist_update',
- route: '/playlist/update',
- module: require('NeteaseCloudMusicApi/module/playlist_update'),
- },
- {
- identifier: 'playlist_tracks',
- route: '/playlist/tracks',
- module: require('NeteaseCloudMusicApi/module/playlist_tracks'),
- },
- {
- identifier: 'playlist_track_delete',
- route: '/playlist/track/delete',
- module: require('NeteaseCloudMusicApi/module/playlist_track_delete'),
- },
- {
- identifier: 'playlist_track_all',
- route: '/playlist/track/all',
- module: require('NeteaseCloudMusicApi/module/playlist_track_all'),
- },
- {
- identifier: 'playlist_track_add',
- route: '/playlist/track/add',
- module: require('NeteaseCloudMusicApi/module/playlist_track_add'),
- },
- {
- identifier: 'playlist_tags_update',
- route: '/playlist/tags/update',
- module: require('NeteaseCloudMusicApi/module/playlist_tags_update'),
- },
- {
- identifier: 'playlist_subscribers',
- route: '/playlist/subscribers',
- module: require('NeteaseCloudMusicApi/module/playlist_subscribers'),
- },
- {
- identifier: 'playlist_subscribe',
- route: '/playlist/subscribe',
- module: require('NeteaseCloudMusicApi/module/playlist_subscribe'),
- },
- {
- identifier: 'playlist_privacy',
- route: '/playlist/privacy',
- module: require('NeteaseCloudMusicApi/module/playlist_privacy'),
- },
- {
- identifier: 'playlist_order_update',
- route: '/playlist/order/update',
- module: require('NeteaseCloudMusicApi/module/playlist_order_update'),
- },
- {
- identifier: 'playlist_name_update',
- route: '/playlist/name/update',
- module: require('NeteaseCloudMusicApi/module/playlist_name_update'),
- },
- {
- identifier: 'playlist_mylike',
- route: '/playlist/mylike',
- module: require('NeteaseCloudMusicApi/module/playlist_mylike'),
- },
- {
- identifier: 'playlist_hot',
- route: '/playlist/hot',
- module: require('NeteaseCloudMusicApi/module/playlist_hot'),
- },
- {
- identifier: 'playlist_highquality_tags',
- route: '/playlist/highquality/tags',
- module: require('NeteaseCloudMusicApi/module/playlist_highquality_tags'),
- },
- {
- identifier: 'playlist_detail_dynamic',
- route: '/playlist/detail/dynamic',
- module: require('NeteaseCloudMusicApi/module/playlist_detail_dynamic'),
- },
- {
- identifier: 'playlist_detail',
- route: '/playlist/detail',
- module: require('NeteaseCloudMusicApi/module/playlist_detail'),
- },
- {
- identifier: 'playlist_desc_update',
- route: '/playlist/desc/update',
- module: require('NeteaseCloudMusicApi/module/playlist_desc_update'),
- },
- {
- identifier: 'playlist_delete',
- route: '/playlist/delete',
- module: require('NeteaseCloudMusicApi/module/playlist_delete'),
- },
- {
- identifier: 'playlist_create',
- route: '/playlist/create',
- module: require('NeteaseCloudMusicApi/module/playlist_create'),
- },
- {
- identifier: 'playlist_cover_update',
- route: '/playlist/cover/update',
- module: require('NeteaseCloudMusicApi/module/playlist_cover_update'),
- },
- {
- identifier: 'playlist_catlist',
- route: '/playlist/catlist',
- module: require('NeteaseCloudMusicApi/module/playlist_catlist'),
- },
- {
- identifier: 'personalized',
- route: '/personalized',
- module: require('NeteaseCloudMusicApi/module/personalized'),
- },
- {
- identifier: 'personal_fm',
- route: '/personal_fm',
- module: require('NeteaseCloudMusicApi/module/personal_fm'),
- },
- {
- identifier: 'mv_url',
- route: '/mv/url',
- module: require('NeteaseCloudMusicApi/module/mv_url'),
- },
- {
- identifier: 'mv_sublist',
- route: '/mv/sublist',
- module: require('NeteaseCloudMusicApi/module/mv_sublist'),
- },
- {
- identifier: 'mv_sub',
- route: '/mv/sub',
- module: require('NeteaseCloudMusicApi/module/mv_sub'),
- },
- {
- identifier: 'mv_first',
- route: '/mv/first',
- module: require('NeteaseCloudMusicApi/module/mv_first'),
- },
- {
- identifier: 'mv_exclusive_rcmd',
- route: '/mv/exclusive/rcmd',
- module: require('NeteaseCloudMusicApi/module/mv_exclusive_rcmd'),
- },
- {
- identifier: 'mv_detail_info',
- route: '/mv/detail/info',
- module: require('NeteaseCloudMusicApi/module/mv_detail_info'),
- },
- {
- identifier: 'mv_detail',
- route: '/mv/detail',
- module: require('NeteaseCloudMusicApi/module/mv_detail'),
- },
- {
- identifier: 'mv_all',
- route: '/mv/all',
- module: require('NeteaseCloudMusicApi/module/mv_all'),
- },
- {
- identifier: 'lyric',
- route: '/lyric',
- module: require('NeteaseCloudMusicApi/module/lyric'),
- },
- {
- identifier: 'logout',
- route: '/logout',
- module: require('NeteaseCloudMusicApi/module/logout'),
- },
- {
- identifier: 'login_status',
- route: '/login/status',
- module: require('NeteaseCloudMusicApi/module/login_status'),
- },
- {
- identifier: 'login_refresh',
- route: '/login/refresh',
- module: require('NeteaseCloudMusicApi/module/login_refresh'),
- },
- {
- identifier: 'login_qr_key',
- route: '/login/qr/key',
- module: require('NeteaseCloudMusicApi/module/login_qr_key'),
- },
- {
- identifier: 'login_qr_create',
- route: '/login/qr/create',
- module: require('NeteaseCloudMusicApi/module/login_qr_create'),
- },
- {
- identifier: 'login_qr_check',
- route: '/login/qr/check',
- module: require('NeteaseCloudMusicApi/module/login_qr_check'),
- },
- {
- identifier: 'login_cellphone',
- route: '/login/cellphone',
- module: require('NeteaseCloudMusicApi/module/login_cellphone'),
- },
- {
- identifier: 'login',
- route: '/login',
- module: require('NeteaseCloudMusicApi/module/login'),
- },
- {
- identifier: 'likelist',
- route: '/likelist',
- module: require('NeteaseCloudMusicApi/module/likelist'),
- },
- {
- identifier: 'like',
- route: '/like',
- module: require('NeteaseCloudMusicApi/module/like'),
- },
- {
- identifier: 'follow',
- route: '/follow',
- module: require('NeteaseCloudMusicApi/module/follow'),
- },
- {
- identifier: 'fm_trash',
- route: '/fm_trash',
- module: require('NeteaseCloudMusicApi/module/fm_trash'),
- },
- {
- identifier: 'daily_signin',
- route: '/daily_signin',
- module: require('NeteaseCloudMusicApi/module/daily_signin'),
- },
- {
- identifier: 'cloudsearch',
- route: '/cloudsearch',
- module: require('NeteaseCloudMusicApi/module/cloudsearch'),
- },
- {
- identifier: 'cloud',
- route: '/cloud',
- module: require('NeteaseCloudMusicApi/module/cloud'),
- },
- {
- identifier: 'check_music',
- route: '/check/music',
- module: require('NeteaseCloudMusicApi/module/check_music'),
- },
- {
- identifier: 'cellphone_existence_check',
- route: '/cellphone/existence/check',
- module: require('NeteaseCloudMusicApi/module/cellphone_existence_check'),
- },
- {
- identifier: 'captcha_verify',
- route: '/captcha/verify',
- module: require('NeteaseCloudMusicApi/module/captcha_verify'),
- },
- {
- identifier: 'captcha_sent',
- route: '/captcha/sent',
- module: require('NeteaseCloudMusicApi/module/captcha_sent'),
- },
- {
- identifier: 'calendar',
- route: '/calendar',
- module: require('NeteaseCloudMusicApi/module/calendar'),
- },
- {
- identifier: 'batch',
- route: '/batch',
- module: require('NeteaseCloudMusicApi/module/batch'),
- },
- {
- identifier: 'banner',
- route: '/banner',
- module: require('NeteaseCloudMusicApi/module/banner'),
- },
- {
- identifier: 'avatar_upload',
- route: '/avatar/upload',
- module: require('NeteaseCloudMusicApi/module/avatar_upload'),
- },
- {
- identifier: 'audio_match',
- route: '/audio/match',
- module: require('NeteaseCloudMusicApi/module/audio_match'),
- },
- {
- identifier: 'artists',
- route: '/artists',
- module: require('NeteaseCloudMusicApi/module/artists'),
- },
- {
- identifier: 'artist_video',
- route: '/artist/video',
- module: require('NeteaseCloudMusicApi/module/artist_video'),
- },
- {
- identifier: 'artist_top_song',
- route: '/artist/top/song',
- module: require('NeteaseCloudMusicApi/module/artist_top_song'),
- },
- {
- identifier: 'artist_sublist',
- route: '/artist/sublist',
- module: require('NeteaseCloudMusicApi/module/artist_sublist'),
- },
- {
- identifier: 'artist_sub',
- route: '/artist/sub',
- module: require('NeteaseCloudMusicApi/module/artist_sub'),
- },
- {
- identifier: 'artist_songs',
- route: '/artist/songs',
- module: require('NeteaseCloudMusicApi/module/artist_songs'),
- },
- {
- identifier: 'artist_new_song',
- route: '/artist/new/song',
- module: require('NeteaseCloudMusicApi/module/artist_new_song'),
- },
- {
- identifier: 'artist_new_mv',
- route: '/artist/new/mv',
- module: require('NeteaseCloudMusicApi/module/artist_new_mv'),
- },
- {
- identifier: 'artist_mv',
- route: '/artist/mv',
- module: require('NeteaseCloudMusicApi/module/artist_mv'),
- },
- {
- identifier: 'artist_list',
- route: '/artist/list',
- module: require('NeteaseCloudMusicApi/module/artist_list'),
- },
- {
- identifier: 'artist_fans',
- route: '/artist/fans',
- module: require('NeteaseCloudMusicApi/module/artist_fans'),
- },
- {
- identifier: 'artist_detail',
- route: '/artist/detail',
- module: require('NeteaseCloudMusicApi/module/artist_detail'),
- },
- {
- identifier: 'artist_desc',
- route: '/artist/desc',
- module: require('NeteaseCloudMusicApi/module/artist_desc'),
- },
- {
- identifier: 'artist_album',
- route: '/artist/album',
- module: require('NeteaseCloudMusicApi/module/artist_album'),
- },
- {
- identifier: 'album_sublist',
- route: '/album/sublist',
- module: require('NeteaseCloudMusicApi/module/album_sublist'),
- },
- {
- identifier: 'album_sub',
- route: '/album/sub',
- module: require('NeteaseCloudMusicApi/module/album_sub'),
- },
- {
- identifier: 'album_songsaleboard',
- route: '/album/songsaleboard',
- module: require('NeteaseCloudMusicApi/module/album_songsaleboard'),
- },
- {
- identifier: 'album_newest',
- route: '/album/newest',
- module: require('NeteaseCloudMusicApi/module/album_newest'),
- },
- {
- identifier: 'album_new',
- route: '/album/new',
- module: require('NeteaseCloudMusicApi/module/album_new'),
- },
- {
- identifier: 'album_list_style',
- route: '/album/list/style',
- module: require('NeteaseCloudMusicApi/module/album_list_style'),
- },
- {
- identifier: 'album_list',
- route: '/album/list',
- module: require('NeteaseCloudMusicApi/module/album_list'),
- },
- {
- identifier: 'album_detail_dynamic',
- route: '/album/detail/dynamic',
- module: require('NeteaseCloudMusicApi/module/album_detail_dynamic'),
- },
- {
- identifier: 'album_detail',
- route: '/album/detail',
- module: require('NeteaseCloudMusicApi/module/album_detail'),
- },
- {
- identifier: 'album',
- route: '/album',
- module: require('NeteaseCloudMusicApi/module/album'),
- },
- {
- identifier: 'activate_init_profile',
- route: '/activate/init/profile',
- module: require('NeteaseCloudMusicApi/module/activate_init_profile'),
- },
-];
diff --git a/src/store/actions.js b/src/store/actions.js
index 83c0666..d29eb88 100644
--- a/src/store/actions.js
+++ b/src/store/actions.js
@@ -5,7 +5,6 @@ import { getPlaylistDetail } from '@/api/playlist';
import { getTrackDetail } from '@/api/track';
import {
userPlaylist,
- userPlayHistory,
userLikedSongsIDs,
likedAlbums,
likedArtists,
@@ -101,7 +100,7 @@ export default {
if (!isLooseLoggedIn()) return;
if (isAccountLoggedIn()) {
return userPlaylist({
- uid: state.data.user?.userId,
+ uid: state.data.user.userId,
limit: 2000, // 最多只加载2000个歌单(等有用户反馈问题再修)
timestamp: new Date().getTime(),
}).then(result => {
@@ -156,8 +155,7 @@ export default {
},
fetchCloudDisk: ({ commit }) => {
if (!isAccountLoggedIn()) return;
- // FIXME: #1242
- return cloudDisk({ limit: 1000 }).then(result => {
+ return cloudDisk().then(result => {
if (result.data) {
commit('updateLikedXXX', {
name: 'cloudDisk',
@@ -166,30 +164,6 @@ export default {
}
});
},
- fetchPlayHistory: ({ state, commit }) => {
- if (!isAccountLoggedIn()) return;
- return Promise.all([
- userPlayHistory({ uid: state.data.user?.userId, type: 0 }),
- userPlayHistory({ uid: state.data.user?.userId, type: 1 }),
- ]).then(result => {
- const data = {};
- const dataType = { 0: 'allData', 1: 'weekData' };
- if (result[0] && result[1]) {
- for (let i = 0; i < result.length; i++) {
- const songData = result[i][dataType[i]].map(item => {
- const song = item.song;
- song.playCount = item.playCount;
- return song;
- });
- data[[dataType[i]]] = songData;
- }
- commit('updateLikedXXX', {
- name: 'playHistory',
- data: data,
- });
- }
- });
- },
fetchUserProfile: ({ commit }) => {
if (!isAccountLoggedIn()) return;
return userAccount().then(result => {
diff --git a/src/store/initLocalStorage.js b/src/store/initLocalStorage.js
index 9540efb..5fa494a 100644
--- a/src/store/initLocalStorage.js
+++ b/src/store/initLocalStorage.js
@@ -19,25 +19,20 @@ let localStorage = {
enableUnblockNeteaseMusic: true,
automaticallyCacheSongs: true,
cacheLimit: 8192,
- enableReversedMode: false,
nyancatStyle: false,
showLyricsTranslation: true,
lyricsBackground: true,
- enableOsdlyricsSupport: false,
closeAppOption: 'ask',
enableDiscordRichPresence: false,
enableGlobalShortcut: true,
showLibraryDefault: false,
subTitleDefault: false,
- linuxEnableCustomTitlebar: false,
enabledPlaylistCategories,
proxyConfig: {
protocol: 'noProxy',
server: '',
port: null,
},
- enableRealIP: false,
- realIP: null,
shortcuts: shortcuts,
},
data: {
diff --git a/src/store/mutations.js b/src/store/mutations.js
index d6a4b3b..42c3c8e 100644
--- a/src/store/mutations.js
+++ b/src/store/mutations.js
@@ -31,8 +31,9 @@ export default {
c => c === name
);
if (index !== -1) {
- state.settings.enabledPlaylistCategories =
- state.settings.enabledPlaylistCategories.filter(c => c !== name);
+ state.settings.enabledPlaylistCategories = state.settings.enabledPlaylistCategories.filter(
+ c => c !== name
+ );
} else {
state.settings.enabledPlaylistCategories.push(name);
}
@@ -72,7 +73,4 @@ export default {
enableScrolling(state, status = null) {
state.enableScrolling = status ? status : !state.enableScrolling;
},
- updateTitle(state, title) {
- state.title = title;
- },
};
diff --git a/src/store/state.js b/src/store/state.js
index 827bee0..4de913a 100644
--- a/src/store/state.js
+++ b/src/store/state.js
@@ -13,7 +13,6 @@ updateApp();
export default {
showLyrics: false,
enableScrolling: true,
- title: 'YesPlayMusic',
liked: {
songs: [],
songsWithDetails: [], // 只有前12首
@@ -22,10 +21,6 @@ export default {
artists: [],
mvs: [],
cloudDisk: [],
- playHistory: {
- weekData: [],
- allData: [],
- },
},
contextMenu: {
clickObjectID: 0,
diff --git a/src/utils/Player.js b/src/utils/Player.js
index 11af73a..20ff303 100644
--- a/src/utils/Player.js
+++ b/src/utils/Player.js
@@ -1,61 +1,19 @@
+import { getTrackDetail, scrobble, getMP3 } from '@/api/track';
+import shuffle from 'lodash/shuffle';
+import { Howler, Howl } from 'howler';
+import { cacheTrackSource, getTrackSource } from '@/utils/db';
import { getAlbum } from '@/api/album';
+import { getPlaylistDetail } from '@/api/playlist';
import { getArtist } from '@/api/artist';
-import { trackScrobble, trackUpdateNowPlaying } from '@/api/lastfm';
-import { fmTrash, personalFM } from '@/api/others';
-import { getPlaylistDetail, intelligencePlaylist } from '@/api/playlist';
-import { getLyric, getMP3, getTrackDetail } from '@/api/track';
+import { personalFM, fmTrash } from '@/api/others';
import store from '@/store';
import { isAccountLoggedIn } from '@/utils/auth';
-import { cacheTrackSource, getTrackSource } from '@/utils/db';
-import { isCreateMpris, isCreateTray } from '@/utils/platform';
-import { Howl, Howler } from 'howler';
-import shuffle from 'lodash/shuffle';
-import { decode as base642Buffer } from '@/utils/base64';
-
-const PLAY_PAUSE_FADE_DURATION = 200;
-
-const INDEX_IN_PLAY_NEXT = -1;
-
-/**
- * @readonly
- * @enum {string}
- */
-const UNPLAYABLE_CONDITION = {
- PLAY_NEXT_TRACK: 'playNextTrack',
- PLAY_PREV_TRACK: 'playPrevTrack',
-};
+import { trackUpdateNowPlaying, trackScrobble } from '@/api/lastfm';
const electron =
process.env.IS_ELECTRON === true ? window.require('electron') : null;
const ipcRenderer =
process.env.IS_ELECTRON === true ? electron.ipcRenderer : null;
-const delay = ms =>
- new Promise(resolve => {
- setTimeout(() => {
- resolve('');
- }, ms);
- });
-const excludeSaveKeys = [
- '_playing',
- '_personalFMLoading',
- '_personalFMNextLoading',
-];
-
-function setTitle(track) {
- document.title = track
- ? `${track.name} · ${track.ar[0].name} - YesPlayMusic`
- : 'YesPlayMusic';
- if (isCreateTray) {
- ipcRenderer?.send('updateTrayTooltip', document.title);
- }
- store.commit('updateTitle', document.title);
-}
-
-function setTrayLikeState(isLiked) {
- if (isCreateTray) {
- ipcRenderer?.send('updateTrayLikeState', isLiked);
- }
-}
export default class {
constructor() {
@@ -65,11 +23,8 @@ export default class {
this._enabled = false; // 是否启用Player
this._repeatMode = 'off'; // off | on | one
this._shuffle = false; // true | false
- this._reversed = false;
this._volume = 1; // 0 to 1
this._volumeBeforeMuted = 1; // 用于保存静音前的音量
- this._personalFMLoading = false; // 是否正在私人FM中加载新的track
- this._personalFMNextLoading = false; // 是否正在缓存私人FM的下一首歌曲
// 播放信息
this._list = []; // 播放列表
@@ -81,17 +36,7 @@ export default class {
this._playNextList = []; // 当这个list不为空时,会优先播放这个list的歌
this._isPersonalFM = false; // 是否是私人FM模式
this._personalFMTrack = { id: 0 }; // 私人FM当前歌曲
- this._personalFMNextTrack = {
- id: 0,
- }; // 私人FM下一首歌曲信息(为了快速加载下一首)
-
- /**
- * The blob records for cleanup.
- *
- * @private
- * @type {string[]}
- */
- this.createdBlobRecords = [];
+ this._personalFMNextTrack = { id: 0 }; // 私人FM下一首歌曲信息(为了快速加载下一首)
// howler (https://github.com/goldfire/howler.js)
this._howler = null;
@@ -130,27 +75,13 @@ export default class {
if (shuffle) {
this._shuffleTheList();
}
- // 同步当前歌曲在列表中的下标
- this.current = this.list.indexOf(this.currentTrackID);
- }
- get reversed() {
- return this._reversed;
- }
- set reversed(reversed) {
- if (this._isPersonalFM) return;
- if (reversed !== true && reversed !== false) {
- console.warn('reversed: invalid args, must be Boolean');
- return;
- }
- console.log('changing reversed to:', reversed);
- this._reversed = reversed;
}
get volume() {
return this._volume;
}
set volume(volume) {
this._volume = volume;
- this._howler?.volume(volume);
+ Howler.volume(volume);
}
get list() {
return this.shuffle ? this._shuffledList : this._list;
@@ -177,9 +108,6 @@ export default class {
get currentTrack() {
return this._currentTrack;
}
- get currentTrackID() {
- return this._currentTrack?.id ?? 0;
- }
get playlistSource() {
return this._playlistSource;
}
@@ -203,9 +131,6 @@ export default class {
set progress(value) {
if (this._howler) {
this._howler.seek(value);
- if (isCreateMpris) {
- ipcRenderer?.send('seeked', this._howler.seek());
- }
}
}
get isCurrentTrackLiked() {
@@ -214,11 +139,13 @@ export default class {
_init() {
this._loadSelfFromLocalStorage();
- this._howler?.volume(this.volume);
+ Howler.autoUnlock = false;
+ Howler.usingWebAudio = true;
+ Howler.volume(this.volume);
if (this._enabled) {
// 恢复当前播放歌曲
- this._replaceCurrentTrack(this.currentTrackID, false).then(() => {
+ this._replaceCurrentTrack(this._currentTrack.id, false).then(() => {
this._howler?.seek(localStorage.getItem('playerCurrentTrackTime') ?? 0);
}); // update audio source and init howler
this._initMediaSession();
@@ -227,11 +154,7 @@ export default class {
this._setIntervals();
// 初始化私人FM
- if (
- this._personalFMTrack.id === 0 ||
- this._personalFMNextTrack.id === 0 ||
- this._personalFMTrack.id === this._personalFMNextTrack.id
- ) {
+ if (this._personalFMTrack.id === 0 || this._personalFMNextTrack.id === 0) {
personalFM().then(result => {
this._personalFMTrack = result.data[0];
this._personalFMNextTrack = result.data[1];
@@ -239,65 +162,39 @@ export default class {
});
}
}
- _setPlaying(isPlaying) {
- this._playing = isPlaying;
- if (isCreateTray) {
- ipcRenderer?.send('updateTrayPlayState', this._playing);
- }
- }
_setIntervals() {
// 同步播放进度
- // TODO: 如果 _progress 在别的地方被改变了,
- // 这个定时器会覆盖之前改变的值,是bug
+ // TODO: 如果 _progress 在别的地方被改变了,这个定时器会覆盖之前改变的值,是bug
setInterval(() => {
if (this._howler === null) return;
this._progress = this._howler.seek();
localStorage.setItem('playerCurrentTrackTime', this._progress);
- if (isCreateMpris) {
- ipcRenderer?.send('playerCurrentTrackTime', this._progress);
- }
}, 1000);
}
_getNextTrack() {
- const next = this._reversed ? this.current - 1 : this.current + 1;
-
if (this._playNextList.length > 0) {
- let trackID = this._playNextList[0];
- return [trackID, INDEX_IN_PLAY_NEXT];
+ let trackID = this._playNextList.shift();
+ return [trackID, this.current];
}
- // 循环模式开启,则重新播放当前模式下的相对的下一首
- if (this.repeatMode === 'on') {
- if (this._reversed && this.current === 0) {
- // 倒序模式,当前歌曲是第一首,则重新播放列表最后一首
- return [this.list[this.list.length - 1], this.list.length - 1];
- } else if (this.list.length === this.current + 1) {
- // 正序模式,当前歌曲是最后一首,则重新播放第一首
- return [this.list[0], 0];
- }
+ // 当歌曲是列表最后一首 && 循环模式开启
+ if (this.list.length === this.current + 1 && this.repeatMode === 'on') {
+ return [this.list[0], 0];
}
// 返回 [trackID, index]
- return [this.list[next], next];
+ return [this.list[this.current + 1], this.current + 1];
}
_getPrevTrack() {
- const next = this._reversed ? this.current + 1 : this.current - 1;
-
- // 循环模式开启,则重新播放当前模式下的相对的下一首
- if (this.repeatMode === 'on') {
- if (this._reversed && this.current === 0) {
- // 倒序模式,当前歌曲是最后一首,则重新播放列表第一首
- return [this.list[0], 0];
- } else if (this.list.length === this.current + 1) {
- // 正序模式,当前歌曲是第一首,则重新播放列表最后一首
- return [this.list[this.list.length - 1], this.list.length - 1];
- }
+ // 当歌曲是列表第一首 && 循环模式开启
+ if (this.current === 0 && this.repeatMode === 'on') {
+ return [this.list[this.list.length - 1], this.list.length - 1];
}
// 返回 [trackID, index]
- return [this.list[next], next];
+ return [this.list[this.current - 1], this.current - 1];
}
- async _shuffleTheList(firstTrackID = this.currentTrackID) {
+ async _shuffleTheList(firstTrackID = this._currentTrack.id) {
let list = this._list.filter(tid => tid !== firstTrackID);
if (firstTrackID === 'first') list = this._list;
this._shuffledList = shuffle(list);
@@ -309,6 +206,11 @@ export default class {
);
const trackDuration = ~~(track.dt / 1000);
time = completed ? trackDuration : ~~time;
+ scrobble({
+ id: track.id,
+ sourceid: this.playlistSource.id,
+ time,
+ });
if (
store.state.lastfm.key !== undefined &&
(time >= trackDuration / 2 || time >= 240)
@@ -329,65 +231,22 @@ export default class {
this._howler = new Howl({
src: [source],
html5: true,
- preload: true,
format: ['mp3', 'flac'],
- onend: () => {
- this._nextTrackCallback();
- },
- });
- this._howler.on('loaderror', (_, errCode) => {
- // https://developer.mozilla.org/en-US/docs/Web/API/MediaError/code
- // code 3: MEDIA_ERR_DECODE
- if (errCode === 3) {
- this._playNextTrack(this._isPersonalFM);
- } else if (errCode === 4) {
- // code 4: MEDIA_ERR_SRC_NOT_SUPPORTED
- store.dispatch('showToast', `无法播放: 不支持的音频格式`);
- this._playNextTrack(this._isPersonalFM);
- } else {
- const t = this.progress;
- this._replaceCurrentTrackAudio(this.currentTrack, false, false).then(
- replaced => {
- // 如果 replaced 为 false,代表当前的 track 已经不是这里想要替换的track
- // 此时则不修改当前的歌曲进度
- if (replaced) {
- this._howler?.seek(t);
- this.play();
- }
- }
- );
- }
});
if (autoplay) {
this.play();
- if (this._currentTrack.name) {
- setTitle(this._currentTrack);
- }
- setTrayLikeState(store.state.liked.songs.includes(this.currentTrack.id));
+ document.title = `${this._currentTrack.name} · ${this._currentTrack.ar[0].name} - YesPlayMusic`;
}
this.setOutputDevice();
- }
- _getAudioSourceBlobURL(data) {
- // Create a new object URL.
- const source = URL.createObjectURL(new Blob([data]));
-
- // Clean up the previous object URLs since we've created a new one.
- // Revoke object URLs can release the memory taken by a Blob,
- // which occupied a large proportion of memory.
- for (const url in this.createdBlobRecords) {
- URL.revokeObjectURL(url);
- }
-
- // Then, we replace the createBlobRecords with new one with
- // our newly created object URL.
- this.createdBlobRecords = [source];
-
- return source;
+ this._howler.once('end', () => {
+ this._nextTrackCallback();
+ });
}
_getAudioSourceFromCache(id) {
return getTrackSource(id).then(t => {
if (!t) return null;
- return this._getAudioSourceBlobURL(t.source);
+ const source = URL.createObjectURL(new Blob([t.source]));
+ return source;
});
}
_getAudioSourceFromNetease(track) {
@@ -408,73 +267,20 @@ export default class {
});
}
}
- async _getAudioSourceFromUnblockMusic(track) {
+ _getAudioSourceFromUnblockMusic(track) {
console.debug(`[debug][Player.js] _getAudioSourceFromUnblockMusic`);
-
if (
process.env.IS_ELECTRON !== true ||
store.state.settings.enableUnblockNeteaseMusic === false
) {
return null;
}
-
- /**
- *
- * @param {string=} searchMode
- * @returns {import("@unblockneteasemusic/rust-napi").SearchMode}
- */
- const determineSearchMode = searchMode => {
- /**
- * FastFirst = 0
- * OrderFirst = 1
- */
- switch (searchMode) {
- case 'fast-first':
- return 0;
- case 'order-first':
- return 1;
- default:
- return 0;
- }
- };
-
- const retrieveSongInfo = await ipcRenderer.invoke(
- 'unblock-music',
- store.state.settings.unmSource,
- track,
- {
- enableFlac: store.state.settings.unmEnableFlac || null,
- proxyUri: store.state.settings.unmProxyUri || null,
- searchMode: determineSearchMode(store.state.settings.unmSearchMode),
- config: {
- 'joox:cookie': store.state.settings.unmJooxCookie || null,
- 'qq:cookie': store.state.settings.unmQQCookie || null,
- 'ytdl:exe': store.state.settings.unmYtDlExe || null,
- },
- }
- );
-
- if (store.state.settings.automaticallyCacheSongs && retrieveSongInfo?.url) {
- // 对于来自 bilibili 的音源
- // retrieveSongInfo.url 是音频数据的base64编码
- // 其他音源为实际url
- const url =
- retrieveSongInfo.source === 'bilibili'
- ? `data:application/octet-stream;base64,${retrieveSongInfo.url}`
- : retrieveSongInfo.url;
- cacheTrackSource(track, url, 128000, `unm:${retrieveSongInfo.source}`);
+ const source = ipcRenderer.sendSync('unblock-music', track);
+ if (store.state.settings.automaticallyCacheSongs && source?.url) {
+ // TODO: 将unblockMusic字样换成真正的来源(比如酷我咪咕等)
+ cacheTrackSource(track, source.url, 128000, 'unblockMusic');
}
-
- if (!retrieveSongInfo) {
- return null;
- }
-
- if (retrieveSongInfo.source !== 'bilibili') {
- return retrieveSongInfo.url;
- }
-
- const buffer = base642Buffer(retrieveSongInfo.url);
- return this._getAudioSourceBlobURL(buffer);
+ return source?.url;
}
_getAudioSource(track) {
return this._getAudioSourceFromCache(String(track.id))
@@ -488,66 +294,32 @@ export default class {
_replaceCurrentTrack(
id,
autoplay = true,
- ifUnplayableThen = UNPLAYABLE_CONDITION.PLAY_NEXT_TRACK
+ ifUnplayableThen = 'playNextTrack'
) {
if (autoplay && this._currentTrack.name) {
this._scrobble(this.currentTrack, this._howler?.seek());
}
return getTrackDetail(id).then(data => {
- const track = data.songs[0];
+ let track = data.songs[0];
this._currentTrack = track;
this._updateMediaSessionMetaData(track);
- return this._replaceCurrentTrackAudio(
- track,
- autoplay,
- true,
- ifUnplayableThen
- );
- });
- }
- /**
- * @returns 是否成功加载音频,并使用加载完成的音频替换了howler实例
- */
- _replaceCurrentTrackAudio(
- track,
- autoplay,
- isCacheNextTrack,
- ifUnplayableThen = UNPLAYABLE_CONDITION.PLAY_NEXT_TRACK
- ) {
- return this._getAudioSource(track).then(source => {
- if (source) {
- let replaced = false;
- if (track.id === this.currentTrackID) {
+ return this._getAudioSource(track).then(source => {
+ if (source) {
this._playAudioSource(source, autoplay);
- replaced = true;
- }
- if (isCacheNextTrack) {
this._cacheNextTrack();
+ return source;
+ } else {
+ store.dispatch('showToast', `无法播放 ${track.name}`);
+ ifUnplayableThen === 'playNextTrack'
+ ? this.playNextTrack()
+ : this.playPrevTrack();
}
- return replaced;
- } else {
- store.dispatch('showToast', `无法播放 ${track.name}`);
- switch (ifUnplayableThen) {
- case UNPLAYABLE_CONDITION.PLAY_NEXT_TRACK:
- this._playNextTrack(this.isPersonalFM);
- break;
- case UNPLAYABLE_CONDITION.PLAY_PREV_TRACK:
- this.playPrevTrack();
- break;
- default:
- store.dispatch(
- 'showToast',
- `undefined Unplayable condition: ${ifUnplayableThen}`
- );
- break;
- }
- return false;
- }
+ });
});
}
_cacheNextTrack() {
let nextTrackID = this._isPersonalFM
- ? this._personalFMNextTrack?.id ?? 0
+ ? this._personalFMNextTrack.id
: this._getNextTrack()[0];
if (!nextTrackID) return;
if (this._personalFMTrack.id == nextTrackID) return;
@@ -575,7 +347,7 @@ export default class {
this.playPrevTrack();
});
navigator.mediaSession.setActionHandler('nexttrack', () => {
- this._playNextTrack(this.isPersonalFM);
+ this.playNextTrack();
});
navigator.mediaSession.setActionHandler('stop', () => {
this.pause();
@@ -599,51 +371,17 @@ export default class {
return;
}
let artists = track.ar.map(a => a.name);
- const metadata = {
+ navigator.mediaSession.metadata = new window.MediaMetadata({
title: track.name,
artist: artists.join(','),
album: track.al.name,
artwork: [
- {
- src: track.al.picUrl + '?param=224y224',
- type: 'image/jpg',
- sizes: '224x224',
- },
{
src: track.al.picUrl + '?param=512y512',
type: 'image/jpg',
sizes: '512x512',
},
],
- length: this.currentTrackDuration,
- trackId: this.current,
- url: '/trackid/' + track.id,
- };
-
- navigator.mediaSession.metadata = new window.MediaMetadata(metadata);
- if (isCreateMpris) {
- this._updateMprisState(track, metadata);
- }
- }
- // OSDLyrics 会检测 Mpris 状态并寻找对应歌词文件,所以要在更新 Mpris 状态之前保证歌词下载完成
- async _updateMprisState(track, metadata) {
- if (!store.state.settings.enableOsdlyricsSupport) {
- return ipcRenderer?.send('metadata', metadata);
- }
-
- let lyricContent = await getLyric(track.id);
-
- if (!lyricContent.lrc || !lyricContent.lrc.lyric) {
- return ipcRenderer?.send('metadata', metadata);
- }
-
- ipcRenderer.send('sendLyrics', {
- track,
- lyrics: lyricContent.lrc.lyric,
- });
-
- ipcRenderer.on('saveLyricFinished', () => {
- ipcRenderer?.send('metadata', metadata);
});
}
_updateMediaSessionPositionState() {
@@ -661,32 +399,17 @@ export default class {
_nextTrackCallback() {
this._scrobble(this._currentTrack, 0, true);
if (!this.isPersonalFM && this.repeatMode === 'one') {
- this._replaceCurrentTrack(this.currentTrackID);
+ this._replaceCurrentTrack(this._currentTrack.id);
} else {
- this._playNextTrack(this.isPersonalFM);
+ this.playNextTrack();
}
}
_loadPersonalFMNextTrack() {
- if (this._personalFMNextLoading) {
- return [false, undefined];
- }
- this._personalFMNextLoading = true;
- return personalFM()
- .then(result => {
- if (!result || !result.data) {
- this._personalFMNextTrack = undefined;
- } else {
- this._personalFMNextTrack = result.data[0];
- this._cacheNextTrack(); // cache next track
- }
- this._personalFMNextLoading = false;
- return [true, this._personalFMNextTrack];
- })
- .catch(() => {
- this._personalFMNextTrack = undefined;
- this._personalFMNextLoading = false;
- return [false, this._personalFMNextTrack];
- });
+ return personalFM().then(result => {
+ this._personalFMNextTrack = result.data[0];
+ this._cacheNextTrack(); // cache next track
+ return this._personalFMNextTrack;
+ });
}
_playDiscordPresence(track, seekTime = 0) {
if (
@@ -697,7 +420,7 @@ export default class {
}
let copyTrack = { ...track };
copyTrack.dt -= seekTime * 1000;
- ipcRenderer?.send('playDiscordPresence', copyTrack);
+ ipcRenderer.send('playDiscordPresence', copyTrack);
}
_pauseDiscordPresence(track) {
if (
@@ -706,96 +429,46 @@ export default class {
) {
return null;
}
- ipcRenderer?.send('pauseDiscordPresence', track);
- }
- _playNextTrack(isPersonal) {
- if (isPersonal) {
- this.playNextFMTrack();
- } else {
- this.playNextTrack();
- }
+ ipcRenderer.send('pauseDiscordPresence', track);
}
+ currentTrackID() {
+ const { list, current } = this._getListAndCurrent();
+ return list[current];
+ }
appendTrack(trackID) {
this.list.append(trackID);
}
- playNextTrack() {
+ playNextTrack(isFM = false) {
+ if (this._isPersonalFM || isFM === true) {
+ this._isPersonalFM = true;
+ this._personalFMTrack = this._personalFMNextTrack;
+ this._replaceCurrentTrack(this._personalFMTrack.id);
+ this._loadPersonalFMNextTrack();
+ return true;
+ }
// TODO: 切换歌曲时增加加载中的状态
const [trackID, index] = this._getNextTrack();
if (trackID === undefined) {
this._howler?.stop();
- this._setPlaying(false);
+ this._playing = false;
return false;
}
- let next = index;
- if (index === INDEX_IN_PLAY_NEXT) {
- this._playNextList.shift();
- next = this.current;
- }
- this.current = next;
+ this.current = index;
this._replaceCurrentTrack(trackID);
return true;
}
- async playNextFMTrack() {
- if (this._personalFMLoading) {
- return false;
- }
-
- this._isPersonalFM = true;
- if (!this._personalFMNextTrack) {
- this._personalFMLoading = true;
- let result = null;
- let retryCount = 5;
- for (; retryCount >= 0; retryCount--) {
- result = await personalFM().catch(() => null);
- if (!result) {
- this._personalFMLoading = false;
- store.dispatch('showToast', 'personal fm timeout');
- return false;
- }
- if (result.data?.length > 0) {
- break;
- } else if (retryCount > 0) {
- await delay(1000);
- }
- }
- this._personalFMLoading = false;
-
- if (retryCount < 0) {
- let content = '获取私人FM数据时重试次数过多,请手动切换下一首';
- store.dispatch('showToast', content);
- console.log(content);
- return false;
- }
- // 这里只能拿到一条数据
- this._personalFMTrack = result.data[0];
- } else {
- if (this._personalFMNextTrack.id === this._personalFMTrack.id) {
- return false;
- }
- this._personalFMTrack = this._personalFMNextTrack;
- }
- if (this._isPersonalFM) {
- this._replaceCurrentTrack(this._personalFMTrack.id);
- }
- this._loadPersonalFMNextTrack();
- return true;
- }
playPrevTrack() {
const [trackID, index] = this._getPrevTrack();
if (trackID === undefined) return false;
this.current = index;
- this._replaceCurrentTrack(
- trackID,
- true,
- UNPLAYABLE_CONDITION.PLAY_PREV_TRACK
- );
+ this._replaceCurrentTrack(trackID, true, 'playPrevTrack');
return true;
}
saveSelfToLocalStorage() {
let player = {};
for (let [key, value] of Object.entries(this)) {
- if (excludeSaveKeys.includes(key)) continue;
+ if (key === '_playing') continue;
player[key] = value;
}
@@ -803,41 +476,26 @@ export default class {
}
pause() {
- this._howler?.fade(this.volume, 0, PLAY_PAUSE_FADE_DURATION);
-
- this._howler?.once('fade', () => {
- this._howler?.pause();
- this._setPlaying(false);
- setTitle(null);
- this._pauseDiscordPresence(this._currentTrack);
- });
+ this._howler?.pause();
+ this._playing = false;
+ document.title = 'YesPlayMusic';
+ this._pauseDiscordPresence(this._currentTrack);
}
play() {
if (this._howler?.playing()) return;
-
this._howler?.play();
-
- this._howler?.once('play', () => {
- this._howler?.fade(0, this.volume, PLAY_PAUSE_FADE_DURATION);
-
- // 播放时确保开启player.
- // 避免因"忘记设置"导致在播放时播放器不显示的Bug
- this._enabled = true;
- this._setPlaying(true);
- if (this._currentTrack.name) {
- setTitle(this._currentTrack);
- }
- this._playDiscordPresence(this._currentTrack, this.seek());
- if (store.state.lastfm.key !== undefined) {
- trackUpdateNowPlaying({
- artist: this.currentTrack.ar[0].name,
- track: this.currentTrack.name,
- album: this.currentTrack.al.name,
- trackNumber: this.currentTrack.no,
- duration: ~~(this.currentTrack.dt / 1000),
- });
- }
- });
+ this._playing = true;
+ document.title = `${this._currentTrack.name} · ${this._currentTrack.ar[0].name} - YesPlayMusic`;
+ this._playDiscordPresence(this._currentTrack, this.seek());
+ if (store.state.lastfm.key !== undefined) {
+ trackUpdateNowPlaying({
+ artist: this.currentTrack.ar[0].name,
+ track: this.currentTrack.name,
+ album: this.currentTrack.al.name,
+ trackNumber: this.currentTrack.no,
+ duration: ~~(this.currentTrack.dt / 1000),
+ });
+ }
}
playOrPause() {
if (this._howler?.playing()) {
@@ -846,14 +504,11 @@ export default class {
this.play();
}
}
- seek(time = null, sendMpris = true) {
- if (isCreateMpris && sendMpris && time) {
- ipcRenderer?.send('seeked', time);
- }
+ seek(time = null) {
if (time !== null) {
this._howler?.seek(time);
if (this._playing)
- this._playDiscordPresence(this._currentTrack, this.seek(null, false));
+ this._playDiscordPresence(this._currentTrack, this.seek());
}
return this._howler === null ? 0 : this._howler.seek();
}
@@ -879,6 +534,7 @@ export default class {
autoPlayTrackID = 'first'
) {
this._isPersonalFM = false;
+ if (!this._enabled) this._enabled = true;
this.list = trackIDs;
this.current = 0;
this._playlistSource = {
@@ -889,7 +545,7 @@ export default class {
if (autoPlayTrackID === 'first') {
this._replaceCurrentTrack(this.list[0]);
} else {
- this.current = this.list.indexOf(autoPlayTrackID);
+ this.current = trackIDs.indexOf(autoPlayTrackID);
this._replaceCurrentTrack(autoPlayTrackID);
}
}
@@ -920,48 +576,33 @@ export default class {
}
this._replaceCurrentTrack(id);
}
- playIntelligenceListById(id, trackID = 'first', noCache = false) {
- getPlaylistDetail(id, noCache).then(data => {
- const randomId = Math.floor(
- Math.random() * (data.playlist.trackIds.length + 1)
- );
- const songId = data.playlist.trackIds[randomId].id;
- intelligencePlaylist({ id: songId, pid: id }).then(result => {
- let trackIDs = result.data.map(t => t.id);
- this.replacePlaylist(trackIDs, id, 'playlist', trackID);
- });
- });
- }
addTrackToPlayNext(trackID, playNow = false) {
this._playNextList.push(trackID);
- if (playNow) {
- this.playNextTrack();
- }
+ if (playNow) this.playNextTrack();
}
playPersonalFM() {
this._isPersonalFM = true;
- if (this.currentTrackID !== this._personalFMTrack.id) {
- this._replaceCurrentTrack(this._personalFMTrack.id, true);
+ if (!this._enabled) this._enabled = true;
+ if (this._currentTrack.id !== this._personalFMTrack.id) {
+ this._replaceCurrentTrack(this._personalFMTrack.id).then(() =>
+ this.playOrPause()
+ );
} else {
this.playOrPause();
}
}
- async moveToFMTrash() {
+ moveToFMTrash() {
this._isPersonalFM = true;
- let id = this._personalFMTrack.id;
- if (await this.playNextFMTrack()) {
- fmTrash(id);
- }
+ this.playNextTrack();
+ fmTrash(this._personalFMTrack.id);
}
sendSelfToIpcMain() {
if (process.env.IS_ELECTRON !== true) return false;
- let liked = store.state.liked.songs.includes(this.currentTrack.id);
- ipcRenderer?.send('player', {
+ ipcRenderer.send('player', {
playing: this.playing,
- likedCurrentTrack: liked,
+ likedCurrentTrack: store.state.liked.songs.includes(this.currentTrack.id),
});
- setTrayLikeState(liked);
}
switchRepeatMode() {
@@ -972,18 +613,9 @@ export default class {
} else {
this.repeatMode = 'on';
}
- if (isCreateMpris) {
- ipcRenderer?.send('switchRepeatMode', this.repeatMode);
- }
}
switchShuffle() {
this.shuffle = !this.shuffle;
- if (isCreateMpris) {
- ipcRenderer?.send('switchShuffle', this.shuffle);
- }
- }
- switchReversed() {
- this.reversed = !this.reversed;
}
clearPlayNextList() {
diff --git a/src/utils/base64.js b/src/utils/base64.js
deleted file mode 100644
index 99ac23c..0000000
--- a/src/utils/base64.js
+++ /dev/null
@@ -1,67 +0,0 @@
-// https://github.com/niklasvh/base64-arraybuffer/blob/master/src/index.ts
-// Copyright (c) 2012 Niklas von Hertzen Licensed under the MIT license.
-
-const chars =
- 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
-
-// Use a lookup table to find the index.
-const lookup = typeof Uint8Array === 'undefined' ? [] : new Uint8Array(256);
-for (let i = 0; i < chars.length; i++) {
- lookup[chars.charCodeAt(i)] = i;
-}
-
-export const encode = arraybuffer => {
- let bytes = new Uint8Array(arraybuffer),
- i,
- len = bytes.length,
- base64 = '';
-
- for (i = 0; i < len; i += 3) {
- base64 += chars[bytes[i] >> 2];
- base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)];
- base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)];
- base64 += chars[bytes[i + 2] & 63];
- }
-
- if (len % 3 === 2) {
- base64 = base64.substring(0, base64.length - 1) + '=';
- } else if (len % 3 === 1) {
- base64 = base64.substring(0, base64.length - 2) + '==';
- }
-
- return base64;
-};
-
-export const decode = base64 => {
- let bufferLength = base64.length * 0.75,
- len = base64.length,
- i,
- p = 0,
- encoded1,
- encoded2,
- encoded3,
- encoded4;
-
- if (base64[base64.length - 1] === '=') {
- bufferLength--;
- if (base64[base64.length - 2] === '=') {
- bufferLength--;
- }
- }
-
- const arraybuffer = new ArrayBuffer(bufferLength),
- bytes = new Uint8Array(arraybuffer);
-
- for (i = 0; i < len; i += 4) {
- encoded1 = lookup[base64.charCodeAt(i)];
- encoded2 = lookup[base64.charCodeAt(i + 1)];
- encoded3 = lookup[base64.charCodeAt(i + 2)];
- encoded4 = lookup[base64.charCodeAt(i + 3)];
-
- bytes[p++] = (encoded1 << 2) | (encoded2 >> 4);
- bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2);
- bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63);
- }
-
- return arraybuffer;
-};
diff --git a/src/utils/checkAuthToken.js b/src/utils/checkAuthToken.js
deleted file mode 100644
index 1086521..0000000
--- a/src/utils/checkAuthToken.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import os from 'os';
-import fs from 'fs';
-import path from 'path';
-
-// extract from NeteasyCloudMusicAPI/generateConfig.js and avoid bugs in there (generateConfig require main.js but the main.js has bugs)
-if (!fs.existsSync(path.resolve(os.tmpdir(), 'anonymous_token'))) {
- fs.writeFileSync(path.resolve(os.tmpdir(), 'anonymous_token'), '', 'utf-8');
-}
diff --git a/src/utils/common.js b/src/utils/common.js
index a89d500..b7f2355 100644
--- a/src/utils/common.js
+++ b/src/utils/common.js
@@ -9,9 +9,6 @@ export function isTrackPlayable(track) {
playable: true,
reason: '',
};
- if (track?.privilege?.pl > 0) {
- return result;
- }
// cloud storage judgement logic
if (isAccountLoggedIn() && track?.privilege?.cs) {
return result;
@@ -221,7 +218,7 @@ export function bytesToSize(bytes) {
export function formatTrackTime(value) {
if (!value) return '';
- let min = ~~(value / 60);
+ let min = ~~((value / 60) % 60);
let sec = (~~(value % 60)).toString().padStart(2, '0');
return `${min}:${sec}`;
}
diff --git a/src/utils/lyrics.js b/src/utils/lyrics.js
index b883f46..f0ed888 100644
--- a/src/utils/lyrics.js
+++ b/src/utils/lyrics.js
@@ -1,113 +1,33 @@
+// copy from https://github.com/sl1673495/vue-netease-music/blob/master/src/utils/lrcparse.js
+
export function lyricParser(lrc) {
return {
lyric: parseLyric(lrc?.lrc?.lyric || ''),
tlyric: parseLyric(lrc?.tlyric?.lyric || ''),
- romalyric: parseLyric(lrc?.romalrc?.lyric || ''),
lyricuser: lrc.lyricUser,
transuser: lrc.transUser,
};
}
-// regexr.com/6e52n
-const extractLrcRegex =
- /^(?(?:\[.+?\])+)(?!\[)(?.+)$/gm;
-const extractTimestampRegex =
- /\[(?\d+):(?\d+)(?:\.|:)*(?\d+)*\]/g;
-
-/**
- * @typedef {{time: number, rawTime: string, content: string}} ParsedLyric
- */
-
-/**
- * Parse the lyric string.
- *
- * @param {string} lrc The `lrc` input.
- * @returns {ParsedLyric[]} The parsed lyric.
- * @example parseLyric("[00:00.00] Hello, World!\n[00:00.10] Test\n");
- */
-function parseLyric(lrc) {
- /**
- * A sorted list of parsed lyric and its timestamp.
- *
- * @type {ParsedLyric[]}
- * @see binarySearch
- */
- const parsedLyrics = [];
-
- /**
- * Find the appropriate index to push our parsed lyric.
- * @param {ParsedLyric} lyric
- */
- const binarySearch = lyric => {
- let time = lyric.time;
-
- let low = 0;
- let high = parsedLyrics.length - 1;
-
- while (low <= high) {
- const mid = Math.floor((low + high) / 2);
- const midTime = parsedLyrics[mid].time;
- if (midTime === time) {
- return mid;
- } else if (midTime < time) {
- low = mid + 1;
- } else {
- high = mid - 1;
+export function parseLyric(lrc) {
+ const lyrics = lrc.split('\n');
+ const lrcObj = [];
+ for (let i = 0; i < lyrics.length; i++) {
+ const lyric = lyrics[i];
+ const timeReg = /\[\d*:\d*((\.|:)\d*)*\]/g;
+ const timeRegExpArr = lyric.match(timeReg);
+ if (!timeRegExpArr) continue;
+ const content = lyric.replace(timeReg, '');
+ for (let k = 0, h = timeRegExpArr.length; k < h; k++) {
+ const t = timeRegExpArr[k];
+ const min = Number(String(t.match(/\[\d*/i)).slice(1));
+ const sec = Number(String(t.match(/:\d*/i)).slice(1));
+ const ms = Number(t.match(/\d*\]/i)[0].slice(0, 2)) / 100;
+ const time = min * 60 + sec + ms;
+ if (content !== '') {
+ lrcObj.push({ time: time, rawTime: timeRegExpArr[0], content });
}
}
-
- return low;
- };
-
- for (const line of lrc.trim().matchAll(extractLrcRegex)) {
- const { lyricTimestamps, content } = line.groups;
-
- for (const timestamp of lyricTimestamps.matchAll(extractTimestampRegex)) {
- const { min, sec, ms } = timestamp.groups;
- const rawTime = timestamp[0];
- const time = Number(min) * 60 + Number(sec) + Number(ms ?? 0) * 0.001;
-
- /** @type {ParsedLyric} */
- const parsedLyric = { rawTime, time, content: trimContent(content) };
- parsedLyrics.splice(binarySearch(parsedLyric), 0, parsedLyric);
- }
- }
-
- return parsedLyrics;
-}
-
-/**
- * @param {string} content
- * @returns {string}
- */
-function trimContent(content) {
- let t = content.trim();
- return t.length < 1 ? content : t;
-}
-
-/**
- * @param {string} lyric
- */
-export async function copyLyric(lyric) {
- const textToCopy = lyric;
- if (navigator.clipboard && navigator.clipboard.writeText) {
- try {
- await navigator.clipboard.writeText(textToCopy);
- } catch (err) {
- alert('复制失败,请手动复制!');
- }
- } else {
- const tempInput = document.createElement('textarea');
- tempInput.value = textToCopy;
- tempInput.style.position = 'absolute';
- tempInput.style.left = '-9999px';
- document.body.appendChild(tempInput);
- tempInput.select();
- try {
- document.execCommand('copy');
- } catch (err) {
- alert('复制失败,请手动复制!');
- }
- document.body.removeChild(tempInput);
}
+ return lrcObj;
}
diff --git a/src/utils/nativeAlert.js b/src/utils/nativeAlert.js
index 123cc70..64e716b 100644
--- a/src/utils/nativeAlert.js
+++ b/src/utils/nativeAlert.js
@@ -13,12 +13,14 @@
*/
const nativeAlert = (() => {
if (process.env.IS_ELECTRON === true) {
- const { dialog } = require('electron');
+ const {
+ remote: { dialog },
+ } = require('electron');
if (dialog) {
return message => {
var options = {
type: 'warning',
- message,
+ detail: message,
};
dialog.showMessageBoxSync(null, options);
};
diff --git a/src/utils/platform.js b/src/utils/platform.js
deleted file mode 100644
index c386d8a..0000000
--- a/src/utils/platform.js
+++ /dev/null
@@ -1,7 +0,0 @@
-export const isWindows = process.platform === 'win32';
-export const isMac = process.platform === 'darwin';
-export const isLinux = process.platform === 'linux';
-export const isDevelopment = process.env.NODE_ENV === 'development';
-
-export const isCreateTray = isWindows || isLinux || isDevelopment;
-export const isCreateMpris = isLinux;
diff --git a/src/utils/playList.js b/src/utils/playList.js
deleted file mode 100644
index d135fc3..0000000
--- a/src/utils/playList.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import router from '../router';
-import state from '../store/state';
-import {
- recommendPlaylist,
- dailyRecommendPlaylist,
- getPlaylistDetail,
-} from '@/api/playlist';
-import { isAccountLoggedIn } from '@/utils/auth';
-
-export function hasListSource() {
- return !state.player.isPersonalFM && state.player.playlistSource.id !== 0;
-}
-
-export function goToListSource() {
- router.push({ path: getListSourcePath() });
-}
-
-export function getListSourcePath() {
- if (state.player.playlistSource.id === state.data.likedSongPlaylistID) {
- return '/library/liked-songs';
- } else if (state.player.playlistSource.type === 'url') {
- return state.player.playlistSource.id;
- } else if (state.player.playlistSource.type === 'cloudDisk') {
- return '/library';
- } else {
- return `/${state.player.playlistSource.type}/${state.player.playlistSource.id}`;
- }
-}
-
-export async function getRecommendPlayList(limit, removePrivateRecommand) {
- if (isAccountLoggedIn()) {
- const playlists = await Promise.all([
- dailyRecommendPlaylist(),
- recommendPlaylist({ limit }),
- ]);
- let recommend = playlists[0].recommend ?? [];
- if (recommend.length) {
- if (removePrivateRecommand) recommend = recommend.slice(1);
- await replaceRecommendResult(recommend);
- }
- return recommend.concat(playlists[1].result).slice(0, limit);
- } else {
- const response = await recommendPlaylist({ limit });
- return response.result;
- }
-}
-
-async function replaceRecommendResult(recommend) {
- for (let r of recommend) {
- if (specialPlaylist.indexOf(r.id) > -1) {
- const data = await getPlaylistDetail(r.id, true);
- const playlist = data.playlist;
- if (playlist) {
- r.name = playlist.name;
- r.picUrl = playlist.coverImgUrl;
- }
- }
- }
-}
-
-const specialPlaylist = [3136952023, 2829883282, 2829816518, 2829896389];
diff --git a/src/utils/request.js b/src/utils/request.js
index 6ac7bc3..6eae75c 100644
--- a/src/utils/request.js
+++ b/src/utils/request.js
@@ -1,6 +1,5 @@
-import router from '@/router';
-import { doLogout, getCookie } from '@/utils/auth';
import axios from 'axios';
+import { getCookie } from '@/utils/auth';
let baseURL = '';
// Web 和 Electron 跑在不同端口避免同时启动时冲突
@@ -22,33 +21,14 @@ const service = axios.create({
service.interceptors.request.use(function (config) {
if (!config.params) config.params = {};
- if (baseURL.length) {
- if (
- baseURL[0] !== '/' &&
- !process.env.IS_ELECTRON &&
- getCookie('MUSIC_U') !== null
- ) {
- config.params.cookie = `MUSIC_U=${getCookie('MUSIC_U')};`;
- }
- } else {
- console.error("You must set up the baseURL in the service's config");
+ if (baseURL[0] !== '/' && !process.env.IS_ELECTRON) {
+ config.params.cookie = `MUSIC_U=${getCookie('MUSIC_U')};`;
}
if (!process.env.IS_ELECTRON && !config.url.includes('/login')) {
config.params.realIP = '211.161.244.70';
}
- // Force real_ip
- const enableRealIP = JSON.parse(
- localStorage.getItem('settings')
- ).enableRealIP;
- const realIP = JSON.parse(localStorage.getItem('settings')).realIP;
- if (process.env.VUE_APP_REAL_IP) {
- config.params.realIP = process.env.VUE_APP_REAL_IP;
- } else if (enableRealIP) {
- config.params.realIP = realIP;
- }
-
const proxy = JSON.parse(localStorage.getItem('settings')).proxyConfig;
if (['HTTP', 'HTTPS'].includes(proxy.protocol)) {
config.params.proxy = `${proxy.protocol}://${proxy.server}:${proxy.port}`;
@@ -62,37 +42,8 @@ service.interceptors.response.use(
const res = response.data;
return res;
},
- async error => {
- /** @type {import('axios').AxiosResponse | null} */
- let response;
- let data;
- if (error === 'TypeError: baseURL is undefined') {
- response = error;
- data = error;
- console.error("You must set up the baseURL in the service's config");
- } else if (error.response) {
- response = error.response;
- data = response.data;
- }
-
- if (
- response &&
- typeof data === 'object' &&
- data.code === 301 &&
- data.msg === '需要登录'
- ) {
- console.warn('Token has expired. Logout now!');
-
- // 登出帳戶
- doLogout();
-
- // 導向登入頁面
- if (process.env.IS_ELECTRON === true) {
- router.push({ name: 'loginAccount' });
- } else {
- router.push({ name: 'login' });
- }
- }
+ error => {
+ return Promise.reject(error);
}
);
diff --git a/src/views/album.vue b/src/views/album.vue
index acc8a40..cebd8df 100644
--- a/src/views/album.vue
+++ b/src/views/album.vue
@@ -28,9 +28,7 @@
Compilation by Various Artists
-
{{
@@ -73,12 +71,12 @@
-
-
-
Disc {{ item.disc }}
+
+
+
Disc {{ cd }}
@@ -98,7 +96,9 @@
{{ $t('album.released') }}
{{ album.publishTime | formatDate('MMMM D, YYYY') }}
-
© {{ album.company }}
+
+ © {{ album.company }}
+
@@ -137,9 +137,6 @@
{{
$t('contextMenu.copyUrl')
}}
-
{{
- $t('contextMenu.openInBrowser')
- }}
@@ -153,7 +150,7 @@ import locale from '@/locale';
import { splitSoundtrackAlbumTitle, splitAlbumTitle } from '@/utils/common';
import NProgress from 'nprogress';
import { isAccountLoggedIn } from '@/utils/auth';
-import { groupBy, toPairs, sortBy } from 'lodash';
+import { groupBy } from 'lodash';
import ExplicitSymbol from '@/components/ExplicitSymbol.vue';
import ButtonTwoTone from '@/components/ButtonTwoTone.vue';
@@ -222,12 +219,7 @@ export default {
}
},
tracksByDisc() {
- if (this.tracks.length <= 1) return [];
- const pairs = toPairs(groupBy(this.tracks, 'cd'));
- return sortBy(pairs, p => p[0]).map(items => ({
- disc: items[0],
- tracks: items[1],
- }));
+ return groupBy(this.tracks, 'cd');
},
},
created() {
@@ -313,7 +305,7 @@ export default {
},
copyUrl(id) {
let showToast = this.showToast;
- this.$copyText(`https://music.163.com/#/album?id=${id}`)
+ this.$copyText('https://music.163.com/#/album?id=' + id)
.then(function () {
showToast(locale.t('toast.copied'));
})
@@ -321,10 +313,6 @@ export default {
showToast(`${locale.t('toast.copyFailed')}${error}`);
});
},
- openInBrowser(id) {
- const url = `https://music.163.com/#/album?id=${id}`;
- window.open(url);
- },
},
};
@@ -390,9 +378,6 @@ export default {
}
}
}
-.disc {
- color: var(--color-text);
-}
.explicit-symbol {
opacity: 0.28;
diff --git a/src/views/artist.vue b/src/views/artist.vue
index d825436..0f0721d 100644
--- a/src/views/artist.vue
+++ b/src/views/artist.vue
@@ -2,7 +2,7 @@
-
![]()
+
{{ artist.name }}
@@ -75,7 +75,7 @@
@mouseleave="mvHover = false"
@click="goToMv(latestMV.id)"
>
-
![]()
+
MVs
- {{
+ {{
$t('home.seeMore')
}}
@@ -169,9 +169,6 @@
{{
$t('contextMenu.copyUrl')
}}
-
{{
- $t('contextMenu.openInBrowser')
- }}
@@ -185,7 +182,6 @@ import {
followAArtist,
similarArtists,
} from '@/api/artist';
-import { getTrackDetail } from '@/api/track';
import locale from '@/locale';
import { isAccountLoggedIn } from '@/utils/auth';
import NProgress from 'nprogress';
@@ -242,9 +238,7 @@ export default {
computed: {
...mapState(['player']),
albums() {
- return this.albumsData.filter(
- a => a.type === '专辑' || a.type === '精选集'
- );
+ return this.albumsData.filter(a => a.type === '专辑');
},
eps() {
return this.albumsData.filter(a =>
@@ -279,7 +273,7 @@ export default {
this.$parent.$refs.main.scrollTo({ top: 0 });
getArtist(id).then(data => {
this.artist = data.artist;
- this.setPopularTracks(data.hotSongs);
+ this.popularTracks = data.hotSongs;
if (next !== undefined) next();
NProgress.done();
this.show = true;
@@ -292,16 +286,8 @@ export default {
this.mvs = data.mvs;
this.hasMoreMV = data.hasMore;
});
- if (isAccountLoggedIn()) {
- similarArtists(id).then(data => {
- this.similarArtists = data.artists;
- });
- }
- },
- setPopularTracks(hotSongs) {
- const trackIDs = hotSongs.map(t => t.id);
- getTrackDetail(trackIDs.join(',')).then(data => {
- this.popularTracks = data.songs;
+ similarArtists(id).then(data => {
+ this.similarArtists = data.artists;
});
},
goToAlbum(id) {
@@ -353,7 +339,7 @@ export default {
},
copyUrl(id) {
let showToast = this.showToast;
- this.$copyText(`https://music.163.com/#/artist?id=${id}`)
+ this.$copyText('https://music.163.com/#/artist?id=' + id)
.then(function () {
showToast(locale.t('toast.copied'));
})
@@ -361,10 +347,6 @@ export default {
showToast(`${locale.t('toast.copyFailed')}${error}`);
});
},
- openInBrowser(id) {
- const url = `https://music.163.com/#/artist?id=${id}`;
- window.open(url);
- },
},
};
diff --git a/src/views/artistMV.vue b/src/views/artistMV.vue
index ba0a8c1..69a7f35 100644
--- a/src/views/artistMV.vue
+++ b/src/views/artistMV.vue
@@ -1,11 +1,9 @@
-
{{ artist.name }}'s Music Videos
+
{{
+ artist.name
+ }}'s Music Videos
diff --git a/src/views/explore.vue b/src/views/explore.vue
index 90624d0..b41b0a3 100644
--- a/src/views/explore.vue
+++ b/src/views/explore.vue
@@ -66,9 +66,13 @@
@@ -762,20 +472,6 @@ export default {
z-index: 1;
- .date {
- max-width: 54vh;
- margin: 24px 0;
- color: var(--color-text);
- text-align: center;
- font-size: 4rem;
- font-weight: 600;
- opacity: 0.88;
- display: -webkit-box;
- -webkit-box-orient: vertical;
- -webkit-line-clamp: 1;
- overflow: hidden;
- }
-
.controls {
max-width: 54vh;
margin-top: 24px;
@@ -806,31 +502,17 @@ export default {
display: flex;
justify-content: space-between;
- .top-right {
+ .buttons {
display: flex;
- justify-content: space-between;
+ align-items: center;
- .volume-control {
- margin: 0 10px;
- display: flex;
- align-items: center;
- .volume-bar {
- width: 84px;
- }
+ button {
+ margin: 0 0 0 4px;
}
- .buttons {
- display: flex;
- align-items: center;
-
- button {
- margin: 0 0 0 4px;
- }
-
- .svg-icon {
- height: 18px;
- width: 18px;
- }
+ .svg-icon {
+ height: 18px;
+ width: 18px;
}
}
}
@@ -895,12 +577,6 @@ export default {
width: 22px;
}
}
- .lyric-switch-icon {
- color: var(--color-text);
- font-size: 14px;
- line-height: 14px;
- opacity: 0.88;
- }
}
}
}
@@ -948,35 +624,19 @@ export default {
max-width: 460px;
overflow-y: auto;
transition: 0.5s;
- scrollbar-width: none; // firefox
.line {
- margin: 2px 0;
- padding: 12px 18px;
- transition: 0.5s;
+ padding: 18px;
+ transition: 0.2s;
border-radius: 12px;
&:hover {
background: var(--color-secondary-bg-for-transparent);
}
- .content {
- transform-origin: center left;
- transform: scale(0.95);
- transition: all 0.35s cubic-bezier(0.25, 0.46, 0.45, 0.94);
- user-select: none;
-
- span {
- opacity: 0.28;
- cursor: default;
- font-size: 1em;
- transition: all 0.35s cubic-bezier(0.25, 0.46, 0.45, 0.94);
- }
-
- span.translation {
- opacity: 0.2;
- font-size: 0.925em;
- }
+ span {
+ opacity: 0.28;
+ cursor: default;
}
}
@@ -984,20 +644,9 @@ export default {
background: unset;
}
- .translation {
- margin-top: 0.1em;
- }
-
- .highlight div.content {
- transform: scale(1);
- span {
- opacity: 0.98;
- display: inline-block;
- }
-
- span.translation {
- opacity: 0.65;
- }
+ .highlight span {
+ opacity: 0.98;
+ transition: 0.5s;
}
}
@@ -1059,12 +708,6 @@ export default {
}
}
-@media screen and (min-width: 1200px) {
- .right-side .lyrics-container {
- max-width: 600px;
- }
-}
-
.slide-up-enter-active,
.slide-up-leave-active {
transition: all 0.4s;
diff --git a/src/views/mv.vue b/src/views/mv.vue
index 54dd544..c060df7 100644
--- a/src/views/mv.vue
+++ b/src/views/mv.vue
@@ -11,14 +11,11 @@
}}
-
{{ mv.data.name }}
-
@@ -31,14 +28,6 @@
{{ $t('mv.moreVideo') }}
-
- {{
- $t('contextMenu.copyUrl')
- }}
- {{
- $t('contextMenu.openInBrowser')
- }}
-
@@ -51,7 +40,6 @@ import '@/assets/css/plyr.css';
import Plyr from 'plyr';
import ButtonIcon from '@/components/ButtonIcon.vue';
-import ContextMenu from '@/components/ContextMenu.vue';
import MvRow from '@/components/MvRow.vue';
import { mapActions } from 'vuex';
@@ -60,7 +48,6 @@ export default {
components: {
MvRow,
ButtonIcon,
- ContextMenu,
},
beforeRouteUpdate(to, from, next) {
this.getData(to.params.id);
@@ -140,23 +127,6 @@ export default {
if (data.code === 200) this.mv.subed = !this.mv.subed;
});
},
- openMenu(e) {
- this.$refs.mvMenu.openMenu(e);
- },
- copyUrl(id) {
- let showToast = this.showToast;
- this.$copyText(`https://music.163.com/#/mv?id=${id}`)
- .then(function () {
- showToast(locale.t('toast.copied'));
- })
- .catch(error => {
- showToast(`${locale.t('toast.copyFailed')}${error}`);
- });
- },
- openInBrowser(id) {
- const url = `https://music.163.com/#/mv?id=${id}`;
- window.open(url);
- },
},
};
@@ -211,11 +181,8 @@ export default {
}
}
-.buttons {
+.like-button {
display: inline-block;
- .button {
- display: inline-block;
- }
.svg-icon {
height: 18px;
width: 18px;
diff --git a/src/views/next.vue b/src/views/next.vue
index 0f31462..3dacf03 100644
--- a/src/views/next.vue
+++ b/src/views/next.vue
@@ -57,9 +57,7 @@ export default {
this.player.current + 1,
this.player.current + 100
);
- return trackIDs
- .map(tid => this.tracks.find(t => t.id === tid))
- .filter(t => t);
+ return this.tracks.filter(t => trackIDs.includes(t.id));
},
playNextList() {
return this.player.playNextList;
diff --git a/src/views/playlist.vue b/src/views/playlist.vue
index f735b84..53b04d4 100644
--- a/src/views/playlist.vue
+++ b/src/views/playlist.vue
@@ -27,7 +27,11 @@
-
- {{ data.user.nickname }}{{ $t('library.sLikedSongs') }}
+
{{
+ data.user.nickname
+ }}{{ $t('library.sLikedSongs') }}
@@ -318,10 +319,6 @@ const specialPlaylist = {
name: '一周原创发现',
gradient: 'gradient-blue-purple',
},
- 2829883282: {
- name: '华语私人雷达',
- gradient: 'gradient-yellow-red',
- },
3136952023: {
name: '私人雷达',
gradient: 'gradient-radar',
diff --git a/src/views/settings.vue b/src/views/settings.vue
index 2fb0063..d4b7046 100644
--- a/src/views/settings.vue
+++ b/src/views/settings.vue
@@ -3,7 +3,7 @@
-
![]()
+