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 + +
+ +## 灵感来自 + +[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 @@ + + + + + + +请在控制台看结果
+ + + + + + 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 = /
+ * 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": "/"
+ }
+ ]
+}