diff --git a/netease_api b/netease_api deleted file mode 160000 index c32bf8b..0000000 --- a/netease_api +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c32bf8b69728bcc52659862c9349bff9a6c5fc28 diff --git a/netease_api/.editorconfig b/netease_api/.editorconfig new file mode 100644 index 0000000..6c725ce --- /dev/null +++ b/netease_api/.editorconfig @@ -0,0 +1,34 @@ + +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true + +# Matches multiple files with brace expansion notation +# Set default charset +[*.{js,py}] +charset = utf-8 + +# 4 space indentation +[*.py] +indent_style = space +indent_size = 4 + +# Tab indentation (no size specified) +[Makefile] +indent_style = tab + +# Indentation override for all JS under lib directory +[*.{js,ts}] +indent_style = space +indent_size = 2 + +# Matches the exact files either package.json or .travis.yml +[{package.json,.travis.yml}] +indent_style = space +indent_size = 2 \ No newline at end of file diff --git a/netease_api/.eslintrc.js b/netease_api/.eslintrc.js new file mode 100644 index 0000000..06d0c5a --- /dev/null +++ b/netease_api/.eslintrc.js @@ -0,0 +1,49 @@ +module.exports = { + root: true, + parserOptions: { + parser: 'babel-eslint', + ecmaVersion: 2018, + sourceType: 'module', + }, + plugins: ['html'], + extends: ['plugin:prettier/recommended'], + env: { + browser: true, + node: true, + }, + + rules: { + indent: ['error', 2, { SwitchCase: 1 }], + 'space-infix-ops': ['error', { int32Hint: false }], + 'key-spacing': [ + 2, + { + beforeColon: false, + afterColon: true, + }, + ], + 'no-octal': 2, + 'no-redeclare': 2, + 'comma-spacing': 2, + 'no-new-object': 2, + 'arrow-spacing': 2, + quotes: [ + 2, + 'single', + { + avoidEscape: true, + allowTemplateLiterals: true, + }, + ], + }, + overrides: [ + { + files: ['**/*.ts'], + parser: '@typescript-eslint/parser', + extends: [ + 'plugin:@typescript-eslint/recommended', // Uses the recommended rules from the @typescript-eslint/eslint-plugin + 'prettier/@typescript-eslint', + ], + }, + ], +} diff --git a/netease_api/.gitignore b/netease_api/.gitignore new file mode 100644 index 0000000..f284b53 --- /dev/null +++ b/netease_api/.gitignore @@ -0,0 +1,5 @@ +.DS_Store +node_modules +*.log +.idea +.vscode \ No newline at end of file diff --git a/netease_api/.npmignore b/netease_api/.npmignore new file mode 100644 index 0000000..1d6a290 --- /dev/null +++ b/netease_api/.npmignore @@ -0,0 +1,4 @@ +static +docs +node_modules +module_example diff --git a/netease_api/.prettierrc b/netease_api/.prettierrc new file mode 100644 index 0000000..05c968c --- /dev/null +++ b/netease_api/.prettierrc @@ -0,0 +1,5 @@ +{ + "semi": false, + "trailingComma": "all", + "singleQuote": true +} diff --git a/netease_api/.travis.yml b/netease_api/.travis.yml new file mode 100644 index 0000000..6e72888 --- /dev/null +++ b/netease_api/.travis.yml @@ -0,0 +1,4 @@ +language: node_js + +node_js: + - 12 diff --git a/netease_api/CHANGELOG.MD b/netease_api/CHANGELOG.MD new file mode 100644 index 0000000..244a19f --- /dev/null +++ b/netease_api/CHANGELOG.MD @@ -0,0 +1,747 @@ +# 更新日志 +### 4.0.8 | 2021.2.27 +- 加入vercel 配置文件,支持 vercel 部署 + +### 4.0.7 | 2021.2.27 +- 更新红心接口,修复红心接口460错误问题 [#1151](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/1151) + +- 更新发送验证码接口 + +- 注册接口添加 countrycode 参数 [#1152](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/1152) + +- 新增绑定手机接口 [#1152](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/1152) + +- 更新 song/detail 接口 [#1143](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/1143) + +- 用户粉丝接口修改分页参数 [#1161](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/1161) + +### 4.0.6 | 2021.2.20 +- 修复 eapi 接口无法正确解密response的问题 [#1138](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/1138) + +### 4.0.5 | 2021.2.19 +- 修复红心接口默认不红心的问题 [#1126](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/1126) + +### 4.0.4 | 2021.2.18 +- 移除云村热评接口(官方下架) [#1111](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/1111) +- 更新 app version + +### 4.0.3 | 2021.1.28 +- 修复云盘接口中文音乐信息乱码的问题 [#1108](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/1108) + +### 4.0.2 | 2021.1.18 +- 修复未绑定手机号对歌单添加或删除歌曲无响应的问题 [#1099](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/1099) + +### 4.0.1 | 2021.1.09 +- 新增歌单详情动态接口 [#1088](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/1088) + +### 4.0.0 | 2021.1.03 +- 新增云盘上传接口,新增二维码登录相关接口和相关demo(http://localhost:3000/qrlogin.html, http://localhost:3000/cloud.html),更新 d.ts + +- 升级部分接口加密方法("linuxapi" 都替换到了"api") + +- 更新 `login/status` 接口(返回字段和之前不一样) + +### 3.47.5 | 2020.12.20 +- 更新appver [#1060](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/1060) + +### 3.47.4 | 2020.12.03 +- 修复收藏的专栏接口无法调用的问题 [#1042](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/1042) + +### 3.47.3 | 2020.11.22 +- 新增歌手详情接口 [#1035](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/1035) + +### 3.47.2 | 2020.11.15 +- 新增关注歌手新歌/新MV接口 [#1028](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/1028) + +### 3.47.1 | 2020.11.14 +- 修复使用post请求取消喜欢音乐会失败的问题 [#1024](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/1024) + +- 新增抱一抱评论和评论抱一抱列表接口 [#1016](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/1016) + +- 新增收藏的专栏接口[#1026](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/1026) + +### 3.46.1 | 2020.11.7 +- 修复私信音乐接口出现风险提示的问题 + +### 3.46.0 | 2020.11.7 +- 添加私信音乐接口 [#1016](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/1016) + +- 添加最近联系人接口 + +- 修复用户动态数量不准确问题 [#1010](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/1010) + +- 修复 cloudsearch 接口分页问题 [#1015](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/1015) + +### 3.45.3 | 2020.11.1 +- `相似歌手`,`首页-发现-圆形图标入口列表`接口增加匿名token[#877](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/877) [#988](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/988) + +- 修复`音乐 url`接口POST方式手动传入cookie报错问题 [#1005](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/1005) + +### 3.45.2 | 2020.10.26 +- 云贝完成任务接口增加`depositCode`参数 + +### 3.45.1 | 2020.10.25 +- 修复代理配置失效的问题 [#992](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/992) + +- 修复新碟上架不返回周数据的问题,修复推荐新音乐接口返回数量问题,并添加limit参数支持 [#981](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/981) + +- 添加`云贝`相关接口 [#985](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/985) + +- 添加`用户账号信息`接口 + +- 替换接口文件所有http url 为 https + +### 3.44.0 | 2020.10.17 +- 更新`电台详情`,`电台节目详情`接口 [#977](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/977) + +#### Breaking change +- `电台详情`接口更新后数据结构有变化 + +### 3.43.0 | 2020.10.16 +- 新增`电台订阅者列表`接口 [#971](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/971) + +### 3.42.4 | 2020.10.07 +- 修复新评论接口分页参数问题 + +### 3.42.3 | 2020.10.05 +- 修复新评论接口分页参数问题 + +### 3.42.2 | 2020.10.05 +- 更新歌单详情接口 + +### 3.42.1 | 2020.10.04 +- 新增`用户绑定信息`,`用户绑定手机`,`新版评论`,`点赞过的视频`,`收藏视频到视频歌单`,`删除视频歌单里的视频`,`最近播放的视频`,`音乐日历`等接口 + +- 创建歌单接口增加`type`参数,可创建视频歌单 + +### 3.41.2 | 2020.09.20 +- 更新`获取音乐 url`接口,未登录状态返回试听片段 [#897](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/897) + +### 3.41.1 | 2020.09.19 +- 新增`电台个性推荐接口` [#824](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/824) + +### 3.41.0 | 2020.09.19 +- 新增`精品歌单标签列表`接口 [#921](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/921) + +- 新增`用户等级信息`接口 [#929](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/929) + +- 增加新接口的 d.ts 文件,修复登录接口的 d.ts 的 countrycode 为非可选属性的错误 + +### 3.40.1 | 2020.09.13 +- 更新 TypeScript 声明 [#928](https://github.com/Binaryify/NeteaseCloudMusicApi/pull/928) + +### 3.40.0 | 2020.09.12 +- 新增 TypeScript 声明文件 [#908](https://github.com/Binaryify/NeteaseCloudMusicApi/pull/908) +- 更改随机 UA 相关逻辑[#922](https://github.com/Binaryify/NeteaseCloudMusicApi/pull/922) + +### 3.39.0 | 2020.08.23 +- 新增`cloudsearch`接口[#893](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/893) +- `mv 地址`接口修改分辨率参数 [#883](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/883) +- 修复新碟上架接口分页问题 [#892](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/892) + +### 3.38.0 | 2020.08.09 +- 新增`楼层评论`,`歌手全部歌曲`接口 [#864](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/864) [#867](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/867) +- 支持收藏VIP或付费歌曲到歌单 [#860](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/860) +- 支持手动传入`realIP` [#863](https://github.com/Binaryify/NeteaseCloudMusicApi/pull/863) + +### 3.37.2 | 2020.08.04 +- 修复依赖问题 + +### 3.37.0 | 2020.08.03 +- 新增`更新头像`,`歌单封面上传`接口和相关例子 [#403](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/403) [#857](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/857) +- 加入`axios`依赖 + +### 3.36.0 | 2020.07.26 +- 新增`全部新碟`,`数字专辑-新碟上架`,`数字专辑&数字单曲-榜单`,`数字专辑-语种风格馆`,`数字专辑详情`接口 [#852](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/852) +- 更新`新碟上架`接口,修改传入参数,返回数据结构有变化 + +### 3.35.0 | 2020.07.18 +- 新增`首页-发现`,`首页-发现-圆形图标入口列表`接口 [#851](https://github.com/Binaryify/NeteaseCloudMusicApi/pull/851) + +### 3.34.2 | 2020.07.13 +- 修复`获取用户播放记录`接口参数错误问题 [#849](https://github.com/Binaryify/NeteaseCloudMusicApi/pull/849) + +- 增加`国家编码列表`接口 [#841](https://github.com/Binaryify/NeteaseCloudMusicApi/pull/841) + +### 3.34.1 | 2020.07.06 +- 登录接口增加 `md5_password` 参数 [#839](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/839) + +### 3.34.0 | 2020.06.25 +- 排行榜接口废弃idx参数,只支持id参数,修复返回数据异常问题 [#830](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/830) +- 新增`获取历史日推可用日期列表`,`获取历史日推详细数据` 接口 + +### 3.33.2 | 2020.06.23 +- 更新每日推荐接口 [#826](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/826) + +### 3.33.1 | 2020.06.15 +- 修复直接调用时传入 cookie 不生效的问题 [#822](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/822) + +### 3.33.0 | 2020.06.10 +- 歌手榜支持地区参数 [#818](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/818) +- 新增视频分类列表,推荐视频,获取全部视频列表接口 [#816](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/816) +- 内置 apicache,修复不能在 NodeJS v13 版本使用的问题 [#817](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/817) + +### 3.32.3 | 2020.06.07 +- 修复 Nodejs 下 cookie 使用格式问题 [#812](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/812) + +### 3.32.2 | 2020.06.05 +- 新增独家放送列表接口 [#808](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/808) + +### 3.32.1 | 2020.06.03 +- 新增歌曲排序接口 + +### 3.32.0 | 2020.06.03 +- 更新排行榜接口,支持传入榜单id +- 新增榜单顺序调整接口 [#806](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/806) +- 完善错误提示信息 + +### 3.31.1 | 2020.05.19 +- 修复`cookie`没返回的问题 [#778](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/778) + +### 3.31.0 | 2020.05.18 +- 支持 `Node.js` 调用,参考`module_example` 文件夹下的 `test.js` + +### 3.30.0 | 2020.05.17 +- 登录接口返回内容增加`cookie`字段,支持手动传入cookie + +### 3.29.1 | 2020.05.13 +- 调整通知接口分页参数 [#761](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/761) + +### 3.29.0 | 2020.05.11 +- 支持批量删除歌单 [#760](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/760) + +### 3.28.0 | 2020.05.05 +- 新增获取 mv 点赞转发评论数数据接口 +- 新增获取视频点赞转发评论数数据接口 + +### 3.27.0 | 2020.04.20 +- 新增购买专辑接口 by [TimonPeng](https://github.com/Binaryify/NeteaseCloudMusicApi/pull/740) + +### 3.26.0 | 2020.04.08 +#### Breaking change +- 更新歌手分类列表接口参数,因`cat`参数失效,调整为`type`和`area`参数 + +### 3.25.4 | 2020.03.18 +- 更新歌词,歌手分类列表接口 + +- 更新文档 + +### 3.25.3 | 2019.11.08 +- 升级依赖,去除多余依赖 + +- 优化 `test.html` + +### 3.25.2 | 2019.11.07 +- 修复邮箱登录状态码错误,增加相关提示 [#633](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/633) + +### 3.25.0 | 2019.11.06 +- 新增 `云村热评` 接口[#626](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/626) + +- 新增 `歌手热门50首歌曲` 接口 + +- 新增`电台24小时节目榜`,`电台24小时主播榜`, `电台最热主播榜`,`电台主播新人榜`,`电台付费精品榜` 接口 [#606](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/606) + +- 调整 `歌手分类列表 ` 接口参数 [#624](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/624) + +### 3.24.2 | 2019.10.28 +- 修改默认绑定 HOST [#620](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/620) + +### 3.24.1 | 2019.10.25 +- 修改默认绑定 HOST [#615](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/615) + +### 3.24.0 | 2019.10.22 +- 新增`类别热门电台` 接口 [#607](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/607) + +### 3.23.0 | 2019.10.16 +- 修复电台 banner 接口无数据问题[#601](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/601) + +- 更新排行榜 [#602](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/602) + +- 新增`电台排行榜`,`新晋电台榜`,`热门电台榜`接口 [#604](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/604) + +### 3.22.4 | 2019.09.26 +- 修复私信历史记录分页参数问题,更新文档 [#599](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/599) + +### 3.22.3 | 2019.09.24 +- 手机号码检测: 添加国家码作为参数,方便检测国外手机号码 [#598](https://github.com/Binaryify/NeteaseCloudMusicApi/pull/598) + +### 3.22.2 | 2019.09.18 +- 排行榜参数更新,更新文档[#592](https://github.com/Binaryify/NeteaseCloudMusicApi/pull/592) + +### 3.22.1 | 2019.09.12 +- 支持回复评论[#589](https://github.com/Binaryify/NeteaseCloudMusicApi/pull/589) + + +### 3.22.0 | 2019.08.25 +- 支持 CORS 预检 [#564](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/564) [#578](https://github.com/Binaryify/NeteaseCloudMusicApi/pull/578) + +### 3.21.1 | 2019.08.21 +- 修复推荐歌单和网易出品mv参数错误,更新文档 [#571](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/571) [#572](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/572) + +### 3.21.0 | 2019.08.20 +- 新增`歌单删除接口`[#570](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/570) + +### 3.20.0 | 2019.08.06 +- 新增`更新歌单描述`,`更新歌单名`,`更新歌单标签`,`默认搜索关键词` 接口,更新文档[#547](https://github.com/Binaryify/NeteaseCloudMusicApi/pull/547) + +### 3.19.0 | 2019.07.24 +- 新增`检测手机号码是否已注册`和`初始化昵称`接口[#540](https://github.com/Binaryify/NeteaseCloudMusicApi/pull/540) + +### 3.18.6 | 2019.07.15 +- 修复注册异常的问题 [#532](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/532) + +### 3.18.5 | 2019.07.14 +- 修复部分歌曲无法获得播放链接的问题 [#531](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/531) + +### 3.18.3 | 2019.07.04 +- 修复全部 mv`/mv/all` 接口分页参数错误的问题 [#524](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/524) + +### 3.18.2 | 2019.07.03 +- 修复听歌打卡接口 `/scrobble` 失效问题 + +### 3.18.1 | 2019.06.30 +- 评论接口增加 `before` 参数以获取超过5000条评论数据 [#521](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/521) + +- 修复 `/msg/comments` 传入参数和文档描述不一致问题 + + +### 3.18.0 | 2019.06.29 +- 新增 `更换绑定手机接口` + +#### Breaking change +1. 调整注册接口由 `/captch/register` 修改为 `/register/cellphone` + +2. 调整发送短信接口由 `/captch/sent` 修改为 `/captcha/sent` + +3. 调整短信验证接口由 `/captch/verify` 修改为 `/captcha/verify` + +### 3.17.0 | 2019.06.29 +- 新增 `专辑动态信息` `热搜列表(详细)` 接口,更新文档 + +### 3.16.0 | 2019.06.27 +- 新增 `收藏/取消收藏专辑` 接口 + +- 调整歌曲评论接口使用客户端版本接口 + +### 3.15.0 | 2019.06.16 +- 新增`获取视频标签列表`,`网易出品`,`全部mv`接口, `最新 mv` 和 `mv 排行` 接口加入地区参数,更新文档 + +### 3.14.0 | 2019.06.10 +- 获取用户粉丝列表接口修改请求参数,更新文档 + +### 3.13.1 | 2019.06.09 +- 修复获取用户粉丝列表接口只能获取1000个的问题 + +### 3.13.0 | 2019.05.19 +- 新增eapi算法 (via:[#491](https://github.com/Binaryify/NeteaseCloudMusicApi/pull/491)) + +- 新增batch批量请求接口 (via:[#491](https://github.com/Binaryify/NeteaseCloudMusicApi/pull/491)) + +- 用户动态增加分页参数 + +### 3.12.0 | 2019.05.10 +- 增加`私信内容、我的数字专辑`接口 + +### 3.11.0 | 2019.05.09 +- 增加`通知-私信、通知-评论、通知-@我、通知-通知、设置、云盘数据详情`接口 + +### 3.10.2 | 2019.05.09 +- 增加`分享歌曲、歌单、mv、电台、电台节目到动态`接口 + +### 3.10.1 | 2019.05.08 +- 增加转发动态接口 + +- 增加删除动态接口 + +### 3.9.0 | 2019.05.03 +- 新增 云盘歌曲删除, 热门话题, 电台 - 推荐类型, 电台 - 非热门类型, 电台 - 今日优选, 心动模式/智能播放等接口 + +- 更新文档:banner接口 增加 `type` 参数; 获取动态消息接口增加 `pagesize` 和 `lasttime` 参数; 电台 - 付费精选接口修改默认`limit`为 30 + +### 3.8.1 | 2019.04.24 +- 修复歌词接口出错问题 + +### 3.8.0 | 2019.04.14 +- 增加注册,发送验证码,校验验证码接口 via:[https://github.com/Binaryify/NeteaseCloudMusicApi/pull/460](https://github.com/Binaryify/NeteaseCloudMusicApi/pull/460) @[KongValley](https://github.com/KongValley) + +### 3.7.1 | 2019.04.09 +- 修复登录460问题 + +### 3.7.0 | 2019.03.20 +- 修复喜欢音乐接口参数判断问题 + +- 增加歌单收藏者列表接口 + +### 3.6.0 | 2019.03.15 +- 调整动态评论获取接口 url,使之和其他评论获取接口更统一 + +### 3.5.0 | 2019.03.14 +- 增加获取动态评论接口 + +- 支持给动态点赞 + +- 支持给动态评论点赞 + +- 支持给动态发送/删除评论 + +### 3.4.0 | 2019.01.29 +- 增加已收藏专辑列表接口 + +### 3.3.0 | 2019.01.27 +- 增加视频标签下的视频获取接口 + +- 增加 pac 代理支持 + +### 3.2.0 | 2019.01.19 +- 增加获取首页新碟上架数据以及更新听歌排行 + +- 更新搜索建议接口 + +### 3.1.0 | 2019.01.06 +- 修复评论接口返回 460 Cheating 的问题 + +- 新增`已收藏MV`接口,更新文档 + +### 3.0.9 | 2018.12.15 +- 修复关注异常的问题 #399 + +### 3.0.8 | 2018.12.12 +- 更新文档 #386 #394 + +- 优化电台节目接口 + +### 3.0.7 | 2018.11.21 +- 修复歌单详情列表,排行榜,所有榜单失效的问题,更新文档 #380 #381 + +### 3.0.4 | 2018.11.15 +- 修复 `/song/url` 接口无法返回多个音乐数据的问题 + +### 3.0.3 | 2018.11.09 +- 修复取消喜欢歌曲失败问题 [#360](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/360) + +- 补充已喜欢音乐列表接口说明文档 [#370](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/370) + +- 默认关闭 debug 模式 [#365](https://github.com/Binaryify/NeteaseCloudMusicApi/pull/365) + +- 更新 Dockerfile 文件 [#367](https://github.com/Binaryify/NeteaseCloudMusicApi/pull/367) + + +### 3.0.1 | 2018.10.21 + +- 合并 PR([#351](https://github.com/Binaryify/NeteaseCloudMusicApi/pull/351)) + +- 文档增加 `/top/song` 接口 + +- `/banner` 换成 linux api,返回结构有所变动 + +- `/check/music` 已知 bug 修复 + +### 3.0.0 | 2018.10.14 + +#### 整体 + +- 完善文档,增加之前没写进文档的接口说明 + +- 重写 createRequest 返回 Promise 对象 + +- 模块化路由 + +- 模块化, 剥离 res,req, 方便导出调用 + +- 增加 cookie-parser + +##### 参数修改 + +- `/song/detail` 增加多 id 支持 + +- `/toplist/detail` 移除参数 + +- `/resource/like` 增加参数 `type` + +- `/top/playlist/highquality` 增加分页参数 `before` + +##### 统一参数 + +- `/artist/sub` 与 `artist/unsub` 合并, 用`query.t` + +- `/follow` 中 `query.type` 换成 `query.t` + +- `/comment` 中 `query.action` 换成 `query.t` + +##### URL 重命名 + +- `/video` 改为 `video/url` + +- `/mv` 改为 `mv/detail` + +- `/music/url` 改为 `/song/url` + +##### 转发逻辑修改 + +- `/toplist/artist` 换成 weapi + +- `/mv/url` 去除了 pipe + +##### BUG 修复 + +- `/playlist/create`, `/playlist/update` 被判欺骗,增加 cookie + +##### 路由增删 + +- 删除 `/recommend/dislike` + +- 增加 `/video/sub` (收藏视频), `/mv/sub` (收藏 MV) + +- 增加 `/video/detail` (视频详情) + +- 增加 `/related/allvideo` (相关视频) + +### 2.20.5 | 2018.09.29 + +修复非法参数 403 #335, 修复代理错误 #334 + +### 2.20.4 | 2018.09.27 + +修复点赞失效的问题 + +### 2.20.3 | 2018.09.26 + +- 增加退出登录接口 +- 修正 /check/music 的检查逻辑 +- 优化 Cookies 设置 +- 重构单元测试 + + [by @nondanee](https://github.com/nondanee) + +- 增加 301 需要登录提示信息 + +- 更新文档 + +### 2.20.2 | 2018.09.22 + +增加热门评论和视频评论接口,更新文档 + +### 2.20.1 | 2018.09.17 + +优化版本检查功能 + +### 2.20.0 | 2018.09.06 + +新增版本检查功能 + +### 2.19.0 | 2018.08.29 + +新增获取视频数据接口,新增发送/删除评论接口,修复登录状态接口问题,完善文档 #301,感谢 @izhenyuls + +### 2.17.0 | 2018.08.28 + +新增登录状态查询接口 #302 ,完善文档,完善路由注册 #297 + +### 2.16.0 | 2018.08.09 + +- Fixed #288,#289,#290 + +解决歌曲 URL 请求被判 Cheating,修复私信接收异常 #291 + +### 2.15.0 | 2018.07.30 + +新增相关歌单推荐和付费精选接口,增加歌手列表接口按首字母索引查找参数 + +### 2.14.0 | 2018.07.03 + +修复无法使用邮箱问题 + +### 2.13.0 | 2018.06.05 + +增加自动注册路由的功能,简化路由注册逻辑 + +### 2.12.0 | 2018.05.27 + +更新文档,优化歌单详情接口 + +### 2.11.1 | 2018.05.24 + +更新文档,优化`/dj/program`接口 + +### 2.11.0 | 2018.05.21 + +增加收藏歌手列表&订阅电台列表 + +### 2.10.0 | 2018.05.17 + +歌单操作调整为批量操作 + +### 2.9.9 | 2018.05.16 + +Bug 修复 + +### 2.9.8 | 2018.05.10 + +新增歌手分类列表,收藏/取消收藏歌手接口,新增更新用户信息,更新歌单接口 + +### 2.9.6 | 2018.05.08 + +新增发送私信相关接口,新增新建歌单,收藏/取消收藏歌单接口 + +### 2.9.4 | 2018.05.04 + +新增热搜接口,更新 banner 接口 + +### 2.9.2 | 2018.02.28 + +修复登录失败会崩溃的问题 + +### 2.9.1 | 2018.01.26 + +docker 构建文件的一些增强以及增加访问日志和调试输出 + +### 2.8.9 | 2018.01.24 + +修复歌单详情数据不完整的问题,更新依赖 + +### 2.8.8 | 2018.01.22 + +修复排行榜数据不完整的问题 , 优化部分代码 , 更新文档部分描述 + +### 2.8.6 | 2018.01.16 + +修复歌单详情接口数据不完整的问题 + +### 2.8.5 | 2018.01.16 + +修复评论点赞失败的问题 + +### 2.8.4 | 2018.01.15 + +优化 cookie 设置 + +### 2.8.3 | 2018.01.12 + +优化部分功能和文档 + +### 2.8.2 | 2018.01.05 + +增加 Dockerfile,支持以 Docker 容器模式运行 + +### 2.8.1 | 2018.01.04 + +添加了 proxy 功能 + +### 2.8.0 | 2018.01.04 + +用 'request' 重写了请求函数 + +### 2.7.9 | 2017.12.11 + +更新排行榜接口 , 新增云音乐 ACG 音乐榜 , 云音乐嘻哈榜 + +### 2.7.7 | 2017.11.27 + +更新 / 修复排行榜接口 , 更新 / 修复推荐歌单接口 + +### 2.7.7 | 2017.11.27 + +更新 / 修复排行榜接口 , 更新 / 修复推荐歌单接口 + +### 2.7.2 | 2017.9.7 + +修复搜索接口 offset 参数失效问题 + +### 2.7.0 | 2017.8.21 + +优化刷新登录代码 + +### 2.6.5 | 2017.7.16 + +优化 CORS 设置 + +### 2.6.4 | 2017.7.16 + +添加缓存机制和随机 UA 机制 感谢[@u3u](https://github.com/u3u) +[issue:77](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/77) 优化请求 +代码 感谢 [@huhuime](https://github.com/huhuime) +[issue:83](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/83) + +### 2.6.2 | 2017.7.16 + +修复垃圾桶接口 + +### 2.6.1 | 2017.7.16 + +修复红心接口 + +### 2.6.0 | 2017.6.25 + +修复签到接口 + +### 2.5.9 | 2017.6.14 + +增加启动说明页 + +### 2.5.8 | 2017.6.1 + +修复若干细节问题 + +### 2.5.7 | 2017.5.22 + +修复若干问题 + +### 2.5.6 | 2017.5.14 + +增加动态消息接口 + +### 2.5.5 | 2017.5.10 + +修复 mv 排行榜接口崩溃问题 + +### 2.5.4 | 2017.5.5 + +新增点赞接口 , 更新文档 + +### 2.5.3 | 2017.5.2 + +修复歌手单曲数据空白问题和文档获取歌手单曲 url 描述问题 , 更新文档 + +### 2.5.0 | 2017.4.29 + +增加 mv/ 专辑 / 歌单评论接口 , 增加云盘相关接口 , 增加获取用户动态 / 信息接口 , +增加关注 / 粉丝列表接口 , 增加收藏歌单接口 , 增加相似 mv/ 歌曲 / 用户接口 , 增加 +banner 接口 , 增加刷新登录接口 , 增加电台相关接口 , 补充评论接口 , 更新文档 + +### 2.4.6 | 2017.4.21 + +增加播放 mv 接口 , 更新文档 + +### 2.4.5 | 2017.4.20 + +增加歌手专辑 , 歌手单曲等接口 , 修复 /album 接口描述错误 , 更新文档 + +### 2.4.0 | 2017.4.20 + +增加歌单(网友精选碟 ), 新碟上架 , 热门歌手等接口 , 更新文档 + +### 2.3.4 | 2017.4.20 + +增加歌曲详情接口 , 更新文档 + +### 2.3.0 | 2017.4.15 + +增加排行榜接口 , 更新文档 + +### 2.2.0 |2017.4.14 + +增加私人 FM, 喜欢歌曲 , 垃圾桶 , 每日签到等接口 , 更新文档 + +### 2.1.3 | 2017.4.6 + +改善文档 + +### 2.1.0 | 2017.4.6 + +增加获取评论接口以及对应单元测试 , 增加更新日志 + +### 2.0.0 | 2017.4.1 + +版本升级到 2.0. 增加使用文档 , 完成项目重构 , 增加更完善的单元测试 , 升级 api 到 +v2+, 支持登录并获取用户信息和创建的歌单 , 可通过获取音乐 url 接口获取用户歌单里 +的的音乐 , 获取每日推荐歌单和每日推荐音乐 diff --git a/netease_api/Dockerfile b/netease_api/Dockerfile new file mode 100644 index 0000000..6691335 --- /dev/null +++ b/netease_api/Dockerfile @@ -0,0 +1,13 @@ +FROM node:lts-alpine + +WORKDIR /app +COPY . /app + +RUN rm -f package-lock.json \ + ; rm -rf .idea \ + ; rm -rf node_modules \ + ; npm config set registry "https://registry.npm.taobao.org/" \ + && npm install + +EXPOSE 3000 +CMD ["node", "app.js"] diff --git a/netease_api/LICENSE b/netease_api/LICENSE new file mode 100644 index 0000000..facc240 --- /dev/null +++ b/netease_api/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013-2016 Binaryify + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/netease_api/README.MD b/netease_api/README.MD new file mode 100644 index 0000000..a5b4389 --- /dev/null +++ b/netease_api/README.MD @@ -0,0 +1,338 @@ +# 网易云音乐 API + +网易云音乐 Node.js API service + +

+Version +License +devDependencies +devDependencies + +

+ +## 灵感来自 + +[disoul/electron-cloud-music](https://github.com/disoul/electron-cloud-music) + +[darknessomi/musicbox](https://github.com/darknessomi/musicbox) + +[sqaiyan/netmusic-node](https://github.com/sqaiyan/netmusic-node) + +[greats3an/pyncm](https://github.com/greats3an/pyncm) + + +## 环境要求 + +需要 NodeJS 8.12+ 环境 + +## 安装 + +```shell + +$ git clone git@github.com:Binaryify/NeteaseCloudMusicApi.git + +$ npm install +``` + +或者 +```shell +$ git clone https://github.com/Binaryify/NeteaseCloudMusicApi.git + +$ npm install +``` + +## 运行 + +```shell +$ node app.js +``` + +服务器启动默认端口为 3000,若不想使用 3000 端口,可使用以下命令: Mac/Linux + +```shell +$ PORT=4000 node app.js +``` + +windows 下使用 git-bash 或者 cmder 等终端执行以下命令: + +```shell +$ set PORT=4000 && node app.js +``` + +## Vercel 部署 +v4.0.8 加入了 Vercel 配置文件,可以直接在 Vercel 下部署了,不需要自己的服务器 +### 操作方法 +1. fork 此项目 +2. 在 Vercel 官网点击 `New Project` +3. 点击 `Import Git Repository` 并选择你 fork 的此项目并点击`import` +4. 点击 `PERSONAL ACCOUNT` 的 `select` +5. 直接点`Continue` +6. `PROJECT NAME`自己填,`FRAMEWORK PRESET` 选 `Other` 然后直接点 `Deploy` 接着等部署完成即可 + +## 可以在Node.js调用 +v3.31.0后支持Node.js调用,导入的方法为`module`内的文件名,返回内容包含`status`和`body`,`status`为状态码,`body`为请求返回内容,参考`module_example` 文件夹下的 `test.js` +```js +const { login_cellphone, user_cloud } = require('NeteaseCloudMusicApi') +async function main() { + try { + const result = await login_cellphone({ + phone: '手机号', + password: '密码' + }) + console.log(result) + const result2 = await user_cloud({ + cookie: result.body.cookie // 凭证 + }) + console.log(result2.body) + + } catch (error) { + console.log(error) + } +} +main() +``` + +## 支持 TypeScript +```ts +// test.ts +import { banner } from 'NeteaseCloudMusicApi' +banner({ type:0 }).then(res=>{ + console.log(res) +}) +``` + + +## 使用文档 + +[文档地址](https://binaryify.github.io/NeteaseCloudMusicApi) + +[文档地址2](https://neteasecloudmusicapi.vercel.app) + +![文档](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/docs.png) + + +## 功能特性 +1. 登录 +2. 刷新登录 +3. 发送验证码 +4. 校验验证码 +5. 注册(修改密码) +6. 获取用户信息 , 歌单,收藏,mv, dj 数量 +7. 获取用户歌单 +8. 获取用户电台 +9. 获取用户关注列表 +10. 获取用户粉丝列表 +11. 获取用户动态 +12. 获取用户播放记录 +13. 获取精品歌单 +14. 获取歌单详情 +15. 搜索 +16. 搜索建议 +17. 获取歌词 +18. 歌曲评论 +19. 收藏单曲到歌单 +20. 专辑评论 +21. 歌单评论 +22. mv 评论 +23. 电台节目评论 +24. banner +25. 获取歌曲详情 +26. 获取专辑内容 +27. 获取歌手单曲 +28. 获取歌手 mv +29. 获取歌手专辑 +30. 获取歌手描述 +31. 获取相似歌手 +32. 获取相似歌单 +33. 相似 mv +34. 获取相似音乐 +35. 获取最近 5 个听了这首歌的用户 +36. 获取每日推荐歌单 +37. 获取每日推荐歌曲 +38. 私人 FM +39. 签到 +40. 喜欢音乐 +41. 垃圾桶 +42. 歌单 ( 网友精选碟 ) +43. 新碟上架 +44. 热门歌手 +45. 最新 mv +46. 推荐 mv +47. 推荐歌单 +48. 推荐新音乐 +49. 推荐电台 +50. 推荐节目 +51. 独家放送 +52. mv 排行 +53. 获取 mv 数据 +54. 播放 mv/视频 +55. 排行榜 +56. 歌手榜 +57. 云盘 +58. 电台 - 推荐 +59. 电台 - 分类 +60. 电台 - 分类推荐 +61. 电台 - 订阅 +62. 电台 - 详情 +63. 电台 - 节目 +64. 给评论点赞 +65. 获取动态 +66. 热搜列表(简略) +67. 发送私信 +68. 发送私信歌单 +69. 新建歌单 +70. 收藏/取消收藏歌单 +71. 歌单分类 +72. 收藏的歌手列表 +73. 订阅的电台列表 +74. 相关歌单推荐 +75. 付费精选接口 +76. 音乐是否可用检查接口 +77. 登录状态 +78. 获取视频播放地址 +79. 发送/删除评论 +80. 热门评论 +81. 视频评论 +82. 退出登录 +83. 所有榜单 +84. 所有榜单内容摘要 +85. 收藏视频 +86. 收藏 MV +87. 视频详情 +88. 相关视频 +89. 关注用户 +90. 新歌速递 +91. 喜欢音乐列表(无序) +92. 收藏的 MV 列表 +93. 获取最新专辑 +94. 听歌打卡 +95. 获取视频标签/分类下的视频 +96. 已收藏专辑列表 +97. 获取动态评论 +98. 歌单收藏者列表 +99. 云盘歌曲删除 +100. 热门话题 +101. 电台 - 推荐类型 +102. 电台 - 非热门类型 +103. 电台 - 今日优选 +104. 心动模式/智能播放 +105. 转发动态 +106. 删除动态 +107. 分享歌曲、歌单、mv、电台、电台节目到动态 +108. 通知-私信 +109. 通知-评论 +110. 通知-@我 +111. 通知-通知 +112. 设置 +113. 云盘数据详情 +114. 私信内容 +115. 我的数字专辑 +116. batch批量请求接口 +117. 获取视频标签列表 +118. 全部mv +119. 网易出品mv +120. 收藏/取消收藏专辑 +121. 专辑动态信息 +122. 热搜列表(详细) +123. 更换绑定手机 +124. 检测手机号码是否已注册 +125. 初始化昵称 +126. 更新歌单描述 +127. 更新歌单名 +128. 更新歌单标签 +129. 默认搜索关键词 +130. 删除歌单 +131. 电台banner +132. 用户电台 +133. 热门电台 +134. 电台 - 节目详情 +135. 电台 - 节目榜 +136. 电台 - 新晋电台榜/热门电台榜 +137. 类别热门电台 +138. 云村热评 +139. 电台24小时节目榜 +140. 电台24小时主播榜 +141. 电台最热主播榜 +142. 电台主播新人榜 +143. 电台付费精品榜 +144. 歌手热门50首歌曲 +145. 购买数字专辑 +146. 获取 mv 点赞转发评论数数据 +147. 获取视频点赞转发评论数数据 +148. 调整歌单顺序 +149. 调整歌曲顺序 +150. 独家放送列表 +151. 获取推荐视频 +152. 获取视频分类列表 +153. 获取全部视频列表接口 +154. 获取历史日推可用日期列表 +155. 获取历史日推详细数据 +156. 国家编码列表 +157. 首页-发现 +158. 首页-发现-圆形图标入口列表 +159. 数字专辑-全部新碟 +160. 数字专辑-热门新碟 +161. 数字专辑&数字单曲-榜单 +162. 数字专辑-语种风格馆 +163. 数字专辑详情 +164. 更新头像 +165. 歌单封面上传 +166. 楼层评论 +167. 歌手全部歌曲 +168. 精品歌单标签列表 +169. 用户等级信息 +170. 电台个性推荐 +171. 用户绑定信息 +172. 用户绑定手机 +173. 新版评论 +174. 点赞过的视频 +175. 收藏视频到视频歌单 +176. 删除视频歌单里的视频 +177. 最近播放的视频 +178. 音乐日历 +179. 电台订阅者列表 +180. 云贝签到信息 +181. 云贝签到 +182. 云贝所有任务 +183. 云贝todo任务 +184. 云贝今日签到信息 +185. 云贝完成任务 +186. 云贝收入 +187. 云贝支出 +188. 云贝账户信息 +189. 账号信息 +190. 最近联系人 +191. 私信音乐 +192. 抱一抱评论 +193. 评论抱一抱列表 +194. 收藏的专栏 +195. 关注歌手新歌 +196. 关注歌手新MV +197. 歌手详情 +198. 云盘上传 +199. 二维码登录 +200. 话题详情 +201. 话题详情热门动态 +202. 歌单详情动态 +203. 绑定手机 + +## 更新日志 + +[changelog](https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/CHANGELOG.MD) + +## 单元测试 + +```shell +$ npm test +``` + +![单元测试](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/screenshot1.png) +![单元测试](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/screenshot2.png) + +## 贡献者 +![](https://opencollective.com/NeteaseCloudMusicApi/contributors.svg?width=890) + + +## License + +[The MIT License (MIT)](https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/LICENSE) diff --git a/netease_api/app.js b/netease_api/app.js new file mode 100644 index 0000000..d78e978 --- /dev/null +++ b/netease_api/app.js @@ -0,0 +1,117 @@ +const fs = require('fs') +const path = require('path') +const express = require('express') +const bodyParser = require('body-parser') +const request = require('./util/request') +const packageJSON = require('./package.json') +const exec = require('child_process').exec +const cache = require('./util/apicache').middleware +const { cookieToJson } = require('./util/index') +const fileUpload = require('express-fileupload') +// version check +exec('npm info NeteaseCloudMusicApi version', (err, stdout, stderr) => { + if (!err) { + let version = stdout.trim() + if (packageJSON.version < version) { + console.log( + `最新版本: ${version}, 当前版本: ${packageJSON.version}, 请及时更新`, + ) + } + } +}) + +const app = express() + +// 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()) + +// static +app.use(express.static(path.join(__dirname, 'public'))) + +// cache +app.use(cache('2 minutes', (req, res) => res.statusCode === 200)) +// router +const special = { + 'daily_signin.js': '/daily_signin', + 'fm_trash.js': '/fm_trash', + 'personal_fm.js': '/personal_fm', +} + +fs.readdirSync(path.join(__dirname, 'module')) + .reverse() + .forEach((file) => { + if (!file.endsWith('.js')) return + let route = + file in special + ? special[file] + : '/' + file.replace(/\.js$/i, '').replace(/_/g, '/') + let question = require(path.join(__dirname, 'module', file)) + + app.use(route, (req, res) => { + 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, + ) + + question(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)) + res.append('Set-Cookie', answer.cookie) + res.status(answer.status).send(answer.body) + }) + .catch((answer) => { + console.log('[ERR]', 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) + }) + }) + }) + +const port = process.env.PORT || 3000 +const host = process.env.HOST || '' + +app.server = app.listen(port, host, () => { + console.log(`server running @ http://${host ? host : 'localhost'}:${port}`) +}) + +module.exports = app diff --git a/netease_api/app.test.js b/netease_api/app.test.js new file mode 100644 index 0000000..94846b2 --- /dev/null +++ b/netease_api/app.test.js @@ -0,0 +1,15 @@ +const fs = require('fs') +const path = require('path') + +let app +before(() => { + app = require('./app.js') + global.host = 'http://localhost:' + app.server.address().port +}) +after((done) => { + app.server.close(done) +}) + +fs.readdirSync(path.join(__dirname, 'test')).forEach((file) => { + require(path.join(__dirname, 'test', file)) +}) diff --git a/netease_api/docs/.nojekyll b/netease_api/docs/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/netease_api/docs/README.md b/netease_api/docs/README.md new file mode 100644 index 0000000..023a18f --- /dev/null +++ b/netease_api/docs/README.md @@ -0,0 +1,3253 @@ +# NeteaseCloudMusicApi + +网易云音乐 NodeJS 版 API + +## 灵感来自 + +[disoul/electron-cloud-music](https://github.com/disoul/electron-cloud-music) + +[darknessomi/musicbox](https://github.com/darknessomi/musicbox) + +[sqaiyan/netmusic-node](https://github.com/sqaiyan/netmusic-node) + +## 工作原理 + +跨站请求伪造 (CSRF), 伪造请求头 , 调用官方 API + +## 功能特性 + +1. 登录 +2. 刷新登录 +3. 发送验证码 +4. 校验验证码 +5. 注册(修改密码) +6. 获取用户信息 , 歌单,收藏,mv, dj 数量 +7. 获取用户歌单 +8. 获取用户电台 +9. 获取用户关注列表 +10. 获取用户粉丝列表 +11. 获取用户动态 +12. 获取用户播放记录 +13. 获取精品歌单 +14. 获取歌单详情 +15. 搜索 +16. 搜索建议 +17. 获取歌词 +18. 歌曲评论 +19. 收藏单曲到歌单 +20. 专辑评论 +21. 歌单评论 +22. mv 评论 +23. 电台节目评论 +24. banner +25. 获取歌曲详情 +26. 获取专辑内容 +27. 获取歌手单曲 +28. 获取歌手 mv +29. 获取歌手专辑 +30. 获取歌手描述 +31. 获取相似歌手 +32. 获取相似歌单 +33. 相似 mv +34. 获取相似音乐 +35. 获取最近 5 个听了这首歌的用户 +36. 获取每日推荐歌单 +37. 获取每日推荐歌曲 +38. 私人 FM +39. 签到 +40. 喜欢音乐 +41. 垃圾桶 +42. 歌单 ( 网友精选碟 ) +43. 新碟上架 +44. 热门歌手 +45. 最新 mv +46. 推荐 mv +47. 推荐歌单 +48. 推荐新音乐 +49. 推荐电台 +50. 推荐节目 +51. 独家放送 +52. mv 排行 +53. 获取 mv 数据 +54. 播放 mv/视频 +55. 排行榜 +56. 歌手榜 +57. 云盘 +58. 电台 - 推荐 +59. 电台 - 分类 +60. 电台 - 分类推荐 +61. 电台 - 订阅 +62. 电台 - 详情 +63. 电台 - 节目 +64. 给评论点赞 +65. 获取动态 +66. 热搜列表(简略) +67. 发送私信 +68. 发送私信歌单 +69. 新建歌单 +70. 收藏/取消收藏歌单 +71. 歌单分类 +72. 收藏的歌手列表 +73. 订阅的电台列表 +74. 相关歌单推荐 +75. 付费精选接口 +76. 音乐是否可用检查接口 +77. 登录状态 +78. 获取视频播放地址 +79. 发送/删除评论 +80. 热门评论 +81. 视频评论 +82. 退出登录 +83. 所有榜单 +84. 所有榜单内容摘要 +85. 收藏视频 +86. 收藏 MV +87. 视频详情 +88. 相关视频 +89. 关注用户 +90. 新歌速递 +91. 喜欢音乐列表(无序) +92. 收藏的 MV 列表 +93. 获取最新专辑 +94. 听歌打卡 +95. 获取视频标签/分类下的视频 +96. 已收藏专辑列表 +97. 获取动态评论 +98. 歌单收藏者列表 +99. 云盘歌曲删除 +100. 热门话题 +101. 电台 - 推荐类型 +102. 电台 - 非热门类型 +103. 电台 - 今日优选 +104. 心动模式/智能播放 +105. 转发动态 +106. 删除动态 +107. 分享歌曲、歌单、mv、电台、电台节目到动态 +108. 通知-私信 +109. 通知-评论 +110. 通知-@我 +111. 通知-通知 +112. 设置 +113. 云盘数据详情 +114. 私信内容 +115. 我的数字专辑 +116. batch批量请求接口 +117. 获取视频标签列表 +118. 全部mv +119. 网易出品mv +120. 收藏/取消收藏专辑 +121. 专辑动态信息 +122. 热搜列表(详细) +123. 更换绑定手机 +124. 检测手机号码是否已注册 +125. 初始化昵称 +126. 更新歌单描述 +127. 更新歌单名 +128. 更新歌单标签 +129. 默认搜索关键词 +130. 删除歌单 +131. 电台banner +132. 用户电台 +133. 热门电台 +134. 电台 - 节目详情 +135. 电台 - 节目榜 +136. 电台 - 新晋电台榜/热门电台榜 +137. 类别热门电台 +138. 云村热评(官方下架,暂不能用) +139. 电台24小时节目榜 +140. 电台24小时主播榜 +141. 电台最热主播榜 +142. 电台主播新人榜 +143. 电台付费精品榜 +144. 歌手热门50首歌曲 +145. 购买数字专辑 +146. 获取 mv 点赞转发评论数数据 +147. 获取视频点赞转发评论数数据 +148. 调整歌单顺序 +149. 调整歌曲顺序 +150. 独家放送列表 +151. 获取推荐视频 +152. 获取视频分类列表 +153. 获取全部视频列表接口 +154. 获取历史日推可用日期列表 +155. 获取历史日推详细数据 +156. 国家编码列表 +157. 首页-发现 +158. 首页-发现-圆形图标入口列表 +159. 全部新碟 +160. 数字专辑-新碟上架 +161. 数字专辑&数字单曲-榜单 +162. 数字专辑-语种风格馆 +163. 数字专辑详情 +164. 更新头像 +165. 歌单封面上传 +166. 楼层评论 +167. 歌手全部歌曲 +168. 精品歌单标签列表 +169. 用户等级信息 +170. 电台个性推荐 +171. 用户绑定信息 +172. 用户绑定手机 +173. 新版评论 +174. 点赞过的视频 +175. 收藏视频到视频歌单 +176. 删除视频歌单里的视频 +177. 最近播放的视频 +178. 音乐日历 +179. 电台订阅者列表 +180. 云贝签到信息 +181. 云贝签到 +182. 云贝所有任务 +183. 云贝todo任务 +184. 云贝今日签到信息 +185. 云贝完成任务 +186. 云贝收入 +187. 云贝支出 +188. 云贝账户信息 +189. 账号信息 +190. 最近联系人 +191. 私信音乐 +192. 抱一抱评论 +193. 评论抱一抱列表 +194. 收藏的专栏 +195. 关注歌手新歌 +196. 关注歌手新MV +197. 歌手详情 +198. 云盘上传 +199. 二维码登录 +200. 话题详情 +201. 话题详情热门动态 +202. 歌单详情动态 +203. 绑定手机 + +## 安装 + +```shell +$ git clone git@github.com:Binaryify/NeteaseCloudMusicApi.git + +$ npm install +``` + +## 运行 + +```shell +$ node app.js +``` + +服务器启动默认端口为 3000, 若不想使用 3000 端口 , 可使用以下命令 : Mac/Linux + +```shell +$ PORT=4000 node app.js +``` + +windows 下使用 git-bash 或者 cmder 等终端执行以下命令 : + +```shell +$ set PORT=4000 && node app.js +``` + +服务器启动默认 host 为localhost,如果需要更改, 可使用以下命令 : Mac/Linux +```shell +$ HOST=127.0.0.1 node app.js +``` +windows 下使用 git-bash 或者 cmder 等终端执行以下命令 : + +```shell +$ set HOST=127.0.0.1 && node app.js +``` + +## Vercel 部署 +v4.0.8 加入了 Vercel 配置文件,可以直接在 Vercel 下部署了,不需要自己的服务器 +### 操作方法 +1. fork 此项目 +2. 在 Vercel 官网点击 `New Project` +3. 点击 `Import Git Repository` 并选择你 fork 的此项目并点击`import` +4. 点击 `PERSONAL ACCOUNT` 的 `select` +5. 直接点`Continue` +6. `PROJECT NAME`自己填,`FRAMEWORK PRESET` 选 `Other` 然后直接点 `Deploy` 接着等部署完成即可 + +## 可以使用代理 + +在 query 参数中加上 proxy=your-proxy 即可让这一次的请求使用 proxy + +```javascript +// 例子 +const url = `http://localhost:3000/song/url?id=33894312&proxy=http://121.196.226.246:84` +fetch(url).then(function() { + // do what you want +}) + +// 结果 +// {"data":[{"id":33894312,"url":"http://m10.music.126.net/20180104125640/930a968b3fb04908b733506b3833e60b/ymusic/0fd6/4f65/43ed/a8772889f38dfcb91c04da915b301617.mp3","br":320000,"size":10691439,"md5":"a8772889f38dfcb91c04da915b301617","code":200,"expi":1200,"type":"mp3","gain":-2.0E-4,"fee":0,"uf":null,"payed":0,"flag":0,"canExtend":false}],"code": 200} +``` +v3.3.0 后支持使用 PAC代理,如 `?proxy=http://192.168.0.1/proxy.pac` + +## 可以在Node.js调用 +v3.31.0后支持Node.js调用,导入的方法为`module`内的文件名,返回内容包含`status`和`body`,`status`为状态码,`body`为请求返回内容,参考`module_example` 文件夹下的 `test.js` +```js +const { login_cellphone, user_cloud } = require('NeteaseCloudMusicApi') +async function main() { + try { + const result = await login_cellphone({ + phone: '手机号', + password: '密码' + }) + console.log(result) + const result2 = await user_cloud({ + cookie: result.body.cookie // 凭证 + }) + console.log(result2.body) + + } catch (error) { + console.log(error) + } +} +main() +``` + +## 支持 TypeScript +```ts +// test.ts +import { banner } from 'NeteaseCloudMusicApi' +banner({ type:0 }).then(res=>{ + console.log(res) +}) +``` + +## 更新到 v3.0 说明 + +!>2018.10.14 更新到 3.0.0,使用了模块化机制,因为部分接口参数和 url 做了调整,如还不想升级到 3.0.0,请查看 [v2 的文档](http://binaryify.github.io/NeteaseCloudMusicApi/#/v2), [更新日志](https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/CHANGELOG.MD), [2.0+下载地址](https://github.com/Binaryify/NeteaseCloudMusicApi/releases/tag/v2.20.5), 同时 2.0+ 将不再维护 + +## Docker 容器运行 + +> 注意: 在 docker 中运行的时候, 由于使用了 request 来发请求, 所以会检查几个 proxy 相关的环境变量(如下所列), 这些环境变量 会影响到 request 的代理, 详情请参考[request 的文档](https://github.com/request/request#proxies), 如果这些环境变量 指向的代理不可用, 那么就会造成错误, 所以在使用 docker 的时候一定要注意这些环境变量. 不过, 要是你在 query 中加上了 proxy 参数, 那么环境变量会被覆盖, 就会用你通过 proxy 参数提供的代理了. + +request 相关的环境变量 + +1. http_proxy +2. https_proxy +3. HTTP_PROXY +4. HTTPS_PROXY +5. no_proxy +6. NO_PROXY + +```shell +docker pull binaryify/netease_cloud_music_api + +docker run -d -p 3000:3000 --name netease_cloud_music_api binaryify/netease_cloud_music_api + + +// 或者 +docker run -d -p 3000:3000 binaryify/netease_cloud_music_api + +// 去掉或者设置相关的环境变量 + +docker run -d -p 3000:3000 --name netease_cloud_music_api -e http_proxy= -e https_proxy= -e no_proxy= -e HTTP_PROXY= -e HTTPS_PROXY= -e NO_PROXY= binaryify/netease_cloud_music_api + +// 或者 +docker run -d -p 3000:3000 -e http_proxy= -e https_proxy= -e no_proxy= -e HTTP_PROXY= -e HTTPS_PROXY= -e NO_PROXY= binaryify/netease_cloud_music_api +``` + +> 以下是自行 build docker 镜像方式 + +``` +$ git clone https://github.com/Binaryify/NeteaseCloudMusicApi && cd NeteaseCloudMusicApi + +$ sudo docker build . -t netease-music-api + +$ sudo docker run -d -p 3000:3000 netease-music-api +``` + +## 接口文档 + +### 调用前须知 +!> 本项目不提供线上 demo,请不要轻易信任使用他人提供的公开服务,以免发生安全问题,泄露自己的账号和密码 + +!> 为使用方便,降低门槛, 文档示例接口直接使用了 GET 请求,本项目同时支持 GET/POST 请按实际需求使用 (POST请求url必须添加时间戳,使每次请求url不一样,不然请求会被缓存) + +!> 由于接口做了缓存处理 ( 缓存 2 分钟,不缓存数据极容易引起网易服务器高频ip错误 , 可在 app.js 设置 , 可能会导致登录后获取不到 cookie), **相同的 url** 会在两分钟内只向网易服务器发一次请求 , 如果遇到不需要缓 +存结果的接口 , 可在请求 url 后面加一个时间戳参数使 url 不同 , 例子 : +`/simi/playlist?id=347230×tamp=1503019930000` (之所以加入缓存机制是因为项目早期没有缓存机制,很多 issues 都是报 IP高频,请按自己需求改造缓存中间件(app.js),源码不复杂) + +!> 如果是跨域请求 , 请在所有请求带上 `xhrFields: { withCredentials: true }` (axios 为 `withCredentials: true`)否则 +可能会因为没带上 cookie 导致 301, 具体例子可看 `public/test.html`, 访问`http://localhost:3000/test.html`(默认端口的话) 例子使用 jQuery 和 axios + +!> 301 错误基本都是没登录就调用了需要登录的接口,如果登录了还是提示 301, 基本都是缓存把数据缓存起来了,解决方法是加时间戳或者等待 2 分钟或者重启服务重新登录后再调用接口,可自行改造缓存方法 + +!> 部分接口如登录接口不能调用太频繁 , 否则可能会触发 503 错误或者 ip 高频错误 ,若需频繁调用 , 需要准备 IP 代理池 (更新:已加入缓存机制,但仍需注意). + +!> 本项目仅供学习使用,请尊重版权,请勿利用此项目从事商业行为或进行破坏版权行为 + +!> 文档可能会有缓存 , 如果文档版本和 github 上的版本不一致,请清除缓存再查看 + +!> 由于网易限制,此项目在国外服务器或部分国内云服务上使用会受到限制,如 `460 cheating异常`,如需解决 , 可使用大陆服务器或者使用代理 , 感谢 [@hiyangguo](https://github.com/hiyangguo)提出的[解决方法](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/29#issuecomment-298358438): +在 '/util/request.js' 的 'headers' 处增加 `X-Real-IP':'211.161.244.70' // 任意国内 IP` +即可解决 + +!> 图片加上 `?param=宽y高` 可控制图片尺寸,如 `http://p4.music.126.net/JzNK4a5PjjPIXAgVlqEc5Q==/109951164154280311.jpg?param=200y200`, `http://p4.music.126.net/JzNK4a5PjjPIXAgVlqEc5Q==/109951164154280311.jpg?param=50y50` + +!> 分页接口返回字段里有`more`,more为true则为有下一页 + +### 登录 + +说明 : 登录有三个接口,建议使用`encodeURIComponent`对密码编码或者使用`POST`请求,避免某些特殊字符无法解析,如`#`(`#`在url中会被识别为hash,而不是query) + +#### 1. 手机登录 + +**必选参数 :** +`phone`: 手机号码 + +`password`: 密码 + + + +**可选参数 :** +`countrycode`: 国家码,用于国外手机号登录,例如美国传入:`1` + +`md5_password`: md5加密后的密码,传入后 `password` 将失效 + +**接口地址 :** `/login/cellphone` + +**调用例子 :** `/login/cellphone?phone=xxx&password=yyy` `/login/cellphone?phone=xxx&md5_password=yyy` + +#### 2. 邮箱登录 + +**必选参数 :** + +`email`: 163 网易邮箱 + +`password`: 密码 + +**可选参数 :** + +`md5_password`: md5加密后的密码,传入后 `password` 将失效 + +**接口地址 :** `/login` + +**调用例子 :** `/login?email=xxx@163.com&password=yyy` + +完成登录后 , 会在浏览器保存一个 Cookies 用作登录凭证 , 大部分 API 都需要用到这个 +Cookies,非跨域情况请求会自动带上 Cookies,跨域情况参考`调用前须知` + +v3.30.0后支持手动传入cookie,登录接口返回内容新增 `cookie` 字段,保存到本地后,get请求带上`?cookie=xxx` 或者 post请求body带上 `cookie` 即可,如:`/user/cloud?cookie=xxx` 或者 +``` +{ + ..., + cookie:"xxx" +} +``` +#### 3. 二维码登录 +说明: 二维码登录涉及到3个接口,调用务必带上时间戳,防止缓存 +##### 1. 二维码key生成接口 + +说明: 调用此接口可生成一个key + +**接口地址 :** `/login/qr/key` +##### 2. 二维码生成接口 +说明: 调用此接口传入上一个接口生成的key可生成二维码图片的base64和二维码信息,可使用base64展示图片,或者使用二维码信息内容自行使用第三方二维码生产库渲染二维码 + +必选参数: `key`,由第一个接口生成 + +可选参数: `qrimg` 传入后会额外返回二维码图片base64编码 + +**接口地址 :** `/login/qr/create` + +**调用例子 :** `/login/qr/create?key=xxx` + + +##### 3. 二维码检测扫码状态接口 +说明: 轮询此接口可获取二维码扫码状态,800为二维码过期,801为等待扫码,802为待确认,803为授权登录成功(803状态码下会返回cookies) + +必选参数: `key`,由第一个接口生成 + +**接口地址 :** `/login/qr/check` + +**调用例子 :** `/login/qr/check?key=xxx` + +调用可参考项目文件例子`/public/qrlogin.html` (访问地址:http://localhost:3000/qrlogin.html) + + +#### 注意 + +调用登录接口的速度比调用其他接口慢 , 因为登录过程调用了加密算法 + +### 刷新登录 + +说明 : 调用此接口 , 可刷新登录状态 + +**调用例子 :** `/login/refresh` + +### 发送验证码 + +说明 : 调用此接口 ,传入手机号码, 可发送验证码 + +**必选参数 :** `phone`: 手机号码 + +**可选参数 :** +`ctcode`: 国家区号,默认86即中国 + +**接口地址 :** `/captcha/sent` + +**调用例子 :** `/captcha/sent?phone=13xxx` + +### 验证验证码 + +说明 : 调用此接口 ,传入手机号码和验证码, 可校验验证码是否正确 + +**必选参数 :** `phone`: 手机号码 + +`captcha`: 验证码 + +**可选参数 :** + +`ctcode`: 国家区号,默认86即中国 + +**接口地址 :** `/captcha/verify` + +**调用例子 :** `/captcha/verify?phone=13xxx&captcha=1597` + + +### 注册(修改密码) + +说明 : 调用此接口 ,传入手机号码和验证码,密码,昵称, 可注册网易云音乐账号(同时可修改密码) + +**必选参数 :** + +`captcha`: 验证码 + +`phone` : 手机号码 + +`password`: 密码 + +`nickname`: 昵称 + +**可选参数 :** + +`countrycode`: 国家码,用于国外手机号,例如美国传入:`1` ,默认86即中国 + +**接口地址 :** `/register/cellphone` + +**调用例子 :** `/register/cellphone?phone=13xxx&password=xxxxx&captcha=1234&nickname=binary1345` + +### 检测手机号码是否已注册 +说明 : 调用此接口 ,可检测手机号码是否已注册 +**必选参数 :** +`phone` : 手机号码 + +**可选参数 :** +`countrycode`: 国家码,用于国外手机号,例如美国传入:`1` ,默认86即中国 + +**接口地址 :** `/cellphone/existence/check` + +**调用例子 :** `/cellphone/existence/check?phone=13xxx` + +### 初始化昵称 +说明 : 刚注册的账号(需登录),调用此接口 ,可初始化昵称 +**必选参数 :** +`nickname` : 昵称 + +**接口地址 :** `/activate/init/profile` + +**调用例子 :** `/activate/init/profile?nickname=testUser2019` + +### 更换绑定手机 +说明 : 调用此接口 ,可更换绑定手机(流程:先发送验证码到原手机号码,再发送验证码到新手机号码然后再调用此接口) + +**必选参数 :** +`oldcaptcha`: 原手机验证码 + +`captcha`: 新手机验证码 + +`phone` : 手机号码 + +`ctcode` : 国家区号,默认86即中国 + +**接口地址 :** `/rebind` + +**调用例子 :** `/rebind?phone=xxx&oldcaptcha=1234&captcha=5678` + +### 退出登录 + +说明 : 调用此接口 , 可退出登录 + +**调用例子 :** `/logout` + +### 登录状态 + +说明 : 调用此接口,可获取登录状态 + +**接口地址 :** `/login/status` + + +### 获取用户详情 + +说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户详情 + +**必选参数 :** `uid` : 用户 id + +**接口地址 :** `/user/detail` + +**调用例子 :** `/user/detail?uid=32953014` + +### 获取账号信息 + +说明 : 登录后调用此接口 ,可获取用户账号信息 + +**接口地址 :** `/user/account` + +**调用例子 :** `/user/account` + +### 获取用户信息 , 歌单,收藏,mv, dj 数量 + +说明 : 登录后调用此接口 , 可以获取用户信息 + +**接口地址 :** `/user/subcount` + +**调用例子 :** `/user/subcount` + +### 获取用户等级信息 + +说明 : 登录后调用此接口 , 可以获取用户等级信息,包含当前登录天数,听歌次数,下一等级需要的登录天数和听歌次数,当前等级进度,对应 https://music.163.com/#/user/level + +**接口地址 :** `/user/level` + +**调用例子 :** `/user/level` + + +### 获取用户绑定信息 + +说明 : 登录后调用此接口 , 可以获取用户绑定信息 + +**必选参数 :** `uid` : 用户 id + + +**接口地址 :** `/user/binding` + +**调用例子 :** `/user/binding?uid=32953014` + + +### 用户绑定手机 + +说明 : 登录后调用此接口 , 可以更换绑定手机 + +**必选参数 :** + +`phone` : 手机号码 + +`oldcaptcha`: 原手机号码的验证码 + +`captcha`:新手机号码的验证码 + +**可选参数 :** + +`countrycode`: 国家地区代码,默认86 + + +**接口地址 :** `/user/replacephone` + +**调用例子 :** `/user/replacephone?phone=xxx&captcha=1234&oldcaptcha=2345` + + +### 更新用户信息 + +说明 : 登录后调用此接口 , 传入相关信息,可以更新用户信息 + +**必选参数 :** + +``` +gender: 性别 0:保密 1:男性 2:女性 + +birthday: 出生日期,时间戳 unix timestamp + +nickname: 用户昵称 + +province: 省份id + +city: 城市id + +signature:用户签名 +``` + +**接口地址 :** `/user/update` + +**调用例子 :** `/user/update?gender=0&signature=测试签名&city=440300&nickname=binary&birthday=1525918298004&province=440000` + +### 更新头像 +说明 : 登录后调用此接口,使用`'Content-Type': 'multipart/form-data'`上传图片formData(name为'imgFile'),可更新头像(参考:https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/public/avatar_update.html),支持命令行调用,参考module_example目录下`avatar_upload.js` + +**可选参数 :** + +`imgSize` : 图片尺寸,默认为300 + +`imgX` : 水平裁剪偏移,方形图片可不传,默认为0 +`imgY` : 垂直裁剪偏移,方形图片可不传,默认为0 + +**接口地址 :** `/avatar/upload` + +**调用例子 :** `/avatar/upload?imgSize=200` + +### 国家编码列表 +说明 : 调用此接口,可获取国家编码列表 + +**接口地址 :** `/countries/code/list` + +### 获取用户歌单 + +说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户歌单 + +**必选参数 :** `uid` : 用户 id + +**可选参数 :** + +`limit` : 返回数量 , 默认为 30 + +`offset` : 偏移数量,用于分页 , 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 + +**接口地址 :** `/user/playlist` + +**调用例子 :** `/user/playlist?uid=32953014` + +返回数据如下图 : +![用户歌单](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E7%94%A8%E6%88%B7%E6%AD%8C%E5%8D%95.png) + +### 更新歌单 + +说明 : 登录后调用此接口,可以更新用户歌单 + +**必选参数 :** + +``` +id:歌单id + +name:歌单名字 + +desc:歌单描述 + +tags:歌单tag ,多个用 `;` 隔开,只能用官方规定标签 +``` + +**接口地址 :** `/playlist/update` + +**调用例子 :** `/playlist/update?id=24381616&name=新歌单&desc=描述&tags=欧美` + +### 更新歌单描述 +说明 : 登录后调用此接口,可以单独更新用户歌单描述 + +**必选参数 :** +``` +id:歌单id + +desc:歌单描述 + +``` +**接口地址 :** `/playlist/desc/update` + +**调用例子 :** `/playlist/desc/update?id=24381616&desc=描述` + +### 更新歌单名 +说明 : 登录后调用此接口,可以单独更新用户歌单名 + +**必选参数 :** + +``` +id: 歌单id + +name: 歌单名 + +``` +**接口地址 :** `/playlist/name/update` + +**调用例子 :** `/playlist/name/update?id=24381616&name=歌单名` + +### 更新歌单标签 +说明 : 登录后调用此接口,可以单独更新用户歌单标签 + +**必选参数 :** + +``` +id: 歌单id + +tags: 歌单标签 + +``` +**接口地址 :** `/playlist/tags/update` + +**调用例子 :** `/playlist/tags/update?id=24381616&tags=学习` + + +### 歌单封面上传 +说明 : 登录后调用此接口,使用`'Content-Type': 'multipart/form-data'`上传图片formData(name为'imgFile'),可更新歌单封面(参考:https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/public/playlist_cover_update.html) + +**必选参数 :** +`id`: 歌单id 3143833470 + +**可选参数 :** + +`imgSize` : 图片尺寸,默认为300 + +`imgX` : 水平裁剪偏移,方形图片可不传,默认为0 +`imgY` : 垂直裁剪偏移,方形图片可不传,默认为0 + +**接口地址 :** `/playlist/cover/update` + +**调用例子 :** `/playlist/cover/update?id=3143833470&imgSize=200` + + +### 调整歌单顺序 +说明 : 登录后调用此接口,可以根据歌单id顺序调整歌单顺序 + + +**必选参数 :** + +`ids`: 歌单id列表 + +**接口地址 :** `/playlist/order/update` + +**调用例子 :** `/playlist/order/update?ids=[111,222]` + +### 调整歌曲顺序 +说明 : 登录后调用此接口,可以根据歌曲id顺序调整歌曲顺序 + + +**必选参数 :** +`pid`: 歌单id + +`ids`: 歌曲id列表 + +**接口地址 :** `/song/order/update` + +**调用例子 :** `/song/order/update?pid=2039116066&ids=[5268328,1219871]` + +### 获取用户电台 + +说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户电台 + +**必选参数 :** `uid` : 用户 id + +**接口地址 :** `/user/dj` + +**调用例子 :** `/user/dj?uid=32953014` + +### 获取用户关注列表 + +说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户关注列表 + +**必选参数 :** `uid` : 用户 id + +**可选参数 :** + +`limit` : 返回数量 , 默认为 30 + +`offset` : 偏移数量,用于分页 ,如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 + +**接口地址 :** `/user/follows` + +**调用例子 :** `/user/follows?uid=32953014` + +### 获取用户粉丝列表 + +说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户粉丝列表 + +**必选参数 :** `uid` : 用户 id + +**可选参数 :** +`limit` : 返回数量 , 默认为 30 + +`offset` : 偏移数量,用于分页 ,如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 + +**接口地址 :** `/user/followeds` + +**调用例子 :** `/user/followeds?uid=32953014` `/user/followeds?uid=416608258&limit=1` `/user/followeds?uid=416608258&limit=1&offset=1` + +### 获取用户动态 + +说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户动态 + +**必选参数 :** `uid` : 用户 id + +**可选参数 :** `limit` : 返回数量 , 默认为 30 + +`lasttime` : 返回数据的 `lasttime` ,默认-1,传入上一次返回结果的 lasttime,将会返回下一页的数据 + +**接口地址 :** `/user/event` + +**调用例子 :** `/user/event?uid=32953014` `/user/event?uid=32953014&limit=1&lasttime=1558011138743` + +返回结果的`type`参数对应: +``` +18 分享单曲 +19 分享专辑 +17、28 分享电台节目 +22 转发 +39 发布视频 +35、13 分享歌单 +24 分享专栏文章 +41、21 分享视频 +``` + +### 转发用户动态 +说明 : 登录后调用此接口 ,可以转发用户动态 + +**必选参数 :** `uid` : 用户 id + +`evId` : 动态 id + +`forwards` : 转发的评论 + +**接口地址 :** `/event/forward` + +**调用例子 :** `/event/forward?evId=6712917601&uid=32953014&forwards=测试内容` + + +### 删除用户动态 +说明 : 登录后调用此接口 ,可以删除用户动态 + +**必选参数 :** `evId` : 动态 id + +**接口地址 :** `/event/del` + +**调用例子 :** `/event/del?evId=6712917601` + +### 分享歌曲、歌单、mv、电台、电台节目到动态 +说明 : 登录后调用此接口 ,可以分享歌曲、歌单、mv、电台、电台节目到动态 + +**必选参数 :** `id` : 资源 id (歌曲,歌单,mv,电台,电台节目对应 id) + +**可选参数 :** `type`: 资源类型,默认歌曲 song,可传 `song`,`playlist`,`mv`,`djradio`,`djprogram` + +`msg`: 内容,140 字限制,支持 emoji,@用户名(`/user/follows`接口获取的用户名,用户名后和内容应该有空格),图片暂不支持 + +**接口地址 :** `/share/resource` + +**调用例子 :** `/share/resource?id=1297494209&msg=测试` `/share/resource?type=djradio&id=336355127` `/share/resource?type=djprogram&id=2061034798` `/share/resource?type=djprogram&id=2061034798&msg=测试@binaryify 测试` + +### 获取动态评论 + +说明 : 登录后调用此接口 , 可以获取动态下评论 + +**必选参数 :** `threadId` : 动态 id,可通过 `/event`,`/user/event` 接口获取 + +**接口地址 :** `/comment/event` + +**调用例子 :** `/comment/event?threadId=A_EV_2_6559519868_32953014` + +### 关注/取消关注用户 + +说明 : 登录后调用此接口 , 传入用户 id, 和操作 t,可关注/取消关注用户 + +**必选参数 :** + +`id` : 用户 id + +`t` : `1`为关注,其他为取消关注 + +**接口地址 :** `/follow` + +**调用例子 :** `/follow?id=32953014&t=1` + +### 获取用户播放记录 + +说明 : 登录后调用此接口 , 传入用户 id, 可获取用户播放记录 + +**必选参数 :** `uid` : 用户 id + +**可选参数 :** `type` : type=1 时只返回 weekData, type=0 时返回 allData + +**接口地址 :** `/user/record` + +**调用例子 :** `/user/record?uid=32953014&type=1` + +### 获取热门话题 + +说明 : 调用此接口 , 可获取热门话题 + +**可选参数 :** `limit`: 取出评论数量 , 默认为 20 + +`offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*20, 其中 20 为 limit 的值 + +**接口地址 :** `/hot/topic` + +**调用例子 :** `/hot/topic?limit=30&offset=30` + +### 获取话题详情 + +说明 : 调用此接口 , 可获取话题详情 + +**接口地址 :** `/topic/detail` + +**调用例子 :** `/topic/detail?actid=111551188` +### 获取话题详情热门动态 + +说明 : 调用此接口 , 可获取话题详情热门动态 + +**接口地址 :** `/topic/detail/event/hot` + +**调用例子 :** `/topic/detail/event/hot?actid=111551188` + + +### 云村热评(官方下架,暂不能用) +说明 : 登录后调用此接口 , 可获取云村热评 + +**接口地址 :** `/comment/hotwall/list` + +**调用例子 :** `/comment/hotwall/list` + +### 心动模式/智能播放 +说明 : 登录后调用此接口 , 可获取心动模式/智能播放列表 +**必选参数 :** `id` : 歌曲 id + +`pid` : 歌单 id + +**可选参数 :** +`sid` : 要开始播放的歌曲的 id + +**接口地址 :** `/playmode/intelligence/list` + +**调用例子 :** `/playmode/intelligence/list?id=33894312&pid=24381616` , `/playmode/intelligence/list?id=33894312&pid=24381616&sid=36871368` + +### 获取动态消息 + +说明 : 调用此接口 , 可获取各种动态 , 对应网页版网易云,朋友界面里的各种动态消息 +,如分享的视频,音乐,照片等! + +**必选参数 :** +`pagesize` : 每页数据,默认20 + +`lasttime` : 返回数据的 `lasttime` ,默认-1,传入上一次返回结果的 lasttime,将会返回下一页的数据 + +**接口地址 :** `/event` + +**调用例子 :** `/event?pagesize=30&lasttime=1556740526369` + +### 歌手分类列表 + +说明 : 调用此接口,可获取歌手分类列表 + +**可选参数 :** + +`limit` : 返回数量 , 默认为 30 + +`offset` : 偏移数量,用于分页 , 如 +: 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 +`initial`: 按首字母索引查找参数,如 `/artist/list?type=1&area=96&initial=b` 返回内容将以 name 字段开头为 b 或者拼音开头为 b 为顺序排列, 热门传-1,#传0 + +`type` 取值: + +``` +-1:全部 +1:男歌手 +2:女歌手 +3:乐队 +``` + +`area` 取值: +``` +-1:全部 +7华语 +96欧美 +8:日本 +16韩国 +0:其他 +``` + + +**接口地址 :** `/artist/list` + +**调用例子 :** `/artist/list?type=1&area=96&initial=b` `/artist/list?type=2&area=2&initial=b` + + +### 收藏/取消收藏歌手 + +说明 : 调用此接口,可收藏歌手 + +**必选参数 :** + +`id` : 歌手 id + +`t`:操作,1 为收藏,其他为取消收藏 + +**接口地址 :** `/artist/sub` + +**调用例子 :** `/artist/sub?id=6452&t=1` + + +### 歌手热门50首歌曲 + +说明 : 调用此接口,可获取歌手热门50首歌曲 + +**必选参数 :** + +`id` : 歌手 id + +**接口地址 :** `/artist/top/song` + +**调用例子 :** `/artist/top/song?id=6452` + +### 歌手全部歌曲 +说明 : 调用此接口,可获取歌手全部歌曲 +**必选参数 :** + +`id` : 歌手 id + +**可选参数 :** + +`order` : `hot` ,`time` 按照热门或者时间排序 + +`limit`: 取出歌单数量 , 默认为 50 + +`offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*50, 其中 50 为 limit 的值 + +**接口地址 :** `/artist/songs` + +**调用例子 :** `/artist/songs?id=6452` + +### 收藏的歌手列表 + +说明 : 调用此接口,可获取收藏的歌手列表 + +**接口地址 :** `/artist/sublist` + +**调用例子 :** `/artist/sublist` + +### 收藏的专栏 + +说明 : 调用此接口,可获取收藏的专栏 + +**可选参数 :** + +`limit`: 取出歌单数量 , 默认为 50 + +`offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*50, 其中 50 为 limit 的值 + +**接口地址 :** `/topic/sublist` + +**调用例子 :** `/topic/sublist?limit=2&offset=1` + +### 收藏视频 + +说明 : 调用此接口,可收藏视频 + +**必选参数 :** + +`id` : 视频 id + +`t` : 1 为收藏,其他为取消收藏 + +**接口地址 :** `/video/sub` + +**调用例子 :** `/video/sub` + +### 收藏/取消收藏 MV + +说明 : 调用此接口,可收藏/取消收藏 MV + +**必选参数 :** + +`mvid` : MV id + +`t` : 1 为收藏,其他为取消收藏 + +**接口地址 :** `/mv/sub` + +**调用例子 :** `/mv/sub` + +### 收藏的 MV 列表 + +说明 : 调用此接口,可获取收藏的 MV 列表 + +**接口地址 :** `/mv/sublist` + +**调用例子 :** `/mv/sublist` + +### 歌单分类 + +说明 : 调用此接口,可获取歌单分类,包含 category 信息 + +**接口地址 :** `/playlist/catlist` + +**调用例子 :** `/playlist/catlist` + +### 热门歌单分类 + +说明 : 调用此接口,可获取歌单分类,包含 category 信息 + +**接口地址 :** `/playlist/hot` + +**调用例子 :** `/playlist/hot` + +### 歌单 ( 网友精选碟 ) + +说明 : 调用此接口 , 可获取网友精选碟歌单 + +**可选参数 :** `order`: 可选值为 'new' 和 'hot', 分别对应最新和最热 , 默认为 +'hot' + +`cat`:`cat`: tag, 比如 " 华语 "、" 古风 " 、" 欧美 "、" 流行 ", 默认为 +"全部",可从歌单分类接口获取(/playlist/catlist) + +`limit`: 取出歌单数量 , 默认为 50 + +`offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*50, 其中 50 为 limit 的值 + +**接口地址 :** `/top/playlist` + +**调用例子 :** `/top/playlist?limit=10&order=new` + +### 精品歌单标签列表 +说明 : 调用此接口 , 可获取精品歌单标签列表 + +**接口地址 :** `/playlist/highquality/tags` + +**调用例子 :** `/playlist/highquality/tags` + +### 获取精品歌单 + +说明 : 调用此接口 , 可获取精品歌单 + +**可选参数 :** `cat`: tag, 比如 " 华语 "、" 古风 " 、" 欧美 "、" 流行 ", 默认为 +"全部",可从精品歌单标签列表接口获取(`/playlist/highquality/tags`) + +`limit`: 取出歌单数量 , 默认为 20 + +`before`: 分页参数,取上一页最后一个歌单的 `updateTime` 获取下一页数据 + +**接口地址 :** `/top/playlist/highquality` + +**调用例子 :** `/top/playlist/highquality?before=1503639064232&limit=3` + +### 相关歌单推荐 + +说明 : 调用此接口,传入歌单 id 可获取相关歌单(对应页面 [https://music.163.com/#/playlist?id=1](https://music.163.com/#/playlist?id=1)) + +**必选参数 :** `id` : 歌单 id + +**接口地址 :** `/related/playlist` + +**调用例子 :** `/related/playlist?id=1` + +### 获取歌单详情 + +说明 : 歌单能看到歌单名字, 但看不到具体歌单内容 , 调用此接口 , 传入歌单 id, 可 +以获取对应歌单内的所有的音乐(未登录状态只能获取不完整的歌单,登录后是完整的),但是返回的trackIds是完整的,tracks 则是不完整的,可拿全部 trackIds 请求一次 `song/detail` 接口获取所有歌曲的详情 ([https://github.com/Binaryify/NeteaseCloudMusicApi/issues/452](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/452)) + +**必选参数 :** `id` : 歌单 id + +**可选参数 :** `s` : 歌单最近的 s 个收藏者,默认为8 + +**接口地址 :** `/playlist/detail` + +**调用例子 :** `/playlist/detail?id=24381616` + +### 歌单详情动态 + +说明 : 调用后可获取歌单详情动态部分,如评论数,是否收藏,播放数 + +**必选参数 :** `id` : 歌单 id + +**接口地址 :** `/playlist/detail/dynamic` + +**调用例子 :** `/playlist/detail/dynamic?id=24381616` + +### 获取音乐 url + +说明 : 使用歌单详情接口后 , 能得到的音乐的 id, 但不能得到的音乐 url, 调用此接口, 传入的音乐 id( 可多个 , 用逗号隔开 ), 可以获取对应的音乐的 url,未登录状态或者非会员返回试听片段(返回字段包含被截取的正常歌曲的开始时间和结束时间) + +> 注 : 部分用户反馈获取的 url 会 403,[hwaphon](https://github.com/hwaphon)找到的解决方案是当获取到音乐的 id 后,将 https://music.163.com/song/media/outer/url?id=id.mp3 以 src 赋予 Audio 即可播放 + +**必选参数 :** `id` : 音乐 id + +**可选参数 :** `br`: 码率,默认设置了 999000 即最大码率,如果要 320k 则可设置为 320000,其他类推 + +**接口地址 :** `/song/url` + +**调用例子 :** `/song/url?id=33894312` `/song/url?id=405998841,33894312` + + +### 音乐是否可用 + +说明: 调用此接口,传入歌曲 id, 可获取音乐是否可用,返回 `{ success: true, message: 'ok' }` 或者 `{ success: false, message: '亲爱的,暂无版权' }` + +**必选参数 :** `id` : 歌曲 id + +**可选参数** : `br`: 码率,默认设置了 999000 即最大码率,如果要 320k 则可设置为 320000,其他类推 + +**接口地址 :** `/check/music` + +**调用例子 :** `/check/music?id=33894312` + +### 搜索 + +说明 : 调用此接口 , 传入搜索关键词可以搜索该音乐 / 专辑 / 歌手 / 歌单 / 用户 , +关键词可以多个 , 以空格隔开 , 如 " 周杰伦 搁浅 "( 不需要登录 ), 搜索获取的 +mp3url 不能直接用 , 可通过 `/song/url` 接口传入歌曲 id 获取具体的播放链接 + +**必选参数 :** `keywords` : 关键词 + +**可选参数 :** `limit` : 返回数量 , 默认为 30 `offset` : 偏移数量,用于分页 , 如 +: 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 + +`type`: 搜索类型;默认为 1 即单曲 , 取值意义 : 1: 单曲, 10: 专辑, 100: 歌手, 1000: +歌单, 1002: 用户, 1004: MV, 1006: 歌词, 1009: 电台, 1014: 视频, 1018:综合 + +**接口地址 :** `/search` 或者 `/cloudsearch`(更全) + +**调用例子 :** `/search?keywords= 海阔天空` `/cloudsearch?keywords= 海阔天空` + +### 默认搜索关键词 +说明 : 调用此接口 , 可获取默认搜索关键词 + +**接口地址 :** `/search/default` + +### 热搜列表(简略) + +说明 : 调用此接口,可获取热门搜索列表 + +**接口地址 :** `/search/hot` + +**调用例子 :** `/search/hot` + +### 热搜列表(详细) + +说明 : 调用此接口,可获取热门搜索列表 + +**接口地址 :** `/search/hot/detail` + +**调用例子 :** `/search/hot/detail` + +### 搜索建议 + +说明 : 调用此接口 , 传入搜索关键词可获得搜索建议 , 搜索结果同时包含单曲 , 歌手 , +歌单 ,mv 信息 + +**必选参数 :** `keywords` : 关键词 + +**可选参数 :** `type` : 如果传 'mobile' 则返回移动端数据 + +**接口地址 :** `/search/suggest` + +**调用例子 :** `/search/suggest?keywords= 海阔天空` `/search/suggest?keywords= 海阔天空&type=mobile` + +### 搜索多重匹配 + +说明 : 调用此接口 , 传入搜索关键词可获得搜索结果 + +**必选参数 :** `keywords` : 关键词 + +**接口地址 :** `/search/multimatch` + +**调用例子 :** `/search/multimatch?keywords= 海阔天空` + +### 新建歌单 + +说明 : 调用此接口 , 传入歌单名字可新建歌单 + +**必选参数 :** `name` : 歌单名 + +**可选参数 :** + +`privacy` : 是否设置为隐私歌单,默认否,传'10'则设置成隐私歌单 + +`type` : 歌单类型,默认'NORMAL',传 'VIDEO'则为视频歌单 + +**接口地址 :** `/playlist/create` + +**调用例子 :** `/playlist/create?name=测试歌单`,`/playlist/create?name=test&type=VIDEO` + +### 删除歌单 + +说明 : 调用此接口 , 传入歌单id可删除歌单 + +**必选参数 :** `id` : 歌单id,可多个,用逗号隔开 + +**接口地址 :** `/playlist/delete` + +**调用例子 :** `/playlist/delete?id=2947311456` , `/playlist/delete?id=5013464397,5013427772` + + +### 收藏/取消收藏歌单 + +说明 : 调用此接口 , 传入类型和歌单 id 可收藏歌单或者取消收藏歌单 + +**必选参数 :** + +`t` : 类型,1:收藏,2:取消收藏 +`id` : 歌单 id + +**接口地址 :** `/playlist/subscribe` + +**调用例子 :** `/playlist/subscribe?t=1&id=106697785` `/playlist/subscribe?t=2&id=106697785` + + + +### 歌单收藏者 +说明 : 调用此接口 , 传入歌单 id 可获取歌单的所有收藏者 +**必选参数 :** + +`id` : 歌单 id + +**可选参数 :** `limit`: 取出评论数量 , 默认为 20 + +`offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*20, 其中 20 为 limit 的值 + +**接口地址 :** `/playlist/subscribers` + +**调用例子 :** `/playlist/subscribers?id=544215255&limit=30` + + +### 对歌单添加或删除歌曲 + +说明 : 调用此接口 , 可以添加歌曲到歌单或者从歌单删除某首歌曲 ( 需要登录 ) + +**必选参数 :** + +`op`: 从歌单增加单曲为 add, 删除为 del + +`pid`: 歌单 id +`tracks`: 歌曲 id,可多个,用逗号隔开 + +**接口地址 :** `/playlist/tracks` + +**调用例子 :** `/playlist/tracks?op=add&pid=24381616&tracks=347231` ( 对应把歌曲添加到 ' 我 ' 的歌单 , 测试的时候请把这里的 pid 换成你自己的, id 和 tracks 不对可能会报 502 错误) + +### 收藏视频到视频歌单 +说明 : 调用此接口 , 可收藏视频到视频歌单 ( 需要登录 ) + +**必选参数 :** + +`pid` : 歌单 id + +`ids` : 视频id,支持多个,用`,`隔开 + +**接口地址 :** `/playlist/track/add` + +**调用例子 :** `/playlist/track/add?pid=5271999357&ids=186041` + +### 删除视频歌单里的视频 +说明 : 调用此接口 , 可删除视频歌单里的视频 ( 需要登录 ) +**必选参数 :** + +`pid` : 歌单 id + +`ids` : 视频id,支持多个,用`,`隔开 + +**接口地址 :** `/playlist/track/delete` + +**调用例子 :** `/playlist/track/delete?pid=5271999357&ids=186041` + +### 最近播放的视频 +说明 : 调用此接口 , 可获取最近播放的视频 ( 需要登录 ) + +**接口地址 :** `/playlist/video/recent` + +**调用例子 :** `/playlist/video/recent` + +### 获取歌词 + +说明 : 调用此接口 , 传入音乐 id 可获得对应音乐的歌词 ( 不需要登录 ) + +**必选参数 :** `id`: 音乐 id + +**接口地址 :** `/lyric` + +**调用例子 :** `/lyric?id=33894312` + +返回数据如下图 : +![获取歌词](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E6%AD%8C%E8%AF%8D.png) + +### 新歌速递 + +说明 : 调用此接口 , 可获取新歌速递 + +**必选参数 :** + +`type`: 地区类型 id,对应以下: + +``` +全部:0 + +华语:7 + +欧美:96 + +日本:8 + +韩国:16 +``` + +**接口地址 :** `/top/song` + +**调用例子 :** `/top/song?type=96` + +### 首页-发现 +说明 : 调用此接口 , 可获取APP首页信息 + +**接口地址 :** `/homepage/block/page` + +**可选参数 :** `refresh`: 是否刷新数据,默认为true + + +### 首页-发现-圆形图标入口列表 +说明 : 调用此接口 , 可获取APP首页圆形图标入口列表 + +**接口地址 :** `/homepage/dragon/ball` + + +### 歌曲评论 + +说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该音乐的所有评论 ( 不需要登录 ) + +**必选参数 :** `id`: 音乐 id + +**可选参数 :** `limit`: 取出评论数量 , 默认为 20 + +`offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*20, 其中 20 为 limit 的值 + +`before`: 分页参数,取上一页最后一项的 `time` 获取下一页数据(获取超过5000条评论的时候需要用到) + +**接口地址 :** `/comment/music` + +**调用例子 :** `/comment/music?id=186016&limit=1` 对应晴天评论 + +返回数据如下图 : +![获取评论](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/comment.png) + +### 楼层评论 + +说明 : 调用此接口 , 传入资源 parentCommentId 和资源类型 type和资源id 参数, 可获得该资源的歌曲楼层评论 + +**必选参数 :** +`parentCommentId`: 楼层评论 id + +`id` : 资源 id + +`tpye`: 数字 , 资源类型 , 对应歌曲 , mv, 专辑 , 歌单 , 电台, 视频对应以下类型 + +``` +0: 歌曲 + +1: mv + +2: 歌单 + +3: 专辑 + +4: 电台 + +5: 视频 +``` + + +**可选参数 :** `limit`: 取出评论数量 , 默认为 20 + +`time`: 分页参数,取上一页最后一项的 `time` 获取下一页数据 + +**接口地址 :** `/comment/floor` + +**调用例子 :** `/comment/floor?parentCommentId=1438569889&id=29764564&type=0` + +### 专辑评论 + +说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该专辑的所有评论 ( 不需要 +登录 ) + +**必选参数 :** `id`: 专辑 id + +**可选参数 :** `limit`: 取出评论数量 , 默认为 20 + +`offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*20, 其中 20 为 limit 的值 + +`before`: 分页参数,取上一页最后一项的 `time` 获取下一页数据(获取超过5000条评论的时候需要用到) + +**接口地址 :** `/comment/album` + +**调用例子 :** `/comment/album?id=32311` + +### 歌单评论 + +说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该歌单的所有评论 ( 不需要 +登录 ) + +**必选参数 :** `id`: 歌单 id + +**可选参数 :** `limit`: 取出评论数量 , 默认为 20 + +`offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*20, 其中 20 为 limit 的值 + +`before`: 分页参数,取上一页最后一项的 `time` 获取下一页数据(获取超过5000条评论的时候需要用到) + +**接口地址 :** `/comment/playlist` + +**调用例子 :** `/comment/playlist?id=705123491` + +### mv 评论 + +说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该 mv 的所有评论 ( 不需要 +登录 ) + +**必选参数 :** `id`: mv id + +**可选参数 :** `limit`: 取出评论数量 , 默认为 20 + +`offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*20, 其中 20 为 limit 的值 + +`before`: 分页参数,取上一页最后一项的 `time` 获取下一页数据(获取超过5000条评论的时候需要用到) + +**接口地址 :** `/comment/mv` + +**调用例子 :** `/comment/mv?id=5436712` + +### 电台节目评论 + +说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该 电台节目 的所有评论 ( +不需要登录 ) + +**必选参数 :** `id`: 电台节目的 id + +**可选参数 :** `limit`: 取出评论数量 , 默认为 20 + +`offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*20, 其中 20 为 limit 的值 + +`before`: 分页参数,取上一页最后一项的 `time` 获取下一页数据(获取超过5000条评论的时候需要用到) + +**接口地址 :** `/comment/dj` + +**调用例子 :** `/comment/dj?id=794062371` + +### 视频评论 + +说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该 视频 的所有评论 ( +不需要登录 ) + +**必选参数 :** `id`: 视频的 id + +**可选参数 :** `limit`: 取出评论数量 , 默认为 20 + +`offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*20, 其中 20 为 limit 的值 + +`before`: 分页参数,取上一页最后一项的 `time` 获取下一页数据(获取超过5000条评论的时候需要用到) + +**接口地址 :** `/comment/video` + +**调用例子 :** `/comment/video?id=89ADDE33C0AAE8EC14B99F6750DB954D` + +### 热门评论 + +说明 : 调用此接口 , 传入 type, 资源 id 可获得对应资源热门评论 ( 不需要登录 ) + +**必选参数 :** + +`id` : 资源 id + +`tpye`: 数字 , 资源类型 , 对应歌曲 , mv, 专辑 , 歌单 , 电台, 视频对应以下类型 + +``` +0: 歌曲 + +1: mv + +2: 歌单 + +3: 专辑 + +4: 电台 + +5: 视频 +``` + +**可选参数 :** `limit`: 取出评论数量 , 默认为 20 + +`offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*20, 其中 20 为 limit 的值 + +`before`: 分页参数,取上一页最后一项的 `time` 获取下一页数据(获取超过5000条评论的时候需要用到) + +**接口地址 :** `/comment/hot` + +**调用例子 :** `/comment/hot?id=186016&type=0` + +### 新版评论接口 +说明 : 调用此接口 , 传入资源类型和资源id,以及排序方式,可获取对应资源的评论 + +**必选参数 :** +`id` : 资源 id, 如歌曲 id,mv id + +`tpye`: 数字 , 资源类型 , 对应歌曲 , mv, 专辑 , 歌单 , 电台, 视频对应以下类型 +``` +0: 歌曲 + +1: mv + +2: 歌单 + +3: 专辑 + +4: 电台 + +5: 视频 + +6: 动态 +``` +**可选参数 :** +`pageNo`:分页参数,第N页,默认为1 + +`pageSize`:分页参数,每页多少条数据,默认20 + +`sortType`: 排序方式,1:按推荐排序,2:按热度排序,3:按时间排序 + +`cursor`: 当`sortType`为3时且页数不是第一页时需传入,值为上一条数据的time + +**接口地址 :** `/comment/new` + +**调用例子 :** `/comment/new?type=0&id=1407551413&sortType=3`, `/comment/new?type=0&id=1407551413&sortType=3&cursor=1602072870260&pageSize=20&pageNo=2` + +### 给评论点赞 + +说明 : 调用此接口 , 传入 type, 资源 id, 和评论 id cid 和 是否点赞参数 t 即可给对 +应评论点赞 ( 需要登录 ) + +**必选参数 :** `id` : 资源 id, 如歌曲 id,mv id + +`cid` : 评论 id + +`t` : 是否点赞 ,1 为点赞 ,0 为取消点赞 + +`tpye`: 数字 , 资源类型 , 对应歌曲 , mv, 专辑 , 歌单 , 电台, 视频对应以下类型 + +``` +0: 歌曲 + +1: mv + +2: 歌单 + +3: 专辑 + +4: 电台 + +5: 视频 + +6: 动态 +``` + +**接口地址 :** `/comment/like` + +**调用例子 :** `/comment/like?id=29178366&cid=12840183&t=1&type=0` 对应给 [https://music.163.com/#/song?id=29178366](https://music.163.com/#/song?id=29178366) 最热门的评论点赞 + + +注意: 动态点赞不需要传入 id 参数,需要传入动态的 `threadId` 参数,如:`/comment/like?type=6&cid=1419532712&threadId=A_EV_2_6559519868_32953014&t=0`, `threadId` 可通过 `/event`,`/user/event` 接口获取 + +### 抱一抱评论 + +说明 : 调用此接口,可抱一抱评论 + +**必选参数 :** + +`uid`: 用户id + +`cid`: 评论id + +`sid`: 资源id + +**接口地址 :** `/hug/comment` + +**调用例子 :** `/hug/comment?uid=285516405&cid=1167145843&sid=863481066` + +### 评论抱一抱列表 + +说明 : 调用此接口,可获取评论抱一抱列表 + +**必选参数 :** + +`uid`: 用户id + +`cid`: 评论id + +`sid`: 资源id + +**可选参数 :** + +`page`: 页数 + +`cursor`: 上一页返回的cursor,默认-1,第一页不需要传 + +`idCursor`: 上一页返回的idCursor,默认-1,第一页不需要传 + +`pageSize` : 每页页数,默认100 + +**接口地址 :** `/comment/hug/list` + +**调用例子 :** `/comment/hug/list?uid=285516405&cid=1167145843&sid=863481066&pageSize=2&page=1` + + +### 发送/删除评论 + +说明 : 调用此接口,可发送评论或者删除评论 + +**接口地址 :** `/comment` + +1. 发送评论 + + **必选参数** + + `t`:1 发送, 2 回复 + + `tpye`: 数字,资源类型,对应歌曲,mv,专辑,歌单,电台,视频对应以下类型 + + ``` + 0: 歌曲 + + 1: mv + + 2: 歌单 + + 3: 专辑 + + 4: 电台 + + 5: 视频 + + 6: 动态 + ``` + + `id`:对应资源 id + + `content` :要发送的内容 + + `commentId` :回复的评论id (回复评论时必填) + + **调用例子** : `/comment?t=1&type=1&id=5436712&content=test` (往广岛之恋 mv 发送评论: test) + + 注意:如给动态发送评论,则不需要传 id,需要传动态的 `threadId`,如:`/comment?t=1&type=6&threadId=A_EV_2_6559519868_32953014&content=test` + +2. 删除评论 + + **必选参数** + + `t`:0 删除 + + `tpye`: 数字,资源类型,对应歌曲,mv,专辑,歌单,电台,视频对应以下类型 + + + ``` + 0: 歌曲 + + 1: mv + + 2: 歌单 + + 3: 专辑 + + 4: 电台 + + + 5: 视频 + + 6: 动态 + + ``` + + `id`:对应资源 id + `content` :内容 id,可通过 `/comment/mv` 等接口获取 + + **调用例子** : `/comment?t=0&type=1&id=5436712&commentId=1535550516319` (在广岛之恋 mv 删除评论) + + + 注意:如给动态删除评论,则不需要传 id,需要传动态的 `threadId`,如:`/comment?t=0&type=6&threadId=A_EV_2_6559519868_32953014&commentId=1419516382` + + +### banner + +说明 : 调用此接口 , 可获取 banner( 轮播图 ) 数据 + +**可选参数 :** + +`type`:资源类型,对应以下类型,默认为 0 即PC + +``` +0: pc + +1: android + +2: iphone + +3: ipad +``` + +**接口地址 :** `/banner` + +**调用例子 :** `/banner`, `/banner?type=2` + +### 资源点赞( MV,电台,视频) + +说明 : 调用此接口 , 可对 MV,电台,视频点赞 + +**必选参数 :** + +`type`:资源类型,对应以下类型 + +``` +1: mv + +4: 电台 + +5: 视频 + +6: 动态 +``` + +`t`: 操作,1 为点赞,其他未取消点赞 + +`id`: 资源 id + +**接口地址 :** `/resource/like` + +**调用例子 :** `/resource/like?t=1&type=1&id=5436712` + +注意:如给动态点赞,不需要传入 id,需要传入 `threadId`,可通过 `event`,`/user/event` 接口获取,如: +`/resource/like?t=1&type=6&threadId=A_EV_2_6559519868_32953014` + +### 获取点赞过的视频 + +说明 : 调用此接口, 可获取获取点赞过的视频 + +**接口地址 :** `/playlist/mylike` + +**调用例子 :** `/playlist/mylike` + +### 获取歌曲详情 + +说明 : 调用此接口 , 传入音乐 id(支持多个 id, 用 `,` 隔开), 可获得歌曲详情(注意:歌曲封面现在需要通过专辑内容接口获取) + +**必选参数 :** `ids`: 音乐 id, 如 `ids=347230` + +**接口地址 :** `/song/detail` + +**调用例子 :** `/song/detail?ids=347230`,`/song/detail?ids=347230,347231` + +返回数据如下图 : +![获取歌曲详情](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/songDetail.png) + +### 获取专辑内容 + +说明 : 调用此接口 , 传入专辑 id, 可获得专辑内容 + +**必选参数 :** `id`: 专辑 id + +**接口地址 :** `/album` + +**调用例子 :** `/album?id=32311` + +返回数据如下图 : +![获取专辑内容](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E4%B8%93%E8%BE%91.png) + + +### 专辑动态信息 +说明 : 调用此接口 , 传入专辑 id, 可获得专辑动态信息,如是否收藏,收藏数,评论数,分享数 + +**必选参数 :** `id`: 专辑 id + +**接口地址 :** `/album/detail/dynamic` + +**调用例子 :** `/album/detail/dynamic?id=32311` + +### 收藏/取消收藏专辑 + +说明 : 调用此接口,可收藏/取消收藏专辑 + +**必选参数 :** + +`id` : 专辑 id + +`t` : 1 为收藏,其他为取消收藏 + +**接口地址 :** `/album/sub` + +**调用例子 :** `/album/sub?t=1` `/album/sub?t=0` + +### 获取已收藏专辑列表 +说明 : 调用此接口 , 可获得已收藏专辑列表 + +**可选参数 :** +`limit`: 取出数量 , 默认为 25 + +`offset`: 偏移数量 , 用于分页 , 如 :( 页数 -1)\*25, 其中 25 为 limit 的值 , 默认 +为 0 + +**接口地址 :** `/album/sublist` + +**调用例子 :** `/album/sublist` ( 周杰伦 ) + +### 获取歌手单曲 + +说明 : 调用此接口 , 传入歌手 id, 可获得歌手部分信息和热门歌曲 + +**必选参数 :** `id`: 歌手 id, 可由搜索接口获得 + +**接口地址 :** `/artists` + +**调用例子 :** `/artists?id=6452` + +返回数据如下图 : +![获取歌手单曲](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/artists.png) + +### 获取歌手 mv + +说明 : 调用此接口 , 传入歌手 id, 可获得歌手 mv 信息 , 具体 mv 播放地址可调 +用`/mv`传入此接口获得的 mvid 来拿到 , 如 : +`/artist/mv?id=6452`,`/mv?mvid=5461064` + +**必选参数 :** `id`: 歌手 id, 可由搜索接口获得 + +**接口地址 :** `/artist/mv` + +**调用例子 :** `/artist/mv?id=6452` + +### 获取歌手专辑 + +说明 : 调用此接口 , 传入歌手 id, 可获得歌手专辑内容 + +**必选参数 :** `id`: 歌手 id + +**可选参数 :** `limit`: 取出数量 , 默认为 50 + +`offset`: 偏移数量 , 用于分页 , 如 :( 页数 -1)\*50, 其中 50 为 limit 的值 , 默认 +为 0 + +**接口地址 :** `/artist/album` + +**调用例子 :** `/artist/album?id=6452&limit=30` ( 周杰伦 ) + +返回数据如下图 : +![获取专辑内容](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/artist_album.png) + +### 获取歌手描述 + +说明 : 调用此接口 , 传入歌手 id, 可获得歌手描述 + +**必选参数 :** `id`: 歌手 id + +**接口地址 :** `/artist/desc` + +**调用例子 :** `/artist/desc?id=6452` ( 周杰伦 ) + +### 获取歌手详情 + +说明 : 调用此接口 , 传入歌手 id, 可获得获取歌手详情 + +**必选参数 :** `id`: 歌手 id + +**接口地址 :** `/artist/detail` + +**调用例子 :** `/artist/detail?id=11972054` (Billie Eilish) + +### 获取相似歌手 + +说明 : 调用此接口 , 传入歌手 id, 可获得相似歌手 + +**必选参数 :** `id`: 歌手 id + +**接口地址 :** `/simi/artist` + +**调用例子 :** `/simi/artist?id=6452` ( 对应和周杰伦相似歌手 ) + +### 获取相似歌单 + +说明 : 调用此接口 , 传入歌曲 id, 可获得相似歌单 + +**必选参数 :** `id`: 歌曲 id + +**接口地址 :** `/simi/playlist` + +**调用例子 :** `/simi/playlist?id=347230` ( 对应 ' 光辉岁月 ' 相似歌单 ) + +### 相似 mv + +说明 : 调用此接口 , 传入 `mvid` 可获取相似 mv + +**必选参数 :** `mvid`: mv id + +**接口地址 :** `/simi/mv` + +**调用例子 :** `/simi/mv?mvid=5436712` + +### 获取相似音乐 + +说明 : 调用此接口 , 传入歌曲 id, 可获得相似歌曲 + +**必选参数 :** `id`: 歌曲 id + +**接口地址 :** `/simi/song` + +**调用例子 :** `/simi/song?id=347230` ( 对应 ' 光辉岁月 ' 相似歌曲 ) + +### 获取最近 5 个听了这首歌的用户 + +说明 : 调用此接口 , 传入歌曲 id, 最近 5 个听了这首歌的用户 + +**必选参数 :** `id`: 歌曲 id + +**接口地址 :** `/simi/user` + +**调用例子 :** `/simi/user?id=347230` ( 对应 ' 光辉岁月 ' 相似歌曲 ) + +### 获取每日推荐歌单 + +说明 : 调用此接口 , 可获得每日推荐歌单 ( 需要登录 ) + +**接口地址 :** `/recommend/resource` + +**调用例子 :** `/recommend/resource` + +返回数据如下图 : +![每日推荐歌单](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E6%8E%A8%E8%8D%90%E6%AD%8C%E5%8D%95.png) + +### 获取每日推荐歌曲 + +说明 : 调用此接口 , 可获得每日推荐歌曲 ( 需要登录 ) + +**接口地址 :** `/recommend/songs` + +**调用例子 :** `/recommend/songs` + +返回数据如下图 : +![每日推荐歌曲](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E6%8E%A8%E8%8D%90%E6%AD%8C%E6%9B%B2.png) + +### 获取历史日推可用日期列表 + +说明 : 调用此接口 , 可获得历史日推可用日期列表 + +**接口地址 :** `/history/recommend/songs` + +**调用例子 :** `/history/recommend/songs` + +### 获取历史日推详情数据 + +说明 : 调用此接口 ,传入当日日期, 可获得当日历史日推数据 + +**必选参数 :** `date`: 日期,通过历史日推可用日期列表接口获取,不能任意日期 + +**接口地址 :** `/history/recommend/songs/detail` + +**调用例子 :** `/history/recommend/songs/detail?date=2020-06-21` + +### 私人 FM + +说明 : 私人 FM( 需要登录 ) + +**接口地址 :** `/personal_fm` + +**调用例子 :** `/personal_fm` + +返回数据如下图 : + +![私人 FM](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/personal_fm.png) + +### 签到 + +说明 : 调用此接口 , 传入签到类型 ( 可不传 , 默认安卓端签到 ), 可签到 ( 需要登录 +), 其中安卓端签到可获得 3 点经验 , web/PC 端签到可获得 2 点经验 + +**可选参数 :** `type`: 签到类型 , 默认 0, 其中 0 为安卓端签到 ,1 为 web/PC 签到 + +**接口地址 :** `/daily_signin` + +**调用例子 :** `/daily_signin` + +返回数据如下图 : + +![签到成功](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/signinSuccess.png) + +![签到失败](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/signinError.png) + +### 喜欢音乐 + +说明 : 调用此接口 , 传入音乐 id, 可喜欢该音乐 + +**必选参数 :** `id`: 歌曲 id + +**可选参数 :** `like`: 布尔值 , 默认为 true 即喜欢 , 若传 false, 则取消喜欢 + +**接口地址 :** `/like` + +**调用例子 :** `/like?id=347230` + +返回数据如下图 : + +![喜欢成功](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/like.png) + +喜欢成功则返回数据的 code 为 200, 其余为失败 + +![喜欢成功截图](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/likeSuccess.png) + +### 喜欢音乐列表 + +说明 : 调用此接口 , 传入用户 id, 可获取已喜欢音乐id列表(id数组) + +**必选参数 :** `uid`: 用户 id + +**接口地址 :** `/likelist` + +**调用例子 :** `/likelist?uid=32953014` + +### 垃圾桶 + +说明 : 调用此接口 , 传入音乐 id, 可把该音乐从私人 FM 中移除至垃圾桶 + +**必选参数 :** `id`: 歌曲 id + +**接口地址 :** `/fm_trash` + +**调用例子 :** `/fm_trash?id=347230` + +返回数据如下图 : + +![移除成功](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/fm_trash.png) + +### 新碟上架 + +说明 : 调用此接口 , 可获取新碟上架列表 , 如需具体音乐信息需要调用获取专辑列表接 +口 `/album` , 然后传入 id, 如 `/album?id=32311&limit=30` + +**可选参数 :** + + `limit`: 取出数量 , 默认为 50 + +`offset`: 偏移数量 , 用于分页 , 如 :( 页数 -1)\*50, 其中 50 为 limit 的值 , 默认 +为 0 + +`area`: ALL:全部,ZH:华语,EA:欧美,KR:韩国,JP:日本 + +`type` : new:全部 hot:热门,默认为 new + +`year` : 年,默认本年 + +`month` : 月,默认本月 + +**接口地址 :** `/top/album` + +**调用例子 :** `/top/album?offset=0&limit=30&year=2019&month=6` + +### 全部新碟 +说明 : 登录后调用此接口 ,可获取全部新碟 + +**可选参数 :** + +`limit` : 返回数量 , 默认为 30 + +`offset` : 偏移数量,用于分页 , 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 + +`area` : ALL:全部,ZH:华语,EA:欧美,KR:韩国,JP:日本 + +**接口地址 :** `/album/new` + +**调用例子 :** `/album/new?area=KR&limit=10` + +### 最新专辑 + +说明 : 调用此接口 ,获取云音乐首页新碟上架数据 + +**接口地址 :** `/album/newest` + +**调用例子 :** `/album/newest` + +### 听歌打卡 + +说明 : 调用此接口 , 传入音乐 id, 来源 id,歌曲时间 time,更新听歌排行数据 + +**必选参数 :** `id`: 歌曲 id, `sourceid`: 歌单或专辑 id + +**可选参数 :** `time`: 歌曲播放时间,单位为秒 + +**接口地址 :** `/scrobble` + +**调用例子 :** `/scrobble?id=518066366&sourceid=36780169&time=291` + +### 热门歌手 + +说明 : 调用此接口 , 可获取热门歌手数据 + +**可选参数 :** `limit`: 取出数量 , 默认为 50 + +`offset`: 偏移数量 , 用于分页 , 如 :( 页数 -1)\*50, 其中 50 为 limit 的值 , 默认 +为 0 + +**接口地址 :** `/top/artists` + +**调用例子 :** `/top/artists?offset=0&limit=30` + +返回数据如下图 : + +![热门歌手](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/top_artists.png) + +### 全部 mv +说明 : 调用此接口 , 可获取全部 mv + +**可选参数 :** +`area`: 地区,可选值为全部,内地,港台,欧美,日本,韩国,不填则为全部 +`type`: 类型,可选值为全部,官方版,原生,现场版,网易出品,不填则为全部 + +`order`: 排序,可选值为上升最快,最热,最新,不填则为上升最快 + +`limit`: 取出数量 , 默认为 30 + +`offset`: 偏移数量 , 用于分页 , 如 :( 页数 -1)\*50, 其中 50 为 limit 的值 , 默认 +为 0 + +**接口地址 :** `/mv/all` + +**调用例子 :** `/mv/all?area=港台` + +### 最新 mv +说明 : 调用此接口 , 可获取最新 mv + +**可选参数 :** `area`: 地区,可选值为全部,内地,港台,欧美,日本,韩国,不填则为全部 + +**可选参数 :** `limit`: 取出数量 , 默认为 30 + +**接口地址 :** `/mv/first` + +**调用例子 :** `/mv/first?limit=10` + +### 网易出品mv + +说明 : 调用此接口 , 可获取网易出品 mv + +**可选参数 :** `limit`: 取出数量 , 默认为 30 + +`offset`: 偏移数量 , 用于分页 , 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认 +为 0 + +**接口地址 :** `/mv/exclusive/rcmd` + +**调用例子 :** `/mv/exclusive/rcmd?limit=10` + +### 推荐 mv + +说明 : 调用此接口 , 可获取推荐 mv + +**接口地址 :** `/personalized/mv` + +**调用例子 :** `/personalized/mv` + +### 推荐歌单 + +说明 : 调用此接口 , 可获取推荐歌单 + +**可选参数 :** `limit`: 取出数量 , 默认为 30 (不支持 offset) + +**接口地址 :** `/personalized` + +**调用例子 :** `/personalized?limit=1` + +### 推荐新音乐 + +说明 : 调用此接口 , 可获取推荐新音乐 + +**可选参数 :** `limit`: 取出数量 , 默认为 10 (不支持 offset) + +**接口地址 :** `/personalized/newsong` + +**调用例子 :** `/personalized/newsong` + +### 推荐电台 + +说明 : 调用此接口 , 可获取推荐电台 + +**接口地址 :** `/personalized/djprogram` + +**调用例子 :** `/personalized/djprogram` + +### 推荐节目 + +说明 : 调用此接口 , 可获取推荐电台 + +**接口地址 :** `/program/recommend` + +**调用例子 :** `/program/recommend` + +### 独家放送(入口列表) + +说明 : 调用此接口 , 可获取独家放送 + +**接口地址 :** `/personalized/privatecontent` + +**调用例子 :** `/personalized/privatecontent` + +### 独家放送列表 + +说明 : 调用此接口 , 可获取独家放送列表 + +**可选参数 :** + +`limit` : 返回数量 , 默认为 60 + +`offset` : 偏移数量,用于分页 , 如 :( 页数 -1)\*60, 其中 60 为 limit 的值 , 默认为 0 + +**接口地址 :** `/personalized/privatecontent/list` + +**调用例子 :** `/personalized/privatecontent/list?limit=1&offset=2` + +### mv 排行 + +说明 : 调用此接口 , 可获取 mv 排行 + +**可选参数 :** `limit`: 取出数量 , 默认为 30 + +`area`: 地区,可选值为内地,港台,欧美,日本,韩国,不填则为全部 + +`offset`: 偏移数量 , 用于分页 , 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认 +为 0 + +**接口地址 :** `/top/mv` + +**调用例子 :** `/top/mv?limit=10` + +### 获取 mv 数据 + +说明 : 调用此接口 , 传入 mvid ( 在搜索音乐的时候传 type=1004 获得 ) , 可获取对应 +MV 数据 , 数据包含 mv 名字 , 歌手 , 发布时间 , mv 视频地址等数据 , 其中 mv 视频 +网易做了防盗链处理 , 可能不能直接播放 , 需要播放的话需要调用 ' mv 地址' 接口 + +**必选参数 :** `mvid`: mv 的 id + +**接口地址 :** `/mv/detail` + +**调用例子 :** `/mv/detail?mvid=5436712` + +返回数据如下图 : + +![mv 数据](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/mv.png) + +### 获取 mv 点赞转发评论数数据 +说明 : 调用此接口 , 传入 mvid ( 在搜索音乐的时候传 type=1004 获得 ) , 可获取对应 +MV 点赞转发评论数数据 + +**必选参数 :** `mvid`: mv 的 id + +**接口地址 :** `/mv/detail/info` + +**调用例子 :** `/mv/detail/info?mvid=5436712` + +### mv 地址 + +说明 : 调用此接口 , 传入 mv id,可获取 mv 播放地址 + +**必选参数 :** `id`: mv id + +**可选参数 :** `r`: 分辨率,默认1080,可从 `/mv/detail` 接口获取分辨率列表 + +**接口地址 :** `/mv/url` + +**调用例子 :** + +`/mv/url?id=5436712` `/mv/url?id=10896407&r=1080` + +### 获取视频标签列表 +说明 : 调用此接口 , 可获取视频标签列表 + +**接口地址 :** `/video/group/list` + +**调用例子 :** `/video/group/list` + +### 获取视频分类列表 +说明 : 调用此接口 , 可获取视频分类列表 + +**接口地址 :** `/video/category/list` + +**调用例子 :** `/video/category/list` + +### 获取视频标签/分类下的视频 +说明 : 调用此接口 , 传入标签/分类`id`,可获取到相关的视频,分页参数只能传入offset + +**必选参数 :** `id`: videoGroup 的 id + +**可选参数 :** `offset`: 默认0 + +**接口地址 :** `/video/group` + +**调用例子 :** `/video/group?id=9104` + +### 获取全部视频列表 +说明 : 调用此接口,可获取视频分类列表,分页参数只能传入offset + +**可选参数 :** `offset`: 默认0 + +**接口地址 :** `/video/timeline/all` + +**调用例子 :** `/video/timeline/all` + +### 获取推荐视频 +说明 : 调用此接口, 可获取推荐视频,分页参数只能传入offset + +**可选参数 :** `offset`: 默认0 + +**接口地址 :** `/video/timeline/recommend` + +**调用例子 :** `/video/timeline/recommend?offset=10` + +### 相关视频 + +说明 : 调用此接口 , 可获取相关视频 + +**必选参数 :** `id`: 视频 的 id + +**接口地址 :** `/related/allvideo` + +**调用例子 :** `/related/allvideo?id=89ADDE33C0AAE8EC14B99F6750DB954D` + + +### 视频详情 + +说明 : 调用此接口 , 可获取视频详情 + +**必选参数 :** `id`: 视频 的 id + +**接口地址 :** `/video/detail` + +**调用例子 :** `/video/detail?id=89ADDE33C0AAE8EC14B99F6750DB954D` + +### 获取视频点赞转发评论数数据 +说明 : 调用此接口 , 传入 vid ( 视频id ) , 可获取对应视频点赞转发评论数数据 +**必选参数 :** `vid`: 视频id + +**接口地址 :** `/video/detail/info` + +**调用例子 :** `/video/detail/info?vid=89ADDE33C0AAE8EC14B99F6750DB954D` + +### 获取视频播放地址 + +说明 : 调用此接口 , 传入视频 id,可获取视频播放地址 + +**必选参数 :** `id`: 视频 的 id + +**接口地址 :** `/video/url` + +**调用例子 :** `/video/url?id=89ADDE33C0AAE8EC14B99F6750DB954D` + + +### 所有榜单 + +说明 : 调用此接口,可获取所有榜单 +**接口地址 :** `/toplist` + +**调用例子 :** `/toplist` + +### 排行榜详情 +说明: 请使用[歌单详情](#获取歌单详情)接口,传入排行榜id获取排行榜详情数据(排行榜也是歌单的一种) + +~~说明 : 调用此接口 , 传入榜单 id, 可获取不同排行榜数据(v3.34.0之后不再支持idx参数)~~ + +~~**必选参数 :** `id`: 榜单id,通过所有榜单接口获取~~ + +~~**接口地址 :** `/top/list`~~ + +~~**调用例子 :** `/top/list?id=2809577409`~~ + + +### 所有榜单内容摘要 + +说明 : 调用此接口,可获取所有榜单内容摘要 + +**接口地址 :** `/toplist/detail` + +**调用例子 :** `/toplist/detail` + +### 歌手榜 + +说明 : 调用此接口 , 可获取排行榜中的歌手榜 + +**可选参数 :** +``` +type : 地区 +1: 华语 +2: 欧美 +3: 韩国 +4: 日本 +``` +**接口地址 :** `/toplist/artist` + +**调用例子 :** `/toplist/artist` + +### 云盘 + +说明 : 登录后调用此接口 , 可获取云盘数据 , 获取的数据没有对应 url, 需要再调用一 +次 `/song/url` 获取 url + +**可选参数 :** + +`limit` : 返回数量 , 默认为 200 + +`offset` : 偏移数量,用于分页 , 如 :( 页数 -1)\*200, 其中 200 为 limit 的值 , 默认为 0 + +**接口地址 :** `/user/cloud` + +**调用例子 :** `/user/cloud` + +### 云盘数据详情 +说明 : 登录后调用此接口 , 传入云盘歌曲 id,可获取云盘数据详情 + +**必选参数 :** `id`: 歌曲id,可多个,用逗号隔开 + +**接口地址 :** `/user/cloud/detail` + +**调用例子 :** `/user/cloud/detail?id=5374627` + + +### 云盘歌曲删除 +说明 : 登录后调用此接口 , 可删除云盘歌曲 + +**必选参数 :** `id`: 歌曲id,可多个,用逗号隔开 + +**接口地址 :** `/user/cloud/del` + +**调用例子 :** `/user/cloud/del` + +### 云盘上传 +说明 : 登录后调用此接口,使用`'Content-Type': 'multipart/form-data'`上传mp3 formData(name为'songFile'),可上传歌曲到云盘 + +参考: https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/public/cloud.html + +访问地址: http://localhost:3000/cloud.html) + +支持命令行调用,参考module_example目录下`song_upload.js` + +**接口地址 :** `/cloud` + +**调用例子 :** `/cloud` + +### 电台banner +说明 : 调用此接口,可获取电台banner + +**接口地址 :** `/dj/banner` + +**调用例子 :** `/dj/banner` + +### 电台个性推荐 +说明 : 调用此接口,可获取电台个性推荐列表 +**可选参数 :** + +`limit` : 返回数量,默认为 6,总条数最多6条 + +**接口地址 :** `/dj/personalize/recommend` + +**调用例子 :** `/dj/personalize/recommend?limit=5` + +### 电台订阅者列表 +说明 : 调用此接口,可获取电台订阅者列表 +**必选参数 :** `id`: 电台id + +**可选参数 :** +`time` : 分页参数,默认-1,传入上一次返回结果的 time,将会返回下一页的数据 + +`limit` : 返回数量,默认为 20 + +**接口地址 :** `/dj/subscriber` + +**调用例子 :** `/dj/subscriber?id=335425050` , `/dj/subscriber?id=335425050&time=1602761825390` + +### 用户电台 + +说明 : 调用此接口, 传入用户id可获取用户创建的电台 + +**必选参数 :** `uid`: 用户id + +**接口地址 :** `/user/audio` + +**调用例子 :** `/user/audio?uid=32953014` + +### 热门电台 +说明 : 调用此接口,可获取热门电台 + +**可选参数 :** + +`limit` : 返回数量 , 默认为 30 + +`offset` : 偏移数量,用于分页 , 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 +**接口地址 :** `/dj/hot` + +**调用例子 :** `/dj/hot` + +### 电台 - 节目榜 + +说明 : 登录后调用此接口 , 可获得电台节目榜 + +**可选参数 :** + +`limit` : 返回数量 , 默认为 100 + +`offset` : 偏移数量,用于分页 , 如 :( 页数 -1)\*100, 其中 100 为 limit 的值 , 默认为 0 + +**接口地址 :** `/dj/program/toplist` + +**调用例子 :** `/dj/program/toplist?limit=1` + +### 电台 - 付费精品 +说明 : 调用此接口,可获取付费精品电台 + +**可选参数 :** + +`limit` : 返回数量 , 默认为 100 (不支持 offset) + +**接口地址 :** `/dj/toplist/pay` + +**调用例子 :** `/dj/toplist/pay?limit=30` + + +### 电台 - 24小时节目榜 +说明 : 调用此接口,可获取24小时节目榜 + +**可选参数 :** + +`limit` : 返回数量 , 默认为 100 (不支持 offset) + +**接口地址 :** `/dj/program/toplist/hours` + +**调用例子 :** `/dj/program/toplist/hours?limit=1` + +### 电台 - 24小时主播榜 +说明 : 调用此接口,可获取24小时主播榜 + +**可选参数 :** + +`limit` : 返回数量 , 默认为 100 (不支持 offset) + +**接口地址 :** `/dj/toplist/hours` + +**调用例子 :** `/dj/toplist/hours?limit=30` + +### 电台 - 主播新人榜 +说明 : 调用此接口,可获取主播新人榜 + +**可选参数 :** + +`limit` : 返回数量 , 默认为 100 (不支持 offset) + +**接口地址 :** `/dj/toplist/newcomer` + +**调用例子 :** `/dj/toplist/newcomer?limit=30` + + +### 电台 - 最热主播榜 +说明 : 调用此接口,可获取最热主播榜 + +**可选参数 :** + +`limit` : 返回数量 , 默认为 100 (不支持 offset) + +**接口地址 :** `/dj/toplist/popular` + +**调用例子 :** `/dj/toplist/popular?limit=30` + +### 电台 - 新晋电台榜/热门电台榜 + +说明 : 登录后调用此接口 , 可获得新晋电台榜/热门电台榜 + +**可选参数 :** + +`limit` : 返回数量 , 默认为 100 + +`offset` : 偏移数量,用于分页 , 如 :( 页数 -1)\*100, 其中 100 为 limit 的值 , 默认为 0 + +`type`: 榜单类型, `new` 为新晋电台榜,`hot`为热门电台榜 + +**接口地址 :** `/dj/toplist` + +**调用例子 :** `/dj/toplist?type=hot` `/dj/toplist?type=new&limit=1` + +### 电台 - 类别热门电台 + +**可选参数 :** + +`limit` : 返回数量 , 默认为 30 + +`offset` : 偏移数量,用于分页 , 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 + +`cateId`: 类别 id,可通过 `/dj/category/recommend` 接口获取 + +**接口地址 :** `/dj/radio/hot` + +**调用例子 :** `/dj/radio/hot?cateId=2001`(创作|翻唱) `/dj/radio/hot?cateId=10002` (3D|电子) + +### 电台 - 推荐 + +说明 : 登录后调用此接口 , 可获得推荐电台 + +**接口地址 :** `/dj/recommend` + +**调用例子 :** `/dj/recommend` + +### 电台 - 分类 + +说明 : 登录后调用此接口 , 可获得电台类型 + +**接口地址 :** `/dj/catelist` + +**调用例子 :** `/dj/catelist` + +### 电台 - 分类推荐 + +说明 : 登录后调用此接口 , 传入分类,可获得对应类型电台列表 + +**必选参数 :** `type`: 电台类型 , 数字 , 可通过`/dj/catelist`获取 , 对应关系为 +id 对应 此接口的 type, name 对应类型 + +**接口地址 :** `/dj/recommend/type` + +**调用例子 :** `/dj/recommend/type?type=1`(明星做主播) `/dj/recommend/type?type=2001` (创作|翻唱) + +### 电台 - 订阅 + +说明 : 登录后调用此接口 , 传入`rid`, 可订阅 dj,dj 的 `rid` 可通过搜索指定 +type='1009' 获取其 id, 如`/search?keywords= 代码时间 &type=1009` + +**必选参数 :** `rid`: 电台 的 id + +**接口地址 :** `/dj/sub` + +**调用例子 :** `/dj/sub?rid=336355127&t=1` ( 对应关注 ' 代码时间 ') +`/dj/sub?rid=336355127&t=0` ( 对应取消关注 ' 代码时间 ') + +### 电台的订阅列表 + +说明 : 登录后调用此接口 , 可获取订阅的电台列表 + +**接口地址 :** `/dj/sublist` + +**调用例子 :** `/dj/sublist` + +### 电台 - 付费精选 + +说明 : 可以获取付费精选的电台列表 , 传入 `limit` 和 `offset` 可以进行分页 + +**可选参数 :** + +`limit` : 返回数量 , 默认为 30 + +`offset` : 偏移数量,用于分页 , 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 + +**接口地址 :** `/dj/paygift` + +**调用例子 :** `/dj/paygift?limit=10&offset=20` + +### 电台 - 非热门类型 + +说明 : 登录后调用此接口, 可获得电台非热门类型 + + +**接口地址 :** `/dj/category/excludehot` + +**调用例子 :** `/dj/category/excludehot` + +### 电台 - 推荐类型 + +说明 : 登录后调用此接口, 可获得电台推荐类型 + + +**接口地址 :** `/dj/category/recommend` + +**调用例子 :** `/dj/category/recommend` + +### 电台 - 今日优选 + +说明 : 登录后调用此接口, 可获得电台今日优选 + + +**接口地址 :** `/dj/today/perfered` + +**调用例子 :** `/dj/today/perfered` + +### 电台 - 详情 + +说明 : 登录后调用此接口 , 传入`rid`, 可获得对应电台的详情介绍 + +**必选参数 :** `rid`: 电台 的 id + +**接口地址 :** `/dj/detail` + +**调用例子 :** `/dj/detail?rid=336355127` ( 对应 ' 代码时间 ' 的详情介绍 ) + +### 电台 - 节目 + +说明 : 登录后调用此接口 , 传入`rid`, 可查看对应电台的电台节目以及对应的 id, 需要 +注意的是这个接口返回的 mp3Url 已经无效 , 都为 null, 但是通过调用 `/song/url` 这 +个接口 , 传入节目 id 仍然能获取到节目音频 , 如 `/song/url?id=478446370` 获取代 +码时间的一个节目的音频 + +**必选参数 :** `rid`: 电台 的 id + +**可选参数 :** + +`limit` : 返回数量 , 默认为 30 + +`offset` : 偏移数量,用于分页 , 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 + +`asc` : 排序方式,默认为 `false` (新 => 老 ) 设置 `true` 可改为 老 => 新 + +**接口地址 :** `/dj/program` + +**调用例子 :** `/dj/program?rid=336355127&limit=40` ( 对应 ' 代码时间 ' 的节目列表 ) + +### 电台 - 节目详情 +说明 : 调用此接口传入电台节目id,可获得电台节目详情 + +**必选参数 :** `id`: 电台节目 的 id + +**接口地址 :** `/dj/program/detail` + +**调用例子 :** `/dj/program/detail?id=1367665101` + +### 通知 - 私信 + +说明 : 登录后调用此接口 ,可获取私信 + +**可选参数 :** + +`limit` : 返回数量 , 默认为 30 + +`offset` : 偏移数量,用于分页 , 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 + +**接口地址 :** `/msg/private` + +**调用例子 :** `/msg/private?limit=3` + +### 发送私信 + +说明 : 登录后调用此接口 , 传入用户 id 和要发送的信息, 可以发送私信,返回内容为历史私信,包含带歌单的私信信息(注:不能发送私信给自己) + +**必选参数 :** + +`user_ids` : 用户 id,多个需用逗号隔开 + +`msg` : 要发送的信息 + +**接口地址 :** `/send/text` + +**调用例子 :** `/send/text?user_ids=32953014&msg=test`,`/send/text?user_ids=32953014,475625142&msg=test` + +### 发送私信(带歌曲) + +说明 : 登录后调用此接口 , 传入用户 id 和要发送的信息,音乐id, 可以发送音乐私信,返回内容为历史私信 + +**必选参数 :** + +`user_ids` : 用户 id,多个需用逗号隔开 + +`id` : 要发送音乐的id + +`msg` : 要发送的信息 + +**接口地址 :** `/send/song` + +**调用例子 :** `/send/song?user_ids=1&id=351318&msg=测试` + +### 发送私信(带专辑) + +说明 : 登录后调用此接口 , 传入用户 id 和要发送的信息,专辑id, 可以发送专辑私信,返回内容为消息id + +**必选参数 :** + +`user_ids` : 用户 id,多个需用逗号隔开 + +`id` : 要发送专辑的id + +`msg` : 要发送的信息 + +**接口地址 :** `/send/album` + +**调用例子 :** `/send/album?user_ids=1&id=351318&msg=测试` + +### 发送私信(带歌单) + +说明 : 登录后调用此接口 , 传入用户 id 和要发送的信息和歌单 id, 可以发送带歌单的私信(注:不能发送重复的歌单) + +**必选参数 :** + +`user_ids` : 用户 id,多个需用逗号隔开 + +`msg` : 要发送的信息 + +**接口地址 :** `/send/playlist` + +**调用例子 :** `/send/playlist?msg=test&user_ids=475625142&playlist=705123491`,`/send/playlist?msg=test2&user_ids=475625142,32953014&playlist=705123493` + +### 最近联系人 +说明 : 登录后调用此接口 ,可获取最接近联系人 + +**接口地址 :** `/msg/recentcontact` + +**调用例子 :** `/msg/recentcontact` + +### 私信内容 +说明 : 登录后调用此接口 , 可获取私信内容 + +**必选参数 :** +`uid` : 用户 id + +**可选参数 :** +`limit` : 返回数量 , 默认为 30 + +`before` : 分页参数,取上一页最后一项的 `time` 获取下一页数据 + +**接口地址 :** +`/msg/private/history` + +**调用例子 :** +`/msg/private/history?uid=9003` (云音乐小秘书) + +### 通知 - 评论 + +说明 : 登录后调用此接口 ,可获取评论 + +**必选参数 :** `uid`: 用户 的 id,只能和登录账号的 id 一致 + +**可选参数 :** + +`limit` : 返回数量 , 默认为 30 + +`before` : 分页参数,取上一页最后一个歌单的 `updateTime` 获取下一页数据 + + +**接口地址 :** `/msg/comments` + +**调用例子 :** `/msg/comments?uid=32953014` + +### 通知 - @我 + +说明 : 登录后调用此接口 ,可获取@我数据 + +**可选参数 :** + +`limit` : 返回数量 , 默认为 30 + +`offset` : 偏移数量,用于分页 , 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 + +**接口地址 :** `/msg/forwards` + +**调用例子 :** `/msg/forwards?limit=3` + + +### 通知 - 通知 + +说明 : 登录后调用此接口 ,可获取通知 + +**可选参数 :** + +`limit` : 返回数量 , 默认为 30 + +`lasttime` : 返回数据的 `time` ,默认-1,传入上一次返回结果的 time,将会返回下一页的数据 + + +**接口地址 :** `/msg/notices` + +**调用例子 :** `/msg/notices?limit=3` + +### 设置 +说明 : 登录后调用此接口 ,可获取用户设置 + +**接口地址 :** `/setting` + +**调用例子 :** `/setting` + +### 数字专辑-新碟上架 +说明 : 调用此接口 ,可获取数字专辑-新碟上架 + +**可选参数 :** + +`limit` : 返回数量 , 默认为 30 + +`offset` : 偏移数量,用于分页 , 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 +**接口地址 :** `/album/list` + +**调用例子 :** `/album/list?limit=10` + +### 数字专辑&数字单曲-榜单 +说明 : 调用此接口 ,可获取数字专辑&数字单曲-榜单 + +**可选参数 :** + +`limit` : 返回数量 , 默认为 30 + +`offset` : 偏移数量,用于分页 , 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 + +`albumType` : 为数字专辑,1为数字单曲 + +`type` : daily:日榜,week:周榜,year:年榜,total:总榜 + +**接口地址 :** `/album_songsaleboard` + +**调用例子 :** `/album/songsaleboard?type=year&year=2020&albumType=0` + +### 数字专辑-语种风格馆 + +说明 : 调用此接口 ,可获取语种风格馆数字专辑列表 + +**可选参数 :** + +`limit` : 返回数量 , 默认为 30 + +`offset` : 偏移数量,用于分页 , 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 + +`area` 地区 Z_H:华语,E_A:欧美,KR:韩国,JP:日本 + +**接口地址 :** `/album/list/style` + +**调用例子 :** `/album/list/style?area=Z_H&offset=2` + +### 数字专辑详情 +说明 : 调用此接口 ,传入数字专辑id可获取数字专辑详情(和歌单详情有差异) + +**接口地址 :** `/album/detail` + +**调用例子 :** `/album/detail?id=84547195` + + +### 我的数字专辑 +说明 : 登录后调用此接口 ,可获取我的数字专辑 + +**接口地址 :** `/digitalAlbum/purchased` + +**调用例子 :** `/digitalAlbum/purchased?limit=10` + +### 购买数字专辑 +说明 : 登录后调用此接口 ,可获取购买数字专辑的地址,把地址生成二维码后,可扫描购买专辑 + +**必选参数 :** + +`id` : 专辑的 id + +`payment` : 支付方式, 0 为支付宝 3 为微信 + +`quantity` : 购买的数量 + +**接口地址 :** `/digitalAlbum/ordering` + +**调用例子 :** `/digitalAlbum/ordering?id=86286082&payment=3&quantity=1` + +### 音乐日历 +说明 : 登录后调用此接口,传入开始和结束时间,可获取音乐日历 + +**接口地址 :** `/calendar` + +**调用例子 :** `/calendar?startTime=1606752000000&endTime=1609430399999` + +### 云贝 +说明 : 登录后调用此接口可获取云贝签到信息(连续签到天数,第二天全部可获得的云贝) + +**接口地址 :** `/yunbei` + +**调用例子 :** `/yunbei` + +### 云贝今日签到信息 +说明 : 登录后调用此接口可获取云贝今日签到信息(今日签到获取的云贝数) + +**接口地址 :** `/yunbei/today` + +**调用例子 :** `/yunbei/today` + +### 云贝签到 +说明 : 登录后调用此接口可进行云贝签到 + +**接口地址 :** `/yunbei/sign` + +**调用例子 :** `/yunbei/sign` + +### 云贝账户信息 +说明 :登录后调用此接口可获取云贝账户信息(账户云贝数) + +**接口地址 :** `/yunbei/info` + +**调用例子 :** `/yunbei/info` + +### 云贝所有任务 +说明 :登录后调用此接口可获取云贝所有任务 + +**接口地址 :** `/yunbei/tasks` + +**调用例子 :** `/yunbei/tasks` + +### 云贝todo任务 +说明 :登录后调用此接口可获取云贝todo任务 + +**接口地址 :** `/yunbei/tasks/todo` + +**调用例子 :** `/yunbei/tasks/todo` + +### 云贝完成任务 +**必选参数 :** + +`userTaskId` : 任务id + +**可选参数 :** + +`depositCode`: 任务depositCode + +**接口地址 :** `/yunbei/task/finish` + +**调用例子 :** `/yunbei/task/finish?userTaskId=5146243240&depositCode=0` + +### 云贝收入 +说明 :登录后调用此接口可获取云贝收入 + +**可选参数 :** `limit`: 取出评论数量 , 默认为 10 + +`offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*10, 其中 10 为 limit 的值 + +**接口地址 :** `/yunbei/tasks/receipt` + +**调用例子 :** `/yunbei/tasks/receipt?limit=1` + +### 云贝支出 +说明 :登录后调用此接口可获取云贝支出 + +**可选参数 :** `limit`: 取出评论数量 , 默认为 10 + +`offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*10, 其中 10 为 limit 的值 +**接口地址 :** `/yunbei/tasks/expense` + +**调用例子 :** `/yunbei/tasks/expense?limit=1` + +### 关注歌手新歌 +说明 :登录后调用此接口可获取关注歌手新歌 + +**可选参数 :** `limit`: 取出评论数量 , 默认为 20 + +`before`: 上一页数据返回的publishTime的数据 + +**接口地址 :** `/artist/new/song` + +**调用例子 :** `/artist/new/song?limit=1` `/artist/new/song?limit=1&before=1602777625000` + + +### 关注歌手新MV +说明 :登录后调用此接口可获取关注歌手新MV + +**可选参数 :** `limit`: 取出评论数量 , 默认为 20 + +`before`: 上一页数据返回的publishTime的数据 + +**接口地址 :** `/artist/new/mv` + +**调用例子 :** `/artist/new/mv?limit=1` `/artist/new/mv?limit=1&before=1602777625000` + + +### batch批量请求接口 +说明 : 登录后调用此接口 ,传入接口和对应原始参数(原始参数非文档里写的参数,需参考源码),可批量请求接口 + +**接口地址 :** `/batch` + +**调用例子 :** 使用GET方式:`/batch?/api/v2/banner/get={"clientType":"pc"}` 使用POST方式传入参数:`{ "/api/v2/banner/get": {"clientType":"pc"} }` + + + +## 离线访问此文档 + +此文档同时也是 Progressive Web Apps(PWA), 加入了 serviceWorker, 可离线访问 + +## 关于此文档 + +此文档由 [docsify](https://github.com/QingWei-Li/docsify/) 生成 docsify 是一个动 +态生成文档网站的工具。不同于 GitBook、Hexo 的地方是它不会生成将 .md 转成 .html +文件,所有转换工作都是在运行时进行。 + +## License + +[The MIT License (MIT)](https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/LICENSE) diff --git a/netease_api/docs/_coverpage.md b/netease_api/docs/_coverpage.md new file mode 100644 index 0000000..e65dce2 --- /dev/null +++ b/netease_api/docs/_coverpage.md @@ -0,0 +1,13 @@ +# 网易云音乐 API + +> 网易云音乐 NodeJS 版 API + +- 全部接口已升级到最新 +- 具备登录接口,多达200多个接口 +- 更完善的文档 + + +[GitHub](https://github.com/Binaryify/NeteaseCloudMusicApi) +[Get Started](#neteasecloudmusicapi) + +![color](#ffffff) diff --git a/netease_api/docs/favicon.ico b/netease_api/docs/favicon.ico new file mode 100644 index 0000000..2e28d04 Binary files /dev/null and b/netease_api/docs/favicon.ico differ diff --git a/netease_api/docs/icon.png b/netease_api/docs/icon.png new file mode 100644 index 0000000..92eda4c Binary files /dev/null and b/netease_api/docs/icon.png differ diff --git a/netease_api/docs/index.html b/netease_api/docs/index.html new file mode 100644 index 0000000..966c514 --- /dev/null +++ b/netease_api/docs/index.html @@ -0,0 +1,46 @@ + + + + + + + 网易云音乐 NodeJS 版 API + + + + + + + + + +
+ + + + + + + + diff --git a/netease_api/docs/sw.js b/netease_api/docs/sw.js new file mode 100644 index 0000000..a50f9ba --- /dev/null +++ b/netease_api/docs/sw.js @@ -0,0 +1,90 @@ +/* =========================================================== + * docsify sw.js + * =========================================================== + * Copyright 2016 @huxpro + * Licensed under Apache 2.0 + * Register service worker. + * ========================================================== */ + +const RUNTIME = 'docsify' +const HOSTNAME_WHITELIST = [ + self.location.hostname, + 'fonts.gstatic.com', + 'fonts.googleapis.com', + 'unpkg.com', +] + +// The Util Function to hack URLs of intercepted requests +const getFixedUrl = (req) => { + var now = Date.now() + var url = new URL(req.url) + + // 1. fixed http URL + // Just keep syncing with location.protocol + // fetch(httpURL) belongs to active mixed content. + // And fetch(httpRequest) is not supported yet. + url.protocol = self.location.protocol + + // 2. add query for caching-busting. + // Github Pages served with Cache-Control: max-age=600 + // max-age on mutable content is error-prone, with SW life of bugs can even extend. + // Until cache mode of Fetch API landed, we have to workaround cache-busting with query string. + // Cache-Control-Bug: https://bugs.chromium.org/p/chromium/issues/detail?id=453190 + if (url.hostname === self.location.hostname) { + url.search += (url.search ? '&' : '?') + 'cache-bust=' + now + } + return url.href +} + +/** + * @Lifecycle Activate + * New one activated when old isnt being used. + * + * waitUntil(): activating ====> activated + */ +self.addEventListener('activate', (event) => { + event.waitUntil(self.clients.claim()) +}) + +/** + * @Functional Fetch + * All network requests are being intercepted here. + * + * void respondWith(Promise r) + */ +self.addEventListener('fetch', (event) => { + // Skip some of cross-origin requests, like those for Google Analytics. + if (HOSTNAME_WHITELIST.indexOf(new URL(event.request.url).hostname) > -1) { + // Stale-while-revalidate + // similar to HTTP's stale-while-revalidate: https://www.mnot.net/blog/2007/12/12/stale + // Upgrade from Jake's to Surma's: https://gist.github.com/surma/eb441223daaedf880801ad80006389f1 + const cached = caches.match(event.request) + const fixedUrl = getFixedUrl(event.request) + const fetched = fetch(fixedUrl, { cache: 'no-store' }) + const fetchedCopy = fetched.then((resp) => resp.clone()) + + // Call respondWith() with whatever we get first. + // If the fetch fails (e.g disconnected), wait for the cache. + // If there’s nothing in cache, wait for the fetch. + // If neither yields a response, return offline pages. + event.respondWith( + Promise.race([fetched.catch((_) => cached), cached]) + .then((resp) => resp || fetched) + .catch((_) => { + /* eat any errors */ + }), + ) + + // Update the cache with the version we fetched (only for ok status) + event.waitUntil( + Promise.all([fetchedCopy, caches.open(RUNTIME)]) + .then( + ([response, cache]) => + response.ok && cache.put(event.request, response), + ) + .catch((_) => { + /* eat any errors */ + }), + ) + } +}) diff --git a/netease_api/docs/v2.md b/netease_api/docs/v2.md new file mode 100644 index 0000000..d8382f3 --- /dev/null +++ b/netease_api/docs/v2.md @@ -0,0 +1,1429 @@ +# NeteaseCloudMusicApi + +网易云音乐 NodeJS 版 API + +## 灵感来自 + +[disoul/electron-cloud-music](https://github.com/disoul/electron-cloud-music) + +[darknessomi/musicbox](https://github.com/darknessomi/musicbox) + +[sqaiyan/netmusic-node](https://github.com/sqaiyan/netmusic-node) + +## 工作原理 + +跨站请求伪造 (CSRF), 伪造请求头 , 调用官方 API + +## 功能特性 + +1. 登录 +2. 刷新登录 +3. 获取用户信息 , 歌单,收藏,mv, dj 数量 +4. 获取用户歌单 +5. 获取用户电台 +6. 获取用户关注列表 +7. 获取用户粉丝列表 +8. 获取用户动态 +9. 获取用户播放记录 +10. 获取精品歌单 +11. 获取歌单详情 +12. 搜索 +13. 搜索建议 +14. 获取歌词 +15. 歌曲评论 +16. 收藏单曲到歌单 +17. 专辑评论 +18. 歌单评论 +19. mv 评论 +20. 电台节目评论 +21. banner +22. 获取歌曲详情 +23. 获取专辑内容 +24. 获取歌手单曲 +25. 获取歌手 mv +26. 获取歌手专辑 +27. 获取歌手描述 +28. 获取相似歌手 +29. 获取相似歌单 +30. 相似 mv +31. 获取相似音乐 +32. 获取最近 5 个听了这首歌的用户 +33. 获取每日推荐歌单 +34. 获取每日推荐歌曲 +35. 私人 FM +36. 签到 +37. 喜欢音乐 +38. 垃圾桶 +39. 歌单 ( 网友精选碟 ) +40. 新碟上架 +41. 热门歌手 +42. 最新 mv +43. 推荐 mv +44. 推荐歌单 +45. 推荐新音乐 +46. 推荐电台 +47. 推荐节目 +48. 独家放送 +49. mv 排行 +50. 获取 mv 数据 +51. 播放 mv/视频 +52. 排行榜 +53. 歌手榜 +54. 云盘 +55. 电台 - 推荐 +56. 电台 - 分类 +57. 电台 - 分类推荐 +58. 电台 - 订阅 +59. 电台 - 详情 +60. 电台 - 节目 +61. 给评论点赞 +62. 获取动态 +63. 获取热搜 +64. 发送私信 +65. 发送私信歌单 +66. 新建歌单 +67. 收藏/取消收藏歌单 +68. 歌单分类 +69. 收藏的歌手列表 +70. 订阅的电台列表 +71. 相关歌单推荐 +72. 付费精选接口 +73. 音乐是否可用检查接口 +74. 登录状态 +75. 获取视频数据 +76. 发送/删除评论 +77. 热门评论 +78. 视频评论 +79. 退出登录 + +## 安装 + +```shell +$ git clone git@github.com:Binaryify/NeteaseCloudMusicApi.git +$ npm install +``` + +## 运行 + +```shell +$ node app.js +``` + +服务器启动默认端口为 3000, 若不想使用 3000 端口 , 可使用以下命令 : Mac/Linux + +```shell +$ PORT=4000 node app.js +``` + +windows 下使用 git-bash 或者 cmder 等终端执行以下命令 : + +```shell +$ set PORT=4000 && node app.js +``` + +## 可以使用代理 + +在 query 参数中加上 proxy=your-proxy 即可让这一次的请求使用 proxy + +```javascript +// 例子 +const url = `http://localhost:3000/music/url?id=33894312&proxy=http://121.196.226.246:84` +fetch(url).then(function() { + // do what you want +}) + +// 结果 +// {"data":[{"id":33894312,"url":"http://m10.music.126.net/20180104125640/930a968b3fb04908b733506b3833e60b/ymusic/0fd6/4f65/43ed/a8772889f38dfcb91c04da915b301617.mp3","br":320000,"size":10691439,"md5":"a8772889f38dfcb91c04da915b301617","code":200,"expi":1200,"type":"mp3","gain":-2.0E-4,"fee":0,"uf":null,"payed":0,"flag":0,"canExtend":false}],"code": 200} +``` + +## Docker 容器运行 + +> 注意: 在 docker 中运行的时候, 由于使用了 request 来发请求, 所以会检查几个 +> proxy 相关的环境变量(如下所列), 这些环境变量 会影响到 request 的代理, 详情请参 +> 考[request 的文档](https://github.com/request/request#proxies), 如果这些环境变 +> 量 指向的代理不可用, 那么就会造成错误, 所以在使用 docker 的时候一定要注意这些 +> 环境变量. 不过, 要是你在 query 中加上了 proxy 参数, 那么环境变量会被覆盖, 就会 +> 用你通过 proxy 参数提供的代理了. + +request 相关的环境变量 + +1. http_proxy +2. https_proxy +3. HTTP_PROXY +4. HTTPS_PROXY +5. no_proxy +6. NO_PROXY + +```shell +docker pull twesix/netease-cloud-music +docker run -d -p 3000:3000 --name netease-cloud-music twesix/netease-music-api + +// 去掉或者设置相关的环境变量 +docker run -d -p 3000:3000 --name netease-cloud-music -e http_proxy= -e https_proxy= -e no_proxy= -e HTTP_PROXY= -e HTTPS_PROXY= -e NO_PROXY= netease-cloud-music +``` + +> 由于 docker 镜像更新不是很及时,推荐自己 build, 以下为 build 镜像的方式 + +``` +$ git clone https://github.com/Binaryify/NeteaseCloudMusicApi && cd NeteaseCloudMusicApi +$ sudo docker build . -t netease-music-api +$ sudo docker run -d -p 3000:3000 netease-music-api +``` + +## 接口文档 + +### 调用前须知 + +!> 为使用方便,降低门槛,登录接口直接使用了 get 明文请求,请按实际需求对源码修改 + +!> 由于接口做了缓存处理 ( 缓存 2 分钟 , 可在 app.js 设置 , 可能会导致登录后获取不 +到 cookie), 相同的 url 会在两分钟内只向网易服务器发一次请求 , 如果遇到不需要缓 +存结果的接口 , 可在请求 url 后面加一个时间戳参数使 url 不同 , 例子 : +`/simi/playlist?id=347230×tamp=1503019930000` + +!> 如果是跨域请求 , 请在所有请求带上 `xhrFields: { withCredentials: true }` 否则 +可能会因为没带上 cookie 导致 301, 具体例子可看 `public/test.html`, 例子使用 jQuery, axios 版本也类似 + +!> 301 错误基本都是没登录就调用了需要登录的接口,如果登录了还是提示 301, 基本都是缓存把数据缓存起来了,解决方法是等待 2 分钟或者重启服务重新登录后再调用接口 + +!> 部分接口如登录接口不能调用太频繁 , 否则可能会触发 503 错误或者 ip 高频错误 ,若需频繁调用 , 需要准备 IP 代理池 (更新:已加入缓存机制,但仍需注意). + +!> 本项目仅供学习使用 , 文档可能会有缓存 , 如果文档版本和 github 上的版本不一致,请清除缓存再查看 + +!> 由于网易限制,此项目在国外服务器上使用会受到限制,如需解决 , 可使用大陆服务器或者使用代理 , 感谢 [@hiyangguo](https://github.com/hiyangguo)提出的[解决方法](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/29#issuecomment-298358438): +在 'util.js' 的 'headers' 处增加 `X-Real-IP':'211.161.244.70' // 任意国内 IP` +即可解决 + +### 登录 + +说明 : 登录有两个接口 + +#### 1. 手机登录 + +**必选参数 :** `phone`: 手机号码 `password`: 密码 + +**接口地址 :** `/login/cellphone` + +**调用例子 :** `/login/cellphone?phone=xxx&password=yyy` + +#### 2. 邮箱登录 + +~~ 注意 : 此接口被网易和谐了 , 待修复 , 暂时使用手机登录 (2017.05.20)~~ + +> 更新 : 此接口已经可以正常使用(2018.07.03) + +**必选参数 :** `email`: 163 网易邮箱 `password`: 密码 + +**接口地址 :** `/login` + +**调用例子 :** `/login?email=xxx@163.com&password=yyy` + +返回数据如下图 : +![登录](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E7%99%BB%E5%BD%95.png) + +完成登录后 , 会在浏览器保存一个 Cookies 用作登录凭证 , 大部分 API 都需要用到这个 +Cookies + +#### 注意 + +调用登录接口的速度比调用其他接口慢 , 因为登录过程调用了加密算法 + +### 刷新登录 + +说明 : 调用此接口 , 可刷新登录状态 + +**调用例子 :** `/login/refresh` + +### 退出登录 + +说明 : 调用此接口 , 可退出登录 + +**调用例子 :** `/logout` + +### 登录状态 + +说明 : 调用此接口,可获取登录状态 + +**接口地址 :** `/login/status` +返回数据如下图: +![数据](https://ws2.sinaimg.cn/large/006tNbRwgy1fup6q18kk6j316i0nw0wa.jpg) + +### 获取用户详情 + +说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户详情 + +**必选参数 :** `uid` : 用户 id + +**接口地址 :** `/user/detail` + +**调用例子 :** `/user/detail?uid=32953014` + +### 获取用户信息 , 歌单,收藏,mv, dj 数量 + +说明 : 登录后调用此接口 , 可以获取用户信息 + +**接口地址 :** `/user/subcount` + +**调用例子 :** `/user/subcount` + +### 更新用户信息 + +说明 : 登录后调用此接口 , 传入相关信息,可以更新用户信息 + +**必选参数 :** + +``` +gender: 性别 0:保密 1:男性 2:女性 +birthday: 出生日期,时间戳 unix timestamp +nickname: 用户昵称 +province: 省份id +city: 城市id +signature:用户签名 +``` + +**接口地址 :** `/user/subcount` + +**调用例子 :** `/user/update/?gender=0&signature=测试签名&city=440300&nickname=binary&birthday=1525918298004&province=440000` + +### 获取用户歌单 + +说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户歌单 + +**必选参数 :** `uid` : 用户 id + +**接口地址 :** `/user/playlist` + +**调用例子 :** `/user/playlist?uid=32953014` + +返回数据如下图 : +![用户歌单](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E7%94%A8%E6%88%B7%E6%AD%8C%E5%8D%95.png) + +### 更新歌单 + +说明 : 登录后调用此接口,可以更新用户歌单 +参数: + +``` +id:歌单id +name:歌单名字 +desc:歌单描述 +tags:歌单tag +``` + +**接口地址 :** `/playlist/update` + +**调用例子 :** `/playlist/update/?id=24381616&name=新歌单&desc=描述&tags=学习` + +### 发送私信 + +说明 : 登录后调用此接口 , 传入用户 id 和要发送的信息, 可以发送私信,返回内容为历史私信,包含带歌单的私信信息(注:不能发送私信给自己) + +**必选参数 :** + +`user_ids` : 用户 id,多个需用逗号隔开 + +`msg` : 要发送的信息 + +**接口地址 :** `/send/text` + +**调用例子 :** `/send/text?user_ids=32953014&msg=test`,`/send/text?user_ids=32953014,475625142&msg=test` +返回数据如下图: +![数据](https://ws1.sinaimg.cn/large/006tKfTcgy1fr3p3hfeudj31kw1aek2e.jpg) + +### 发送私信(带歌单) + +说明 : 登录后调用此接口 , 传入用户 id 和要发送的信息和歌单 id, 可以发送带歌单的私信(注:不能发送重复的歌单) + +**必选参数 :** + +`user_ids` : 用户 id,多个需用逗号隔开 + +`msg` : 要发送的信息 + +**接口地址 :** `/send/playlist` + +**调用例子 :** `/send/playlist?msg=test&user_ids=475625142&playlist=705123491`,`/send/playlist?msg=test2&user_ids=475625142,32953014&playlist=705123493` +返回数据如下图: +![数据](https://ws1.sinaimg.cn/large/006tKfTcgy1fr3p1z7qmcj30v409adg5.jpg) + +### 获取用户电台 + +说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户电台 + +**必选参数 :** `uid` : 用户 id + +**接口地址 :** `/user/dj` + +**调用例子 :** `/user/dj?uid=32953014` + +### 获取用户关注列表 + +说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户关注列表 + +**必选参数 :** `uid` : 用户 id + +**可选参数 :** +`limit` : 返回数量 , 默认为 30 + +`offset` : 偏移数量,用于分页 , 如 +: 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 + +**接口地址 :** `/user/follows` + +**调用例子 :** `/user/follows?uid=32953014` + +### 获取用户粉丝列表 + +说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户粉丝列表 + +**必选参数 :** `uid` : 用户 id + +**可选参数 :** `limit` : 返回数量 , 默认为 30 `offset` : 偏移数量,用于分页 , 如 +: 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 + +**接口地址 :** `/user/followeds` + +**调用例子 :** `/user/followeds?uid=32953014` + +### 获取用户动态 + +说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户动态 + +**必选参数 :** `uid` : 用户 id + +**接口地址 :** `/user/event` + +**调用例子 :** `/user/event?uid=32953014` + +### 获取用户播放记录 + +说明 : 登录后调用此接口 , 传入用户 id, 可获取用户播放记录 + +**必选参数 :** `uid` : 用户 id + +**可选参数 :** `type` : type=1 时只返回 weekData, type=0 时返回 allData + +**接口地址 :** `/user/record` + +**调用例子 :** `/user/record?uid=32953014&type=1` + +### 获取动态消息 + +说明 : 调用此接口 , 可获取各种动态 , 对应网页版网易云,朋友界面里的各种动态消息 +,如分享的视频,音乐,照片等! + +**必选参数 :** 未知 + +**接口地址 :** `/event` + +**调用例子 :** `/event` + +### 歌手分类列表 + +说明 : 调用此接口,可获取歌手分类列表 +**必选参数 :** `cat` : 即 category Code,歌手类型,默认 1001,返回华语男歌手数据 +**可选参数 :** +`limit` : 返回数量 , 默认为 30 + +`offset` : 偏移数量,用于分页 , 如 +: 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 +`initial`: 按首字母索引查找参数,如 `/artist/list?cat=1001&initial=b` 返回内容将以 name 字段开头为 b 或者拼音开头为 b 为顺序排列 + +category Code 取值: + +``` +入驻歌手 5001 +华语男歌手 1001 +华语女歌手 1002 +华语组合/乐队 1003 +欧美男歌手 2001 +欧美女歌手 2002 +欧美组合/乐队 2003 +日本男歌手 6001 +日本女歌手 6002 +日本组合/乐队 6003 +韩国男歌手 7001 +韩国女歌手 7002 +韩国组合/乐队 7003 +其他男歌手 4001 +其他女歌手 4002 +其他组合/乐队 4003 +``` + +**接口地址 :** `/artist/list` + +**调用例子 :** `/artist/list?cat=1001` + +返回数据如下图: +![数据](https://ws1.sinaimg.cn/large/006tKfTcgy1fr60g9zps9j31kw1bpk4n.jpg) + +### 收藏歌手 + +说明 : 调用此接口,可收藏歌手 +**必选参数 :** `artistId` : 歌手 id + +**接口地址 :** `/artist/sub` + +**调用例子 :** `/artist/sub?id=6452` + +### 取消收藏歌手 + +说明 : 调用此接口,可取消收藏歌手 +**必选参数 :** `artistId` : 歌手 id + +**接口地址 :** `/artist/unsub` + +**调用例子 :** `/artist/unsub?id=6452` + +### 收藏的歌手列表 + +说明 : 调用此接口,可获取收藏的歌手列表 + +**接口地址 :** `/artist/sublist` + +**调用例子 :** `/artist/sublist` + +### 歌单分类 + +说明 : 调用此接口,可获取歌单分类,包含 category 信息 + +**接口地址 :** `/playlist/catlist` + +**调用例子 :** `/playlist/catlist` + +### 热门歌单分类 + +说明 : 调用此接口,可获取歌单分类,包含 category 信息 + +**接口地址 :** `/playlist/hot` + +**调用例子 :** `/playlist/hot` + +### 歌单 ( 网友精选碟 ) + +说明 : 调用此接口 , 可获取网友精选碟歌单 + +**可选参数 :** `order`: 可选值为 'new' 和 'hot', 分别对应最新和最热 , 默认为 +'hot' + +`cat`:`cat`: tag, 比如 " 华语 "、" 古风 " 、" 欧美 "、" 流行 ", 默认为 +"全部",可从歌单分类接口获取(/playlist/catlist) + +**接口地址 :** `/top/playlist` + +**调用例子 :** `/top/playlist?limit=10&order=new` + +返回数据如下图 : + +![精选碟](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/top_playlist.png) +![对应位置](https://ws2.sinaimg.cn/large/006tKfTcgy1fr3wnpyg6jj317e0vcqdc.jpg) +![返回数据](https://ws4.sinaimg.cn/large/006tKfTcgy1fr3wqs5lw9j31ic1re4c4.jpg) + +### 获取精品歌单 + +说明 : 调用此接口 , 可获取精品歌单 + +**可选参数 :** `cat`: tag, 比如 " 华语 "、" 古风 " 、" 欧美 "、" 流行 ", 默认为 +"全部",可从歌单分类接口获取(/playlist/catlist) + +`limit`: 取出歌单数量 , 默认为 20 + +**接口地址 :** `/top/playlist/highquality` + +**调用例子 :** `/top/playlist/highquality?limit=30` + +### 相关歌单推荐 + +说明 : 调用此接口,传入歌单 id 可获取相关歌单(对应页面 [https://music.163.com/#/playlist?id=1](https://music.163.com/#/playlist?id=1)) + +**必选参数 :** `id` : 歌单 id + +**接口地址 :** `/related/playlist` + +**调用例子 :** `/related/playlist?id=1` + +### 获取歌单详情 + +说明 : 歌单能看到歌单名字 , 但看不到具体歌单内容 , 调用此接口 , 传入歌单 id, 可 +以获取对应歌单内的所有的音乐 + +**必选参数 :** `id` : 歌单 id + +**可选参数 :** `s` : 歌单最近的 s 个收藏者 + +**接口地址 :** `/playlist/detail` + +**调用例子 :** `/playlist/detail?id=24381616` + +返回数据如下图 : +![歌单详情](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E6%AD%8C%E5%8D%95%E8%AF%A6%E6%83%85.png) + +### 获取音乐 url + +说明 : 使用歌单详情接口后 , 能得到的音乐的 id, 但不能得到的音乐 url, 调用此接口 +, 传入的音乐 id( 可多个 , 用逗号隔开 ), 可以获取对应的音乐的 url( 不需要登录 ) + +> 注 : 部分用户反馈获取的 url 会 403,[hwaphon](https://github.com/hwaphon)找到的 +> 解决方案是当获取到音乐的 id 后,将 +> https://music.163.com/song/media/outer/url?id=id.mp3 以 src 赋予 Audio 即可播放 + +**必选参数 :** `id` : 音乐 id + +**可选参数 :** `br`: 码率,默认设置了 999000 即最大码率,如果要 320k 则可设置为 320000,其他类推 + +**接口地址 :** `/music/url` + +**调用例子 :** `/music/url?id=33894312` `/music/url?id=405998841,33894312` + +返回数据如下图 : +![音乐 url](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E9%9F%B3%E4%B9%90%20url.png) + +### 音乐是否可用 + +说明: 调用此接口,传入歌曲 id, 可获取音乐是否可用,返回 `{ success: true, message: 'ok' }` 或者 `{ success: false, message: '亲爱的,暂无版权' }` + +**必选参数 :** `id` : 歌曲 id + +**可选参数** : `br`: 码率,默认设置了 999000 即最大码率,如果要 320k 则可设置为 320000,其他类推 + +**接口地址 :** `/check/music` + +**调用例子 :** `/check/music?id=33894312` + +### 搜索 + +说明 : 调用此接口 , 传入搜索关键词可以搜索该音乐 / 专辑 / 歌手 / 歌单 / 用户 , +关键词可以多个 , 以空格隔开 , 如 " 周杰伦 搁浅 "( 不需要登录 ), 搜索获取的 +mp3url 不能直接用 , 可通过 `/music/url` 接口传入歌曲 id 获取具体的播放链接 + +**必选参数 :** `keywords` : 关键词 + +**可选参数 :** `limit` : 返回数量 , 默认为 30 `offset` : 偏移数量,用于分页 , 如 +: 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 + +`type`: 搜索类型;默认为 1 即单曲 , 取值意义 : 1: 单曲, 10: 专辑, 100: 歌手, 1000: +歌单, 1002: 用户, 1004: MV, 1006: 歌词, 1009: 电台, 1014: 视频 + +**接口地址 :** `/search` + +**调用例子 :** `/search?keywords= 海阔天空` + +返回数据如下图 : +![搜索音乐](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E6%90%9C%E7%B4%A2.png) + +### 热搜 + +说明 : 调用此接口,可获取热门搜索列表 + +**接口地址 :** `/search/hot` + +**调用例子 :** `/search/hot` + +### 搜索建议 + +说明 : 调用此接口 , 传入搜索关键词可获得搜索建议 , 搜索结果同时包含单曲 , 歌手 , +歌单 ,mv 信息 + +**必选参数 :** `keywords` : 关键词 + +**可选参数 :** +`limit` : 返回数量 , 默认为 30 + +`offset` : 偏移数量,用于分页 , 如 +: 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 + +`type`: 搜索类型;默认为 1 即单曲 , 取值意义 : 1: 单曲 10: 专辑 100: 歌手 1000: +歌单 1002: 用户 1004: MV 1006: 歌词 1009: 电台 + +**接口地址 :** `/search/suggest` + +**调用例子 :** `/search/suggest?keywords= 海阔天空` + +### 搜索多重匹配 + +说明 : 调用此接口 , 传入搜索关键词可获得搜索结果 + +**必选参数 :** `keywords` : 关键词 + +**接口地址 :** `/search/multimatch` + +**调用例子 :** `/search/multimatch?keywords= 海阔天空` + +### 新建歌单 + +说明 : 调用此接口 , 传入歌单名字可新建歌单 + +**必选参数 :** `name` : 歌单名 + +**接口地址 :** `/playlist/create` + +**调用例子 :** `/playlist/create?name=测试歌单` + +返回数据如下图: +![数据](https://ws1.sinaimg.cn/large/006tKfTcgy1fr3va885z5j31a617qwjy.jpg) + +### 收藏/取消收藏歌单 + +说明 : 调用此接口 , 传入类型和歌单 id 可收藏歌单或者取消收藏歌单 + +**必选参数 :** +`t` : 类型,1:收藏,2:取消收藏 +`id` : 歌单 id + +**接口地址 :** `/playlist/subscribe` + +**调用例子 :** `/playlist/subscribe?t=1&id=106697785` `/playlist/subscribe?t=2&id=106697785` + +返回数据如下图: +![数据](https://ws1.sinaimg.cn/large/006tKfTcgy1fr3vdwx0hvj30s405u74b.jpg) + +### 对歌单添加或删除歌曲 + +说明 : 调用此接口 , 可以添加歌曲到歌单或者从歌单删除某首歌曲 ( 需要登录 ) + +**必选参数 :** +`op`: 从歌单增加单曲为 add, 删除为 del + +`pid`: 歌单 id +`tracks`: 歌曲 id,可多个,用逗号隔开 + +**接口地址 :** `/playlist/tracks` + +**调用例子 :** `/playlist/tracks?op=add&pid=24381616&tracks=347231` ( 对应把歌曲添加到 ' 我 ' 的歌单 , 测试的时候请把这里的 pid 换成你自己的, id 和 tracks 不对可能会报 502 错误) + +### 获取歌词 + +说明 : 调用此接口 , 传入音乐 id 可获得对应音乐的歌词 ( 不需要登录 ) + +**必选参数 :** `id`: 音乐 id + +**接口地址 :** `/lyric` + +**调用例子 :** `/lyric?id=33894312` + +返回数据如下图 : +![获取歌词](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E6%AD%8C%E8%AF%8D.png) + +### 歌曲评论 + +说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该音乐的所有评论 ( 不需要 +登录 ) + +**必选参数 :** `id`: 音乐 id + +**可选参数 :** `limit`: 取出评论数量 , 默认为 20 + +`offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*20, 其中 20 为 limit 的值 + +**接口地址 :** `/comment/music` + +**调用例子 :** `/comment/music?id=186016&limit=1` 对应晴天评论 + +返回数据如下图 : +![获取评论](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/comment.png) + +### 专辑评论 + +说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该专辑的所有评论 ( 不需要 +登录 ) + +**必选参数 :** `id`: 专辑 id + +**可选参数 :** `limit`: 取出评论数量 , 默认为 20 + +`offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*20, 其中 20 为 limit 的值 + +**接口地址 :** `/comment/album` + +**调用例子 :** `/comment/album?id=32311` + +### 歌单评论 + +说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该歌单的所有评论 ( 不需要 +登录 ) + +**必选参数 :** `id`: 歌单 id + +**可选参数 :** `limit`: 取出评论数量 , 默认为 20 + +`offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*20, 其中 20 为 limit 的值 + +**接口地址 :** `/comment/playlist` + +**调用例子 :** `/comment/playlist?id=705123491` + +### mv 评论 + +说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该 mv 的所有评论 ( 不需要 +登录 ) + +**必选参数 :** `id`: mv id + +**可选参数 :** `limit`: 取出评论数量 , 默认为 20 + +`offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*20, 其中 20 为 limit 的值 + +**接口地址 :** `/comment/mv` + +**调用例子 :** `/comment/mv?id=5436712` + +### 电台节目评论 + +说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该 电台节目 的所有评论 ( +不需要登录 ) + +**必选参数 :** `id`: 电台节目的 id + +**可选参数 :** `limit`: 取出评论数量 , 默认为 20 + +`offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*20, 其中 20 为 limit 的值 + +**接口地址 :** `/comment/dj` + +**调用例子 :** `/comment/dj?id=794062371` + +### 视频评论 + +说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该 视频 的所有评论 ( +不需要登录 ) + +**必选参数 :** `id`: 视频的 id + +**可选参数 :** `limit`: 取出评论数量 , 默认为 20 + +`offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*20, 其中 20 为 limit 的值 + +**接口地址 :** `/comment/video` + +**调用例子 :** `/comment/video?id=89ADDE33C0AAE8EC14B99F6750DB954D` + +### 热门评论 + +说明 : 调用此接口 , 传入 type, 资源 id 可获得对应资源热门评论 ( 不需要登录 ) + +**必选参数 :** + +`id` : 资源 id + +`tpye`: 数字 , 资源类型 , 对应歌曲 , mv, 专辑 , 歌单 , 电台, 视频对应以下类型 + +``` +0: 歌曲 +1: mv +2: 歌单 +3: 专辑 +4: 电台 +5: 视频 +``` + +**接口地址 :** `/comment/hot` + +**调用例子 :** `/comment/hot?id=186016&type=0` + +### 给评论点赞 + +说明 : 调用此接口 , 传入 type, 资源 id, 和评论 id cid 和 是否点赞参数 t 即可给对 +应评论点赞 ( 需要登录 ) + +**必选参数 :** `id` : 资源 id, 如歌曲 id,mv id + +`cid` : 评论 id + +`t` : 是否点赞 ,1 为点赞 ,0 为取消点赞 + +`tpye`: 数字 , 资源类型 , 对应歌曲 , mv, 专辑 , 歌单 , 电台, 视频对应以下类型 + +``` +0: 歌曲 +1: mv +2: 歌单 +3: 专辑 +4: 电台 +5: 视频 +``` + +**接口地址 :** `comment/like` + +**调用例子 :** `/comment/like?id=29178366&cid=12840183&t=1&type=0` 对应给 [https://music.163.com/#/song?id=29178366](https://music.163.com/#/song?id=29178366) 最热门的评论点赞 + +### 发送/删除评论 + +说明 : 调用此接口,可发送评论或者删除评论 + +**接口地址 :** `/comment` + +1. 发送评论 + + **必选参数** + `action`:1 发送 + + `tpye`: 数字,资源类型,对应歌曲,mv,专辑,歌单,电台,视频对应以下类型 + + ``` + 0: 歌曲 + 1: mv + 2: 歌单 + 3: 专辑 + 4: 电台 + 5: 视频 + ``` + + `id`:对应资源 id + + `content` :要发送的内容 + + **调用例子** : `/comment?action=1&type=1&id=5436712&content=test` (往广岛之恋 mv 发送评论: test) + +2. 删除评论 + + **必选参数** + `action`:0 删除 + + `tpye`: 数字,资源类型,对应歌曲,mv,专辑,歌单,电台,视频对应以下类型 + + ``` + 0: 歌曲 + 1: mv + 2: 歌单 + 3: 专辑 + 4: 电台 + 5: 视频 + ``` + + `id`:对应资源 id + `content` :内容 id,可通过 `/comment/mv` 等接口获取 + + **调用例子** : `/comment?action=0&type=1&id=5436712&commentId=1535550516319` (在广岛之恋 mv 删除评论) + +### banner + +说明 : 调用此接口 , 可获取 banner( 轮播图 ) 数据注 : 因参数未知 , 只能获取比较旧 +的数据 , 如果有知道参数的小伙伴 , 可提交 PR + +**接口地址 :** `/banner` + +**调用例子 :** `/banner` + +### 获取歌曲详情 + +说明 : 调用此接口 , 传入音乐 id, 可获得歌曲详情(注意:歌曲封面现在需要通过专辑内容接口获取) + +**必选参数 :** `ids`: 音乐 id, 如 `ids=347230` + +**接口地址 :** `/song/detail` + +**调用例子 :** `/song/detail?ids=347230` + +返回数据如下图 : +![获取歌曲详情](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/songDetail.png) + +### 获取专辑内容 + +说明 : 调用此接口 , 传入专辑 id, 可获得专辑内容 + +**必选参数 :** `id`: 专辑 id + +**接口地址 :** `/album` + +**调用例子 :** `/album?id=32311` + +返回数据如下图 : +![获取专辑内容](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E4%B8%93%E8%BE%91.png) + +### 获取歌手单曲 + +说明 : 调用此接口 , 传入歌手 id, 可获得歌手部分信息和热门歌曲 + +**必选参数 :** `id`: 歌手 id, 可由搜索接口获得 + +**接口地址 :** `/artists` + +**调用例子 :** `/artists?id=6452` + +返回数据如下图 : +![获取歌手单曲](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/artists.png) + +### 获取歌手 mv + +说明 : 调用此接口 , 传入歌手 id, 可获得歌手 mv 信息 , 具体 mv 播放地址可调 +用`/mv`传入此接口获得的 mvid 来拿到 , 如 : +`/artist/mv?id=6452`,`/mv?mvid=5461064` + +**必选参数 :** `id`: 歌手 id, 可由搜索接口获得 + +**接口地址 :** `/artist/mv` + +**调用例子 :** `/artist/mv?id=6452` + +### 获取歌手专辑 + +说明 : 调用此接口 , 传入歌手 id, 可获得歌手专辑内容 + +**必选参数 :** `id`: 歌手 id + +**可选参数 :** `limit`: 取出数量 , 默认为 50 + +`offset`: 偏移数量 , 用于分页 , 如 :( 页数 -1)\*50, 其中 50 为 limit 的值 , 默认 +为 0 + +**接口地址 :** `/artist/album` + +**调用例子 :** `/artist/album?id=6452&limit=30` ( 周杰伦 ) + +返回数据如下图 : +![获取专辑内容](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/artist_album.png) + +### 获取歌手描述 + +说明 : 调用此接口 , 传入歌手 id, 可获得歌手描述 + +**必选参数 :** `id`: 歌手 id + +**接口地址 :** `/artist/desc` + +**调用例子 :** `/artist/desc?id=6452` ( 周杰伦 ) + +### 获取相似歌手 + +说明 : 调用此接口 , 传入歌手 id, 可获得相似歌手 + +**必选参数 :** `id`: 歌手 id + +**接口地址 :** `/simi/artist` + +**调用例子 :** `/simi/artist?id=6452` ( 对应和周杰伦相似歌手 ) + +### 获取相似歌单 + +说明 : 调用此接口 , 传入歌曲 id, 可获得相似歌单 + +**必选参数 :** `id`: 歌曲 id + +**接口地址 :** `/simi/playlist` + +**调用例子 :** `/simi/playlist?id=347230` ( 对应 ' 光辉岁月 ' 相似歌单 ) + +### 相似 mv + +说明 : 调用此接口 , 传入 `mvid` 可获取相似 mv + +**必选参数 :** `mvid`: mv id + +**接口地址 :** `/simi/mv` + +**调用例子 :** `/simi/mv?mvid=5436712` + +### 获取相似音乐 + +说明 : 调用此接口 , 传入歌曲 id, 可获得相似歌曲 + +**必选参数 :** `id`: 歌曲 id + +**接口地址 :** `/simi/song` + +**调用例子 :** `/simi/song?id=347230` ( 对应 ' 光辉岁月 ' 相似歌曲 ) + +### 获取最近 5 个听了这首歌的用户 + +说明 : 调用此接口 , 传入歌曲 id, 最近 5 个听了这首歌的用户 + +**必选参数 :** `id`: 歌曲 id + +**接口地址 :** `/simi/user` + +**调用例子 :** `/simi/user?id=347230` ( 对应 ' 光辉岁月 ' 相似歌曲 ) + +### 获取每日推荐歌单 + +说明 : 调用此接口 , 可获得每日推荐歌单 ( 需要登录 ) + +**接口地址 :** `/recommend/resource` + +**调用例子 :** `/recommend/resource` + +返回数据如下图 : +![每日推荐歌单](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E6%8E%A8%E8%8D%90%E6%AD%8C%E5%8D%95.png) + +### 获取每日推荐歌曲 + +说明 : 调用此接口 , 可获得每日推荐歌曲 ( 需要登录 ) + +**接口地址 :** `/recommend/songs` + +**调用例子 :** `/recommend/songs` + +返回数据如下图 : +![每日推荐歌曲](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E6%8E%A8%E8%8D%90%E6%AD%8C%E6%9B%B2.png) + +### 私人 FM + +说明 : 私人 FM( 需要登录 ) + +**接口地址 :** `/personal_fm` + +**调用例子 :** `/personal_fm` + +返回数据如下图 : + +![私人 FM](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/personal_fm.png) + +### 签到 + +说明 : 调用此接口 , 传入签到类型 ( 可不传 , 默认安卓端签到 ), 可签到 ( 需要登录 +), 其中安卓端签到可获得 3 点经验 , web/PC 端签到可获得 2 点经验 + +**可选参数 :** `type`: 签到类型 , 默认 0, 其中 0 为安卓端签到 ,1 为 web/PC 签到 + +**接口地址 :** `/daily_signin` + +**调用例子 :** `/daily_signin` + +返回数据如下图 : + +![签到成功](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/signinSuccess.png) + +![签到失败](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/signinError.png) + +### 喜欢音乐 + +说明 : 调用此接口 , 传入音乐 id, 可喜欢该音乐 + +**必选参数 :** `id`: 歌曲 id + +**可选参数 :** `like`: 布尔值 , 默认为 true 即喜欢 , 若传 false, 则取消喜欢 + +**接口地址 :** `/like` + +**调用例子 :** `/like?id=347230` + +返回数据如下图 : + +![喜欢成功](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/like.png) + +喜欢成功则返回数据的 code 为 200, 其余为失败 + +![喜欢成功截图](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/likeSuccess.png) + +### 垃圾桶 + +说明 : 调用此接口 , 传入音乐 id, 可把该音乐从私人 FM 中移除至垃圾桶 + +**必选参数 :** `id`: 歌曲 id + +**接口地址 :** `/fm_trash` + +**调用例子 :** `/fm_trash?id=347230` + +返回数据如下图 : + +![移除成功](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/fm_trash.png) + +### 新碟上架 + +说明 : 调用此接口 , 可获取新碟上架列表 , 如需具体音乐信息需要调用获取专辑列表接 +口 `/album` , 然后传入 id, 如 `/album?id=32311&limit=30` + +**可选参数 :** `limit`: 取出数量 , 默认为 50 + +`offset`: 偏移数量 , 用于分页 , 如 :( 页数 -1)\*50, 其中 50 为 limit 的值 , 默认 +为 0 + +**接口地址 :** `/top/album` + +**调用例子 :** `/top/album?offset=0&limit=30` + +返回数据如下图 : + +![新碟上架](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/new_albums.png) + +### 热门歌手 + +说明 : 调用此接口 , 可获取热门歌手数据 + +**可选参数 :** `limit`: 取出数量 , 默认为 50 + +`offset`: 偏移数量 , 用于分页 , 如 :( 页数 -1)\*50, 其中 50 为 limit 的值 , 默认 +为 0 + +**接口地址 :** `/top/artists` + +**调用例子 :** `/top/artists?offset=0&limit=30` + +返回数据如下图 : + +![热门歌手](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/top_artists.png) + +### 最新 mv + +说明 : 调用此接口 , 可获取最新 mv + +**可选参数 :** `limit`: 取出数量 , 默认为 30 + +**接口地址 :** `/mv/first` + +**调用例子 :** `/mv/first?limit=10` + +### 推荐 mv + +说明 : 调用此接口 , 可获取推荐 mv + +**接口地址 :** `/personalized/mv` + +**调用例子 :** `/personalized/mv` + +### 推荐歌单 + +说明 : 调用此接口 , 可获取推荐歌单 + +**接口地址 :** `/personalized` + +**调用例子 :** `/personalized` + +### 推荐新音乐 + +说明 : 调用此接口 , 可获取推荐新音乐 + +**接口地址 :** `/personalized/newsong` + +**调用例子 :** `/personalized/newsong` + +### 推荐电台 + +说明 : 调用此接口 , 可获取推荐电台 + +**接口地址 :** `/personalized/djprogram` + +**调用例子 :** `/personalized/djprogram` + +### 推荐节目 + +说明 : 调用此接口 , 可获取推荐电台 + +**接口地址 :** `/program/recommend` + +**调用例子 :** `/program/recommend` + +### 独家放送 + +说明 : 调用此接口 , 可获取独家放送 + +**接口地址 :** `/personalized/privatecontent` + +**调用例子 :** `/personalized/privatecontent` + +### mv 排行 + +说明 : 调用此接口 , 可获取 mv 排行 + +**可选参数 :** `limit`: 取出数量 , 默认为 30 + +`offset`: 偏移数量 , 用于分页 , 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认 +为 0 + +**接口地址 :** `top/mv` + +**调用例子 :** `top/mv?limit=10` + +### 获取 mv 数据 + +说明 : 调用此接口 , 传入 mvid ( 在搜索音乐的时候传 type=1004 获得 ) , 可获取对应 +MV 数据 , 数据包含 mv 名字 , 歌手 , 发布时间 , mv 视频地址等数据 , 其中 mv 视频 +网易做了防盗链处理 , 可能不能直接播放 , 需要播放的话需要调用 ' 播放 mv/视频' 接口 + +**必选参数 :** `mvid`: mv 的 id + +**接口地址 :** `/mv` + +**调用例子 :** `/mv?mvid=5436712` + +返回数据如下图 : + +![热门歌手](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/mv.png) + +### 获取视频数据 + +说明 : 调用此接口 , 传入视频的 id ( 在搜索音乐的时候传 type=1014 获得 ) , 可获取对应 +视频数据,其中视频网易做了防盗链处理 , 可能不能直接播放 , 需要播放的话需要调用 ' 播放 mv/视频' 接口 + +**必选参数 :** `id`: 视频 的 id + +**接口地址 :** `/video` + +**调用例子 :** `/video?id=89ADDE33C0AAE8EC14B99F6750DB954D` + +返回数据如下图 : + +![视频数据](https://ws1.sinaimg.cn/large/006tNbRwgy1fuqdv10p5rj31kw0da76y.jpg) + +### 播放 mv/视频 + +说明 : 调用此接口 , 传入 mv/视频 地址 , 可播放 mv/视频, 也可将接口嵌入 video 标签使用 , 由 +于使用了 'pipe', 进度条无法通过拖动进度条控制进度 , 如有解决方案可提出 PR 或者自 +行改造 + +**可选参数 :** `url`: mv/视频 的 地址 + +**接口地址 :** `/mv/url` + +**调用例子 :** +`/mv/url?url=http://v4.music.126.net/20170422034915/c98eab2f5e2c85fc8de2ab3f0f8ed1c6/web/cloudmusic/MjQ3NDQ3MjUw/89a6a279dc2acfcd068b45ce72b1f560/533e4183a709699d566180ed0cd9abe9.mp4` + +如下图 : + +![播放视频](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/play_mv.png) + +### 排行榜 + +说明 : 调用此接口 , 传入数字 idx, 可获取不同排行榜 + +**必选参数 :** `idx`: 对象 key, 对应以下排行榜 + +``` +"0": 云音乐新歌榜, +"1": 云音乐热歌榜, +"2": 网易原创歌曲榜, +"3": 云音乐飙升榜, +"4": 云音乐电音榜, +"5": UK排行榜周榜, +"6": 美国Billboard周榜 +"7": KTV嗨榜, +"8": iTunes榜, +"9": Hit FM Top榜, +"10": 日本Oricon周榜 +"11": 韩国Melon排行榜周榜, +"12": 韩国Mnet排行榜周榜, +"13": 韩国Melon原声周榜, +"14": 中国TOP排行榜(港台榜), +"15": 中国TOP排行榜(内地榜) +"16": 香港电台中文歌曲龙虎榜, +"17": 华语金曲榜, +"18": 中国嘻哈榜, +"19": 法国 NRJ EuroHot 30周榜, +"20": 台湾Hito排行榜, +"21": Beatport全球电子舞曲榜, +"22": 云音乐ACG音乐榜, +"23": 云音乐嘻哈榜 +``` + +**接口地址 :** `/top/list` + +**调用例子 :** `/top/list?idx=6` + +返回数据如下图 : + +![排行榜](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/top_list.png) + +### 歌手榜 + +说明 : 调用此接口 , 可获取 PC 版排行榜中的歌手榜 + +**接口地址 :** `/toplist/artist` + +**调用例子 :** `/toplist/artist` + +### 云盘 + +说明 : 登录后调用此接口 , 可获取云盘数据 , 获取的数据没有对应 url, 需要再调用一 +次 `/music/url` 获取 url + +**接口地址 :** `/user/cloud` + +**调用例子 :** `/user/cloud` + +### 电台 - 推荐 + +说明 : 登录后调用此接口 , 可获得推荐电台 + +**接口地址 :** `/dj/recommend` + +**调用例子 :** `/dj/recommend` + +### 电台 - 分类 + +说明 : 登录后调用此接口 , 可获得电台类型 + +**接口地址 :** `/dj/catelist` + +**调用例子 :** `/dj/catelist` + +### 电台 - 分类推荐 + +说明 : 登录后调用此接口 , 可获得推荐电台 + +**必选参数 :** `type`: 电台类型 , 数字 , 可通过`/dj/catelist`获取 , 对应关系为 +id 对应 此接口的 type, name 对应类型意义 + +**接口地址 :** `/dj/recommend/type` + +**调用例子 :** `/dj/recommend/type?type=1` + +### 电台 - 订阅 + +说明 : 登录后调用此接口 , 传入`rid`, 可订阅 dj,dj 的 `rid` 可通过搜索指定 +type='1009' 获取其 id, 如`/search?keywords= 代码时间 &type=1009` + +**必选参数 :** `rid`: 电台 的 id + +**接口地址 :** `/dj/sub` + +**调用例子 :** `/dj/sub?rid=336355127&t=1` ( 对应关注 ' 代码时间 ') +`/dj/sub?rid=336355127&t=0` ( 对应取消关注 ' 代码时间 ') + +### 电台的订阅列表 + +说明 : 登录后调用此接口 , 可获取订阅的电台列表 + +**接口地址 :** `/dj/sublist` + +**调用例子 :** `/dj/sublist` + +### 电台 - 付费精选 + +说明 : 可以获取付费精选的电台列表 , 传入 `limit` 和 `offset` 可以进行分页 + +**接口地址 :** `/dj/paygift` + +**调用例子 :** `/dj/paygift?limit=10&offset=20` + +### 电台 - 详情 + +说明 : 登录后调用此接口 , 传入`rid`, 可获得对应电台的详情介绍 + +**必选参数 :** `rid`: 电台 的 id + +**接口地址 :** `/dj/detail?rid=336355127` + +**调用例子 :** `/dj/detail?rid=336355127` ( 对应 ' 代码时间 ' 的详情介绍 ) + +### 电台 - 节目 + +说明 : 登录后调用此接口 , 传入`rid`, 可查看对应电台的电台节目以及对应的 id, 需要 +注意的是这个接口返回的 mp3Url 已经无效 , 都为 null, 但是通过调用 `/music/url` 这 +个接口 , 传入节目 id 仍然能获取到节目音频 , 如 `/music/url?id=478446370` 获取代 +码时间的一个节目的音频 + +**必选参数 :** `rid`: 电台 的 id + +**可选参数 :** +`limit` : 返回数量 , 默认为 30 + +`offset` : 偏移数量,用于分页 , 如 +: 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 + +**接口地址 :** `/dj/program` + +**调用例子 :** `/dj/program?rid=336355127&limit=40` ( 对应 ' 代码时间 ' 的节目列表 ) + +## 离线访问此文档 + +此文档同时也是 Progressive Web Apps(PWA), 加入了 serviceWorker, 可离线访问 + +## 关于此文档 + +此文档由 [docsify](https://github.com/QingWei-Li/docsify/) 生成 docsify 是一个动 +态生成文档网站的工具。不同于 GitBook、Hexo 的地方是它不会生成将 .md 转成 .html +文件,所有转换工作都是在运行时进行。 + +## License + +[The MIT License (MIT)](https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/LICENSE) diff --git a/netease_api/index.js b/netease_api/index.js new file mode 100644 index 0000000..39d0ba3 --- /dev/null +++ b/netease_api/index.js @@ -0,0 +1 @@ +require('./app.js') diff --git a/netease_api/interface.d.ts b/netease_api/interface.d.ts new file mode 100644 index 0000000..4a7687b --- /dev/null +++ b/netease_api/interface.d.ts @@ -0,0 +1,1407 @@ +export interface RequestBaseConfig { + cookie?: string + realIP?: string // IPv4/IPv6 filled in X-Real-IP + proxy?: string // HTTP proxy +} + +export interface MultiPageConfig { + limit?: string | number + offset?: string | number +} + +export interface ImageUploadConfig { + imgFile: { + name: string + data: string | Buffer + } + imgSize?: number + imgX?: number + imgY?: number +} + +export interface APIBaseResponse { + code: number + cookie: string + [index: string]: unknown +} + +export interface Response { + status: number // The Http Response Code + body: APIBaseResponse // API Response body + cookie: string[] +} + +export const enum SubAction { + sub = 1, + unsub = 0, +} + +export function activate_init_profile( + params: { nickname: string } & RequestBaseConfig, +): Promise + +export function album( + params: { id: string | number } & RequestBaseConfig, +): Promise + +export function album_detail( + params: { id: string | number } & RequestBaseConfig, +): Promise + +export function album_detail_dynamic( + params: { id: string | number } & RequestBaseConfig, +): Promise + +export const enum AlbumListArea { + all = 'ALL', + zh = 'ZH', + ea = 'EA', + kr = 'KR', + jp = 'JP', +} + +export const enum ListOrder { + hot = 'hot', + new = 'new', +} + +export function album_list( + params: { area?: AlbumListArea; type: string } & MultiPageConfig & + RequestBaseConfig, +): Promise + +export const enum AlbumListStyleArea { + zh = 'Z_H', + ea = 'E_A', + kr = 'KR', + jp = 'JP', +} + +export function album_list_style( + params: { area?: AlbumListStyleArea } & MultiPageConfig & RequestBaseConfig, +): Promise + +export function album_new( + params: { area?: AlbumListArea } & MultiPageConfig & RequestBaseConfig, +): Promise + +export function album_newest(params: RequestBaseConfig): Promise + +export const enum AlbumSongsaleboardType { + daily = 'daily', + week = 'week', + year = 'year', + total = 'total', +} + +export const enum AlbumSongsaleboardAlbumType { + album = 0, + single = 1, +} + +export function album_songsaleboard( + params: { + albumType?: AlbumSongsaleboardAlbumType // 0 为数字专辑,1 为数字单曲 + type?: AlbumSongsaleboardType + year?: string | number // 年份,默认本年。 type 为 year 时有效 + } & RequestBaseConfig, +): Promise + +export function album_sub( + params: { + id: string | number + t: SubAction + } & RequestBaseConfig, +): Promise + +export function album_sublist( + params: MultiPageConfig & RequestBaseConfig, +): Promise + +export function artist_album( + params: { id: string | number } & MultiPageConfig & RequestBaseConfig, +): Promise + +export function artist_desc( + params: { id: string | number } & RequestBaseConfig, +): Promise + +export const enum ArtistListArea { + zh = 'Z_H', + ea = 'E_A', + kr = 'KR', + jp = 'JP', +} + +export const enum ArtistArea { + all = '-1', + zh = '7', + ea = '96', + ja = '8', + kr = '16', + other = '0', +} + +export const enum ArtistType { + male = '1', + female = '2', + band = '3', +} + +export function artist_list( + params: { + area: ArtistArea + initial?: + | 'a' + | 'b' + | 'c' + | 'd' + | 'e' + | 'f' + | 'g' + | 'h' + | 'i' + | 'j' + | 'k' + | 'l' + | 'm' + | 'n' + | 'o' + | 'p' + | 'q' + | 'r' + | 's' + | 't' + | 'u' + | 'v' + | 'w' + | 'x' + | 'y' + | 'z' + | 'A' + | 'B' + | 'C' + | 'D' + | 'E' + | 'F' + | 'G' + | 'H' + | 'I' + | 'J' + | 'K' + | 'L' + | 'M' + | 'N' + | 'O' + | 'P' + | 'Q' + | 'R' + | 'S' + | 'T' + | 'U' + | 'V' + | 'W' + | 'X' + | 'Y' + | 'Z' + type?: ArtistType + } & MultiPageConfig & + RequestBaseConfig, +): Promise + +export function artist_mv( + params: { id: string | number } & MultiPageConfig & RequestBaseConfig, +): Promise + +export const enum ArtistSongsOrder { + hot = 'hot', + time = 'time', +} + +export function artist_songs( + params: { + id: string | number + order?: ArtistSongsOrder + } & MultiPageConfig & + RequestBaseConfig, +): Promise + +export function artist_sub( + params: { id: string | number; t: SubAction } & RequestBaseConfig, +): Promise + +export function artist_sublist( + params: MultiPageConfig & RequestBaseConfig, +): Promise + +export function artist_top_song( + params: { + id: string | number + } & RequestBaseConfig, +): Promise + +export function artists( + params: { id: string | number } & RequestBaseConfig, +): Promise + +export function avatar_upload( + params: ImageUploadConfig & RequestBaseConfig, +): Promise + +export const enum BannerType { + pc = 0, + android = 1, + iphone = 2, + ipad = 3, +} + +export function banner( + params: { type?: BannerType } & RequestBaseConfig, +): Promise + +export function batch( + params: { [index: string]: unknown } & RequestBaseConfig, +): Promise + +export function captcha_sent( + params: { cellphone: string; ctcode?: number | string } & RequestBaseConfig, +): Promise + +export function captcha_verify( + params: { + ctcode?: number | string + cellphone: number | string + captcha: string + } & RequestBaseConfig, +): Promise + +export function cellphone_existence_check( + params: { + cellphone: number | string + countrycode: number | string + } & RequestBaseConfig, +): Promise + +export function check_music( + params: { id: string | number; br: string | number } & RequestBaseConfig, +): Promise + +export const enum SearchType { + single = 1, + album = 10, + artist = 100, + playlist = 1000, + user = 1002, + mv = 1004, + lyric = 1006, + dj = 1009, + video = 1014, + complex = 1018, +} + +export function cloudsearch( + params: { + keywords: string + type?: SearchType + } & MultiPageConfig & + RequestBaseConfig, +): Promise + +export const enum CommentType { + song = 0, + mv = 1, + playlist = 2, + album = 3, + dj = 4, + video = 5, + event = 6, +} + +export const enum CommentAction { + add = 1, + delete = 0, + reply = 2, +} + +export function comment( + params: { + id: string | number + type: CommentType + t: CommentAction.delete + commentId: string | number + } & RequestBaseConfig, +): Promise + +export function comment( + params: { + type: CommentType.event + t: CommentAction.delete + threadId: string + commentId: string | number + } & RequestBaseConfig, +): Promise + +export function comment( + params: { + id: string | number + type: CommentType + t: CommentAction.add + content: string | number + } & RequestBaseConfig, +): Promise + +export function comment( + params: { + type: CommentType.event + t: CommentAction.add + threadId: string + content: string | number + } & RequestBaseConfig, +): Promise + +export function comment( + params: { + id: string | number + type: CommentType + t: CommentAction.reply + content: string | number + commentId: string | number + } & RequestBaseConfig, +): Promise + +export function comment( + params: { + type: CommentType.event + t: CommentAction.reply + threadId: string + content: string | number + commentId: string | number + } & RequestBaseConfig, +): Promise + +export function comment_album( + params: { + id: string | number + before?: string | number + } & MultiPageConfig & + RequestBaseConfig, +): Promise + +export function comment_dj( + params: { + id: string | number + before?: string | number + } & MultiPageConfig & + RequestBaseConfig, +): Promise + +export function comment_event( + params: { + threadId: string + before?: string | number + } & MultiPageConfig & + RequestBaseConfig, +): Promise + +export function comment_floor( + params: { + id: string | number + parentCommentId: string | number + type: CommentType + limit?: string | number + time?: string | number + } & RequestBaseConfig, +): Promise + +export function comment_hot( + params: { + id: string | number + type: CommentType + before?: string | number + } & MultiPageConfig & + RequestBaseConfig, +): Promise + +export function comment_hotwall_list( + params: RequestBaseConfig, +): Promise + +export function comment_like( + params: { + id: string | number + type: CommentType + t: SubAction + cid: string | number + threadId?: string + } & RequestBaseConfig, +): Promise + +export function comment_music( + params: { + id: string | number + before?: string | number + } & MultiPageConfig & + RequestBaseConfig, +): Promise + +export function comment_mv( + params: { + id: string | number + before?: string | number + } & MultiPageConfig & + RequestBaseConfig, +): Promise + +export function comment_playlist( + params: { + id: string | number + + before?: string | number + } & MultiPageConfig & + RequestBaseConfig, +): Promise + +export function comment_video( + params: { + id: string | number + before?: string | number + } & MultiPageConfig & + RequestBaseConfig, +): Promise + +export function countries_code_list( + params: RequestBaseConfig, +): Promise + +export const enum DailySigninType { + android = 0, + pc = 1, +} + +export function daily_signin( + params: { type?: DailySigninType } & RequestBaseConfig, +): Promise + +export function digitalAlbum_ordering( + params: { + payment: string + id: string | number + quantity: string + } & RequestBaseConfig, +): Promise + +export function digitalAlbum_purchased( + params: MultiPageConfig & RequestBaseConfig, +): Promise + +export function dj_banner(params: RequestBaseConfig): Promise + +export function dj_category_excludehot( + params: RequestBaseConfig, +): Promise + +export function dj_category_recommend( + params: RequestBaseConfig, +): Promise + +export function dj_catelist(params: RequestBaseConfig): Promise + +export function dj_detail( + params: { rid: string | number } & RequestBaseConfig, +): Promise + +export function dj_hot( + params: MultiPageConfig & RequestBaseConfig, +): Promise + +export function dj_paygift( + params: MultiPageConfig & RequestBaseConfig, +): Promise + +export function dj_personalize_recommend( + params: { limit?: string | number } & RequestBaseConfig, +): Promise + +export function dj_program( + params: { + rid: string | number + asc: 'true' | 1 | 'false' | 0 + } & MultiPageConfig & + RequestBaseConfig, +): Promise + +export function dj_program_detail( + params: { id: string | number } & RequestBaseConfig, +): Promise + +export function dj_program_toplist( + params: MultiPageConfig & RequestBaseConfig, +): Promise + +export function dj_program_toplist_hours( + params: { limit?: string | number } & RequestBaseConfig, +): Promise + +export function dj_radio_hot( + params: { + cateId: string | number + } & MultiPageConfig & + RequestBaseConfig, +): Promise + +export function dj_recommend(params: RequestBaseConfig): Promise + +/* + 有声书 10001 + 知识技能 453050 + 商业财经 453051 + 人文历史 11 + 外语世界 13 + 亲子宝贝 14 + 创作|翻唱 2001 + 音乐故事 2 + 3D|电子 10002 + 相声曲艺 8 + 情感调频 3 + 美文读物 6 + 脱口秀 5 + 广播剧 7 + 二次元 3001 + 明星做主播 1 + 娱乐|影视 4 + 科技科学 453052 + 校园|教育 4001 + 旅途|城市 12 +*/ + +export function dj_recommend_type( + params: { type: number } & RequestBaseConfig, +): Promise + +export function dj_sub( + params: { t: SubAction; rid: string | number } & RequestBaseConfig, +): Promise + +export function dj_sublist( + params: MultiPageConfig & RequestBaseConfig, +): Promise + +export function dj_today_perfered( + params: { page?: string | number } & RequestBaseConfig, +): Promise + +export function dj_toplist( + params: { type?: ListOrder } & MultiPageConfig & RequestBaseConfig, +): Promise + +export function dj_toplist_hours( + params: { limit?: string | number } & RequestBaseConfig, +): Promise + +export function dj_toplist_newcomer( + params: MultiPageConfig & RequestBaseConfig, +): Promise + +export function dj_toplist_pay( + params: { limit?: string | number } & RequestBaseConfig, +): Promise + +export function dj_toplist_popular( + params: { limit?: string | number } & RequestBaseConfig, +): Promise + +export function event( + params: { pagesize?: number; lasttime?: number } & RequestBaseConfig, +): Promise + +export function event_del( + params: { evId: string | number } & RequestBaseConfig, +): Promise + +export function event_forward( + params: { + forwords: string + evId: string | number + uid: string | number + } & RequestBaseConfig, +): Promise + +export function fm_trash( + params: { id: string | number; time?: string | number } & RequestBaseConfig, +): Promise + +export function follow( + params: { t: SubAction; id: string | number } & RequestBaseConfig, +): Promise + +export function history_recommend_songs( + params: RequestBaseConfig, +): Promise + +export function history_recommend_songs_detail( + params: { date?: string } & RequestBaseConfig, +): Promise + +export function homepage_block_page( + params: { refresh?: 'true' | 'false' | boolean } & RequestBaseConfig, +): Promise + +export function homepage_dragon_ball( + params: RequestBaseConfig, +): Promise + +export function hot_topic( + params: MultiPageConfig & RequestBaseConfig, +): Promise + +export function like( + params: { + like?: 'true' | 'false' | boolean + id: string | number + alg?: string + time?: string | number + } & RequestBaseConfig, +): Promise + +export function likelist( + params: { uid: string | number } & RequestBaseConfig, +): Promise + +export function login( + params: { email: string; password: string } & RequestBaseConfig, +): Promise + +export function login( + params: { email: string; md5_password: string } & RequestBaseConfig, +): Promise + +export function login_cellphone( + params: { + phone: number | string + countrycode?: number | string + password: string + } & RequestBaseConfig, +): Promise + +export function login_cellphone( + params: { + phone: number | string + countrycode?: number | string + md5_password: string + } & RequestBaseConfig, +): Promise + +export function login_refresh(params: RequestBaseConfig): Promise + +export function login_status(params: RequestBaseConfig): Promise + +export function logout(params: RequestBaseConfig): Promise + +export function lyric( + params: { id: string | number } & RequestBaseConfig, +): Promise + +export function msg_comments( + params: { + uid: string | number + before?: string | number + limit?: string | number + } & RequestBaseConfig, +): Promise + +export function msg_forwards( + params: MultiPageConfig & RequestBaseConfig, +): Promise + +export function msg_notices( + params: { + limit?: string | number + lasttime?: string | number + } & RequestBaseConfig, +): Promise + +export function msg_private( + params: MultiPageConfig & RequestBaseConfig, +): Promise + +export function msg_private_history( + params: { + before?: string | number + limit?: string | number + uid: string | number + } & RequestBaseConfig, +): Promise + +export const enum MvArea { + all = '全部', + zh = '内地', + hk = '港台', + ea = '欧美', + kr = '韩国', + jp = '日本', +} + +export const enum MvType { + all = '全部', + offical = '官方版', + raw = '原生', + live = '现场版', + netease = '网易出品', +} + +export const enum MvOrder { + trend = '上升最快', + hot = '最热', + new = '最新', +} + +export function mv_all( + params: { + area?: MvArea + type?: MvType + order?: MvOrder + } & MultiPageConfig & + RequestBaseConfig, +): Promise + +export function mv_detail( + params: { mvid?: string | number } & RequestBaseConfig, +): Promise + +export function mv_detail_info( + params: { mvid: string | number } & RequestBaseConfig, +): Promise + +export function mv_exclusive_rcmd( + params: MultiPageConfig & RequestBaseConfig, +): Promise + +export function mv_first( + params: { area?: MvArea; limit?: string | number } & RequestBaseConfig, +): Promise + +export function mv_sub( + params: { t: SubAction; mvid: string | number } & RequestBaseConfig, +): Promise + +export function mv_sublist( + params: MultiPageConfig & RequestBaseConfig, +): Promise + +export function mv_url( + params: { id?: string | number; r?: string | number } & RequestBaseConfig, +): Promise + +export function personal_fm(params: RequestBaseConfig): Promise + +export function personalized( + params: { limit?: string | number } & RequestBaseConfig, +): Promise + +export function personalized_djprogram( + params: RequestBaseConfig, +): Promise + +export function personalized_mv(params: RequestBaseConfig): Promise + +export function personalized_newsong( + params: { + area?: string | number + limit?: string | number + } & RequestBaseConfig, +): Promise + +export function personalized_privatecontent( + params: RequestBaseConfig, +): Promise + +export function personalized_privatecontent_list( + params: MultiPageConfig & RequestBaseConfig, +): Promise + +export function playlist_catlist(params: RequestBaseConfig): Promise + +export function playlist_cover_update( + params: { id: string } & ImageUploadConfig & RequestBaseConfig, +): Promise + +export function playlist_create( + params: { + name: string + privacy: 0 | 10 + type?: PlaylistType + } & RequestBaseConfig, +): Promise + +export function playlist_delete( + params: { id: string | number } & RequestBaseConfig, +): Promise + +export function playlist_desc_update( + params: { id: string | number; desc: string } & RequestBaseConfig, +): Promise + +export function playlist_detail( + params: { id: string | number; s?: string | number } & RequestBaseConfig, +): Promise + +export function playlist_highquality_tags( + params: RequestBaseConfig, +): Promise + +export function playlist_hot(params: RequestBaseConfig): Promise + +export function playlist_name_update( + params: { id: string | number; name: string } & RequestBaseConfig, +): Promise + +export function playlist_order_update( + params: { ids: string } & RequestBaseConfig, +): Promise + +export function playlist_subscribe( + params: { t: SubAction; id: string | number } & RequestBaseConfig, +): Promise + +export function playlist_subscribers( + params: { id?: string | number } & MultiPageConfig & RequestBaseConfig, +): Promise + +export function playlist_tags_update( + params: { id: string | number; tags: string } & RequestBaseConfig, +): Promise + +export function playlist_tracks( + params: { + op: 'add' | 'del' + pid: string | number + tracks: string + } & RequestBaseConfig, +): Promise + +export function playlist_update( + params: { + id: string | number + name: string + desc?: string + tags?: string + } & RequestBaseConfig, +): Promise + +export function playmode_intelligence_list( + params: { + id: string | number + pid: string | number + sid?: string | number + count?: string | number + } & RequestBaseConfig, +): Promise + +export function program_recommend( + params: { type: string } & MultiPageConfig & RequestBaseConfig, +): Promise + +export function rebind( + params: { + captcha: string + phone: string + oldcaptcha: string + ctcode?: number | string + } & RequestBaseConfig, +): Promise + +export function recommend_resource(params: RequestBaseConfig): Promise + +export function recommend_songs(params: RequestBaseConfig): Promise + +export function register_cellphone( + params: { + captcha: string + phone: string + password: string + nickname: string + } & RequestBaseConfig, +): Promise + +export function related_allvideo( + params: { id: string | number } & RequestBaseConfig, +): Promise + +export function related_playlist( + params: { id: string | number } & RequestBaseConfig, +): Promise + +export const enum ResourceType { + mv = 1, + dj = 4, + video = 5, + event = 6, +} +type PlaylistType = 'NROMAL' | 'VIDEO' + +export function resource_like( + params: { + t: SubAction + type: ResourceType + id?: string | number + threadId?: string + } & RequestBaseConfig, +): Promise + +export function scrobble( + params: { + id: string | number + sourceid: string | number + time: string | number + } & RequestBaseConfig, +): Promise + +export function search( + params: { + keywords: string + type?: SearchType + } & MultiPageConfig & + RequestBaseConfig, +): Promise + +export function search_default(params: RequestBaseConfig): Promise + +export function search_hot(params: RequestBaseConfig): Promise + +export function search_hot_detail(params: RequestBaseConfig): Promise + +export function search_multimatch( + params: { type?: number; keywords: string } & RequestBaseConfig, +): Promise + +export const enum SearchSuggestType { + mobile = 'mobile', + web = 'web', +} + +export function search_suggest( + params: { keywords: string; type?: SearchSuggestType } & RequestBaseConfig, +): Promise + +export function send_playlist( + params: { + playlist: string | number + msg: string + user_ids: string + } & RequestBaseConfig, +): Promise + +export function send_text( + params: { msg: string; user_ids: string } & RequestBaseConfig, +): Promise + +export function setting(params: RequestBaseConfig): Promise + +export const enum ShareResourceType { + song = 'song', + playlist = 'playlist', + mv = 'mv', + djprogram = 'djprogram', + djradio = 'djradio', +} + +export function share_resource( + params: { + type?: ShareResourceType + msg?: string + id?: string | number + } & RequestBaseConfig, +): Promise + +export function simi_artist( + params: { id: string | number } & RequestBaseConfig, +): Promise + +export function simi_mv( + params: { mvid: string | number } & RequestBaseConfig, +): Promise + +export function simi_playlist( + params: { id: string | number } & MultiPageConfig & RequestBaseConfig, +): Promise + +export function simi_song( + params: { id: string | number } & MultiPageConfig & RequestBaseConfig, +): Promise + +export function simi_user( + params: { id: string | number } & MultiPageConfig & RequestBaseConfig, +): Promise + +export function song_detail( + params: { ids: string } & RequestBaseConfig, +): Promise + +export function song_order_update( + params: { pid: string | number; ids: string } & RequestBaseConfig, +): Promise + +export function song_url( + params: { id: string | number; br?: string | number } & RequestBaseConfig, +): Promise + +export function top_album( + params: { + area?: AlbumListArea + type?: ListOrder + year?: string + mouth?: string + } & MultiPageConfig & + RequestBaseConfig, +): Promise + +export function top_artists( + params: MultiPageConfig & RequestBaseConfig, +): Promise + +export function top_list( + params: { id: string | number } & RequestBaseConfig, +): Promise + +export function top_mv( + params: { area?: MvArea } & MultiPageConfig & RequestBaseConfig, +): Promise + +export function top_playlist( + params: { cat?: string; order?: ListOrder } & MultiPageConfig & + RequestBaseConfig, +): Promise + +export function top_playlist_highquality( + params: { + cat?: string + before?: string | number + limit?: string | number + } & RequestBaseConfig, +): Promise + +export const enum TopSongType { + all = 0, + zh = 7, + ea = 96, + kr = 16, + ja = 8, +} + +export function top_song( + params: { type: TopSongType } & RequestBaseConfig, +): Promise + +export function toplist(params: RequestBaseConfig): Promise + +export const enum ToplistArtistType { + zh = 1, + ea = 2, + kr = 3, + ja = 4, +} + +export function toplist_artist( + params: { type?: ToplistArtistType } & RequestBaseConfig, +): Promise + +export function toplist_detail(params: RequestBaseConfig): Promise + +export function user_audio( + params: { uid: string | number } & RequestBaseConfig, +): Promise + +export function user_cloud( + params: MultiPageConfig & RequestBaseConfig, +): Promise + +export function user_cloud_del( + params: { id: string | number } & RequestBaseConfig, +): Promise + +export function user_cloud_detail( + params: { id: string | number } & RequestBaseConfig, +): Promise + +export function user_detail( + params: { uid: string | number } & RequestBaseConfig, +): Promise + +export function user_dj( + params: { uid: string | number } & MultiPageConfig & RequestBaseConfig, +): Promise + +export function user_event( + params: { + lasttime?: string | number + limit?: string | number + uid: string | number + } & RequestBaseConfig, +): Promise + +export function user_followeds( + params: { + uid: string | number + lasttime?: string | number + limit?: string | number + } & RequestBaseConfig, +): Promise + +export function user_follows( + params: { uid: string | number } & MultiPageConfig & RequestBaseConfig, +): Promise + +export function user_level(params: RequestBaseConfig): Promise + +export function user_playlist( + params: { uid: string | number } & MultiPageConfig & RequestBaseConfig, +): Promise + +export const enum UserRecordType { + all = 0, + weekly = 1, +} + +export function user_record( + params: { uid: string | number; type?: UserRecordType } & RequestBaseConfig, +): Promise + +export function user_subcount(params: RequestBaseConfig): Promise + +export function user_update( + params: { + birthday: string + city: string + gender: string + nickname: string + province: string + signature: string + } & RequestBaseConfig, +): Promise + +export function video_category_list( + params: MultiPageConfig & RequestBaseConfig, +): Promise + +export function video_detail( + params: { id: string } & RequestBaseConfig, +): Promise + +export function video_detail_info( + params: { vid: string } & RequestBaseConfig, +): Promise + +export function video_group( + params: { id: string; offset?: string | number } & RequestBaseConfig, +): Promise + +export function video_group_list(params: RequestBaseConfig): Promise + +export function video_sub( + params: { t?: SubAction; id: string } & RequestBaseConfig, +): Promise + +export function video_timeline_all( + params: { offset?: string | number } & RequestBaseConfig, +): Promise + +export function video_timeline_recommend( + params: { offset?: string | number } & RequestBaseConfig, +): Promise + +export function video_url( + params: { id: string | number; res?: number } & RequestBaseConfig, +): Promise + +export function weblog( + params: { data?: { [index: string]: unknown } } & RequestBaseConfig, +): Promise + +export function playlist_mylike( + params: { + time?: number | string + limit: number | string + } & RequestBaseConfig, +): Promise + +export function playlist_track_add( + params: { pid?: number | string; ids: number | string } & RequestBaseConfig, +): Promise + +export function playlist_track_delete( + params: { pid?: number | string; ids: number | string } & RequestBaseConfig, +): Promise + +export function comment_new( + params: { + type?: number | string + id: number | string + pageNo?: number | string + pageSize?: number | string + sortType?: number | string + } & RequestBaseConfig, +): Promise + +export function calendar( + params: { + startTime?: number | string + endTime: number | string + } & RequestBaseConfig, +): Promise + +export function playlist_video_recent( + params: RequestBaseConfig, +): Promise + +export function user_binding( + params: { uid?: number | string } & RequestBaseConfig, +): Promise + +export function user_replacephone( + params: { + phone: number | string + captcha: number | string + oldcaptcha: number | string + countrycode?: number | string + } & RequestBaseConfig, +): Promise + +export function user_safe(params: RequestBaseConfig): Promise + +export function dj_subscriber( + params: { + id: number | string + limit?: number | string + time?: number | string + } & RequestBaseConfig, +): Promise + +export function user_account(params: RequestBaseConfig): Promise + +export function yunbei(params: RequestBaseConfig): Promise + +export function yunbei_info(params: RequestBaseConfig): Promise + +export function yunbei_sign(params: RequestBaseConfig): Promise + +export function yunbei_receipt( + params: { + limit?: number | string + offset?: number | string + } & RequestBaseConfig, +): Promise + +export function yunbei_expense( + params: { + limit?: number | string + offset?: number | string + } & RequestBaseConfig, +): Promise + +export function yunbei_tasks(params: RequestBaseConfig): Promise + +export function yunbei_today(params: RequestBaseConfig): Promise + +export function yunbei_tasks_todo(params: RequestBaseConfig): Promise + +export function yunbei_task_finish( + params: { + userTaskId: number | string + depositCode?: number | string + } & RequestBaseConfig, +): Promise + +export function msg_recentcontact(params: RequestBaseConfig): Promise + +export function hug_comment( + params: { + uid: number | string + cid: number | string + sid: number | string + } & RequestBaseConfig, +): Promise + +export function comment_hug_list( + params: { + page: number | string + cursor: number | string + idCursor: number | string + pageSize?: number | string + } & RequestBaseConfig, +): Promise + +export function topic_sublist( + params: { + limit?: number | string + offset?: number | string + } & RequestBaseConfig, +): Promise + +export function topic_sublist( + params: { + limit?: number | string + offset?: number | string + } & RequestBaseConfig, +): Promise + +export function artist_new_mv( + params: { + limit?: number | string + startTimestamp?: number | string + } & RequestBaseConfig, +): Promise + +export function artist_new_song( + params: { + limit?: number | string + startTimestamp?: number | string + } & RequestBaseConfig, +): Promise + +export function artist_detail( + params: { + id: number | string + } & RequestBaseConfig, +): Promise + +export function cloud(params: RequestBaseConfig): Promise + +export function topic_detail( + params: { + actid?: number | string + } & RequestBaseConfig, +): Promise + +export function topic_detail_event_hot( + params: { + actid?: number | string + } & RequestBaseConfig, +): Promise + +export function login_qr_key(params: RequestBaseConfig): Promise + +export function login_qr_create( + params: { + key?: number | string + qrimg?: boolean | string + } & RequestBaseConfig, +): Promise + +export function login_qr_check( + params: { + key?: number | string + } & RequestBaseConfig, +): Promise + +export function playlist_detail_dynamic( + params: { id: string | number } & RequestBaseConfig, +): Promise + +export function user_bindingcellphone( + params: { + phone: number | string + captcha: number | string + countrycode?: number | string + password?: string + } & RequestBaseConfig, +): Promise diff --git a/netease_api/issue_template.md b/netease_api/issue_template.md new file mode 100644 index 0000000..3b7bcb8 --- /dev/null +++ b/netease_api/issue_template.md @@ -0,0 +1,29 @@ +## 环境 +- 系统/平台: <你的系统和平台> + +- nodejs 版本: <你的 NodeJS 版本号> + +- API版本:<运行的云音乐 API 的版本号, 对应 package.json 里面的 version> + +## 出现问题 +<出现的问题> + +## 重现步骤 +<重现步骤> + +## 期待效果 +<现在的效果,期待的效果> + + + +>先看文档有没有相关说明,调用前须知必看 + +>先在 issues 搜一下是否有相似问题,没有再发,否则直接关闭 + +>不处理别人搭建的线上服务的问题,此项目不提供任何线上服务,请自行搭建 + +>重现步骤尽量详细,不能含糊不清,包含请求地址和对应参数以及操作过程描述,不是每个人都喜欢猜别人遇到了什么问题和找参数一个个试,也比较浪费时间 + +>如果不是提建议,提 issues 如果不照着模版来将不会优先处理或直接关闭 + +>460 cheating 的问题把 `utils/request.js` 里面的 `headers['X-Real-IP']` 的注释取消掉就好 diff --git a/netease_api/main.js b/netease_api/main.js new file mode 100644 index 0000000..0b21490 --- /dev/null +++ b/netease_api/main.js @@ -0,0 +1,26 @@ +const fs = require('fs') +const path = require('path') +const request = require('./util/request') +const { cookieToJson } = require('./util/index') + +let obj = {} +fs.readdirSync(path.join(__dirname, 'module')) + .reverse() + .forEach((file) => { + if (!file.endsWith('.js')) return + let fileModule = require(path.join(__dirname, 'module', file)) + obj[file.split('.').shift()] = function (data) { + if (typeof data.cookie === 'string') { + data.cookie = cookieToJson(data.cookie) + } + return fileModule( + { + ...data, + cookie: data.cookie ? data.cookie : {}, + }, + request, + ) + } + }) + +module.exports = obj diff --git a/netease_api/module/activate_init_profile.js b/netease_api/module/activate_init_profile.js new file mode 100644 index 0000000..0fe48ba --- /dev/null +++ b/netease_api/module/activate_init_profile.js @@ -0,0 +1,19 @@ +// 初始化名字 + +module.exports = (query, request) => { + const data = { + nickname: query.nickname, + } + return request( + 'POST', + `https://music.163.com/eapi/activate/initProfile`, + data, + { + crypto: 'eapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + url: '/api/activate/initProfile', + }, + ) +} diff --git a/netease_api/module/album.js b/netease_api/module/album.js new file mode 100644 index 0000000..bc5e086 --- /dev/null +++ b/netease_api/module/album.js @@ -0,0 +1,15 @@ +// 专辑内容 + +module.exports = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/v1/album/${query.id}`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/album_detail.js b/netease_api/module/album_detail.js new file mode 100644 index 0000000..a26fef3 --- /dev/null +++ b/netease_api/module/album_detail.js @@ -0,0 +1,17 @@ +// 数字专辑详情 +module.exports = (query, request) => { + const data = { + id: query.id, + } + return request( + 'POST', + `https://music.163.com/weapi/vipmall/albumproduct/detail`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/album_detail_dynamic.js b/netease_api/module/album_detail_dynamic.js new file mode 100644 index 0000000..3d08e64 --- /dev/null +++ b/netease_api/module/album_detail_dynamic.js @@ -0,0 +1,17 @@ +// 专辑动态信息 +module.exports = (query, request) => { + const data = { + id: query.id, + } + return request( + 'POST', + `https://music.163.com/api/album/detail/dynamic`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/album_list.js b/netease_api/module/album_list.js new file mode 100644 index 0000000..fe70dd8 --- /dev/null +++ b/netease_api/module/album_list.js @@ -0,0 +1,21 @@ +// 数字专辑-新碟上架 +module.exports = (query, request) => { + const data = { + limit: query.limit || 30, + offset: query.offset || 0, + total: true, + area: query.area || 'ALL', //ALL:全部,ZH:华语,EA:欧美,KR:韩国,JP:日本 + type: query.type, + } + return request( + 'POST', + `https://music.163.com/weapi/vipmall/albumproduct/list`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/album_list_style.js b/netease_api/module/album_list_style.js new file mode 100644 index 0000000..8b92a7a --- /dev/null +++ b/netease_api/module/album_list_style.js @@ -0,0 +1,20 @@ +// 数字专辑-语种风格馆 +module.exports = (query, request) => { + const data = { + limit: query.limit || 10, + offset: query.offset || 0, + total: true, + area: query.area || 'Z_H', //Z_H:华语,E_A:欧美,KR:韩国,JP:日本 + } + return request( + 'POST', + `https://music.163.com/weapi/vipmall/appalbum/album/style`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/album_new.js b/netease_api/module/album_new.js new file mode 100644 index 0000000..b4652d3 --- /dev/null +++ b/netease_api/module/album_new.js @@ -0,0 +1,15 @@ +// 全部新碟 +module.exports = (query, request) => { + const data = { + limit: query.limit || 30, + offset: query.offset || 0, + total: true, + area: query.area || 'ALL', //ALL:全部,ZH:华语,EA:欧美,KR:韩国,JP:日本 + } + return request('POST', `https://music.163.com/weapi/album/new`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/album_newest.js b/netease_api/module/album_newest.js new file mode 100644 index 0000000..fe1f650 --- /dev/null +++ b/netease_api/module/album_newest.js @@ -0,0 +1,15 @@ +// 最新专辑 + +module.exports = (query, request) => { + return request( + 'POST', + `https://music.163.com/api/discovery/newAlbum`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/album_songsaleboard.js b/netease_api/module/album_songsaleboard.js new file mode 100644 index 0000000..a797418 --- /dev/null +++ b/netease_api/module/album_songsaleboard.js @@ -0,0 +1,24 @@ +// 数字专辑&数字单曲-榜单 +module.exports = (query, request) => { + let data = { + albumType: query.albumType || 0, //0为数字专辑,1为数字单曲 + } + const type = query.type || 'daily' // daily,week,year,total + if (type === 'year') { + data = { + ...data, + year: query.year, + } + } + return request( + 'POST', + `https://music.163.com/api/feealbum/songsaleboard/${type}/type`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/album_sub.js b/netease_api/module/album_sub.js new file mode 100644 index 0000000..65c6b24 --- /dev/null +++ b/netease_api/module/album_sub.js @@ -0,0 +1,14 @@ +// 收藏/取消收藏专辑 + +module.exports = (query, request) => { + query.t = query.t == 1 ? 'sub' : 'unsub' + const data = { + id: query.id, + } + return request('POST', `https://music.163.com/api/album/${query.t}`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/album_sublist.js b/netease_api/module/album_sublist.js new file mode 100644 index 0000000..5d01578 --- /dev/null +++ b/netease_api/module/album_sublist.js @@ -0,0 +1,15 @@ +// 已收藏专辑列表 + +module.exports = (query, request) => { + const data = { + limit: query.limit || 25, + offset: query.offset || 0, + total: true, + } + return request('POST', `https://music.163.com/weapi/album/sublist`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/artist_album.js b/netease_api/module/artist_album.js new file mode 100644 index 0000000..92a04a7 --- /dev/null +++ b/netease_api/module/artist_album.js @@ -0,0 +1,20 @@ +// 歌手专辑列表 + +module.exports = (query, request) => { + const data = { + limit: query.limit || 30, + offset: query.offset || 0, + total: true, + } + return request( + 'POST', + `https://music.163.com/weapi/artist/albums/${query.id}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/artist_desc.js b/netease_api/module/artist_desc.js new file mode 100644 index 0000000..c67d707 --- /dev/null +++ b/netease_api/module/artist_desc.js @@ -0,0 +1,18 @@ +// 歌手介绍 + +module.exports = (query, request) => { + const data = { + id: query.id, + } + return request( + 'POST', + `https://music.163.com/weapi/artist/introduction`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/artist_detail.js b/netease_api/module/artist_detail.js new file mode 100644 index 0000000..8bbb9d9 --- /dev/null +++ b/netease_api/module/artist_detail.js @@ -0,0 +1,15 @@ +module.exports = (query, request) => { + return request( + 'POST', + `https://music.163.com/api/artist/head/info/get`, + { + id: query.id, + }, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/artist_list.js b/netease_api/module/artist_list.js new file mode 100644 index 0000000..fe95864 --- /dev/null +++ b/netease_api/module/artist_list.js @@ -0,0 +1,37 @@ +// 歌手分类 + +/* + type 取值 + 1:男歌手 + 2:女歌手 + 3:乐队 + + area 取值 + -1:全部 + 7华语 + 96欧美 + 8:日本 + 16韩国 + 0:其他 + + initial 取值 a-z/A-Z +*/ + +module.exports = (query, request) => { + const data = { + initial: isNaN(query.initial) + ? (query.initial || '').toUpperCase().charCodeAt() || undefined + : query.initial, + offset: query.offset || 0, + limit: query.limit || 30, + total: true, + type: query.type || '1', + area: query.area, + } + return request('POST', `https://music.163.com/api/v1/artist/list`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/artist_mv.js b/netease_api/module/artist_mv.js new file mode 100644 index 0000000..8decc04 --- /dev/null +++ b/netease_api/module/artist_mv.js @@ -0,0 +1,16 @@ +// 歌手相关MV + +module.exports = (query, request) => { + const data = { + artistId: query.id, + limit: query.limit, + offset: query.offset, + total: true, + } + return request('POST', `https://music.163.com/weapi/artist/mvs`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/artist_new_mv.js b/netease_api/module/artist_new_mv.js new file mode 100644 index 0000000..6c65343 --- /dev/null +++ b/netease_api/module/artist_new_mv.js @@ -0,0 +1,19 @@ +module.exports = (query, request) => { + query.cookie.os = 'ios' + query.cookie.appver = '8.1.20' + const data = { + limit: query.limit || 20, + startTimestamp: query.before || Date.now(), + } + return request( + 'POST', + `https://music.163.com/api/sub/artist/new/works/mv/list`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/artist_new_song.js b/netease_api/module/artist_new_song.js new file mode 100644 index 0000000..a367f8c --- /dev/null +++ b/netease_api/module/artist_new_song.js @@ -0,0 +1,19 @@ +module.exports = (query, request) => { + query.cookie.os = 'ios' + query.cookie.appver = '8.1.20' + const data = { + limit: query.limit || 20, + startTimestamp: query.before || Date.now(), + } + return request( + 'POST', + `https://music.163.com/api/sub/artist/new/works/song/list`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/artist_songs.js b/netease_api/module/artist_songs.js new file mode 100644 index 0000000..533e1e5 --- /dev/null +++ b/netease_api/module/artist_songs.js @@ -0,0 +1,17 @@ +module.exports = (query, request) => { + query.cookie.os = 'pc' + const data = { + id: query.id, + private_cloud: 'true', + work_type: 1, + order: query.order || 'hot', //hot,time + offset: query.offset || 0, + limit: query.limit || 100, + } + return request('POST', `https://music.163.com/api/v1/artist/songs`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/artist_sub.js b/netease_api/module/artist_sub.js new file mode 100644 index 0000000..ff46b04 --- /dev/null +++ b/netease_api/module/artist_sub.js @@ -0,0 +1,20 @@ +// 收藏与取消收藏歌手 + +module.exports = (query, request) => { + query.t = query.t == 1 ? 'sub' : 'unsub' + const data = { + artistId: query.id, + artistIds: '[' + query.id + ']', + } + return request( + 'POST', + `https://music.163.com/weapi/artist/${query.t}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/artist_sublist.js b/netease_api/module/artist_sublist.js new file mode 100644 index 0000000..c4adf40 --- /dev/null +++ b/netease_api/module/artist_sublist.js @@ -0,0 +1,15 @@ +// 关注歌手列表 + +module.exports = (query, request) => { + const data = { + limit: query.limit || 25, + offset: query.offset || 0, + total: true, + } + return request('POST', `https://music.163.com/weapi/artist/sublist`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/artist_top_song.js b/netease_api/module/artist_top_song.js new file mode 100644 index 0000000..c86136e --- /dev/null +++ b/netease_api/module/artist_top_song.js @@ -0,0 +1,12 @@ +// 歌手热门 50 首歌曲 +module.exports = (query, request) => { + const data = { + id: query.id, + } + return request('POST', `https://music.163.com/api/artist/top/song`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/artists.js b/netease_api/module/artists.js new file mode 100644 index 0000000..3f29e7f --- /dev/null +++ b/netease_api/module/artists.js @@ -0,0 +1,15 @@ +// 歌手单曲 + +module.exports = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/v1/artist/${query.id}`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/audio_match.js b/netease_api/module/audio_match.js new file mode 100644 index 0000000..a9a2cfa --- /dev/null +++ b/netease_api/module/audio_match.js @@ -0,0 +1,19 @@ +const realData = + 'eJx10mtIU2EcBvDtnCwNMfO2klUSmSQ5ZugKW/v/0TIjJVdhDStbXpqXrhY5Kwhtrcwiut9VSqMUMxX6IFqsD92sD1YgWGHRBcowKrpnPa/v+drg4flt572ds2PQ6XQut7MwJ940w2TOyS0pzF+/BV/MJrNO+3TVLOHUzKx5iw3/H5uZ7yxegct3tTl7Cr6QEa0gZ/dZOFsvfe5YHe1D+yFZxpncqEj/cCdwoirdVxHNnZrX3xygU5g7Eh6I9uOx8Ch4y9FQjlKkDz1pYrFXIJLUOovFGcYivqJgXqaXDqu7Rzc0XzmZxG81B/fF8wRVusn2jN5rDnwca8tFhyAJP4L4qiI9vX8cWzEmVKzT/46qxNpIdZOZz2HNcHhSkZ3D4AjYFpfGFkX6+dB+FvcSBe/SWbkLPVnEOJ1DFelXxVVci/Wj4TsBLhrQ/LGoaU4HxsTA28L76Cc8Dfau/U6F6FgkyBDDJar0g8tesmOvOHioWeXXmme6l3MLbIIre6wciU5E2t/k8WVxHfHvuUWXsH4SPCv1NW1Cz0aivgYO34vw1AEvi3MlIw0xHl6JNVPEGW41UJsqPaXYYTuEnotMdHwYfv7CFR/i+aXmrY5wrlSkEwr+0EJ0GvLmdw4/RS9Amj93UAbGZMIF40ezE3PtcG/yBWrT3L6oh66hFyMXK4xsUKT7aufzapxnFTwiNc3Wis5Bdm+OYCvmOuHj/ZeoQPOI00PUrUjXpG+kMFU61tFFDvQaZOn5DH4mzoLw4Hsaj14rzu/K4jF66fSWTnJinW3wBvcveqjZN3iFjKp0qKuF1mi21keST3NtTcbwu1eG3Dussr9eemljLIco0tVH7HwA493wOr+FlIjfy+GvkR4uwfjt4v/6G8K3NX8K38lt6B1ISa+Bv2O8Fy69foZOovci2S4Lr1aku4P9OEWVTt9wgMQ7exgJ8JXyI0W694WFyuBjcH75XyrEXsfhg+ZSvqZIf/Lct8Wp0md2tJN4PifEfjcm8gu02Ptbj459eum8eg8bFWlLXTb/A+uo9bM=' +module.exports = (query, request) => { + query.cookie.os = 'pc' + const data = { + algorithmCode: 'shazam_v2', + times: 1, + sessionId: 'C999431ACDC84EDBB984763654E6F8D7', + duration: 3.3066249999999995, + from: 'recognize-song', + rawdata: realData, + } + return request('POST', `https://music.163.com/api/music/audio/match`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/avatar_upload.js b/netease_api/module/avatar_upload.js new file mode 100644 index 0000000..94f018b --- /dev/null +++ b/netease_api/module/avatar_upload.js @@ -0,0 +1,27 @@ +const uploadPlugin = require('../plugins/upload') +module.exports = async (query, request) => { + const uploadInfo = await uploadPlugin(query, request) + const res = await request( + 'POST', + `https://music.163.com/weapi/user/avatar/upload/v1`, + { + imgid: uploadInfo.imgId, + }, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) + return { + status: 200, + body: { + code: 200, + data: { + ...uploadInfo, + ...res.body, + }, + }, + } +} diff --git a/netease_api/module/banner.js b/netease_api/module/banner.js new file mode 100644 index 0000000..00f52c9 --- /dev/null +++ b/netease_api/module/banner.js @@ -0,0 +1,17 @@ +// 首页轮播图 + +module.exports = (query, request) => { + const type = + { + 0: 'pc', + 1: 'android', + 2: 'iphone', + 3: 'ipad', + }[query.type || 0] || 'pc' + return request( + 'POST', + `https://music.163.com/api/v2/banner/get`, + { clientType: type }, + { crypto: 'api', proxy: query.proxy, realIP: query.realIP }, + ) +} diff --git a/netease_api/module/batch.js b/netease_api/module/batch.js new file mode 100644 index 0000000..2e95070 --- /dev/null +++ b/netease_api/module/batch.js @@ -0,0 +1,19 @@ +// 批量请求接口 + +module.exports = (query, request) => { + const data = { + e_r: true, + } + Object.keys(query).forEach((i) => { + if (/^\/api\//.test(i)) { + data[i] = query[i] + } + }) + return request('POST', `https://music.163.com/eapi/batch`, data, { + crypto: 'eapi', + proxy: query.proxy, + url: '/api/batch', + cookie: query.cookie, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/calendar.js b/netease_api/module/calendar.js new file mode 100644 index 0000000..61bc387 --- /dev/null +++ b/netease_api/module/calendar.js @@ -0,0 +1,12 @@ +module.exports = (query, request) => { + const data = { + startTime: query.startTime || Date.now(), + endTime: query.endTime || Date.now(), + } + return request('POST', `https://music.163.com/api/mcalendar/detail`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/captcha_sent.js b/netease_api/module/captcha_sent.js new file mode 100644 index 0000000..076dcbb --- /dev/null +++ b/netease_api/module/captcha_sent.js @@ -0,0 +1,14 @@ +// 发送验证码 + +module.exports = (query, request) => { + const data = { + ctcode: query.ctcode || '86', + cellphone: query.phone, + } + return request('POST', `https://music.163.com/api/sms/captcha/sent`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/captcha_verify.js b/netease_api/module/captcha_verify.js new file mode 100644 index 0000000..990ce27 --- /dev/null +++ b/netease_api/module/captcha_verify.js @@ -0,0 +1,20 @@ +// 校验验证码 + +module.exports = (query, request) => { + const data = { + ctcode: query.ctcode || '86', + cellphone: query.phone, + captcha: query.captcha, + } + return request( + 'POST', + `https://music.163.com/weapi/sms/captcha/verify`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/cellphone_existence_check.js b/netease_api/module/cellphone_existence_check.js new file mode 100644 index 0000000..c4912ae --- /dev/null +++ b/netease_api/module/cellphone_existence_check.js @@ -0,0 +1,20 @@ +// 检测手机号码是否已注册 + +module.exports = (query, request) => { + const data = { + cellphone: query.phone, + countrycode: query.countrycode, + } + return request( + 'POST', + `https://music.163.com/eapi/cellphone/existence/check`, + data, + { + crypto: 'eapi', + cookie: query.cookie, + proxy: query.proxy, + url: '/api/cellphone/existence/check', + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/check_music.js b/netease_api/module/check_music.js new file mode 100644 index 0000000..0e32ef9 --- /dev/null +++ b/netease_api/module/check_music.js @@ -0,0 +1,34 @@ +// 歌曲可用性 + +module.exports = (query, request) => { + const data = { + ids: '[' + parseInt(query.id) + ']', + br: parseInt(query.br || 999000), + } + return request( + 'POST', + `https://music.163.com/weapi/song/enhance/player/url`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ).then((response) => { + let playable = false + if (response.body.code == 200) { + if (response.body.data[0].code == 200) { + playable = true + } + } + if (playable) { + response.body = { success: true, message: 'ok' } + return response + } else { + response.status = 404 + response.body = { success: false, message: '亲爱的,暂无版权' } + return Promise.reject(response) + } + }) +} diff --git a/netease_api/module/cloud.js b/netease_api/module/cloud.js new file mode 100644 index 0000000..b7cdac3 --- /dev/null +++ b/netease_api/module/cloud.js @@ -0,0 +1,147 @@ +const mm = require('music-metadata') +const uploadPlugin = require('../plugins/songUpload') +const md5 = require('md5') +module.exports = async (query, request) => { + query.cookie.os = 'pc' + query.cookie.appver = '2.7.1.198277' + const bitrate = 999000 + if (!query.songFile) { + return Promise.reject({ + status: 500, + body: { + msg: '请上传音乐文件', + code: 500, + }, + }) + } + if (!query.songFile.md5) { + // 命令行上传没有md5和size信息,需要填充 + query.songFile.md5 = md5(query.songFile.data) + query.songFile.size = query.songFile.data.byteLength + } + const res = await request( + 'POST', + `https://interface.music.163.com/api/cloud/upload/check`, + { + bitrate: String(bitrate), + ext: '', + length: query.songFile.size, + md5: query.songFile.md5, + songId: '0', + version: 1, + }, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) + let artist = '' + let album = '' + let songName = '' + try { + const metadata = await mm.parseBuffer(query.songFile.data, 'audio/mpeg') + const info = metadata.common + if (info.title) { + songName = info.title + } + if (info.album) { + album = info.album + } + if (info.artist) { + artist = info.artist + } + // if (metadata.native.ID3v1) { + // metadata.native.ID3v1.forEach((item) => { + // // console.log(item.id, item.value) + // if (item.id === 'title') { + // songName = item.value + // } + // if (item.id === 'artist') { + // artist = item.value + // } + // if (item.id === 'album') { + // album = item.value + // } + // }) + // // console.log({ + // // songName, + // // album, + // // songName, + // // }) + // } + // console.log({ + // songName, + // album, + // songName, + // }) + } catch (error) { + console.log(error) + } + const tokenRes = await request( + 'POST', + `https://music.163.com/weapi/nos/token/alloc`, + { + bucket: '', + 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 }, + ) + + if (res.body.needUpload) { + const uploadInfo = await uploadPlugin(query, request) + // console.log('uploadInfo', uploadInfo.body.result.resourceId) + } + // console.log(tokenRes.body.result) + const res2 = await request( + 'POST', + `https://music.163.com/api/upload/cloud/info/v2`, + { + md5: query.songFile.md5, + songid: res.body.songId, + filename: query.songFile.name, + song: songName || query.songFile.name.replace('.mp3', ''), + album: album || '未知专辑', + artist: artist || '未知艺术家', + bitrate: String(bitrate), + resourceId: tokenRes.body.result.resourceId, + }, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) + // console.log({ res2, privateCloud: res2.body.privateCloud }) + // console.log(res.body.songId, 'songid') + const res3 = await request( + 'POST', + `https://interface.music.163.com/api/cloud/pub/v2`, + { + songid: res2.body.songId, + }, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) + // console.log({ res3 }) + return { + status: 200, + body: { + ...res.body, + ...res3.body, + // ...uploadInfo, + }, + cookie: res.cookie, + } +} diff --git a/netease_api/module/cloudsearch.js b/netease_api/module/cloudsearch.js new file mode 100644 index 0000000..e768e85 --- /dev/null +++ b/netease_api/module/cloudsearch.js @@ -0,0 +1,17 @@ +// 搜索 + +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, + total: true, + } + return request('POST', `https://music.163.com/api/cloudsearch/pc`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/comment.js b/netease_api/module/comment.js new file mode 100644 index 0000000..9395bf3 --- /dev/null +++ b/netease_api/module/comment.js @@ -0,0 +1,36 @@ +const { resourceTypeMap } = require('../util/config.json') +// 发送与删除评论 + +module.exports = (query, request) => { + query.cookie.os = 'pc' + query.t = { + 1: 'add', + 0: 'delete', + 2: 'reply', + }[query.t] + query.type = resourceTypeMap[query.type] + const data = { + threadId: query.type + query.id, + } + + if (query.type == 'A_EV_2_') { + data.threadId = query.threadId + } + if (query.t == 'add') data.content = query.content + else if (query.t == 'delete') data.commentId = query.commentId + else if (query.t == 'reply') { + data.commentId = query.commentId + data.content = query.content + } + return request( + 'POST', + `https://music.163.com/weapi/resource/comments/${query.t}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/comment_album.js b/netease_api/module/comment_album.js new file mode 100644 index 0000000..d701d2d --- /dev/null +++ b/netease_api/module/comment_album.js @@ -0,0 +1,22 @@ +// 专辑评论 + +module.exports = (query, request) => { + query.cookie.os = 'pc' + const data = { + rid: query.id, + limit: query.limit || 20, + offset: query.offset || 0, + beforeTime: query.before || 0, + } + return request( + 'POST', + `https://music.163.com/weapi/v1/resource/comments/R_AL_3_${query.id}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/comment_dj.js b/netease_api/module/comment_dj.js new file mode 100644 index 0000000..70b7dbf --- /dev/null +++ b/netease_api/module/comment_dj.js @@ -0,0 +1,22 @@ +// 电台评论 + +module.exports = (query, request) => { + query.cookie.os = 'pc' + const data = { + rid: query.id, + limit: query.limit || 20, + offset: query.offset || 0, + beforeTime: query.before || 0, + } + return request( + 'POST', + `https://music.163.com/weapi/v1/resource/comments/A_DJ_1_${query.id}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/comment_event.js b/netease_api/module/comment_event.js new file mode 100644 index 0000000..460a560 --- /dev/null +++ b/netease_api/module/comment_event.js @@ -0,0 +1,20 @@ +// 获取动态评论 + +module.exports = (query, request) => { + const data = { + limit: query.limit || 20, + offset: query.offset || 0, + beforeTime: query.before || 0, + } + return request( + 'POST', + `https://music.163.com/weapi/v1/resource/comments/${query.threadId}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/comment_floor.js b/netease_api/module/comment_floor.js new file mode 100644 index 0000000..de28470 --- /dev/null +++ b/netease_api/module/comment_floor.js @@ -0,0 +1,21 @@ +const { resourceTypeMap } = require('../util/config.json') +module.exports = (query, request) => { + query.type = resourceTypeMap[query.type] + const data = { + parentCommentId: query.parentCommentId, + threadId: query.type + query.id, + time: query.time || -1, + limit: query.limit || 20, + } + return request( + 'POST', + `https://music.163.com/api/resource/comment/floor/get`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/comment_hot.js b/netease_api/module/comment_hot.js new file mode 100644 index 0000000..4858678 --- /dev/null +++ b/netease_api/module/comment_hot.js @@ -0,0 +1,24 @@ +const { resourceTypeMap } = require('../util/config.json') +// 热门评论 + +module.exports = (query, request) => { + query.cookie.os = 'pc' + query.type = resourceTypeMap[query.type] + const data = { + rid: query.id, + limit: query.limit || 20, + offset: query.offset || 0, + beforeTime: query.before || 0, + } + return request( + 'POST', + `https://music.163.com/weapi/v1/resource/hotcomments/${query.type}${query.id}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/comment_hug_list.js b/netease_api/module/comment_hug_list.js new file mode 100644 index 0000000..394a2df --- /dev/null +++ b/netease_api/module/comment_hug_list.js @@ -0,0 +1,27 @@ +const { resourceTypeMap } = require('../util/config.json') +module.exports = (query, request) => { + query.cookie.os = 'ios' + query.cookie.appver = '8.1.20' + query.type = resourceTypeMap[query.type || 0] + const threadId = query.type + query.sid + const data = { + targetUserId: query.uid, + commentId: query.cid, + cursor: query.cursor || '-1', + threadId: threadId, + pageNo: query.page || 1, + idCursor: query.idCursor || -1, + pageSize: query.pageSize || 100, + } + return request( + 'POST', + `https://music.163.com/api/v2/resource/comments/hug/list`, + data, + { + crypto: 'api', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/comment_like.js b/netease_api/module/comment_like.js new file mode 100644 index 0000000..fa382a8 --- /dev/null +++ b/netease_api/module/comment_like.js @@ -0,0 +1,26 @@ +const { resourceTypeMap } = require('../util/config.json') +// 点赞与取消点赞评论 + +module.exports = (query, request) => { + query.cookie.os = 'pc' + query.t = query.t == 1 ? 'like' : 'unlike' + query.type = resourceTypeMap[query.type] + const data = { + threadId: query.type + query.id, + commentId: query.cid, + } + if (query.type == 'A_EV_2_') { + data.threadId = query.threadId + } + return request( + 'POST', + `https://music.163.com/weapi/v1/comment/${query.t}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/comment_music.js b/netease_api/module/comment_music.js new file mode 100644 index 0000000..9fbc8f1 --- /dev/null +++ b/netease_api/module/comment_music.js @@ -0,0 +1,22 @@ +// 歌曲评论 + +module.exports = (query, request) => { + query.cookie.os = 'pc' + const data = { + rid: query.id, + limit: query.limit || 20, + offset: query.offset || 0, + beforeTime: query.before || 0, + } + return request( + 'POST', + `https://music.163.com/api/v1/resource/comments/R_SO_4_${query.id}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/comment_mv.js b/netease_api/module/comment_mv.js new file mode 100644 index 0000000..979c035 --- /dev/null +++ b/netease_api/module/comment_mv.js @@ -0,0 +1,22 @@ +// MV评论 + +module.exports = (query, request) => { + query.cookie.os = 'pc' + const data = { + rid: query.id, + limit: query.limit || 20, + offset: query.offset || 0, + beforeTime: query.before || 0, + } + return request( + 'POST', + `https://music.163.com/weapi/v1/resource/comments/R_MV_5_${query.id}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/comment_new.js b/netease_api/module/comment_new.js new file mode 100644 index 0000000..ad3cb0b --- /dev/null +++ b/netease_api/module/comment_new.js @@ -0,0 +1,31 @@ +const { resourceTypeMap } = require('../util/config.json') +// 评论 + +module.exports = (query, request) => { + query.cookie.os = 'pc' + query.type = resourceTypeMap[query.type] + const threadId = query.type + query.id + const pageSize = query.pageSize || 20 + const pageNo = query.pageNo || 1 + const data = { + threadId: threadId, + pageNo, + showInner: query.showInner || true, + pageSize, + cursor: + +query.sortType === 3 ? query.cursor || '0' : (pageNo - 1) * pageSize, + sortType: query.sortType || 1, //1:按推荐排序,2:按热度排序,3:按时间排序 + } + return request( + 'POST', + `https://music.163.com/api/v2/resource/comments`, + data, + { + crypto: 'eapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + url: '/api/v2/resource/comments', + }, + ) +} diff --git a/netease_api/module/comment_playlist.js b/netease_api/module/comment_playlist.js new file mode 100644 index 0000000..52fc544 --- /dev/null +++ b/netease_api/module/comment_playlist.js @@ -0,0 +1,22 @@ +// 歌单评论 + +module.exports = (query, request) => { + query.cookie.os = 'pc' + const data = { + rid: query.id, + limit: query.limit || 20, + offset: query.offset || 0, + beforeTime: query.before || 0, + } + return request( + 'POST', + `https://music.163.com/weapi/v1/resource/comments/A_PL_0_${query.id}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/comment_video.js b/netease_api/module/comment_video.js new file mode 100644 index 0000000..ae015a9 --- /dev/null +++ b/netease_api/module/comment_video.js @@ -0,0 +1,22 @@ +// 视频评论 + +module.exports = (query, request) => { + query.cookie.os = 'pc' + const data = { + rid: query.id, + limit: query.limit || 20, + offset: query.offset || 0, + beforeTime: query.before || 0, + } + return request( + 'POST', + `https://music.163.com/weapi/v1/resource/comments/R_VI_62_${query.id}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/countries_code_list.js b/netease_api/module/countries_code_list.js new file mode 100644 index 0000000..15a76b6 --- /dev/null +++ b/netease_api/module/countries_code_list.js @@ -0,0 +1,16 @@ +// 国家编码列表 +module.exports = (query, request) => { + const data = {} + return request( + 'POST', + `https://interface3.music.163.com/eapi/lbs/countries/v1`, + data, + { + crypto: 'eapi', + cookie: query.cookie, + proxy: query.proxy, + url: '/api/lbs/countries/v1', + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/daily_signin.js b/netease_api/module/daily_signin.js new file mode 100644 index 0000000..2bb7dee --- /dev/null +++ b/netease_api/module/daily_signin.js @@ -0,0 +1,20 @@ +// 签到 + +/* + 0为安卓端签到 3点经验, 1为网页签到,2点经验 + 签到成功 {'android': {'point': 3, 'code': 200}, 'web': {'point': 2, 'code': 200}} + 重复签到 {'android': {'code': -2, 'msg': '重复签到'}, 'web': {'code': -2, 'msg': '重复签到'}} + 未登录 {'android': {'code': 301}, 'web': {'code': 301}} +*/ + +module.exports = (query, request) => { + const data = { + type: query.type || 0, + } + return request('POST', `https://music.163.com/weapi/point/dailyTask`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/digitalAlbum_ordering.js b/netease_api/module/digitalAlbum_ordering.js new file mode 100644 index 0000000..471d95b --- /dev/null +++ b/netease_api/module/digitalAlbum_ordering.js @@ -0,0 +1,27 @@ +// 购买数字专辑 + +module.exports = (query, request) => { + const data = { + business: 'Album', + paymentMethod: query.payment, + digitalResources: JSON.stringify([ + { + business: 'Album', + resourceID: query.id, + quantity: query.quantity, + }, + ]), + from: 'web', + } + return request( + 'POST', + `https://music.163.com/api/ordering/web/digital`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/digitalAlbum_purchased.js b/netease_api/module/digitalAlbum_purchased.js new file mode 100644 index 0000000..362dee1 --- /dev/null +++ b/netease_api/module/digitalAlbum_purchased.js @@ -0,0 +1,20 @@ +// 我的数字专辑 + +module.exports = (query, request) => { + const data = { + limit: query.limit || 30, + offset: query.offset || 0, + total: true, + } + return request( + 'POST', + `https://music.163.com/api/digitalAlbum/purchased`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/dj_banner.js b/netease_api/module/dj_banner.js new file mode 100644 index 0000000..1ec17ba --- /dev/null +++ b/netease_api/module/dj_banner.js @@ -0,0 +1,17 @@ +// 电台banner + +module.exports = (query, request) => { + const data = {} + query.cookie.os = 'pc' + return request( + 'POST', + `https://music.163.com/weapi/djradio/banner/get`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/dj_category_excludehot.js b/netease_api/module/dj_category_excludehot.js new file mode 100644 index 0000000..cfd4266 --- /dev/null +++ b/netease_api/module/dj_category_excludehot.js @@ -0,0 +1,15 @@ +// 电台非热门类型 + +module.exports = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/djradio/category/excludehot`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/dj_category_recommend.js b/netease_api/module/dj_category_recommend.js new file mode 100644 index 0000000..a0e4bf1 --- /dev/null +++ b/netease_api/module/dj_category_recommend.js @@ -0,0 +1,15 @@ +// 电台推荐类型 + +module.exports = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/djradio/home/category/recommend`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/dj_catelist.js b/netease_api/module/dj_catelist.js new file mode 100644 index 0000000..8866be4 --- /dev/null +++ b/netease_api/module/dj_catelist.js @@ -0,0 +1,15 @@ +// 电台分类列表 + +module.exports = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/djradio/category/get`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/dj_detail.js b/netease_api/module/dj_detail.js new file mode 100644 index 0000000..941024b --- /dev/null +++ b/netease_api/module/dj_detail.js @@ -0,0 +1,13 @@ +// 电台详情 + +module.exports = (query, request) => { + const data = { + id: query.rid, + } + return request('POST', `https://music.163.com/api/djradio/v2/get`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/dj_hot.js b/netease_api/module/dj_hot.js new file mode 100644 index 0000000..5f7e30f --- /dev/null +++ b/netease_api/module/dj_hot.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/weapi/djradio/hot/v1`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/dj_paygift.js b/netease_api/module/dj_paygift.js new file mode 100644 index 0000000..4424ab9 --- /dev/null +++ b/netease_api/module/dj_paygift.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/djradio/home/paygift/list?_nmclfl=1`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/dj_personalize_recommend.js b/netease_api/module/dj_personalize_recommend.js new file mode 100644 index 0000000..b8d7570 --- /dev/null +++ b/netease_api/module/dj_personalize_recommend.js @@ -0,0 +1,17 @@ +// 电台个性推荐 + +module.exports = (query, request) => { + return request( + 'POST', + `https://music.163.com/api/djradio/personalize/rcmd`, + { + limit: query.limit || 6, + }, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/dj_program.js b/netease_api/module/dj_program.js new file mode 100644 index 0000000..a0fa646 --- /dev/null +++ b/netease_api/module/dj_program.js @@ -0,0 +1,21 @@ +// 电台节目列表 +const { toBoolean } = require('../util') +module.exports = (query, request) => { + const data = { + radioId: query.rid, + limit: query.limit || 30, + offset: query.offset || 0, + asc: toBoolean(query.asc), + } + return request( + 'POST', + `https://music.163.com/weapi/dj/program/byradio`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/dj_program_detail.js b/netease_api/module/dj_program_detail.js new file mode 100644 index 0000000..70f3d2e --- /dev/null +++ b/netease_api/module/dj_program_detail.js @@ -0,0 +1,13 @@ +// 电台节目详情 + +module.exports = (query, request) => { + const data = { + id: query.id, + } + return request('POST', `https://music.163.com/api/dj/program/detail`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/dj_program_toplist.js b/netease_api/module/dj_program_toplist.js new file mode 100644 index 0000000..898cf9d --- /dev/null +++ b/netease_api/module/dj_program_toplist.js @@ -0,0 +1,14 @@ +// 电台节目榜 + +module.exports = (query, request) => { + const data = { + limit: query.limit || 100, + offset: query.offset || 0, + } + return request('POST', `https://music.163.com/api/program/toplist/v1`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/dj_program_toplist_hours.js b/netease_api/module/dj_program_toplist_hours.js new file mode 100644 index 0000000..4547636 --- /dev/null +++ b/netease_api/module/dj_program_toplist_hours.js @@ -0,0 +1,18 @@ +// 电台24小时节目榜 +module.exports = (query, request) => { + const data = { + limit: query.limit || 100, + // 不支持 offset + } + return request( + 'POST', + `https://music.163.com/api/djprogram/toplist/hours`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/dj_radio_hot.js b/netease_api/module/dj_radio_hot.js new file mode 100644 index 0000000..30e0b42 --- /dev/null +++ b/netease_api/module/dj_radio_hot.js @@ -0,0 +1,15 @@ +// 类别热门电台 + +module.exports = (query, request) => { + const data = { + cateId: query.cateId, + limit: query.limit || 30, + offset: query.offset || 0, + } + return request('POST', `https://music.163.com/api/djradio/hot`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/dj_recommend.js b/netease_api/module/dj_recommend.js new file mode 100644 index 0000000..e23b056 --- /dev/null +++ b/netease_api/module/dj_recommend.js @@ -0,0 +1,15 @@ +// 精选电台 + +module.exports = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/djradio/recommend/v1`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/dj_recommend_type.js b/netease_api/module/dj_recommend_type.js new file mode 100644 index 0000000..6f3df61 --- /dev/null +++ b/netease_api/module/dj_recommend_type.js @@ -0,0 +1,41 @@ +// 精选电台分类 + +/* + 有声书 10001 + 知识技能 453050 + 商业财经 453051 + 人文历史 11 + 外语世界 13 + 亲子宝贝 14 + 创作|翻唱 2001 + 音乐故事 2 + 3D|电子 10002 + 相声曲艺 8 + 情感调频 3 + 美文读物 6 + 脱口秀 5 + 广播剧 7 + 二次元 3001 + 明星做主播 1 + 娱乐|影视 4 + 科技科学 453052 + 校园|教育 4001 + 旅途|城市 12 +*/ + +module.exports = (query, request) => { + const data = { + cateId: query.type, + } + return request( + 'POST', + `https://music.163.com/weapi/djradio/recommend`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/dj_sub.js b/netease_api/module/dj_sub.js new file mode 100644 index 0000000..cec5ad7 --- /dev/null +++ b/netease_api/module/dj_sub.js @@ -0,0 +1,19 @@ +// 订阅与取消电台 + +module.exports = (query, request) => { + query.t = query.t == 1 ? 'sub' : 'unsub' + const data = { + id: query.rid, + } + return request( + 'POST', + `https://music.163.com/weapi/djradio/${query.t}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/dj_sublist.js b/netease_api/module/dj_sublist.js new file mode 100644 index 0000000..6d4bcf2 --- /dev/null +++ b/netease_api/module/dj_sublist.js @@ -0,0 +1,20 @@ +// 订阅电台列表 + +module.exports = (query, request) => { + const data = { + limit: query.limit || 30, + offset: query.offset || 0, + total: true, + } + return request( + 'POST', + `https://music.163.com/weapi/djradio/get/subed`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/dj_subscriber.js b/netease_api/module/dj_subscriber.js new file mode 100644 index 0000000..0760834 --- /dev/null +++ b/netease_api/module/dj_subscriber.js @@ -0,0 +1,16 @@ +// 电台详情 + +module.exports = (query, request) => { + const data = { + time: query.time || '-1', + id: query.id, + limit: query.limit || '20', + total: 'true', + } + return request('POST', `https://music.163.com/api/djradio/subscriber`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/dj_today_perfered.js b/netease_api/module/dj_today_perfered.js new file mode 100644 index 0000000..a4881c8 --- /dev/null +++ b/netease_api/module/dj_today_perfered.js @@ -0,0 +1,18 @@ +// 电台今日优选 + +module.exports = (query, request) => { + const data = { + page: query.page || 0, + } + return request( + 'POST', + `https://music.163.com/weapi/djradio/home/today/perfered`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/dj_toplist.js b/netease_api/module/dj_toplist.js new file mode 100644 index 0000000..cbe04d7 --- /dev/null +++ b/netease_api/module/dj_toplist.js @@ -0,0 +1,18 @@ +// 新晋电台榜/热门电台榜 +const typeMap = { + new: 0, + hot: 1, +} +module.exports = (query, request) => { + const data = { + limit: query.limit || 100, + offset: query.offset || 0, + type: typeMap[query.type || 'new'] || '0', //0为新晋,1为热门 + } + return request('POST', `https://music.163.com/api/djradio/toplist`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/dj_toplist_hours.js b/netease_api/module/dj_toplist_hours.js new file mode 100644 index 0000000..8c8b6a3 --- /dev/null +++ b/netease_api/module/dj_toplist_hours.js @@ -0,0 +1,14 @@ +// 电台24小时主播榜 + +module.exports = (query, request) => { + const data = { + limit: query.limit || 100, + // 不支持 offset + } + return request('POST', `https://music.163.com/api/dj/toplist/hours`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/dj_toplist_newcomer.js b/netease_api/module/dj_toplist_newcomer.js new file mode 100644 index 0000000..8f28511 --- /dev/null +++ b/netease_api/module/dj_toplist_newcomer.js @@ -0,0 +1,18 @@ +// 电台新人榜 +module.exports = (query, request) => { + const data = { + limit: query.limit || 100, + offset: query.offset || 0, + } + return request( + 'POST', + `https://music.163.com/api/dj/toplist/newcomer`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/dj_toplist_pay.js b/netease_api/module/dj_toplist_pay.js new file mode 100644 index 0000000..5e6caf3 --- /dev/null +++ b/netease_api/module/dj_toplist_pay.js @@ -0,0 +1,18 @@ +// 付费精品 +module.exports = (query, request) => { + const data = { + limit: query.limit || 100, + // 不支持 offset + } + return request( + 'POST', + `https://music.163.com/api/djradio/toplist/pay`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/dj_toplist_popular.js b/netease_api/module/dj_toplist_popular.js new file mode 100644 index 0000000..fcb0b33 --- /dev/null +++ b/netease_api/module/dj_toplist_popular.js @@ -0,0 +1,14 @@ +// 电台最热主播榜 + +module.exports = (query, request) => { + const data = { + limit: query.limit || 100, + // 不支持 offset + } + return request('POST', `https://music.163.com/api/dj/toplist/popular`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/event.js b/netease_api/module/event.js new file mode 100644 index 0000000..b975ab7 --- /dev/null +++ b/netease_api/module/event.js @@ -0,0 +1,14 @@ +// 动态 + +module.exports = (query, request) => { + const data = { + pagesize: query.pagesize || 20, + lasttime: query.lasttime || -1, + } + return request('POST', `https://music.163.com/weapi/v1/event/get`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/event_del.js b/netease_api/module/event_del.js new file mode 100644 index 0000000..8f17ebe --- /dev/null +++ b/netease_api/module/event_del.js @@ -0,0 +1,13 @@ +// 删除动态 + +module.exports = (query, request) => { + const data = { + id: query.evId, + } + return request('POST', `https://music.163.com/eapi/event/delete`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/event_forward.js b/netease_api/module/event_forward.js new file mode 100644 index 0000000..f4eddc4 --- /dev/null +++ b/netease_api/module/event_forward.js @@ -0,0 +1,16 @@ +// 转发动态 + +module.exports = (query, request) => { + query.cookie.os = 'pc' + const data = { + forwards: query.forwards, + id: query.evId, + eventUserId: query.uid, + } + return request('POST', `https://music.163.com/weapi/event/forward`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/fm_trash.js b/netease_api/module/fm_trash.js new file mode 100644 index 0000000..a2019d7 --- /dev/null +++ b/netease_api/module/fm_trash.js @@ -0,0 +1,20 @@ +// 垃圾桶 + +module.exports = (query, request) => { + const data = { + songId: query.id, + } + return request( + 'POST', + `https://music.163.com/weapi/radio/trash/add?alg=RT&songId=${ + query.id + }&time=${query.time || 25}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/follow.js b/netease_api/module/follow.js new file mode 100644 index 0000000..d14acf0 --- /dev/null +++ b/netease_api/module/follow.js @@ -0,0 +1,17 @@ +// 关注与取消关注用户 + +module.exports = (query, request) => { + query.cookie.os = 'pc' + query.t = query.t == 1 ? 'follow' : 'delfollow' + return request( + 'POST', + `https://music.163.com/weapi/user/${query.t}/${query.id}`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/history_recommend_songs.js b/netease_api/module/history_recommend_songs.js new file mode 100644 index 0000000..de282c0 --- /dev/null +++ b/netease_api/module/history_recommend_songs.js @@ -0,0 +1,17 @@ +// 历史每日推荐歌曲 + +module.exports = (query, request) => { + query.cookie.os = 'ios' + const data = {} + return request( + 'POST', + `https://music.163.com/api/discovery/recommend/songs/history/recent`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/history_recommend_songs_detail.js b/netease_api/module/history_recommend_songs_detail.js new file mode 100644 index 0000000..d98c869 --- /dev/null +++ b/netease_api/module/history_recommend_songs_detail.js @@ -0,0 +1,19 @@ +// 历史每日推荐歌曲详情 + +module.exports = (query, request) => { + query.cookie.os = 'ios' + const data = { + date: query.date || '', + } + return request( + 'POST', + `https://music.163.com/api/discovery/recommend/songs/history/detail`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/homepage_block_page.js b/netease_api/module/homepage_block_page.js new file mode 100644 index 0000000..618e534 --- /dev/null +++ b/netease_api/module/homepage_block_page.js @@ -0,0 +1,19 @@ +// 首页-发现 block page +// 这个接口为移动端接口,首页-发现页,数据结构可以参考 https://github.com/hcanyz/flutter-netease-music-api/blob/master/lib/src/api/uncategorized/bean.dart#L259 HomeBlockPageWrap +// query.refresh 是否刷新数据 +module.exports = (query, request) => { + query.cookie.os = 'ios' + query.cookie.appver = '8.1.20' + const data = { refresh: query.refresh || true } + return request( + 'POST', + `https://music.163.com/api/homepage/block/page`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/homepage_dragon_ball.js b/netease_api/module/homepage_dragon_ball.js new file mode 100644 index 0000000..76973aa --- /dev/null +++ b/netease_api/module/homepage_dragon_ball.js @@ -0,0 +1,27 @@ +// 首页-发现 dragon ball +// 这个接口为移动端接口,首页-发现页(每日推荐、歌单、排行榜 那些入口) +// 数据结构可以参考 https://github.com/hcanyz/flutter-netease-music-api/blob/master/lib/src/api/uncategorized/bean.dart#L290 HomeDragonBallWrap +// !需要登录或者匿名登录,非登录返回 [] +const config = require('../util/config.json') +module.exports = (query, request) => { + if (typeof query.cookie === 'string') { + query.cookie = cookieToJson(query.cookie) + } + if (!('MUSIC_U' in query.cookie)) + query.cookie.MUSIC_A = config.anonymous_token + const data = {} + query.cookie.os = 'ios' + query.cookie.appver = '8.1.20' + return request( + 'POST', + `https://music.163.com/eapi/homepage/dragon/ball/static`, + data, + { + crypto: 'eapi', + cookie: query.cookie, + proxy: query.proxy, + url: '/api/homepage/dragon/ball/static', + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/hot_topic.js b/netease_api/module/hot_topic.js new file mode 100644 index 0000000..f901492 --- /dev/null +++ b/netease_api/module/hot_topic.js @@ -0,0 +1,14 @@ +//热门话题 + +module.exports = (query, request) => { + const data = { + limit: query.limit || 20, + offset: query.offset || 0, + } + return request('POST', `https://music.163.com/api/act/hot`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/hug_comment.js b/netease_api/module/hug_comment.js new file mode 100644 index 0000000..ce44528 --- /dev/null +++ b/netease_api/module/hug_comment.js @@ -0,0 +1,23 @@ +const { resourceTypeMap } = require('../util/config.json') +module.exports = (query, request) => { + query.cookie.os = 'ios' + query.cookie.appver = '8.1.20' + query.type = resourceTypeMap[query.type || 0] + const threadId = query.type + query.sid + const data = { + targetUserId: query.uid, + commentId: query.cid, + threadId: threadId, + } + return request( + 'POST', + `https://music.163.com/api/v2/resource/comments/hug/listener`, + data, + { + crypto: 'api', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/like.js b/netease_api/module/like.js new file mode 100644 index 0000000..bd90591 --- /dev/null +++ b/netease_api/module/like.js @@ -0,0 +1,19 @@ +// 红心与取消红心歌曲 + +module.exports = (query, request) => { + query.cookie.os = 'pc' + query.cookie.appver = '2.7.1.198277' + query.like = query.like == 'false' ? false : true + const data = { + alg: 'itembased', + trackId: query.id, + like: query.like, + time: '3', + } + return request('POST', `https://music.163.com/api/radio/like`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/likelist.js b/netease_api/module/likelist.js new file mode 100644 index 0000000..abb4680 --- /dev/null +++ b/netease_api/module/likelist.js @@ -0,0 +1,13 @@ +// 喜欢的歌曲(无序) + +module.exports = (query, request) => { + const data = { + uid: query.uid, + } + return request('POST', `https://music.163.com/weapi/song/like/get`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/login.js b/netease_api/module/login.js new file mode 100644 index 0000000..44787ce --- /dev/null +++ b/netease_api/module/login.js @@ -0,0 +1,47 @@ +// 邮箱登录 + +const crypto = require('crypto') + +module.exports = async (query, request) => { + query.cookie.os = 'pc' + const data = { + username: query.email, + password: + query.md5_password || + crypto.createHash('md5').update(query.password).digest('hex'), + rememberLogin: 'true', + } + let result = await request( + 'POST', + `https://music.163.com/weapi/login`, + data, + { + crypto: 'weapi', + ua: 'pc', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) + if (result.body.code === 502) { + return { + status: 200, + body: { + msg: '账号或密码错误', + code: 502, + message: '账号或密码错误', + }, + } + } + if (result.body.code === 200) { + result = { + status: 200, + body: { + ...result.body, + cookie: result.cookie.join(';'), + }, + cookie: result.cookie, + } + } + return result +} diff --git a/netease_api/module/login_cellphone.js b/netease_api/module/login_cellphone.js new file mode 100644 index 0000000..0d2e7ae --- /dev/null +++ b/netease_api/module/login_cellphone.js @@ -0,0 +1,39 @@ +// 手机登录 + +const crypto = require('crypto') + +module.exports = async (query, request) => { + query.cookie.os = 'pc' + const data = { + phone: query.phone, + countrycode: query.countrycode || '86', + password: + query.md5_password || + crypto.createHash('md5').update(query.password).digest('hex'), + rememberLogin: 'true', + } + let result = await request( + 'POST', + `https://music.163.com/weapi/login/cellphone`, + data, + { + crypto: 'weapi', + ua: 'pc', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) + + if (result.body.code === 200) { + result = { + status: 200, + body: { + ...result.body, + cookie: result.cookie.join(';'), + }, + cookie: result.cookie, + } + } + return result +} diff --git a/netease_api/module/login_qr_check.js b/netease_api/module/login_qr_check.js new file mode 100644 index 0000000..9c396e2 --- /dev/null +++ b/netease_api/module/login_qr_check.js @@ -0,0 +1,34 @@ +module.exports = async (query, request) => { + const data = { + key: query.key, + type: 1, + } + try { + let result = await request( + 'POST', + `https://music.163.com/weapi/login/qrcode/client/login`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) + result = { + status: 200, + body: { + ...result.body, + cookie: result.cookie.join(';'), + }, + cookie: result.cookie, + } + return result + } catch (error) { + return { + status: 200, + body: {}, + cookie: result.cookie, + } + } +} diff --git a/netease_api/module/login_qr_create.js b/netease_api/module/login_qr_create.js new file mode 100644 index 0000000..aeb6943 --- /dev/null +++ b/netease_api/module/login_qr_create.js @@ -0,0 +1,18 @@ +const QRCode = require('qrcode') + +module.exports = (query, request) => { + return new Promise(async (resolve) => { + const url = `https://music.163.com/login?codekey=${query.key}` + return resolve({ + code: 200, + status: 200, + body: { + code: 200, + data: { + qrurl: url, + qrimg: query.qrimg ? await QRCode.toDataURL(url) : '', + }, + }, + }) + }) +} diff --git a/netease_api/module/login_qr_key.js b/netease_api/module/login_qr_key.js new file mode 100644 index 0000000..bbee4be --- /dev/null +++ b/netease_api/module/login_qr_key.js @@ -0,0 +1,24 @@ +module.exports = async (query, request) => { + const data = { + type: 1, + } + const result = await request( + 'POST', + `https://music.163.com/weapi/login/qrcode/unikey`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) + return { + status: 200, + body: { + data: result.body, + code: 200, + }, + cookie: result.cookie, + } +} diff --git a/netease_api/module/login_refresh.js b/netease_api/module/login_refresh.js new file mode 100644 index 0000000..ac2b6a6 --- /dev/null +++ b/netease_api/module/login_refresh.js @@ -0,0 +1,16 @@ +// 登录刷新 + +module.exports = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/login/token/refresh`, + {}, + { + crypto: 'weapi', + ua: 'pc', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/login_status.js b/netease_api/module/login_status.js new file mode 100644 index 0000000..23286bc --- /dev/null +++ b/netease_api/module/login_status.js @@ -0,0 +1,26 @@ +module.exports = async (query, request) => { + const data = {} + let result = await request( + 'POST', + `https://music.163.com/weapi/w/nuser/account/get`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) + if (result.body.code === 200) { + result = { + status: 200, + body: { + data: { + ...result.body, + }, + }, + cookie: result.cookie, + } + } + return result +} diff --git a/netease_api/module/logout.js b/netease_api/module/logout.js new file mode 100644 index 0000000..a92ce47 --- /dev/null +++ b/netease_api/module/logout.js @@ -0,0 +1,16 @@ +// 退出登录 + +module.exports = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/logout`, + {}, + { + crypto: 'weapi', + ua: 'pc', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/lyric.js b/netease_api/module/lyric.js new file mode 100644 index 0000000..c3e8721 --- /dev/null +++ b/netease_api/module/lyric.js @@ -0,0 +1,17 @@ +// 歌词 + +module.exports = (query, request) => { + query.cookie.os = 'pc' + const data = { + id: query.id, + lv: -1, + kv: -1, + tv: -1, + } + return request('POST', `https://music.163.com/api/song/lyric`, data, { + crypto: 'api', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/msg_comments.js b/netease_api/module/msg_comments.js new file mode 100644 index 0000000..76bab8f --- /dev/null +++ b/netease_api/module/msg_comments.js @@ -0,0 +1,22 @@ +// 评论 + +module.exports = (query, request) => { + const data = { + beforeTime: query.before || '-1', + limit: query.limit || 30, + total: 'true', + uid: query.uid, + } + + return request( + 'POST', + `https://music.163.com/api/v1/user/comments/${query.uid}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/msg_forwards.js b/netease_api/module/msg_forwards.js new file mode 100644 index 0000000..f89dc98 --- /dev/null +++ b/netease_api/module/msg_forwards.js @@ -0,0 +1,15 @@ +// @我 + +module.exports = (query, request) => { + const data = { + offset: query.offset || 0, + limit: query.limit || 30, + total: 'true', + } + return request('POST', `https://music.163.com/api/forwards/get`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/msg_notices.js b/netease_api/module/msg_notices.js new file mode 100644 index 0000000..9208168 --- /dev/null +++ b/netease_api/module/msg_notices.js @@ -0,0 +1,14 @@ +// 通知 + +module.exports = (query, request) => { + const data = { + limit: query.limit || 30, + time: query.lasttime || -1, + } + return request('POST', `https://music.163.com/api/msg/notices`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/msg_private.js b/netease_api/module/msg_private.js new file mode 100644 index 0000000..a30751c --- /dev/null +++ b/netease_api/module/msg_private.js @@ -0,0 +1,15 @@ +// 私信 + +module.exports = (query, request) => { + const data = { + offset: query.offset || 0, + limit: query.limit || 30, + total: 'true', + } + return request('POST', `https://music.163.com/api/msg/private/users`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/msg_private_history.js b/netease_api/module/msg_private_history.js new file mode 100644 index 0000000..0a83b02 --- /dev/null +++ b/netease_api/module/msg_private_history.js @@ -0,0 +1,21 @@ +// 私信内容 + +module.exports = (query, request) => { + const data = { + userId: query.uid, + limit: query.limit || 30, + time: query.before || 0, + total: 'true', + } + return request( + 'POST', + `https://music.163.com/api/msg/private/history`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/msg_recentcontact.js b/netease_api/module/msg_recentcontact.js new file mode 100644 index 0000000..cb17c3a --- /dev/null +++ b/netease_api/module/msg_recentcontact.js @@ -0,0 +1,16 @@ +// 最近联系 + +module.exports = (query, request) => { + const data = {} + return request( + 'POST', + `https://music.163.com/api/msg/recentcontact/get`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/mv_all.js b/netease_api/module/mv_all.js new file mode 100644 index 0000000..85c1c46 --- /dev/null +++ b/netease_api/module/mv_all.js @@ -0,0 +1,20 @@ +// 全部MV + +module.exports = (query, request) => { + const data = { + tags: JSON.stringify({ + 地区: query.area || '全部', + 类型: query.type || '全部', + 排序: query.order || '上升最快', + }), + offset: query.offset || 0, + total: 'true', + limit: query.limit || 30, + } + return request('POST', `https://interface.music.163.com/api/mv/all`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/mv_detail.js b/netease_api/module/mv_detail.js new file mode 100644 index 0000000..e1b0152 --- /dev/null +++ b/netease_api/module/mv_detail.js @@ -0,0 +1,13 @@ +// MV详情 + +module.exports = (query, request) => { + const data = { + id: query.mvid, + } + return request('POST', `https://music.163.com/api/v1/mv/detail`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/mv_detail_info.js b/netease_api/module/mv_detail_info.js new file mode 100644 index 0000000..b758a46 --- /dev/null +++ b/netease_api/module/mv_detail_info.js @@ -0,0 +1,19 @@ +// MV 点赞转发评论数数据 + +module.exports = (query, request) => { + const data = { + threadid: `R_MV_5_${query.mvid}`, + 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/mv_exclusive_rcmd.js b/netease_api/module/mv_exclusive_rcmd.js new file mode 100644 index 0000000..aee8b2d --- /dev/null +++ b/netease_api/module/mv_exclusive_rcmd.js @@ -0,0 +1,19 @@ +// 网易出品 + +module.exports = (query, request) => { + const data = { + offset: query.offset || 0, + limit: query.limit || 30, + } + return request( + 'POST', + `https://interface.music.163.com/api/mv/exclusive/rcmd`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/mv_first.js b/netease_api/module/mv_first.js new file mode 100644 index 0000000..ae61ad9 --- /dev/null +++ b/netease_api/module/mv_first.js @@ -0,0 +1,21 @@ +// 最新MV + +module.exports = (query, request) => { + const data = { + // 'offset': query.offset || 0, + area: query.area || '', + limit: query.limit || 30, + total: true, + } + return request( + 'POST', + `https://interface.music.163.com/weapi/mv/first`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/mv_sub.js b/netease_api/module/mv_sub.js new file mode 100644 index 0000000..249998e --- /dev/null +++ b/netease_api/module/mv_sub.js @@ -0,0 +1,15 @@ +// 收藏与取消收藏MV + +module.exports = (query, request) => { + query.t = query.t == 1 ? 'sub' : 'unsub' + const data = { + mvId: query.mvid, + mvIds: '["' + query.mvid + '"]', + } + return request('POST', `https://music.163.com/weapi/mv/${query.t}`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/mv_sublist.js b/netease_api/module/mv_sublist.js new file mode 100644 index 0000000..2118c41 --- /dev/null +++ b/netease_api/module/mv_sublist.js @@ -0,0 +1,20 @@ +// 已收藏MV列表 + +module.exports = (query, request) => { + const data = { + limit: query.limit || 25, + offset: query.offset || 0, + total: true, + } + return request( + 'POST', + `https://music.163.com/weapi/cloudvideo/allvideo/sublist`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/mv_url.js b/netease_api/module/mv_url.js new file mode 100644 index 0000000..1b8c518 --- /dev/null +++ b/netease_api/module/mv_url.js @@ -0,0 +1,19 @@ +// MV链接 + +module.exports = (query, request) => { + const data = { + id: query.id, + r: query.r || 1080, + } + return request( + 'POST', + `https://music.163.com/weapi/song/enhance/play/mv/url`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/personal_fm.js b/netease_api/module/personal_fm.js new file mode 100644 index 0000000..72ee1fb --- /dev/null +++ b/netease_api/module/personal_fm.js @@ -0,0 +1,15 @@ +// 私人FM + +module.exports = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/v1/radio/get`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/personalized.js b/netease_api/module/personalized.js new file mode 100644 index 0000000..38a44ca --- /dev/null +++ b/netease_api/module/personalized.js @@ -0,0 +1,21 @@ +// 推荐歌单 + +module.exports = (query, request) => { + const data = { + limit: query.limit || 30, + // offset: query.offset || 0, + total: true, + n: 1000, + } + return request( + 'POST', + `https://music.163.com/weapi/personalized/playlist`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/personalized_djprogram.js b/netease_api/module/personalized_djprogram.js new file mode 100644 index 0000000..aa31dd3 --- /dev/null +++ b/netease_api/module/personalized_djprogram.js @@ -0,0 +1,15 @@ +// 推荐电台 + +module.exports = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/personalized/djprogram`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/personalized_mv.js b/netease_api/module/personalized_mv.js new file mode 100644 index 0000000..362c9b3 --- /dev/null +++ b/netease_api/module/personalized_mv.js @@ -0,0 +1,15 @@ +// 推荐MV + +module.exports = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/personalized/mv`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/personalized_newsong.js b/netease_api/module/personalized_newsong.js new file mode 100644 index 0000000..283b92a --- /dev/null +++ b/netease_api/module/personalized_newsong.js @@ -0,0 +1,20 @@ +// 推荐新歌 + +module.exports = (query, request) => { + const data = { + type: 'recommend', + limit: query.limit || 10, + areaId: query.areaId || 0, + } + return request( + 'POST', + `https://music.163.com/weapi/personalized/newsong`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/personalized_privatecontent.js b/netease_api/module/personalized_privatecontent.js new file mode 100644 index 0000000..5633738 --- /dev/null +++ b/netease_api/module/personalized_privatecontent.js @@ -0,0 +1,15 @@ +// 独家放送 + +module.exports = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/personalized/privatecontent`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/personalized_privatecontent_list.js b/netease_api/module/personalized_privatecontent_list.js new file mode 100644 index 0000000..f9ff49e --- /dev/null +++ b/netease_api/module/personalized_privatecontent_list.js @@ -0,0 +1,20 @@ +// 独家放送列表 + +module.exports = (query, request) => { + const data = { + offset: query.offset || 0, + total: 'true', + limit: query.limit || 60, + } + return request( + 'POST', + `https://music.163.com/api/v2/privatecontent/list`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/playlist_catlist.js b/netease_api/module/playlist_catlist.js new file mode 100644 index 0000000..9b148f6 --- /dev/null +++ b/netease_api/module/playlist_catlist.js @@ -0,0 +1,15 @@ +// 全部歌单分类 + +module.exports = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/playlist/catalogue`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/playlist_cover_update.js b/netease_api/module/playlist_cover_update.js new file mode 100644 index 0000000..957b9cc --- /dev/null +++ b/netease_api/module/playlist_cover_update.js @@ -0,0 +1,28 @@ +const uploadPlugin = require('../plugins/upload') +module.exports = async (query, request) => { + const uploadInfo = await uploadPlugin(query, request) + const res = await request( + 'POST', + `https://music.163.com/weapi/playlist/cover/update`, + { + id: query.id, + coverImgId: uploadInfo.imgId, + }, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) + return { + status: 200, + body: { + code: 200, + data: { + ...uploadInfo, + ...res.body, + }, + }, + } +} diff --git a/netease_api/module/playlist_create.js b/netease_api/module/playlist_create.js new file mode 100644 index 0000000..8a1ae26 --- /dev/null +++ b/netease_api/module/playlist_create.js @@ -0,0 +1,16 @@ +// 创建歌单 + +module.exports = (query, request) => { + query.cookie.os = 'pc' + const data = { + name: query.name, + privacy: query.privacy, //0 为普通歌单,10 为隐私歌单 + type: query.type || 'NORMAL', // NORMAL|VIDEO + } + return request('POST', `https://music.163.com/api/playlist/create`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/playlist_delete.js b/netease_api/module/playlist_delete.js new file mode 100644 index 0000000..d388a0e --- /dev/null +++ b/netease_api/module/playlist_delete.js @@ -0,0 +1,14 @@ +// 删除歌单 + +module.exports = (query, request) => { + query.cookie.os = 'pc' + const data = { + ids: '[' + query.id + ']', + } + return request('POST', `https://music.163.com/weapi/playlist/remove`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/playlist_desc_update.js b/netease_api/module/playlist_desc_update.js new file mode 100644 index 0000000..bebd9bb --- /dev/null +++ b/netease_api/module/playlist_desc_update.js @@ -0,0 +1,20 @@ +// 更新歌单描述 + +module.exports = (query, request) => { + const data = { + id: query.id, + desc: query.desc, + } + return request( + 'POST', + `https://interface3.music.163.com/eapi/playlist/desc/update`, + data, + { + crypto: 'eapi', + cookie: query.cookie, + proxy: query.proxy, + url: '/api/playlist/desc/update', + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/playlist_detail.js b/netease_api/module/playlist_detail.js new file mode 100644 index 0000000..39718f7 --- /dev/null +++ b/netease_api/module/playlist_detail.js @@ -0,0 +1,15 @@ +// 歌单详情 + +module.exports = (query, request) => { + const data = { + id: query.id, + n: 100000, + s: query.s || 8, + } + return request('POST', `https://music.163.com/api/v6/playlist/detail`, data, { + crypto: 'api', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/playlist_detail_dynamic.js b/netease_api/module/playlist_detail_dynamic.js new file mode 100644 index 0000000..e3362d2 --- /dev/null +++ b/netease_api/module/playlist_detail_dynamic.js @@ -0,0 +1,20 @@ +// 初始化名字 + +module.exports = (query, request) => { + const data = { + id: query.id, + n: 100000, + s: query.s || 8, + } + return request( + 'POST', + `https://music.163.com/api/playlist/detail/dynamic`, + data, + { + crypto: 'api', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/playlist_highquality_tags.js b/netease_api/module/playlist_highquality_tags.js new file mode 100644 index 0000000..0848c52 --- /dev/null +++ b/netease_api/module/playlist_highquality_tags.js @@ -0,0 +1,15 @@ +// 精品歌单 tags +module.exports = (query, request) => { + const data = {} + return request( + 'POST', + `https://music.163.com/api/playlist/highquality/tags`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/playlist_hot.js b/netease_api/module/playlist_hot.js new file mode 100644 index 0000000..6c085e4 --- /dev/null +++ b/netease_api/module/playlist_hot.js @@ -0,0 +1,15 @@ +// 热门歌单分类 + +module.exports = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/playlist/hottags`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/playlist_mylike.js b/netease_api/module/playlist_mylike.js new file mode 100644 index 0000000..779b507 --- /dev/null +++ b/netease_api/module/playlist_mylike.js @@ -0,0 +1,17 @@ +module.exports = (query, request) => { + const data = { + time: query.time || '-1', + limit: query.limit || '12', + } + return request( + 'POST', + `https://music.163.com/api/mlog/playlist/mylike/bytime/get`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/playlist_name_update.js b/netease_api/module/playlist_name_update.js new file mode 100644 index 0000000..ae53946 --- /dev/null +++ b/netease_api/module/playlist_name_update.js @@ -0,0 +1,20 @@ +// 更新歌单名 + +module.exports = (query, request) => { + const data = { + id: query.id, + name: query.name, + } + return request( + 'POST', + `https://interface3.music.163.com/eapi/playlist/update/name`, + data, + { + crypto: 'eapi', + cookie: query.cookie, + proxy: query.proxy, + url: '/api/playlist/update/name', + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/playlist_order_update.js b/netease_api/module/playlist_order_update.js new file mode 100644 index 0000000..268c6ea --- /dev/null +++ b/netease_api/module/playlist_order_update.js @@ -0,0 +1,19 @@ +// 编辑歌单顺序 + +module.exports = (query, request) => { + query.cookie.os = 'pc' + const data = { + ids: query.ids, + } + return request( + 'POST', + `https://music.163.com/api/playlist/order/update`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/playlist_subscribe.js b/netease_api/module/playlist_subscribe.js new file mode 100644 index 0000000..e0cce16 --- /dev/null +++ b/netease_api/module/playlist_subscribe.js @@ -0,0 +1,19 @@ +// 收藏与取消收藏歌单 + +module.exports = (query, request) => { + query.t = query.t == 1 ? 'subscribe' : 'unsubscribe' + const data = { + id: query.id, + } + return request( + 'POST', + `https://music.163.com/weapi/playlist/${query.t}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/playlist_subscribers.js b/netease_api/module/playlist_subscribers.js new file mode 100644 index 0000000..04260cb --- /dev/null +++ b/netease_api/module/playlist_subscribers.js @@ -0,0 +1,20 @@ +// 歌单收藏者 + +module.exports = (query, request) => { + const data = { + id: query.id, + limit: query.limit || 20, + offset: query.offset || 0, + } + return request( + 'POST', + `https://music.163.com/weapi/playlist/subscribers`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/playlist_tags_update.js b/netease_api/module/playlist_tags_update.js new file mode 100644 index 0000000..44de8c6 --- /dev/null +++ b/netease_api/module/playlist_tags_update.js @@ -0,0 +1,20 @@ +// 更新歌单标签 + +module.exports = (query, request) => { + const data = { + id: query.id, + tags: query.tags, + } + return request( + 'POST', + `https://interface3.music.163.com/eapi/playlist/tags/update`, + data, + { + crypto: 'eapi', + cookie: query.cookie, + proxy: query.proxy, + url: '/api/playlist/tags/update', + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/playlist_track_add.js b/netease_api/module/playlist_track_add.js new file mode 100644 index 0000000..c2391f3 --- /dev/null +++ b/netease_api/module/playlist_track_add.js @@ -0,0 +1,20 @@ +module.exports = async (query, request) => { + query.cookie.os = 'pc' + query.ids = query.ids || '' + const data = { + id: query.pid, + tracks: JSON.stringify( + query.ids.split(',').map((item) => { + return { type: 3, id: item } + }), + ), + } + console.log(data) + + return request('POST', `https://music.163.com/api/playlist/track/add`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/playlist_track_delete.js b/netease_api/module/playlist_track_delete.js new file mode 100644 index 0000000..54ef409 --- /dev/null +++ b/netease_api/module/playlist_track_delete.js @@ -0,0 +1,26 @@ +// 收藏单曲到歌单 从歌单删除歌曲 + +module.exports = async (query, request) => { + query.cookie.os = 'pc' + query.ids = query.ids || '' + const data = { + id: query.id, + tracks: JSON.stringify( + query.ids.split(',').map((item) => { + return { type: 3, id: item } + }), + ), + } + + return request( + 'POST', + `https://music.163.com/api/playlist/track/delete`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/playlist_tracks.js b/netease_api/module/playlist_tracks.js new file mode 100644 index 0000000..be70c7c --- /dev/null +++ b/netease_api/module/playlist_tracks.js @@ -0,0 +1,56 @@ +// 收藏单曲到歌单 从歌单删除歌曲 + +module.exports = async (query, request) => { + query.cookie.os = 'pc' + const tracks = query.tracks.split(',') + const data = { + op: query.op, // del,add + pid: query.pid, // 歌单id + trackIds: JSON.stringify(tracks), // 歌曲id + imme: 'true', + } + + try { + const res = await request( + 'POST', + `https://music.163.com/api/playlist/manipulate/tracks`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) + return { + status: 200, + body: { + ...res, + }, + } + } catch (error) { + if (error.body.code === 512) { + return request( + 'POST', + `https://music.163.com/api/playlist/manipulate/tracks`, + { + op: query.op, // del,add + pid: query.pid, // 歌单id + trackIds: JSON.stringify([...tracks, ...tracks]), + imme: 'true', + }, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) + } else if (error.body.code === 521) { + return { + status: 200, + body: error.body, + } + } + } +} diff --git a/netease_api/module/playlist_update.js b/netease_api/module/playlist_update.js new file mode 100644 index 0000000..085d195 --- /dev/null +++ b/netease_api/module/playlist_update.js @@ -0,0 +1,18 @@ +// 编辑歌单 + +module.exports = (query, request) => { + query.cookie.os = 'pc' + query.desc = query.desc || '' + query.tags = query.tags || '' + const data = { + '/api/playlist/desc/update': `{"id":${query.id},"desc":"${query.desc}"}`, + '/api/playlist/tags/update': `{"id":${query.id},"tags":"${query.tags}"}`, + '/api/playlist/update/name': `{"id":${query.id},"name":"${query.name}"}`, + } + return request('POST', `https://music.163.com/weapi/batch`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/playlist_video_recent.js b/netease_api/module/playlist_video_recent.js new file mode 100644 index 0000000..1430211 --- /dev/null +++ b/netease_api/module/playlist_video_recent.js @@ -0,0 +1,14 @@ +module.exports = (query, request) => { + const data = {} + return request( + 'POST', + `https://music.163.com/api/playlist/video/recent`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/playmode_intelligence_list.js b/netease_api/module/playmode_intelligence_list.js new file mode 100644 index 0000000..81b61ba --- /dev/null +++ b/netease_api/module/playmode_intelligence_list.js @@ -0,0 +1,22 @@ +// 智能播放 + +module.exports = (query, request) => { + const data = { + songId: query.id, + type: 'fromPlayOne', + playlistId: query.pid, + startMusicId: query.sid || query.id, + count: query.count || 1, + } + return request( + 'POST', + `https://music.163.com/weapi/playmode/intelligence/list`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/program_recommend.js b/netease_api/module/program_recommend.js new file mode 100644 index 0000000..bd63e7a --- /dev/null +++ b/netease_api/module/program_recommend.js @@ -0,0 +1,20 @@ +// 推荐节目 + +module.exports = (query, request) => { + const data = { + cateId: query.type, + limit: query.limit || 10, + offset: query.offset || 0, + } + return request( + 'POST', + `https://music.163.com/weapi/program/recommend/v1`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/rebind.js b/netease_api/module/rebind.js new file mode 100644 index 0000000..053bcba --- /dev/null +++ b/netease_api/module/rebind.js @@ -0,0 +1,21 @@ +// 更换手机 + +module.exports = (query, request) => { + const data = { + captcha: query.captcha, + phone: query.phone, + oldcaptcha: query.oldcaptcha, + ctcode: query.ctcode || '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/recommend_resource.js b/netease_api/module/recommend_resource.js new file mode 100644 index 0000000..3465087 --- /dev/null +++ b/netease_api/module/recommend_resource.js @@ -0,0 +1,15 @@ +// 每日推荐歌单 + +module.exports = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/v1/discovery/recommend/resource`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/recommend_songs.js b/netease_api/module/recommend_songs.js new file mode 100644 index 0000000..f83481e --- /dev/null +++ b/netease_api/module/recommend_songs.js @@ -0,0 +1,17 @@ +// 每日推荐歌曲 + +module.exports = (query, request) => { + query.cookie.os = 'ios' + const data = {} + return request( + 'POST', + `https://music.163.com/api/v3/discovery/recommend/songs`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/register_cellphone.js b/netease_api/module/register_cellphone.js new file mode 100644 index 0000000..d03c51a --- /dev/null +++ b/netease_api/module/register_cellphone.js @@ -0,0 +1,19 @@ +// 注册账号 +const crypto = require('crypto') + +module.exports = (query, request) => { + query.cookie.os = 'pc' + const data = { + captcha: query.captcha, + phone: query.phone, + password: crypto.createHash('md5').update(query.password).digest('hex'), + nickname: query.nickname, + countrycode: query.countrycode || '86', + } + return request('POST', `https://music.163.com/api/register/cellphone`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) +} diff --git a/netease_api/module/related_allvideo.js b/netease_api/module/related_allvideo.js new file mode 100644 index 0000000..e75a8c4 --- /dev/null +++ b/netease_api/module/related_allvideo.js @@ -0,0 +1,19 @@ +// 相关视频 + +module.exports = (query, request) => { + const data = { + id: query.id, + type: /^\d+$/.test(query.id) ? 0 : 1, + } + return request( + 'POST', + `https://music.163.com/weapi/cloudvideo/v1/allvideo/rcmd`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ) +} diff --git a/netease_api/module/related_playlist.js b/netease_api/module/related_playlist.js new file mode 100644 index 0000000..6f64b3d --- /dev/null +++ b/netease_api/module/related_playlist.js @@ -0,0 +1,38 @@ +// 相关歌单 + +module.exports = (query, request) => { + return request( + 'GET', + `https://music.163.com/playlist?id=${query.id}`, + {}, + { + ua: 'pc', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ).then((response) => { + try { + const pattern = /
[\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..effef6b --- /dev/null +++ b/netease_api/module/simi_artist.js @@ -0,0 +1,23 @@ +// 相似歌手 +const config = require('../util/config.json') +module.exports = (query, request) => { + if (typeof query.cookie === 'string') { + query.cookie = cookieToJson(query.cookie) + } + 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..172b34c --- /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/weapi/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_url.js b/netease_api/module/song_url.js new file mode 100644 index 0000000..49b5ed7 --- /dev/null +++ b/netease_api/module/song_url.js @@ -0,0 +1,28 @@ +// 歌曲链接 + +const crypto = require('crypto') +const { cookieToJson } = require('../util/index') +module.exports = (query, request) => { + if (typeof query.cookie === 'string') { + query.cookie = cookieToJson(query.cookie) + } + 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_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/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_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..c5c85f3 --- /dev/null +++ b/netease_api/plugins/songUpload.js @@ -0,0 +1,39 @@ +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: '', + 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/ymusic/${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, + }) + } catch (error) { + console.log('error', 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..4f6de8e --- /dev/null +++ b/netease_api/routes/index.js @@ -0,0 +1,8812 @@ +const { cookieToJson } = require('../util/index'); +const crypto = require('crypto'); +const request = require('../util/request'); +module.exports = { + '/yunbei/today': (req, res) => { + 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, + ); + const yunbei_today = (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, + }, + ); + }; + yunbei_today(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/yunbei/tasks/todo': (req, res) => { + 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, + ); + const yunbei_tasks_todo = (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, + }, + ); + }; + yunbei_tasks_todo(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/yunbei/tasks': (req, res) => { + 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, + ); + const yunbei_tasks = (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, + }, + ); + }; + yunbei_tasks(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/yunbei/task/finish': (req, res) => { + 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, + ); + const yunbei_task_finish = (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, + }, + ); + }; + yunbei_task_finish(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/yunbei/sign': (req, res) => { + 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, + ); + const yunbei_sign = (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, + }, + ); + }; + yunbei_sign(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/yunbei/receipt': (req, res) => { + 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, + ); + const yunbei_receipt = (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, + }, + ); + }; + yunbei_receipt(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/yunbei/info': (req, res) => { + 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, + ); + const yunbei_info = (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, + }); + }; + yunbei_info(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/yunbei/expense': (req, res) => { + 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, + ); + const yunbei_expense = (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, + }, + ); + }; + yunbei_expense(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/yunbei': (req, res) => { + 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, + ); + const yunbei = (query, request) => { + const data = {}; + return request( + 'POST', + `https://music.163.com/api/point/signed/get`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + yunbei(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/weblog': (req, res) => { + 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, + ); + const weblog = (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, + }, + ); + }; + weblog(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/video/url': (req, res) => { + 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, + ); + const video_url = (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, + }, + ); + }; + video_url(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/video/timeline/recommend': (req, res) => { + 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, + ); + const video_timeline_recommend = (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, + }, + ); + }; + video_timeline_recommend(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/video/timeline/all': (req, res) => { + 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, + ); + const video_timeline_all = (query, request) => { + const data = { + groupId: 0, + offset: query.offset || 0, + need_preview_url: 'true', + total: true, + }; + return request( + 'POST', + `https://music.163.com/api/videotimeline/otherclient/get`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + video_timeline_all(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/video/sub': (req, res) => { + 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, + ); + const video_sub = (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, + }, + ); + }; + video_sub(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/video/group/list': (req, res) => { + 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, + ); + const video_group_list = (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, + }, + ); + }; + video_group_list(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/video/group': (req, res) => { + 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, + ); + const video_group = (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, + }, + ); + }; + video_group(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/video/detail/info': (req, res) => { + 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, + ); + const video_detail_info = (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, + }, + ); + }; + video_detail_info(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/video/detail': (req, res) => { + 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, + ); + const video_detail = (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, + }, + ); + }; + video_detail(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/video/category/list': (req, res) => { + 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, + ); + const video_category_list = (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, + }, + ); + }; + video_category_list(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/user/update': (req, res) => { + 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, + ); + const user_update = (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, + }, + ); + }; + user_update(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/user/subcount': (req, res) => { + 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, + ); + const user_subcount = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/subcount`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + user_subcount(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/user/replacephone': (req, res) => { + 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, + ); + const user_replacephone = (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, + }, + ); + }; + user_replacephone(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/user/record': (req, res) => { + 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, + ); + const user_record = (query, request) => { + const data = { uid: query.uid, type: query.type || 0 }; + return request( + 'POST', + `https://music.163.com/weapi/v1/play/record`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + user_record(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/user/playlist': (req, res) => { + 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, + ); + const user_playlist = (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, + }); + }; + user_playlist(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/user/level': (req, res) => { + 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, + ); + const user_level = (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, + }); + }; + user_level(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/user/follows': (req, res) => { + 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, + ); + const user_follows = (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, + }, + ); + }; + user_follows(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/user/followeds': (req, res) => { + 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, + ); + const user_followeds = (query, request) => { + const data = { + userId: query.uid, + time: query.lasttime || -1, + limit: query.limit || 30, + }; + 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, + }, + ); + }; + user_followeds(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/user/event': (req, res) => { + 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, + ); + const user_event = (query, request) => { + const data = { + getcounts: true, + time: query.lasttime || -1, + limit: query.limit || 30, + total: false, + }; + return request( + 'POST', + `https://music.163.com/weapi/event/get/${query.uid}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + user_event(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/user/dj': (req, res) => { + 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, + ); + const user_dj = (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, + }, + ); + }; + user_dj(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/user/detail': (req, res) => { + 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, + ); + const user_detail = (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, + }, + ); + }; + user_detail(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/user/cloud/detail': (req, res) => { + 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, + ); + const user_cloud_detail = (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, + }, + ); + }; + user_cloud_detail(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/user/cloud/del': (req, res) => { + 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, + ); + const user_cloud_del = (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, + }); + }; + user_cloud_del(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/user/cloud': (req, res) => { + 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, + ); + const user_cloud = (query, request) => { + const data = { limit: query.limit || 30, offset: query.offset || 0 }; + return request('POST', `https://music.163.com/weapi/v1/cloud/get`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }); + }; + user_cloud(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/user/binding': (req, res) => { + 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, + ); + const user_binding = (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, + }, + ); + }; + user_binding(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/user/audio': (req, res) => { + 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, + ); + const user_audio = (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, + }, + ); + }; + user_audio(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/user/account': (req, res) => { + 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, + ); + const user_account = (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, + }, + ); + }; + user_account(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/toplist/detail': (req, res) => { + 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, + ); + const toplist_detail = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/toplist/detail`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + toplist_detail(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/toplist/artist': (req, res) => { + 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, + ); + const toplist_artist = (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, + }, + ); + }; + toplist_artist(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/toplist': (req, res) => { + 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, + ); + const toplist = (query, request) => { + return request( + 'POST', + `https://music.163.com/api/toplist`, + {}, + { + crypto: 'linuxapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + toplist(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/top/song': (req, res) => { + 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, + ); + const top_song = (query, request) => { + const data = { areaId: query.type || 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, + }, + ); + }; + top_song(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/top/playlist/highquality': (req, res) => { + 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, + ); + const top_playlist_highquality = (query, request) => { + const data = { + cat: query.cat || '全部', + limit: query.limit || 50, + lasttime: query.before || 0, + 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, + }, + ); + }; + top_playlist_highquality(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/top/playlist': (req, res) => { + 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, + ); + const top_playlist = (query, request) => { + const data = { + cat: query.cat || '全部', + order: query.order || 'hot', + 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, + }, + ); + }; + top_playlist(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/top/mv': (req, res) => { + 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, + ); + const top_mv = (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, + }); + }; + top_mv(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/top/list': (req, res) => { + 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, + ); + const top_list = (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, + }, + ); + }; + top_list(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/top/artists': (req, res) => { + 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, + ); + const top_artists = (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, + }); + }; + top_artists(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/top/album': (req, res) => { + 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, + ); + const top_album = (query, request) => { + const date = new Date(); + const data = { + area: query.area || 'ALL', + 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, + }, + ); + }; + top_album(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/song/url': (req, res) => { + 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, + ); + const song_url = (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', + }, + ); + }; + song_url(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/song/order/update': (req, res) => { + 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, + ); + const song_order_update = (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, + }, + ); + }; + song_order_update(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/song/detail': (req, res) => { + 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, + ); + const song_detail = (query, request) => { + query.ids = query.ids.split(/\s*,\s*/); + const data = { + c: '[' + query.ids.map((id) => '{"id":' + id + '}').join(',') + ']', + ids: '[' + query.ids.join(',') + ']', + }; + return request( + 'POST', + `https://music.163.com/weapi/v3/song/detail`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + song_detail(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/simi/user': (req, res) => { + 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, + ); + const simi_user = (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, + }, + ); + }; + simi_user(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/simi/song': (req, res) => { + 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, + ); + const simi_song = (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, + }, + ); + }; + simi_song(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/simi/playlist': (req, res) => { + 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, + ); + const simi_playlist = (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, + }, + ); + }; + simi_playlist(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/simi/mv': (req, res) => { + 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, + ); + const simi_mv = (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, + }, + ); + }; + simi_mv(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/simi/artist': (req, res) => { + 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, + ); + const simi_artist = (query, request) => { + 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, + }, + ); + }; + simi_artist(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/share/resource': (req, res) => { + 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, + ); + const share_resource = (query, request) => { + const data = { + type: query.type || 'song', + 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, + }, + ); + }; + share_resource(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/setting': (req, res) => { + 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, + ); + const setting = (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, + }); + }; + setting(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/send/text': (req, res) => { + 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, + ); + const send_text = (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, + }, + ); + }; + send_text(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/send/playlist': (req, res) => { + 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, + ); + const send_playlist = (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, + }, + ); + }; + send_playlist(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/search/suggest': (req, res) => { + 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, + ); + const search_suggest = (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, + }, + ); + }; + search_suggest(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/search/multimatch': (req, res) => { + 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, + ); + const search_multimatch = (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, + }, + ); + }; + search_multimatch(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/search/hot/detail': (req, res) => { + 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, + ); + const search_hot_detail = (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, + }, + ); + }; + search_hot_detail(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/search/hot': (req, res) => { + 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, + ); + const search_hot = (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, + }); + }; + search_hot(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/search/default': (req, res) => { + 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, + ); + const search_default = (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, + }, + ); + }; + search_default(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/search': (req, res) => { + 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, + ); + const search = (query, request) => { + const data = { + s: query.keywords, + type: query.type || 1, + 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, + }); + }; + search(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/scrobble': (req, res) => { + 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, + ); + const scrobble = (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, + }, + ); + }; + scrobble(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/resource/like': (req, res) => { + 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, + ); + const resource_like = (query, request) => { + query.cookie.os = 'pc'; + query.t = query.t == 1 ? 'like' : 'unlike'; + query.type = { 1: 'R_MV_5_', 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, + }, + ); + }; + resource_like(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/related/allvideo': (req, res) => { + 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, + ); + const related_allvideo = (query, request) => { + const data = { id: query.id, type: /^\\d+$/.test(query.id) ? 0 : 1 }; + return request( + 'POST', + `https://music.163.com/weapi/cloudvideo/v1/allvideo/rcmd`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + related_allvideo(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/register/cellphone': (req, res) => { + 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, + ); + const register_cellphone = (query, request) => { + query.cookie.os = 'pc'; + const data = { + captcha: query.captcha, + phone: query.phone, + password: crypto.createHash('md5').update(query.password).digest('hex'), + nickname: query.nickname, + }; + return request( + 'POST', + `https://music.163.com/api/register/cellphone`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + register_cellphone(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/recommend/songs': (req, res) => { + 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, + ); + const recommend_songs = (query, request) => { + query.cookie.os = 'ios'; + const data = {}; + return request( + 'POST', + `https://music.163.com/api/v3/discovery/recommend/songs`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + recommend_songs(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/recommend/resource': (req, res) => { + 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, + ); + const recommend_resource = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/v1/discovery/recommend/resource`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + recommend_resource(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/rebind': (req, res) => { + 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, + ); + const rebind = (query, request) => { + const data = { + captcha: query.captcha, + phone: query.phone, + oldcaptcha: query.oldcaptcha, + ctcode: query.ctcode || '86', + }; + return request( + 'POST', + `https://music.163.com/api/user/replaceCellphone`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + rebind(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/program/recommend': (req, res) => { + 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, + ); + const program_recommend = (query, request) => { + const data = { + cateId: query.type, + limit: query.limit || 10, + offset: query.offset || 0, + }; + return request( + 'POST', + `https://music.163.com/weapi/program/recommend/v1`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + program_recommend(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/playmode/intelligence/list': (req, res) => { + 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, + ); + const playmode_intelligence_list = (query, request) => { + const data = { + songId: query.id, + type: 'fromPlayOne', + playlistId: query.pid, + startMusicId: query.sid || query.id, + count: query.count || 1, + }; + return request( + 'POST', + `https://music.163.com/weapi/playmode/intelligence/list`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + playmode_intelligence_list(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/playlist/video/recent': (req, res) => { + 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, + ); + const playlist_video_recent = (query, request) => { + const data = {}; + return request( + 'POST', + `https://music.163.com/api/playlist/video/recent`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + playlist_video_recent(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/playlist/update': (req, res) => { + 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, + ); + const playlist_update = (query, request) => { + query.cookie.os = 'pc'; + query.desc = query.desc || ''; + query.tags = query.tags || ''; + const data = { + '/api/playlist/desc/update': `{\"id\":${query.id},\"desc\":\"${query.desc}\"}`, + '/api/playlist/tags/update': `{\"id\":${query.id},\"tags\":\"${query.tags}\"}`, + '/api/playlist/update/name': `{\"id\":${query.id},\"name\":\"${query.name}\"}`, + }; + return request('POST', `https://music.163.com/weapi/batch`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }); + }; + playlist_update(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/playlist/tracks': (req, res) => { + 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, + ); + const playlist_tracks = async (query, request) => { + query.cookie.os = 'pc'; + const tracks = query.tracks.split(','); + const data = { + op: query.op, + pid: query.pid, + trackIds: JSON.stringify(tracks), + imme: 'true', + }; + try { + const res = await request( + 'POST', + `https://music.163.com/api/playlist/manipulate/tracks`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + return { status: 200, body: { ...res } }; + } catch (error) { + if (error.body.code === 512) { + return request( + 'POST', + `https://music.163.com/api/playlist/manipulate/tracks`, + { + op: query.op, + pid: query.pid, + trackIds: JSON.stringify([...tracks, ...tracks]), + imme: 'true', + }, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + } + } + }; + playlist_tracks(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/playlist/track/delete': (req, res) => { + 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, + ); + const playlist_track_delete = async (query, request) => { + query.cookie.os = 'pc'; + query.ids = query.ids || ''; + const data = { + id: query.id, + tracks: JSON.stringify( + query.ids.split(',').map((item) => { + return { type: 3, id: item }; + }), + ), + }; + return request( + 'POST', + `https://music.163.com/api/playlist/track/delete`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + playlist_track_delete(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/playlist/track/add': (req, res) => { + 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, + ); + const playlist_track_add = async (query, request) => { + query.cookie.os = 'pc'; + query.ids = query.ids || ''; + const data = { + id: query.pid, + tracks: JSON.stringify( + query.ids.split(',').map((item) => { + return { type: 3, id: item }; + }), + ), + }; + console.log(data); + return request( + 'POST', + `https://music.163.com/api/playlist/track/add`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + playlist_track_add(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/playlist/tags/update': (req, res) => { + 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, + ); + const playlist_tags_update = (query, request) => { + const data = { id: query.id, tags: query.tags }; + return request( + 'POST', + `https://interface3.music.163.com/eapi/playlist/tags/update`, + data, + { + crypto: 'eapi', + cookie: query.cookie, + proxy: query.proxy, + url: '/api/playlist/tags/update', + realIP: query.realIP, + }, + ); + }; + playlist_tags_update(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/playlist/subscribers': (req, res) => { + 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, + ); + const playlist_subscribers = (query, request) => { + const data = { + id: query.id, + limit: query.limit || 20, + offset: query.offset || 0, + }; + return request( + 'POST', + `https://music.163.com/weapi/playlist/subscribers`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + playlist_subscribers(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/playlist/subscribe': (req, res) => { + 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, + ); + const playlist_subscribe = (query, request) => { + query.t = query.t == 1 ? 'subscribe' : 'unsubscribe'; + const data = { id: query.id }; + return request( + 'POST', + `https://music.163.com/weapi/playlist/${query.t}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + playlist_subscribe(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/playlist/order/update': (req, res) => { + 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, + ); + const playlist_order_update = (query, request) => { + query.cookie.os = 'pc'; + const data = { ids: query.ids }; + return request( + 'POST', + `https://music.163.com/api/playlist/order/update`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + playlist_order_update(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/playlist/name/update': (req, res) => { + 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, + ); + const playlist_name_update = (query, request) => { + const data = { id: query.id, name: query.name }; + return request( + 'POST', + `https://interface3.music.163.com/eapi/playlist/update/name`, + data, + { + crypto: 'eapi', + cookie: query.cookie, + proxy: query.proxy, + url: '/api/playlist/update/name', + realIP: query.realIP, + }, + ); + }; + playlist_name_update(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/playlist/mylike': (req, res) => { + 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, + ); + const playlist_mylike = (query, request) => { + const data = { time: query.time || '-1', limit: query.limit || '12' }; + return request( + 'POST', + `https://music.163.com/api/mlog/playlist/mylike/bytime/get`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + playlist_mylike(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/playlist/hot': (req, res) => { + 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, + ); + const playlist_hot = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/playlist/hottags`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + playlist_hot(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/playlist/highquality/tags': (req, res) => { + 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, + ); + const playlist_highquality_tags = (query, request) => { + const data = {}; + return request( + 'POST', + `https://music.163.com/api/playlist/highquality/tags`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + playlist_highquality_tags(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/playlist/detail': (req, res) => { + 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, + ); + const playlist_detail = (query, request) => { + const data = { id: query.id, n: 100000, s: query.s || 8 }; + return request( + 'POST', + `https://music.163.com/api/v6/playlist/detail`, + data, + { + crypto: 'linuxapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + playlist_detail(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/playlist/desc/update': (req, res) => { + 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, + ); + const playlist_desc_update = (query, request) => { + const data = { id: query.id, desc: query.desc }; + return request( + 'POST', + `https://interface3.music.163.com/eapi/playlist/desc/update`, + data, + { + crypto: 'eapi', + cookie: query.cookie, + proxy: query.proxy, + url: '/api/playlist/desc/update', + realIP: query.realIP, + }, + ); + }; + playlist_desc_update(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/playlist/delete': (req, res) => { + 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, + ); + const playlist_delete = (query, request) => { + query.cookie.os = 'pc'; + const data = { ids: '[' + query.id + ']' }; + return request( + 'POST', + `https://music.163.com/weapi/playlist/remove`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + playlist_delete(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/playlist/create': (req, res) => { + 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, + ); + const playlist_create = (query, request) => { + query.cookie.os = 'pc'; + const data = { + name: query.name, + privacy: query.privacy, + type: query.type || 'NORMAL', + }; + return request( + 'POST', + `https://music.163.com/api/playlist/create`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + playlist_create(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/playlist/cover/update': (req, res) => { + 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, + ); + const playlist_cover_update = async (query, request) => { + const uploadInfo = await uploadPlugin(query, request); + const res = await request( + 'POST', + `https://music.163.com/weapi/playlist/cover/update`, + { id: query.id, coverImgId: uploadInfo.imgId }, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + return { + status: 200, + body: { code: 200, data: { ...uploadInfo, ...res.body } }, + }; + }; + playlist_cover_update(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/playlist/catlist': (req, res) => { + 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, + ); + const playlist_catlist = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/playlist/catalogue`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + playlist_catlist(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/personalized/privatecontent/list': (req, res) => { + 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, + ); + const personalized_privatecontent_list = (query, request) => { + const data = { + offset: query.offset || 0, + total: 'true', + limit: query.limit || 60, + }; + return request( + 'POST', + `https://music.163.com/api/v2/privatecontent/list`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + personalized_privatecontent_list(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/personalized/privatecontent': (req, res) => { + 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, + ); + const personalized_privatecontent = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/personalized/privatecontent`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + personalized_privatecontent(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/personalized/newsong': (req, res) => { + 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, + ); + const personalized_newsong = (query, request) => { + const data = { + type: 'recommend', + limit: query.limit || 10, + areaId: query.areaId || 0, + }; + return request( + 'POST', + `https://music.163.com/weapi/personalized/newsong`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + personalized_newsong(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/personalized/mv': (req, res) => { + 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, + ); + const personalized_mv = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/personalized/mv`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + personalized_mv(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/personalized/djprogram': (req, res) => { + 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, + ); + const personalized_djprogram = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/personalized/djprogram`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + personalized_djprogram(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/personalized': (req, res) => { + 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, + ); + const personalized = (query, request) => { + const data = { limit: query.limit || 30, total: true, n: 1000 }; + return request( + 'POST', + `https://music.163.com/weapi/personalized/playlist`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + personalized(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/personal_fm': (req, res) => { + 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, + ); + const personal_fm = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/v1/radio/get`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + personal_fm(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/mv/url': (req, res) => { + 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, + ); + const mv_url = (query, request) => { + const data = { id: query.id, r: query.r || 1080 }; + return request( + 'POST', + `https://music.163.com/weapi/song/enhance/play/mv/url`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + mv_url(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/mv/sublist': (req, res) => { + 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, + ); + const mv_sublist = (query, request) => { + const data = { + limit: query.limit || 25, + offset: query.offset || 0, + total: true, + }; + return request( + 'POST', + `https://music.163.com/weapi/cloudvideo/allvideo/sublist`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + mv_sublist(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/mv/sub': (req, res) => { + 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, + ); + const mv_sub = (query, request) => { + query.t = query.t == 1 ? 'sub' : 'unsub'; + const data = { mvId: query.mvid, mvIds: '["' + query.mvid + '"]' }; + return request( + 'POST', + `https://music.163.com/weapi/mv/${query.t}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + mv_sub(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/mv/first': (req, res) => { + 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, + ); + const mv_first = (query, request) => { + const data = { + area: query.area || '', + limit: query.limit || 30, + total: true, + }; + return request( + 'POST', + `https://interface.music.163.com/weapi/mv/first`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + mv_first(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/mv/exclusive/rcmd': (req, res) => { + 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, + ); + const mv_exclusive_rcmd = (query, request) => { + const data = { offset: query.offset || 0, limit: query.limit || 30 }; + return request( + 'POST', + `https://interface.music.163.com/api/mv/exclusive/rcmd`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + mv_exclusive_rcmd(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/mv/detail/info': (req, res) => { + 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, + ); + const mv_detail_info = (query, request) => { + const data = { threadid: `R_MV_5_${query.mvid}`, 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, + }, + ); + }; + mv_detail_info(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/mv/detail': (req, res) => { + 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, + ); + const mv_detail = (query, request) => { + const data = { id: query.mvid }; + return request('POST', `https://music.163.com/api/v1/mv/detail`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }); + }; + mv_detail(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/mv/all': (req, res) => { + 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, + ); + const mv_all = (query, request) => { + const data = { + tags: JSON.stringify({ + 地区: query.area || '全部', + 类型: query.type || '全部', + 排序: query.order || '上升最快', + }), + offset: query.offset || 0, + total: 'true', + limit: query.limit || 30, + }; + return request( + 'POST', + `https://interface.music.163.com/api/mv/all`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + mv_all(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/msg/private/history': (req, res) => { + 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, + ); + const msg_private_history = (query, request) => { + const data = { + userId: query.uid, + limit: query.limit || 30, + time: query.before || 0, + total: 'true', + }; + return request( + 'POST', + `https://music.163.com/api/msg/private/history`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + msg_private_history(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/msg/private': (req, res) => { + 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, + ); + const msg_private = (query, request) => { + const data = { + offset: query.offset || 0, + limit: query.limit || 30, + total: 'true', + }; + return request( + 'POST', + `https://music.163.com/api/msg/private/users`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + msg_private(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/msg/notices': (req, res) => { + 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, + ); + const msg_notices = (query, request) => { + const data = { limit: query.limit || 30, time: query.lasttime || -1 }; + return request('POST', `https://music.163.com/api/msg/notices`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }); + }; + msg_notices(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/msg/forwards': (req, res) => { + 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, + ); + const msg_forwards = (query, request) => { + const data = { + offset: query.offset || 0, + limit: query.limit || 30, + total: 'true', + }; + return request('POST', `https://music.163.com/api/forwards/get`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }); + }; + msg_forwards(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/msg/comments': (req, res) => { + 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, + ); + const msg_comments = (query, request) => { + const data = { + beforeTime: query.before || '-1', + limit: query.limit || 30, + total: 'true', + uid: query.uid, + }; + return request( + 'POST', + `https://music.163.com/api/v1/user/comments/${query.uid}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + msg_comments(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/lyric': (req, res) => { + 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, + ); + const lyric = (query, request) => { + query.cookie.os = 'pc'; + const data = { id: query.id, lv: -1, kv: -1, tv: -1 }; + return request('POST', `https://music.163.com/api/song/lyric`, data, { + crypto: 'linuxapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }); + }; + lyric(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/logout': (req, res) => { + 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, + ); + const logout = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/logout`, + {}, + { + crypto: 'weapi', + ua: 'pc', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + logout(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/login/status': (req, res) => { + 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, + ); + const login_status = (query, request) => { + return request( + 'GET', + `https://music.163.com`, + {}, + { cookie: query.cookie, proxy: query.proxy, realIP: query.realIP }, + ).then((response) => { + try { + let profile = eval( + `(${/GUser\\s*=\\s*([^;]+);/.exec(response.body)[1]})`, + ); + let bindings = eval( + `(${/GBinds\\s*=\\s*([^;]+);/.exec(response.body)[1]})`, + ); + response.body = { code: 200, profile: profile, bindings: bindings }; + return response; + } catch (err) { + response.status = 301; + response.body = { code: 301 }; + return Promise.reject(response); + } + }); + }; + login_status(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/login/refresh': (req, res) => { + 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, + ); + const login_refresh = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/login/token/refresh`, + {}, + { + crypto: 'weapi', + ua: 'pc', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + login_refresh(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/login/cellphone': (req, res) => { + 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, + ); + const login_cellphone = async (query, request) => { + query.cookie.os = 'pc'; + const data = { + phone: query.phone, + countrycode: query.countrycode || '86', + password: + query.md5_password || + crypto.createHash('md5').update(query.password).digest('hex'), + rememberLogin: 'true', + }; + let result = await request( + 'POST', + `https://music.163.com/weapi/login/cellphone`, + data, + { + crypto: 'weapi', + ua: 'pc', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + if (result.body.code === 200) { + result = { + status: 200, + body: { ...result.body, cookie: result.cookie.join(';') }, + cookie: result.cookie, + }; + } + return result; + }; + login_cellphone(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/login': (req, res) => { + 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, + ); + const login = async (query, request) => { + query.cookie.os = 'pc'; + const data = { + username: query.email, + password: + query.md5_password || + crypto.createHash('md5').update(query.password).digest('hex'), + rememberLogin: 'true', + }; + let result = await request( + 'POST', + `https://music.163.com/weapi/login`, + data, + { + crypto: 'weapi', + ua: 'pc', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + if (result.body.code === 502) { + return { + status: 200, + body: { msg: '账号或密码错误', code: 502, message: '账号或密码错误' }, + }; + } + if (result.body.code === 200) { + result = { + status: 200, + body: { ...result.body, cookie: result.cookie.join(';') }, + cookie: result.cookie, + }; + } + return result; + }; + login(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/likelist': (req, res) => { + 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, + ); + const likelist = (query, request) => { + const data = { uid: query.uid }; + return request( + 'POST', + `https://music.163.com/weapi/song/like/get`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + likelist(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/like': (req, res) => { + 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, + ); + const like = (query, request) => (query, request) => { + query.cookie.os = 'pc' + query.cookie.appver = '2.7.1.198277' + query.like = query.like == 'false' ? false : true + const data = { + alg: 'itembased', + trackId: query.id, + like: query.like, + time: '3', + } + return request('POST', `https://music.163.com/api/radio/like`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }) + } + + like(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/hot/topic': (req, res) => { + 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, + ); + const hot_topic = (query, request) => { + const data = { limit: query.limit || 20, offset: query.offset || 0 }; + return request('POST', `https://music.163.com/weapi/act/hot`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }); + }; + hot_topic(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/homepage/dragon/ball': (req, res) => { + 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, + ); + const homepage_dragon_ball = (query, request) => { + const data = {}; + return request( + 'POST', + `https://music.163.com/eapi/homepage/dragon/ball/static`, + data, + { + crypto: 'eapi', + cookie: query.cookie, + proxy: query.proxy, + url: '/api/homepage/dragon/ball/static', + realIP: query.realIP, + }, + ); + }; + homepage_dragon_ball(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/homepage/block/page': (req, res) => { + 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, + ); + const homepage_block_page = (query, request) => { + const data = { refresh: query.refresh || true }; + return request( + 'POST', + `https://music.163.com/api/homepage/block/page`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + homepage_block_page(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/history/recommend/songs/detail': (req, res) => { + 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, + ); + const history_recommend_songs_detail = (query, request) => { + query.cookie.os = 'ios'; + const data = { date: query.date || '' }; + return request( + 'POST', + `https://music.163.com/api/discovery/recommend/songs/history/detail`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + history_recommend_songs_detail(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/history/recommend/songs': (req, res) => { + 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, + ); + const history_recommend_songs = (query, request) => { + query.cookie.os = 'ios'; + const data = {}; + return request( + 'POST', + `https://music.163.com/api/discovery/recommend/songs/history/recent`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + history_recommend_songs(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/follow': (req, res) => { + 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, + ); + const follow = (query, request) => { + query.cookie.os = 'pc'; + query.t = query.t == 1 ? 'follow' : 'delfollow'; + return request( + 'POST', + `https://music.163.com/weapi/user/${query.t}/${query.id}`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + follow(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/fm_trash': (req, res) => { + 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, + ); + const fm_trash = (query, request) => { + const data = { songId: query.id }; + return request( + 'POST', + `https://music.163.com/weapi/radio/trash/add?alg=RT&songId=${ + query.id + }&time=${query.time || 25}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + fm_trash(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/event/forward': (req, res) => { + 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, + ); + const event_forward = (query, request) => { + query.cookie.os = 'pc'; + const data = { + forwards: query.forwards, + id: query.evId, + eventUserId: query.uid, + }; + return request( + 'POST', + `https://music.163.com/weapi/event/forward`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + event_forward(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/event/del': (req, res) => { + 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, + ); + const event_del = (query, request) => { + const data = { id: query.evId }; + return request('POST', `https://music.163.com/eapi/event/delete`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }); + }; + event_del(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/event': (req, res) => { + 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, + ); + const event = (query, request) => { + const data = { + pagesize: query.pagesize || 20, + lasttime: query.lasttime || -1, + }; + return request('POST', `https://music.163.com/weapi/v1/event/get`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }); + }; + event(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/toplist/popular': (req, res) => { + 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, + ); + const dj_toplist_popular = (query, request) => { + const data = { limit: query.limit || 100 }; + return request( + 'POST', + `https://music.163.com/api/dj/toplist/popular`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + dj_toplist_popular(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/toplist/pay': (req, res) => { + 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, + ); + const dj_toplist_pay = (query, request) => { + const data = { limit: query.limit || 100 }; + return request( + 'POST', + `https://music.163.com/api/djradio/toplist/pay`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + dj_toplist_pay(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/toplist/newcomer': (req, res) => { + 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, + ); + const dj_toplist_newcomer = (query, request) => { + const data = { limit: query.limit || 100, offset: query.offset || 0 }; + return request( + 'POST', + `https://music.163.com/api/dj/toplist/newcomer`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + dj_toplist_newcomer(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/toplist/hours': (req, res) => { + 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, + ); + const dj_toplist_hours = (query, request) => { + const data = { limit: query.limit || 100 }; + return request( + 'POST', + `https://music.163.com/api/dj/toplist/hours`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + dj_toplist_hours(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/toplist': (req, res) => { + 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, + ); + const dj_toplist = (query, request) => { + const data = { + limit: query.limit || 100, + offset: query.offset || 0, + type: typeMap[query.type || 'new'] || '0', + }; + return request( + 'POST', + `https://music.163.com/api/djradio/toplist`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + dj_toplist(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/today/perfered': (req, res) => { + 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, + ); + const dj_today_perfered = (query, request) => { + const data = { page: query.page || 0 }; + return request( + 'POST', + `https://music.163.com/weapi/djradio/home/today/perfered`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + dj_today_perfered(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/subscriber': (req, res) => { + 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, + ); + const dj_subscriber = (query, request) => { + const data = { + time: query.time || '-1', + id: query.id, + limit: query.limit || '20', + total: 'true', + }; + return request( + 'POST', + `https://music.163.com/api/djradio/subscriber`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + dj_subscriber(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/sublist': (req, res) => { + 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, + ); + const dj_sublist = (query, request) => { + const data = { + limit: query.limit || 30, + offset: query.offset || 0, + total: true, + }; + return request( + 'POST', + `https://music.163.com/weapi/djradio/get/subed`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + dj_sublist(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/sub': (req, res) => { + 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, + ); + const dj_sub = (query, request) => { + query.t = query.t == 1 ? 'sub' : 'unsub'; + const data = { id: query.rid }; + return request( + 'POST', + `https://music.163.com/weapi/djradio/${query.t}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + dj_sub(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/recommend/type': (req, res) => { + 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, + ); + const dj_recommend_type = (query, request) => { + const data = { cateId: query.type }; + return request( + 'POST', + `https://music.163.com/weapi/djradio/recommend`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + dj_recommend_type(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/recommend': (req, res) => { + 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, + ); + const dj_recommend = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/djradio/recommend/v1`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + dj_recommend(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/radio/hot': (req, res) => { + 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, + ); + const dj_radio_hot = (query, request) => { + const data = { + cateId: query.cateId, + limit: query.limit || 30, + offset: query.offset || 0, + }; + return request('POST', `https://music.163.com/api/djradio/hot`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }); + }; + dj_radio_hot(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/program/toplist/hours': (req, res) => { + 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, + ); + const dj_program_toplist_hours = (query, request) => { + const data = { limit: query.limit || 100 }; + return request( + 'POST', + `https://music.163.com/api/djprogram/toplist/hours`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + dj_program_toplist_hours(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/program/toplist': (req, res) => { + 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, + ); + const dj_program_toplist = (query, request) => { + const data = { limit: query.limit || 100, offset: query.offset || 0 }; + return request( + 'POST', + `https://music.163.com/api/program/toplist/v1`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + dj_program_toplist(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/program/detail': (req, res) => { + 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, + ); + const dj_program_detail = (query, request) => { + const data = { id: query.id }; + return request( + 'POST', + `https://music.163.com/api/dj/program/detail`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + dj_program_detail(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/program': (req, res) => { + 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, + ); + const dj_program = (query, request) => { + const data = { + radioId: query.rid, + limit: query.limit || 30, + offset: query.offset || 0, + asc: toBoolean(query.asc), + }; + return request( + 'POST', + `https://music.163.com/weapi/dj/program/byradio`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + dj_program(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/personalize/recommend': (req, res) => { + 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, + ); + const dj_personalize_recommend = (query, request) => { + return request( + 'POST', + `https://music.163.com/api/djradio/personalize/rcmd`, + { limit: query.limit || 6 }, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + dj_personalize_recommend(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/paygift': (req, res) => { + 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, + ); + const dj_paygift = (query, request) => { + const data = { limit: query.limit || 30, offset: query.offset || 0 }; + return request( + 'POST', + `https://music.163.com/weapi/djradio/home/paygift/list?_nmclfl=1`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + dj_paygift(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/hot': (req, res) => { + 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, + ); + const dj_hot = (query, request) => { + const data = { limit: query.limit || 30, offset: query.offset || 0 }; + return request( + 'POST', + `https://music.163.com/weapi/djradio/hot/v1`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + dj_hot(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/detail': (req, res) => { + 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, + ); + const dj_detail = (query, request) => { + const data = { id: query.rid }; + return request('POST', `https://music.163.com/api/djradio/v2/get`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }); + }; + dj_detail(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/catelist': (req, res) => { + 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, + ); + const dj_catelist = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/djradio/category/get`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + dj_catelist(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/category/recommend': (req, res) => { + 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, + ); + const dj_category_recommend = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/djradio/home/category/recommend`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + dj_category_recommend(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/category/excludehot': (req, res) => { + 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, + ); + const dj_category_excludehot = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/djradio/category/excludehot`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + dj_category_excludehot(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/dj/banner': (req, res) => { + 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, + ); + const dj_banner = (query, request) => { + const data = {}; + query.cookie.os = 'pc'; + return request( + 'POST', + `https://music.163.com/weapi/djradio/banner/get`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + dj_banner(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/digitalAlbum/purchased': (req, res) => { + 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, + ); + const digitalAlbum_purchased = (query, request) => { + const data = { + limit: query.limit || 30, + offset: query.offset || 0, + total: true, + }; + return request( + 'POST', + `https://music.163.com/api/digitalAlbum/purchased`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + digitalAlbum_purchased(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/digitalAlbum/ordering': (req, res) => { + 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, + ); + const digitalAlbum_ordering = (query, request) => { + const data = { + business: 'Album', + paymentMethod: query.payment, + digitalResources: JSON.stringify([ + { business: 'Album', resourceID: query.id, quantity: query.quantity }, + ]), + from: 'web', + }; + return request( + 'POST', + `https://music.163.com/api/ordering/web/digital`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + digitalAlbum_ordering(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/daily_signin': (req, res) => { + 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, + ); + const daily_signin = (query, request) => { + const data = { type: query.type || 0 }; + return request( + 'POST', + `https://music.163.com/weapi/point/dailyTask`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + daily_signin(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/countries/code/list': (req, res) => { + 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, + ); + const countries_code_list = (query, request) => { + const data = {}; + return request( + 'POST', + `https://interface3.music.163.com/eapi/lbs/countries/v1`, + data, + { + crypto: 'eapi', + cookie: query.cookie, + proxy: query.proxy, + url: '/api/lbs/countries/v1', + realIP: query.realIP, + }, + ); + }; + countries_code_list(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/comment/video': (req, res) => { + 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, + ); + const comment_video = (query, request) => { + query.cookie.os = 'pc'; + const data = { + rid: query.id, + limit: query.limit || 20, + offset: query.offset || 0, + beforeTime: query.before || 0, + }; + return request( + 'POST', + `https://music.163.com/weapi/v1/resource/comments/R_VI_62_${query.id}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + comment_video(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/comment/playlist': (req, res) => { + 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, + ); + const comment_playlist = (query, request) => { + query.cookie.os = 'pc'; + const data = { + rid: query.id, + limit: query.limit || 20, + offset: query.offset || 0, + beforeTime: query.before || 0, + }; + return request( + 'POST', + `https://music.163.com/weapi/v1/resource/comments/A_PL_0_${query.id}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + comment_playlist(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/comment/new': (req, res) => { + 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, + ); + const comment_new = (query, request) => { + query.cookie.os = 'pc'; + query.type = { + 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_', + }[query.type]; + const threadId = query.type + query.id; + const pageSize = query.pageSize || 20; + const pageNo = query.pageNo || 1; + const data = { + threadId: threadId, + pageNo, + showInner: query.showInner || true, + pageSize, + cursor: + +query.sortType === 3 ? query.cursor || '0' : (pageNo - 1) * pageSize, + sortType: query.sortType || 1, + }; + return request( + 'POST', + `https://music.163.com/api/v2/resource/comments`, + data, + { + crypto: 'eapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + url: '/api/v2/resource/comments', + }, + ); + }; + comment_new(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/comment/mv': (req, res) => { + 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, + ); + const comment_mv = (query, request) => { + query.cookie.os = 'pc'; + const data = { + rid: query.id, + limit: query.limit || 20, + offset: query.offset || 0, + beforeTime: query.before || 0, + }; + return request( + 'POST', + `https://music.163.com/weapi/v1/resource/comments/R_MV_5_${query.id}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + comment_mv(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/comment/music': (req, res) => { + 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, + ); + const comment_music = (query, request) => { + query.cookie.os = 'pc'; + const data = { + rid: query.id, + limit: query.limit || 20, + offset: query.offset || 0, + beforeTime: query.before || 0, + }; + return request( + 'POST', + `https://music.163.com/api/v1/resource/comments/R_SO_4_${query.id}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + comment_music(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/comment/like': (req, res) => { + 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, + ); + const comment_like = (query, request) => { + query.cookie.os = 'pc'; + query.t = query.t == 1 ? 'like' : 'unlike'; + query.type = { + 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_', + }[query.type]; + const data = { threadId: query.type + query.id, commentId: query.cid }; + if (query.type == 'A_EV_2_') { + data.threadId = query.threadId; + } + return request( + 'POST', + `https://music.163.com/weapi/v1/comment/${query.t}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + comment_like(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/comment/hotwall/list': (req, res) => { + 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, + ); + const comment_hotwall_list = (query, request) => { + const data = {}; + return request( + 'POST', + `https://music.163.com/api/comment/hotwall/list/get`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + comment_hotwall_list(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/comment/hot': (req, res) => { + 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, + ); + const comment_hot = (query, request) => { + query.cookie.os = 'pc'; + query.type = { + 0: 'R_SO_4_', + 1: 'R_MV_5_', + 2: 'A_PL_0_', + 3: 'R_AL_3_', + 4: 'A_DJ_1_', + 5: 'R_VI_62_', + }[query.type]; + const data = { + rid: query.id, + limit: query.limit || 20, + offset: query.offset || 0, + beforeTime: query.before || 0, + }; + return request( + 'POST', + `https://music.163.com/weapi/v1/resource/hotcomments/${query.type}${query.id}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + comment_hot(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/comment/floor': (req, res) => { + 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, + ); + const comment_floor = (query, request) => { + query.type = { + 0: 'R_SO_4_', + 1: 'R_MV_5_', + 2: 'A_PL_0_', + 3: 'R_AL_3_', + 4: 'A_DJ_1_', + 5: 'R_VI_62_', + }[query.type]; + const data = { + parentCommentId: query.parentCommentId, + threadId: query.type + query.id, + time: query.time || -1, + limit: query.limit || 20, + }; + return request( + 'POST', + `https://music.163.com/api/resource/comment/floor/get`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + comment_floor(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/comment/event': (req, res) => { + 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, + ); + const comment_event = (query, request) => { + const data = { + limit: query.limit || 20, + offset: query.offset || 0, + beforeTime: query.before || 0, + }; + return request( + 'POST', + `https://music.163.com/weapi/v1/resource/comments/${query.threadId}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + comment_event(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/comment/dj': (req, res) => { + 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, + ); + const comment_dj = (query, request) => { + query.cookie.os = 'pc'; + const data = { + rid: query.id, + limit: query.limit || 20, + offset: query.offset || 0, + beforeTime: query.before || 0, + }; + return request( + 'POST', + `https://music.163.com/weapi/v1/resource/comments/A_DJ_1_${query.id}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + comment_dj(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/comment/album': (req, res) => { + 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, + ); + const comment_album = (query, request) => { + query.cookie.os = 'pc'; + const data = { + rid: query.id, + limit: query.limit || 20, + offset: query.offset || 0, + beforeTime: query.before || 0, + }; + return request( + 'POST', + `https://music.163.com/weapi/v1/resource/comments/R_AL_3_${query.id}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + comment_album(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/comment': (req, res) => { + 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, + ); + const comment = (query, request) => { + query.cookie.os = 'pc'; + query.t = { 1: 'add', 0: 'delete', 2: 'reply' }[query.t]; + query.type = { + 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_', + }[query.type]; + const data = { threadId: query.type + query.id }; + if (query.type == 'A_EV_2_') { + data.threadId = query.threadId; + } + if (query.t == 'add') data.content = query.content; + else if (query.t == 'delete') data.commentId = query.commentId; + else if (query.t == 'reply') { + data.commentId = query.commentId; + data.content = query.content; + } + return request( + 'POST', + `https://music.163.com/weapi/resource/comments/${query.t}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + comment(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/cloudsearch': (req, res) => { + 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, + ); + const cloudsearch = (query, request) => { + const data = { + s: query.keywords, + type: query.type || 1, + limit: query.limit || 30, + offset: query.offset || 0, + }; + return request( + 'POST', + `https://music.163.com/weapi/cloudsearch/get/web`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + cloudsearch(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/check/music': (req, res) => { + 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, + ); + const check_music = (query, request) => { + const data = { + ids: '[' + parseInt(query.id) + ']', + br: parseInt(query.br || 999000), + }; + return request( + 'POST', + `https://music.163.com/weapi/song/enhance/player/url`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ).then((response) => { + let playable = false; + if (response.body.code == 200) { + if (response.body.data[0].code == 200) { + playable = true; + } + } + if (playable) { + response.body = { success: true, message: 'ok' }; + return response; + } else { + response.status = 404; + response.body = { success: false, message: '亲爱的,暂无版权' }; + return Promise.reject(response); + } + }); + }; + check_music(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/cellphone/existence/check': (req, res) => { + 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, + ); + const cellphone_existence_check = (query, request) => { + const data = { cellphone: query.phone, countrycode: query.countrycode }; + return request( + 'POST', + `https://music.163.com/eapi/cellphone/existence/check`, + data, + { + crypto: 'eapi', + cookie: query.cookie, + proxy: query.proxy, + url: '/api/cellphone/existence/check', + realIP: query.realIP, + }, + ); + }; + cellphone_existence_check(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/captcha/verify': (req, res) => { + 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, + ); + const captcha_verify = (query, request) => { + const data = { + ctcode: query.ctcode || '86', + cellphone: query.phone, + captcha: query.captcha, + }; + return request( + 'POST', + `https://music.163.com/weapi/sms/captcha/verify`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + captcha_verify(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/captcha/sent': (req, res) => { + 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, + ); + const captcha_sent = (query, request) => { + const data = { ctcode: query.ctcode || '86', cellphone: query.phone }; + return request( + 'POST', + `https://music.163.com/weapi/sms/captcha/sent`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + captcha_sent(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/calendar': (req, res) => { + 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, + ); + const calendar = (query, request) => { + const data = { + startTime: query.startTime || Date.now(), + endTime: query.endTime || Date.now(), + }; + return request( + 'POST', + `https://music.163.com/api/mcalendar/detail`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + calendar(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/banner': (req, res) => { + 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, + ); + const banner = (query, request) => { + const type = + { 0: 'pc', 1: 'android', 2: 'iphone', 3: 'ipad' }[query.type || 0] || + 'pc'; + return request( + 'POST', + `https://music.163.com/api/v2/banner/get`, + { clientType: type }, + { crypto: 'linuxapi', proxy: query.proxy, realIP: query.realIP }, + ); + }; + banner(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/avatar/upload': (req, res) => { + 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, + ); + const avatar_upload = async (query, request) => { + const uploadInfo = await uploadPlugin(query, request); + const res = await request( + 'POST', + `https://music.163.com/weapi/user/avatar/upload/v1`, + { imgid: uploadInfo.imgId }, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + return { + status: 200, + body: { code: 200, data: { ...uploadInfo, ...res.body } }, + }; + }; + avatar_upload(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/audio/match': (req, res) => { + 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, + ); + const audio_match = (query, request) => { + query.cookie.os = 'pc'; + const data = { + algorithmCode: 'shazam_v2', + times: 1, + sessionId: 'C999431ACDC84EDBB984763654E6F8D7', + duration: 3.3066249999999995, + from: 'recognize-song', + rawdata: realData, + }; + return request( + 'POST', + `https://music.163.com/api/music/audio/match`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + audio_match(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/artists': (req, res) => { + 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, + ); + const artists = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/v1/artist/${query.id}`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + artists(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/artist/top/song': (req, res) => { + 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, + ); + const artist_top_song = (query, request) => { + const data = { id: query.id }; + return request( + 'POST', + `https://music.163.com/api/artist/top/song`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + artist_top_song(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/artist/sublist': (req, res) => { + 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, + ); + const artist_sublist = (query, request) => { + const data = { + limit: query.limit || 25, + offset: query.offset || 0, + total: true, + }; + return request( + 'POST', + `https://music.163.com/weapi/artist/sublist`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + artist_sublist(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/artist/sub': (req, res) => { + 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, + ); + const artist_sub = (query, request) => { + query.t = query.t == 1 ? 'sub' : 'unsub'; + const data = { artistId: query.id, artistIds: '[' + query.id + ']' }; + return request( + 'POST', + `https://music.163.com/weapi/artist/${query.t}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + artist_sub(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/artist/songs': (req, res) => { + 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, + ); + const artist_songs = (query, request) => { + query.cookie.os = 'pc'; + const data = { + id: query.id, + private_cloud: 'true', + work_type: 1, + order: query.order || 'hot', + offset: query.offset || 0, + limit: query.limit || 100, + }; + return request( + 'POST', + `https://music.163.com/api/v1/artist/songs`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + artist_songs(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/artist/mv': (req, res) => { + 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, + ); + const artist_mv = (query, request) => { + const data = { + artistId: query.id, + limit: query.limit, + offset: query.offset, + total: true, + }; + return request('POST', `https://music.163.com/weapi/artist/mvs`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }); + }; + artist_mv(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/artist/list': (req, res) => { + 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, + ); + const artist_list = (query, request) => { + const data = { + initial: isNaN(query.initial) + ? (query.initial || '').toUpperCase().charCodeAt() || undefined + : query.initial, + offset: query.offset || 0, + limit: query.limit || 30, + total: true, + type: query.type || '1', + area: query.area, + }; + return request('POST', `https://music.163.com/api/v1/artist/list`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }); + }; + artist_list(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/artist/desc': (req, res) => { + 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, + ); + const artist_desc = (query, request) => { + const data = { id: query.id }; + return request( + 'POST', + `https://music.163.com/weapi/artist/introduction`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + artist_desc(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/artist/album': (req, res) => { + 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, + ); + const artist_album = (query, request) => { + const data = { + limit: query.limit || 30, + offset: query.offset || 0, + total: true, + }; + return request( + 'POST', + `https://music.163.com/weapi/artist/albums/${query.id}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + artist_album(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/album/sublist': (req, res) => { + 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, + ); + const album_sublist = (query, request) => { + const data = { + limit: query.limit || 25, + offset: query.offset || 0, + total: true, + }; + return request( + 'POST', + `https://music.163.com/weapi/album/sublist`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + album_sublist(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/album/sub': (req, res) => { + 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, + ); + const album_sub = (query, request) => { + query.t = query.t == 1 ? 'sub' : 'unsub'; + const data = { id: query.id }; + return request( + 'POST', + `https://music.163.com/api/album/${query.t}`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + album_sub(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/album/songsaleboard': (req, res) => { + 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, + ); + const album_songsaleboard = (query, request) => { + let data = { albumType: query.albumType || 0 }; + const type = query.type || 'daily'; + if (type === 'year') { + data = { ...data, year: query.year }; + } + return request( + 'POST', + `https://music.163.com/api/feealbum/songsaleboard/${type}/type`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + album_songsaleboard(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/album/newest': (req, res) => { + 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, + ); + const album_newest = (query, request) => { + return request( + 'POST', + `https://music.163.com/api/discovery/newAlbum`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + album_newest(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/album/new': (req, res) => { + 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, + ); + const album_new = (query, request) => { + const data = { + limit: query.limit || 30, + offset: query.offset || 0, + total: true, + area: query.area || 'ALL', + }; + return request('POST', `https://music.163.com/weapi/album/new`, data, { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }); + }; + album_new(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/album/list/style': (req, res) => { + 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, + ); + const album_list_style = (query, request) => { + const data = { + limit: query.limit || 10, + offset: query.offset || 0, + total: true, + area: query.area || 'Z_H', + }; + return request( + 'POST', + `https://music.163.com/weapi/vipmall/appalbum/album/style`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + album_list_style(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/album/list': (req, res) => { + 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, + ); + const album_list = (query, request) => { + const data = { + limit: query.limit || 30, + offset: query.offset || 0, + total: true, + area: query.area || 'ALL', + type: query.type, + }; + return request( + 'POST', + `https://music.163.com/weapi/vipmall/albumproduct/list`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + album_list(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/album/detail/dynamic': (req, res) => { + 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, + ); + const album_detail_dynamic = (query, request) => { + const data = { id: query.id }; + return request( + 'POST', + `https://music.163.com/api/album/detail/dynamic`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + album_detail_dynamic(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/album/detail': (req, res) => { + 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, + ); + const album_detail = (query, request) => { + const data = { id: query.id }; + return request( + 'POST', + `https://music.163.com/weapi/vipmall/albumproduct/detail`, + data, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + album_detail(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/album': (req, res) => { + 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, + ); + const album = (query, request) => { + return request( + 'POST', + `https://music.163.com/weapi/v1/album/${query.id}`, + {}, + { + crypto: 'weapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ); + }; + album(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/activate/init/profile': (req, res) => { + 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, + ); + const activate_init_profile = (query, request) => { + const data = { nickname: query.nickname }; + return request( + 'POST', + `https://music.163.com/eapi/activate/initProfile`, + data, + { + crypto: 'eapi', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + url: '/api/activate/initProfile', + }, + ); + }; + activate_init_profile(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + '/related/playlist': (req, res) => { + 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, + ); + const related_playlist = (query, request) => { + return request( + 'GET', + `https://music.163.com/playlist?id=${query.id}`, + {}, + { + ua: 'pc', + cookie: query.cookie, + proxy: query.proxy, + realIP: query.realIP, + }, + ).then((response) => { + try { + const pattern = /
[\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); + } + }); + }; + related_playlist(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, + + '/batch': (req, res) => { + 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, + ); + const batch = (query, request) => { + const data = { + e_r: true, + }; + Object.keys(query).forEach((i) => { + if (/^\/api\//.test(i)) { + data[i] = query[i]; + } + }); + return request('POST', `https://music.163.com/eapi/batch`, data, { + crypto: 'eapi', + proxy: query.proxy, + url: '/api/batch', + cookie: query.cookie, + realIP: query.realIP, + }); + }; + batch(query, request) + .then((answer) => { + console.log('[OK]', decodeURIComponent(req.originalUrl)); + res.append('Set-Cookie', answer.cookie); + res.status(answer.status).send(answer.body); + }) + .catch((answer) => { + console.log('[ERR]', 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); + }); + }, +}; 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..b15d694 --- /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 }), + } + + 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": "/" + } + ] +}