├── .bumpversion.cfg ├── .gitattributes ├── .github └── workflows │ └── publish.yml ├── .gitignore ├── CHANGELOG.md ├── README.md ├── api_test.py ├── config.json ├── docs ├── .nojekyll ├── README.md ├── _coverpage.md ├── favicon.ico ├── icon.png ├── index.html ├── test_report.png ├── v2.md └── 开发指南.md ├── example.py ├── package ├── LICENSE ├── MANIFEST.in ├── NeteaseCloudMusic.egg-info │ ├── PKG-INFO │ ├── SOURCES.txt │ ├── dependency_links.txt │ ├── requires.txt │ └── top_level.txt ├── NeteaseCloudMusic │ ├── NeteaseCloudMusicApi.js │ ├── __init__.py │ ├── config.json │ ├── help.py │ ├── main.py │ └── utils.py ├── README.md ├── build │ └── lib │ │ └── NeteaseCloudMusic │ │ ├── NeteaseCloudMusicApi.js │ │ ├── __init__.py │ │ ├── config.json │ │ ├── help.py │ │ ├── main.py │ │ └── utils.py ├── dist │ ├── NeteaseCloudMusic-0.1.7-py2.py3-none-any.whl │ └── NeteaseCloudMusic-0.1.7.tar.gz └── setup.py ├── publish.py ├── pytest.yml ├── report.html ├── requirements.txt ├── static ├── Python.jpg ├── Qt.jpg ├── idea.jpg ├── javascript.jpg ├── wish.jpg └── 网易云.png ├── test.py ├── test_gender ├── __init__.py ├── generator.py ├── report.html ├── some.txt └── template └── towncrier.toml /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 0.1.10 3 | commit = True 4 | tag = True 5 | 6 | [bumpversion:file:package/setup.py] 7 | 8 | [bumpversion:file:towncrier.toml] 9 | 10 | [bumpversion:file:package/NeteaseCloudMusic/__init__.py] 11 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | docs/ linguist-vendored 2 | docs/ linguist-generated 3 | report.html linguist-vendored 4 | report.html linguist-generated 5 | static/ linguist-vendored 6 | static/ linguist-generated 7 | *.js linguist-vendored 8 | *.js linguist-generated 9 | package/NeteaseCloudMusic/NeteaseCloudMusicApi.js linguist-vendored 10 | package/NeteaseCloudMusic/NeteaseCloudMusicApi.js linguist-generated -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Python 🐍 distributions 📦 to PyPI 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | build-n-publish: 10 | name: Build and publish Python 🐍 distributions 📦 to PyPI 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Checkout code 15 | uses: actions/checkout@v2 16 | 17 | - name: Set up Python 18 | uses: actions/setup-python@v2 19 | with: 20 | python-version: 3. 21 | 22 | id: get_version 23 | run: | 24 | echo "VERSION=${GITHUB_REF/refs\/tags\/v/}" >> $GITHUB_ENV 25 | 26 | - name: Print the version 27 | run: | 28 | echo ${{ env.VERSION }} 29 | echo ${{ github.ref }} 30 | ls ./package/dist/ 31 | cat ./package/setup.py 32 | 33 | - name: Install dependencies 34 | run: | 35 | python -m pip install build towncrier setuptools wheel 36 | 37 | - name: Generate release notes 38 | run: | 39 | towncrier --draft > release_notes.txt 40 | 41 | - name: Generate version notes with towncrier 42 | run: | 43 | towncrier --yes 44 | 45 | - name: Build a binary wheel and a source tarball 46 | run: | 47 | cd package 48 | python setup.py upload 49 | ls ./dist/ 50 | 51 | - name: Publish distribution 📦 to PyPI 52 | run: | 53 | cd package 54 | pip install twine 55 | twine upload dist/* 56 | env: 57 | TWINE_USERNAME: __token__ 58 | TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} 59 | 60 | - name: Create Release 61 | id: create_release 62 | uses: actions/create-release@v1 63 | env: 64 | GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} 65 | with: 66 | tag_name: ${{ github.ref }} 67 | release_name: Release ${{ github.ref }} 68 | body_path: release_notes.txt 69 | 70 | - name: Upload Release Asset gz 71 | uses: actions/upload-release-asset@v1 72 | env: 73 | GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} 74 | with: 75 | upload_url: ${{ steps.create_release.outputs.upload_url }} 76 | asset_path: ./package/dist/NeteaseCloudMusic-${{ env.VERSION }}.tar.gz 77 | asset_name: NeteaseCloudMusic-${{ env.VERSION }}.tar.gz 78 | asset_content_type: application/zip 79 | 80 | - name: Upload Release Asset whl 81 | uses: actions/upload-release-asset@v1 82 | env: 83 | GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} 84 | with: 85 | upload_url: ${{ steps.create_release.outputs.upload_url }} 86 | asset_path: ./package/dist/NeteaseCloudMusic-${{ env.VERSION }}-py2.py3-none-any.whl 87 | asset_name: NeteaseCloudMusic-${{ env.VERSION }}-py2.py3-none-any.whl 88 | asset_content_type: application/zip 89 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | __pycache__/ 3 | .env 4 | .pytest_cache/ 5 | cookie_storage 6 | /情非得已 (童声版) - 群星.mp3 7 | /cache/ 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 0.1.10 (2023-12-20) 2 | 3 | ### Misc 4 | 5 | - workflow_update 6 | 7 | 8 | 0.1.7 (2023-12-20) 9 | 10 | ### Bugfixes 11 | 12 | - 重新利用Max-Age判断cookie是否过期 (cookie_expires) 13 | - 修复因为补充的encodeURIComponent函数无法识别非字符的True或False而导致的cookie项remberme为空从而使login_refresh接口返回400的问题 (login_refresh) 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NeteaseCloudMusic_PythonSDK 2 | ## 最新消息:***Binaryify/NeteaseCloudMusicApi*** 受到网易法律警告目前已删库且不再维护,该项目也被迫暂停维护 3 | 4 | 有关***Binaryify/NeteaseCloudMusicApi***最新版本的js其实已经改写完毕了,但是作者懒得继续写Python版本,有意向自己开发的可以联系我进行接手。 5 | 6 | 有空的的话我会写文档简述这个项目的思路,以及我在进行过程遇到的问题和解决方案。😆不用太期待,没什么难度主要还是自己辛苦哈。 7 | 8 | 现已同步原项目接口且测试通过的有200多个 :wave: :wave: :star: 求赞 :star: 9 | 10 | ![](https://img.shields.io/badge/py_mini_racer-@0.6.0-red.svg) ![License](https://img.shields.io/badge/license-MIT-yellow)[![PyPI Downloads](https://pepy.tech/badge/NeteaseCloudMusic)](https://pepy.tech/project/NeteaseCloudMusic)[![PyPI version](https://badge.fury.io/py/NeteaseCloudMusic.svg)](https://badge.fury.io/py/NeteaseCloudMusic) 11 | 12 | > 基于 [NeteaseCloudMusicApi](https://github.com/Binaryify/NeteaseCloudMusicApi) 封装的 Python SDK。 13 | > 网易云API Python版本。 14 | > 已发布到PyPi,可直接使用pip安装。项目地址:[GitHub](https://github.com/2061360308/NeteaseCloudMusic_PythonSDK) 15 | > 16 | > 在此感谢`NeteaseCloudMusicApi`项目及其作者`Binaryify` 17 | > 18 | > 当然也感谢史上最最最好用的听歌软件——网易云音乐 19 | > 20 | > 项目仅用于学习,还望大家合理使用该项目 21 | 22 |
23 | 24 |
25 | 26 | ### :four_leaf_clover:项目背景 27 | 28 | Binaryify 创建了有趣的项目[NeteaseCloudMusicApi](https://github.com/Binaryify/NeteaseCloudMusicApi)提供了较为完善的网易云接口。 29 | 30 | 但是这个项目是基于Node服务器的,对于不懂Node或是服务器搭建的小伙伴来说不易于上手,而且开发出来的项目开源后也必须依赖于Node后端服务。 31 | 32 | 这样一来这些衍生的项目在介绍时就离不开告诉使用者“如何搭建后端等等的一系列操作”,增加了项目上手的难度。他人没法快速体验一番你的作品,需要先学习后端的搭建。 33 | 34 | 事实上,我们知道,除却在网页上独有的限制,只能依赖于服务器转发,在其他平台我们完全可以不需要服务器。 35 | 36 | 所以这个Python项目诞生了。 :joy: :joy: :joy: 37 | 38 | ### :heart:作者寄语 39 | 40 | 本项目使用Python开发,在我印象中这是一门非常活跃的语言,拥有一群怀揣许许多多“奇思妙想”的使用者。[NeteaseCloudMusicApi](https://github.com/Binaryify/NeteaseCloudMusicApi)项目开源有好多年了,得到了3万颗星,无疑是一个优质的项目。但在此之前,我发现大多都是“前端们”使用前端技术(vue,electron)进行创作,这次我把这个接口项目封装到Python平台,相信我们的小伙伴们一定能为这个优质项目注入新的活力! 41 | 42 | 希望你们在开心创作的同时能够有不菲的收获。 43 | 44 |
45 | 46 |
47 | 48 | ### :mushroom:项目用途 49 | 50 | 1. 仿网易云制作出专属于你的音乐软件 51 | 2. 赋予你的项目“音乐的力量” 52 | 3. 嗯,互联网上“下歌”,“获取歌词”,等等的炫酷操作你也能轻松实现了 53 | 4. 其他有待创新…… 54 | 55 | ### :muscle:项目特点 56 | 57 | - 完全封装于Python,不含其他知识点,不用自己处理网络请求,小白可用 58 | - 不需要Node后端!!所有内容都封装到了库内部,可以随你的项目直接打包,其他人也可以直接下载体验,无需配置后端 59 | - 发布到PyPI,简单使用 60 | - 基于Python调用ECMScript,没有打包繁重的Node环境,体积小,效率高。 61 | 62 | ### 依赖于 63 | - [ NeteaseCloudMusicApi](https://github.com/Binaryify/NeteaseCloudMusicApi) 64 | - [ NeteaseCloudMusicApi_V8 ](https://github.com/2061360308/NeteaseCloudMusicApi_V8) 65 | 66 | ### 项目原理 67 | - 通过 `py_mini_racer` 调用 `NeteaseCloudMusicApi_V8` 的 `js` 方法。进一步进行了简单封装。 68 | 69 |
70 | 71 |
72 | 73 | ### :dragon_face:使用方法 74 | - 安装 `pip install NeteaseCloudMusic` 75 | - 导入API进行使用(具体查看[`example.py`](./example.py)中的示例) 76 | ```python 77 | from NeteaseCloudMusic import NeteaseCloudMusicApi, api_help, api_list 78 | import os 79 | 80 | netease_cloud_music_api = NeteaseCloudMusicApi() # 初始化API 81 | netease_cloud_music_api.cookie = "你的cookie" # 设置cookie, 如果没有cookie需要先登录 具体见example.py 82 | response = netease_cloud_music_api.request("song_url_v1", {"id": 33894312, "level": "exhigh"}) # 调用API 83 | 84 | # 获取帮助 85 | print(api_help()) 86 | print(api_help('song_url_v1')) 87 | # 获取API列表 88 | print(api_list()) 89 | ``` 90 | 91 | > 注意: request(self, name, query=None) 的第一个参数为API名称,第二个参数为API参数,具体API名称和参数请参考 [NeteaseCloudMusicApi文档](https://docs.neteasecloudmusicapi.binaryify.com),name支持`/song/url/v1`和`song_url_v1`两种写法。 92 | 93 | > api已加入自动缓存(需要自己开启默认关闭),在测试接口时,如果频繁调用获取结果在query里应该加上timestamp参数来区分,例如 94 | > ```python 95 | > response = netease_cloud_music_api.request("song_url_v1", {"id": 33894312, "level": "exhigh", "timestamp": time.time()}) 96 | > ``` 97 | 98 | ### :eyes:开发 99 | 如果想要参与项目开发,或是自己修改源码,请参照[开发指南](./docs/开发指南.md)。 100 | 101 | ### 测试 102 | 103 | 测试文件见[api_test.py](./api_test.py),测试使用了`pytest`框架 104 | 105 | 测试结果请见[`report.html`](./report.html) 106 | 107 | ### :cherry_blossom:功能特性 108 | 109 | > 项目初创,一些涉及上传东西的接口等还未进行支持,具体可见下方未支持的接口(急需某个未支持的接口可以发issue,我会优先解决) 110 | > 111 | > 接口文档具体参考原文档[NeteaseCloudMusicApi文档](https://docs.neteasecloudmusicapi.binaryify.com) 112 | 113 | 1. 登录 114 | 2. 刷新登录 115 | 3. 发送验证码 116 | 4. 校验验证码 117 | 5. 注册(修改密码) 118 | 6. 获取用户信息 , 歌单,收藏,mv, dj 数量 119 | 7. 获取用户歌单 120 | 8. 获取用户电台 121 | 9. 获取用户关注列表 122 | 10. 获取用户粉丝列表 123 | 11. 获取用户动态 124 | 12. 获取用户播放记录 125 | 13. 获取精品歌单 126 | 14. 获取歌单详情 127 | 15. 搜索 128 | 16. 搜索建议 129 | 17. 获取歌词 130 | 18. 歌曲评论 131 | 19. 收藏单曲到歌单 132 | 20. 专辑评论 133 | 21. 歌单评论 134 | 22. mv 评论 135 | 23. 电台节目评论 136 | 24. banner 137 | 25. 获取歌曲详情 138 | 26. 获取专辑内容 139 | 27. 获取歌手单曲 140 | 28. 获取歌手 mv 141 | 29. 获取歌手专辑 142 | 30. 获取歌手描述 143 | 31. 获取相似歌手 144 | 32. 获取相似歌单 145 | 33. 相似 mv 146 | 34. 获取相似音乐 147 | 35. 获取最近 5 个听了这首歌的用户 148 | 36. 获取每日推荐歌单 149 | 37. 获取每日推荐歌曲 150 | 38. 私人 FM 151 | 39. 签到 152 | 40. 喜欢音乐 153 | 41. 垃圾桶 154 | 42. 歌单 ( 网友精选碟 ) 155 | 43. 新碟上架 156 | 44. 热门歌手 157 | 45. 最新 mv 158 | 46. 推荐 mv 159 | 47. 推荐歌单 160 | 48. 推荐新音乐 161 | 49. 推荐电台 162 | 50. 推荐节目 163 | 51. 独家放送 164 | 52. mv 排行 165 | 53. 获取 mv 数据 166 | 54. 播放 mv/视频 167 | 55. 排行榜 168 | 56. 歌手榜 169 | 57. 云盘 170 | 58. 电台 - 推荐 171 | 59. 电台 - 分类 172 | 60. 电台 - 分类推荐 173 | 61. 电台 - 订阅 174 | 62. 电台 - 详情 175 | 63. 电台 - 节目 176 | 64. 给评论点赞 177 | 65. 获取动态 178 | 66. 热搜列表(简略) 179 | 67. 发送私信 180 | 68. 发送私信歌单 181 | 69. 新建歌单 182 | 70. 收藏/取消收藏歌单 183 | 71. 歌单分类 184 | 72. 收藏的歌手列表 185 | 73. 订阅的电台列表 186 | 74. 相关歌单推荐 187 | 75. 付费精选接口 188 | 76. 音乐是否可用检查接口 189 | 77. 登录状态 190 | 78. 获取视频播放地址 191 | 79. 发送/删除评论 192 | 80. 热门评论 193 | 81. 视频评论 194 | 82. 退出登录 195 | 83. 所有榜单 196 | 84. 所有榜单内容摘要 197 | 85. 收藏视频 198 | 86. 收藏 MV 199 | 87. 视频详情 200 | 88. 相关视频 201 | 89. 关注用户 202 | 90. 新歌速递 203 | 91. 喜欢音乐列表(无序) 204 | 92. 收藏的 MV 列表 205 | 93. 获取最新专辑 206 | 94. 听歌打卡 207 | 95. 获取视频标签/分类下的视频 208 | 96. 已收藏专辑列表 209 | 97. 获取动态评论 210 | 98. 歌单收藏者列表 211 | 99. 云盘歌曲删除 212 | 100. 热门话题 213 | 101. 电台 - 推荐类型 214 | 102. 电台 - 非热门类型 215 | 103. 电台 - 今日优选 216 | 104. 心动模式/智能播放 217 | 105. 转发动态 218 | 106. 删除动态 219 | 107. 分享歌曲、歌单、mv、电台、电台节目到动态 220 | 108. 通知-私信 221 | 109. 通知-评论 222 | 110. 通知-@我 223 | 111. 通知-通知 224 | 112. 设置 225 | 113. 云盘数据详情 226 | 114. 私信内容 227 | 115. 我的数字专辑 228 | 116. batch批量请求接口 229 | 117. 获取视频标签列表 230 | 118. 全部mv 231 | 119. 网易出品mv 232 | 120. 收藏/取消收藏专辑 233 | 121. 专辑动态信息 234 | 122. 热搜列表(详细) 235 | 123. 更换绑定手机 236 | 124. 检测手机号码是否已注册 237 | 125. 初始化昵称 238 | 126. 更新歌单描述 239 | 127. 更新歌单名 240 | 128. 更新歌单标签 241 | 129. 默认搜索关键词 242 | 130. 删除歌单 243 | 131. 电台banner 244 | 132. 用户电台 245 | 133. 热门电台 246 | 134. 电台 - 节目详情 247 | 135. 电台 - 节目榜 248 | 136. 电台 - 新晋电台榜/热门电台榜 249 | 137. 类别热门电台 250 | 138. 云村热评 251 | 139. 电台24小时节目榜 252 | 140. 电台24小时主播榜 253 | 141. 电台最热主播榜 254 | 142. 电台主播新人榜 255 | 143. 电台付费精品榜 256 | 144. 歌手热门50首歌曲 257 | 145. 购买数字专辑 258 | 146. 获取 mv 点赞转发评论数数据 259 | 147. 获取视频点赞转发评论数数据 260 | 148. 调整歌单顺序 261 | 149. 调整歌曲顺序 262 | 150. 独家放送列表 263 | 151. 获取推荐视频 264 | 152. 获取视频分类列表 265 | 153. 获取全部视频列表接口 266 | 154. 获取历史日推可用日期列表 267 | 155. 获取历史日推详细数据 268 | 156. 国家编码列表 269 | 157. 首页-发现 270 | 158. 首页-发现-圆形图标入口列表 271 | 159. 数字专辑-全部新碟 272 | 160. 数字专辑-热门新碟 273 | 161. 数字专辑&数字单曲-榜单 274 | 162. 数字专辑-语种风格馆 275 | 163. 数字专辑详情 276 | 164. 更新头像 277 | 165. 歌单封面上传 278 | 166. 楼层评论 279 | 167. 歌手全部歌曲 280 | 168. 精品歌单标签列表 281 | 169. 用户等级信息 282 | 170. 电台个性推荐 283 | 171. 用户绑定信息 284 | 172. 用户绑定手机 285 | 173. 新版评论 286 | 174. 点赞过的视频 287 | 175. 收藏视频到视频歌单 288 | 176. 删除视频歌单里的视频 289 | 177. 最近播放的视频 290 | 178. 音乐日历 291 | 179. 电台订阅者列表 292 | 180. 云贝签到信息 293 | 181. 云贝签到 294 | 182. 云贝所有任务 295 | 183. 云贝todo任务 296 | 184. 云贝今日签到信息 297 | 185. 云贝完成任务 298 | 186. 云贝收入 299 | 187. 云贝支出 300 | 188. 云贝账户信息 301 | 189. 账号信息 302 | 190. 最近联系人 303 | 191. 私信音乐 304 | 192. 抱一抱评论 305 | 193. 评论抱一抱列表 306 | 194. 收藏的专栏 307 | 195. 关注歌手新歌 308 | 196. 关注歌手新MV 309 | 197. 歌手详情 310 | 198. 云盘上传 311 | 199. 二维码登录 312 | 200. 话题详情 313 | 201. 话题详情热门动态 314 | 202. 歌单详情动态 315 | 203. 绑定手机 316 | 204. 一起听状态 317 | 205. 用户历史评论 318 | 206. 云盘歌曲信息匹配纠正 319 | 207. 云贝推歌 320 | 208. 云贝推歌历史记录 321 | 209. 已购单曲 322 | 210. 获取mlog播放地址 323 | 211. 将mlog id转为视频id 324 | 212. vip成长值 325 | 213. vip成长值获取记录 326 | 214. vip任务 327 | 215. 领取vip成长值 328 | 216. 歌手粉丝 329 | 217. 数字专辑详情 330 | 218. 数字专辑销量 331 | 219. 音乐人数据概况 332 | 220. 音乐人播放趋势 333 | 221. 音乐人任务 334 | 222. 账号云豆数 335 | 223. 领取云豆 336 | 224. 获取 VIP 信息 337 | 225. 音乐人签到 338 | 226. 发送文本动态 339 | 227. 获取客户端歌曲下载 url 340 | 228. 获取歌单所有歌曲 341 | 229. 乐签信息 342 | 230. 最近播放-歌曲 343 | 231. 最近播放-视频 344 | 232. 最近播放-声音 345 | 233. 最近播放-歌单 346 | 234. 最近播放-专辑 347 | 235. 最近播放-播客 348 | 236. 签到进度 349 | 237. 重复昵称检测 350 | 238. 歌手粉丝数量 351 | 239. 音乐人任务(新) 352 | 240. 内部版本接口 353 | 241. 歌单更新播放量 354 | 242. 黑胶时光机 355 | 243. 音乐百科 - 简要信息 356 | 244. 乐谱列表 357 | 245. 乐谱内容 358 | 246. 曲风列表 359 | 247. 曲风偏好 360 | 248. 曲风详情 361 | 249. 曲风-歌曲 362 | 250. 曲风-专辑 363 | 251. 曲风-歌单 364 | 252. 曲风-歌手 365 | 253. 私信和通知接口 366 | 254. 回忆坐标 367 | 255. 播客搜索 368 | 256. 播客声音上传 369 | 257. 验证接口-二维码生成 370 | 258. 验证接口-二维码检测 371 | 259. 听歌识曲 372 | 260. 根据nickname获取userid接口 373 | 261. 播客声音列表 374 | 262. 专辑简要百科信息 375 | 263. 歌曲简要百科信息 376 | 264. 歌手简要百科信息 377 | 265. mv简要百科信息 378 | 266. 搜索歌手 379 | 267. 用户贡献内容 380 | 268. 用户贡献条目、积分、云贝数量 381 | 269. 年度听歌报告 382 | 270. 播客声音搜索 383 | 384 | ### 改进 385 | > 下列API未支持 386 | > 387 | - request_reference.js 388 | - avatar_upload.js 389 | - cloud.js 390 | - playlist_cover_update.js 391 | - voice_upload.js 392 | - register_anonimous.js 393 | - verify_getQr.js 394 | 395 | > 以下api未测试(这些接口测试起来比较繁琐) 396 | > 397 | - /user/replacephone 398 | - /audio/match 399 | - /rebind 400 | - /nickname/check 401 | - /activate/init/profile 402 | - /cellphone/existence/check 403 | - /register/cellphone 404 | - /captcha/verify 405 | - /captcha/sent 406 | - /login/refresh 407 | - /logout 408 | - /user/update 409 | - /pl/count 410 | - /playlist/update 411 | - /playlist/desc/update 412 | - /playlist/name/update 413 | - /playlist/tags/update 414 | - /event/forward 415 | - /event/del 416 | - /share/resource 417 | - /send/text 418 | - /send/playlist 419 | - /playlist/create 420 | - /playlist/tracks 421 | - /daily_signin 422 | - /fm_trash 423 | 424 | ### 欢迎提交PR 425 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2061360308/NeteaseCloudMusic_PythonSDK/02a34af715dc3a25ea370fb3b0f69f3978b6960f/docs/.nojekyll -------------------------------------------------------------------------------- /docs/_coverpage.md: -------------------------------------------------------------------------------- 1 | # 网易云音乐 API 2 | 3 | > 网易云音乐 NodeJS 版 API 4 | 5 | - 全部接口已升级到最新 6 | - 具备登录接口,多达200多个接口 7 | - 更完善的文档 8 | 9 | 10 | [GitHub](https://github.com/Binaryify/NeteaseCloudMusicApi) 11 | [Get Started](#neteasecloudmusicapi) 12 | 13 | ![color](#ffffff) 14 | -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2061360308/NeteaseCloudMusic_PythonSDK/02a34af715dc3a25ea370fb3b0f69f3978b6960f/docs/favicon.ico -------------------------------------------------------------------------------- /docs/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2061360308/NeteaseCloudMusic_PythonSDK/02a34af715dc3a25ea370fb3b0f69f3978b6960f/docs/icon.png -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 网易云音乐 NodeJS 版 API 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 21 | 22 |
23 | 24 | 31 | 32 | 37 | 38 | 39 | 46 | 47 | -------------------------------------------------------------------------------- /docs/test_report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2061360308/NeteaseCloudMusic_PythonSDK/02a34af715dc3a25ea370fb3b0f69f3978b6960f/docs/test_report.png -------------------------------------------------------------------------------- /docs/v2.md: -------------------------------------------------------------------------------- 1 | # NeteaseCloudMusicApi 2 | 3 | 网易云音乐 NodeJS 版 API 4 | 5 | ## 灵感来自 6 | 7 | [disoul/electron-cloud-music](https://github.com/disoul/electron-cloud-music) 8 | 9 | [darknessomi/musicbox](https://github.com/darknessomi/musicbox) 10 | 11 | [sqaiyan/netmusic-node](https://github.com/sqaiyan/netmusic-node) 12 | 13 | ## 工作原理 14 | 15 | 跨站请求伪造 (CSRF), 伪造请求头 , 调用官方 API 16 | 17 | ## 功能特性 18 | 19 | 1. 登录 20 | 2. 刷新登录 21 | 3. 获取用户信息 , 歌单,收藏,mv, dj 数量 22 | 4. 获取用户歌单 23 | 5. 获取用户电台 24 | 6. 获取用户关注列表 25 | 7. 获取用户粉丝列表 26 | 8. 获取用户动态 27 | 9. 获取用户播放记录 28 | 10. 获取精品歌单 29 | 11. 获取歌单详情 30 | 12. 搜索 31 | 13. 搜索建议 32 | 14. 获取歌词 33 | 15. 歌曲评论 34 | 16. 收藏单曲到歌单 35 | 17. 专辑评论 36 | 18. 歌单评论 37 | 19. mv 评论 38 | 20. 电台节目评论 39 | 21. banner 40 | 22. 获取歌曲详情 41 | 23. 获取专辑内容 42 | 24. 获取歌手单曲 43 | 25. 获取歌手 mv 44 | 26. 获取歌手专辑 45 | 27. 获取歌手描述 46 | 28. 获取相似歌手 47 | 29. 获取相似歌单 48 | 30. 相似 mv 49 | 31. 获取相似音乐 50 | 32. 获取最近 5 个听了这首歌的用户 51 | 33. 获取每日推荐歌单 52 | 34. 获取每日推荐歌曲 53 | 35. 私人 FM 54 | 36. 签到 55 | 37. 喜欢音乐 56 | 38. 垃圾桶 57 | 39. 歌单 ( 网友精选碟 ) 58 | 40. 新碟上架 59 | 41. 热门歌手 60 | 42. 最新 mv 61 | 43. 推荐 mv 62 | 44. 推荐歌单 63 | 45. 推荐新音乐 64 | 46. 推荐电台 65 | 47. 推荐节目 66 | 48. 独家放送 67 | 49. mv 排行 68 | 50. 获取 mv 数据 69 | 51. 播放 mv/视频 70 | 52. 排行榜 71 | 53. 歌手榜 72 | 54. 云盘 73 | 55. 电台 - 推荐 74 | 56. 电台 - 分类 75 | 57. 电台 - 分类推荐 76 | 58. 电台 - 订阅 77 | 59. 电台 - 详情 78 | 60. 电台 - 节目 79 | 61. 给评论点赞 80 | 62. 获取动态 81 | 63. 获取热搜 82 | 64. 发送私信 83 | 65. 发送私信歌单 84 | 66. 新建歌单 85 | 67. 收藏/取消收藏歌单 86 | 68. 歌单分类 87 | 69. 收藏的歌手列表 88 | 70. 订阅的电台列表 89 | 71. 相关歌单推荐 90 | 72. 付费精选接口 91 | 73. 音乐是否可用检查接口 92 | 74. 登录状态 93 | 75. 获取视频数据 94 | 76. 发送/删除评论 95 | 77. 热门评论 96 | 78. 视频评论 97 | 79. 退出登录 98 | 99 | ## 安装 100 | 101 | ```shell 102 | $ git clone git@github.com:Binaryify/NeteaseCloudMusicApi.git 103 | $ npm install 104 | ``` 105 | 106 | ## 运行 107 | 108 | ```shell 109 | $ node app.js 110 | ``` 111 | 112 | 服务器启动默认端口为 3000, 若不想使用 3000 端口 , 可使用以下命令 : Mac/Linux 113 | 114 | ```shell 115 | $ PORT=4000 node app.js 116 | ``` 117 | 118 | windows 下使用 git-bash 或者 cmder 等终端执行以下命令 : 119 | 120 | ```shell 121 | $ set PORT=4000 && node app.js 122 | ``` 123 | 124 | ## 可以使用代理 125 | 126 | 在 query 参数中加上 proxy=your-proxy 即可让这一次的请求使用 proxy 127 | 128 | ```javascript 129 | // 例子 130 | const url = `http://localhost:3000/music/url?id=33894312&proxy=http://121.196.226.246:84` 131 | fetch(url).then(function() { 132 | // do what you want 133 | }) 134 | 135 | // 结果 136 | // {"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} 137 | ``` 138 | 139 | ## Docker 容器运行 140 | 141 | > 注意: 在 docker 中运行的时候, 由于使用了 request 来发请求, 所以会检查几个 142 | > proxy 相关的环境变量(如下所列), 这些环境变量 会影响到 request 的代理, 详情请参 143 | > 考[request 的文档](https://github.com/request/request#proxies), 如果这些环境变 144 | > 量 指向的代理不可用, 那么就会造成错误, 所以在使用 docker 的时候一定要注意这些 145 | > 环境变量. 不过, 要是你在 query 中加上了 proxy 参数, 那么环境变量会被覆盖, 就会 146 | > 用你通过 proxy 参数提供的代理了. 147 | 148 | request 相关的环境变量 149 | 150 | 1. http_proxy 151 | 2. https_proxy 152 | 3. HTTP_PROXY 153 | 4. HTTPS_PROXY 154 | 5. no_proxy 155 | 6. NO_PROXY 156 | 157 | ```shell 158 | docker pull twesix/netease-cloud-music 159 | docker run -d -p 3000:3000 --name netease-cloud-music twesix/netease-music-api 160 | 161 | // 去掉或者设置相关的环境变量 162 | docker run -d -p 3000:3000 --name netease-cloud-music -e http_proxy= -e https_proxy= -e no_proxy= -e HTTP_PROXY= -e HTTPS_PROXY= -e NO_PROXY= netease-cloud-music 163 | ``` 164 | 165 | > 由于 docker 镜像更新不是很及时,推荐自己 build, 以下为 build 镜像的方式 166 | 167 | ``` 168 | $ git clone https://github.com/Binaryify/NeteaseCloudMusicApi && cd NeteaseCloudMusicApi 169 | $ sudo docker build . -t netease-music-api 170 | $ sudo docker run -d -p 3000:3000 netease-music-api 171 | ``` 172 | 173 | ## 接口文档 174 | 175 | ### 调用前须知 176 | 177 | !> 为使用方便,降低门槛,登录接口直接使用了 get 明文请求,请按实际需求对源码修改 178 | 179 | !> 由于接口做了缓存处理 ( 缓存 2 分钟 , 可在 app.js 设置 , 可能会导致登录后获取不 180 | 到 cookie), 相同的 url 会在两分钟内只向网易服务器发一次请求 , 如果遇到不需要缓 181 | 存结果的接口 , 可在请求 url 后面加一个时间戳参数使 url 不同 , 例子 : 182 | `/simi/playlist?id=347230×tamp=1503019930000` 183 | 184 | !> 如果是跨域请求 , 请在所有请求带上 `xhrFields: { withCredentials: true }` 否则 185 | 可能会因为没带上 cookie 导致 301, 具体例子可看 `public/test.html`, 例子使用 jQuery, axios 版本也类似 186 | 187 | !> 301 错误基本都是没登录就调用了需要登录的接口,如果登录了还是提示 301, 基本都是缓存把数据缓存起来了,解决方法是等待 2 分钟或者重启服务重新登录后再调用接口 188 | 189 | !> 部分接口如登录接口不能调用太频繁 , 否则可能会触发 503 错误或者 ip 高频错误 ,若需频繁调用 , 需要准备 IP 代理池 (更新:已加入缓存机制,但仍需注意). 190 | 191 | !> 本项目仅供学习使用 , 文档可能会有缓存 , 如果文档版本和 github 上的版本不一致,请清除缓存再查看 192 | 193 | !> 由于网易限制,此项目在国外服务器上使用会受到限制,如需解决 , 可使用大陆服务器或者使用代理 , 感谢 [@hiyangguo](https://github.com/hiyangguo)提出的[解决方法](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/29#issuecomment-298358438): 194 | 在 'util.js' 的 'headers' 处增加 `X-Real-IP':'211.161.244.70' // 任意国内 IP` 195 | 即可解决 196 | 197 | ### 登录 198 | 199 | 说明 : 登录有两个接口 200 | 201 | #### 1. 手机登录 202 | 203 | **必选参数 :** `phone`: 手机号码 `password`: 密码 204 | 205 | **接口地址 :** `/login/cellphone` 206 | 207 | **调用例子 :** `/login/cellphone?phone=xxx&password=yyy` 208 | 209 | #### 2. 邮箱登录 210 | 211 | ~~ 注意 : 此接口被网易和谐了 , 待修复 , 暂时使用手机登录 (2017.05.20)~~ 212 | 213 | > 更新 : 此接口已经可以正常使用(2018.07.03) 214 | 215 | **必选参数 :** `email`: 163 网易邮箱 `password`: 密码 216 | 217 | **接口地址 :** `/login` 218 | 219 | **调用例子 :** `/login?email=xxx@163.com&password=yyy` 220 | 221 | 返回数据如下图 : 222 | ![登录](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E7%99%BB%E5%BD%95.png) 223 | 224 | 完成登录后 , 会在浏览器保存一个 Cookies 用作登录凭证 , 大部分 API 都需要用到这个 225 | Cookies 226 | 227 | #### 注意 228 | 229 | 调用登录接口的速度比调用其他接口慢 , 因为登录过程调用了加密算法 230 | 231 | ### 刷新登录 232 | 233 | 说明 : 调用此接口 , 可刷新登录状态 234 | 235 | **调用例子 :** `/login/refresh` 236 | 237 | ### 退出登录 238 | 239 | 说明 : 调用此接口 , 可退出登录 240 | 241 | **调用例子 :** `/logout` 242 | 243 | ### 登录状态 244 | 245 | 说明 : 调用此接口,可获取登录状态 246 | 247 | **接口地址 :** `/login/status` 248 | 返回数据如下图: 249 | ![数据](https://ws2.sinaimg.cn/large/006tNbRwgy1fup6q18kk6j316i0nw0wa.jpg) 250 | 251 | ### 获取用户详情 252 | 253 | 说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户详情 254 | 255 | **必选参数 :** `uid` : 用户 id 256 | 257 | **接口地址 :** `/user/detail` 258 | 259 | **调用例子 :** `/user/detail?uid=32953014` 260 | 261 | ### 获取用户信息 , 歌单,收藏,mv, dj 数量 262 | 263 | 说明 : 登录后调用此接口 , 可以获取用户信息 264 | 265 | **接口地址 :** `/user/subcount` 266 | 267 | **调用例子 :** `/user/subcount` 268 | 269 | ### 更新用户信息 270 | 271 | 说明 : 登录后调用此接口 , 传入相关信息,可以更新用户信息 272 | 273 | **必选参数 :** 274 | 275 | ``` 276 | gender: 性别 0:保密 1:男性 2:女性 277 | birthday: 出生日期,时间戳 unix timestamp 278 | nickname: 用户昵称 279 | province: 省份id 280 | city: 城市id 281 | signature:用户签名 282 | ``` 283 | 284 | **接口地址 :** `/user/subcount` 285 | 286 | **调用例子 :** `/user/update/?gender=0&signature=测试签名&city=440300&nickname=binary&birthday=1525918298004&province=440000` 287 | 288 | ### 获取用户歌单 289 | 290 | 说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户歌单 291 | 292 | **必选参数 :** `uid` : 用户 id 293 | 294 | **接口地址 :** `/user/playlist` 295 | 296 | **调用例子 :** `/user/playlist?uid=32953014` 297 | 298 | 返回数据如下图 : 299 | ![用户歌单](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E7%94%A8%E6%88%B7%E6%AD%8C%E5%8D%95.png) 300 | 301 | ### 更新歌单 302 | 303 | 说明 : 登录后调用此接口,可以更新用户歌单 304 | 参数: 305 | 306 | ``` 307 | id:歌单id 308 | name:歌单名字 309 | desc:歌单描述 310 | tags:歌单tag 311 | ``` 312 | 313 | **接口地址 :** `/playlist/update` 314 | 315 | **调用例子 :** `/playlist/update/?id=24381616&name=新歌单&desc=描述&tags=学习` 316 | 317 | ### 发送私信 318 | 319 | 说明 : 登录后调用此接口 , 传入用户 id 和要发送的信息, 可以发送私信,返回内容为历史私信,包含带歌单的私信信息(注:不能发送私信给自己) 320 | 321 | **必选参数 :** 322 | 323 | `user_ids` : 用户 id,多个需用逗号隔开 324 | 325 | `msg` : 要发送的信息 326 | 327 | **接口地址 :** `/send/text` 328 | 329 | **调用例子 :** `/send/text?user_ids=32953014&msg=test`,`/send/text?user_ids=32953014,475625142&msg=test` 330 | 返回数据如下图: 331 | ![数据](https://ws1.sinaimg.cn/large/006tKfTcgy1fr3p3hfeudj31kw1aek2e.jpg) 332 | 333 | ### 发送私信(带歌单) 334 | 335 | 说明 : 登录后调用此接口 , 传入用户 id 和要发送的信息和歌单 id, 可以发送带歌单的私信(注:不能发送重复的歌单) 336 | 337 | **必选参数 :** 338 | 339 | `user_ids` : 用户 id,多个需用逗号隔开 340 | 341 | `msg` : 要发送的信息 342 | 343 | **接口地址 :** `/send/playlist` 344 | 345 | **调用例子 :** `/send/playlist?msg=test&user_ids=475625142&playlist=705123491`,`/send/playlist?msg=test2&user_ids=475625142,32953014&playlist=705123493` 346 | 返回数据如下图: 347 | ![数据](https://ws1.sinaimg.cn/large/006tKfTcgy1fr3p1z7qmcj30v409adg5.jpg) 348 | 349 | ### 获取用户电台 350 | 351 | 说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户电台 352 | 353 | **必选参数 :** `uid` : 用户 id 354 | 355 | **接口地址 :** `/user/dj` 356 | 357 | **调用例子 :** `/user/dj?uid=32953014` 358 | 359 | ### 获取用户关注列表 360 | 361 | 说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户关注列表 362 | 363 | **必选参数 :** `uid` : 用户 id 364 | 365 | **可选参数 :** 366 | `limit` : 返回数量 , 默认为 30 367 | 368 | `offset` : 偏移数量,用于分页 , 如 369 | : 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 370 | 371 | **接口地址 :** `/user/follows` 372 | 373 | **调用例子 :** `/user/follows?uid=32953014` 374 | 375 | ### 获取用户粉丝列表 376 | 377 | 说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户粉丝列表 378 | 379 | **必选参数 :** `uid` : 用户 id 380 | 381 | **可选参数 :** `limit` : 返回数量 , 默认为 30 `offset` : 偏移数量,用于分页 , 如 382 | : 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 383 | 384 | **接口地址 :** `/user/followeds` 385 | 386 | **调用例子 :** `/user/followeds?uid=32953014` 387 | 388 | ### 获取用户动态 389 | 390 | 说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户动态 391 | 392 | **必选参数 :** `uid` : 用户 id 393 | 394 | **接口地址 :** `/user/event` 395 | 396 | **调用例子 :** `/user/event?uid=32953014` 397 | 398 | ### 获取用户播放记录 399 | 400 | 说明 : 登录后调用此接口 , 传入用户 id, 可获取用户播放记录 401 | 402 | **必选参数 :** `uid` : 用户 id 403 | 404 | **可选参数 :** `type` : type=1 时只返回 weekData, type=0 时返回 allData 405 | 406 | **接口地址 :** `/user/record` 407 | 408 | **调用例子 :** `/user/record?uid=32953014&type=1` 409 | 410 | ### 获取动态消息 411 | 412 | 说明 : 调用此接口 , 可获取各种动态 , 对应网页版网易云,朋友界面里的各种动态消息 413 | ,如分享的视频,音乐,照片等! 414 | 415 | **必选参数 :** 未知 416 | 417 | **接口地址 :** `/event` 418 | 419 | **调用例子 :** `/event` 420 | 421 | ### 歌手分类列表 422 | 423 | 说明 : 调用此接口,可获取歌手分类列表 424 | **必选参数 :** `cat` : 即 category Code,歌手类型,默认 1001,返回华语男歌手数据 425 | **可选参数 :** 426 | `limit` : 返回数量 , 默认为 30 427 | 428 | `offset` : 偏移数量,用于分页 , 如 429 | : 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 430 | `initial`: 按首字母索引查找参数,如 `/artist/list?cat=1001&initial=b` 返回内容将以 name 字段开头为 b 或者拼音开头为 b 为顺序排列 431 | 432 | category Code 取值: 433 | 434 | ``` 435 | 入驻歌手 5001 436 | 华语男歌手 1001 437 | 华语女歌手 1002 438 | 华语组合/乐队 1003 439 | 欧美男歌手 2001 440 | 欧美女歌手 2002 441 | 欧美组合/乐队 2003 442 | 日本男歌手 6001 443 | 日本女歌手 6002 444 | 日本组合/乐队 6003 445 | 韩国男歌手 7001 446 | 韩国女歌手 7002 447 | 韩国组合/乐队 7003 448 | 其他男歌手 4001 449 | 其他女歌手 4002 450 | 其他组合/乐队 4003 451 | ``` 452 | 453 | **接口地址 :** `/artist/list` 454 | 455 | **调用例子 :** `/artist/list?cat=1001` 456 | 457 | 返回数据如下图: 458 | ![数据](https://ws1.sinaimg.cn/large/006tKfTcgy1fr60g9zps9j31kw1bpk4n.jpg) 459 | 460 | ### 收藏歌手 461 | 462 | 说明 : 调用此接口,可收藏歌手 463 | **必选参数 :** `artistId` : 歌手 id 464 | 465 | **接口地址 :** `/artist/sub` 466 | 467 | **调用例子 :** `/artist/sub?id=6452` 468 | 469 | ### 取消收藏歌手 470 | 471 | 说明 : 调用此接口,可取消收藏歌手 472 | **必选参数 :** `artistId` : 歌手 id 473 | 474 | **接口地址 :** `/artist/unsub` 475 | 476 | **调用例子 :** `/artist/unsub?id=6452` 477 | 478 | ### 收藏的歌手列表 479 | 480 | 说明 : 调用此接口,可获取收藏的歌手列表 481 | 482 | **接口地址 :** `/artist/sublist` 483 | 484 | **调用例子 :** `/artist/sublist` 485 | 486 | ### 歌单分类 487 | 488 | 说明 : 调用此接口,可获取歌单分类,包含 category 信息 489 | 490 | **接口地址 :** `/playlist/catlist` 491 | 492 | **调用例子 :** `/playlist/catlist` 493 | 494 | ### 热门歌单分类 495 | 496 | 说明 : 调用此接口,可获取歌单分类,包含 category 信息 497 | 498 | **接口地址 :** `/playlist/hot` 499 | 500 | **调用例子 :** `/playlist/hot` 501 | 502 | ### 歌单 ( 网友精选碟 ) 503 | 504 | 说明 : 调用此接口 , 可获取网友精选碟歌单 505 | 506 | **可选参数 :** `order`: 可选值为 'new' 和 'hot', 分别对应最新和最热 , 默认为 507 | 'hot' 508 | 509 | `cat`:`cat`: tag, 比如 " 华语 "、" 古风 " 、" 欧美 "、" 流行 ", 默认为 510 | "全部",可从歌单分类接口获取(/playlist/catlist) 511 | 512 | **接口地址 :** `/top/playlist` 513 | 514 | **调用例子 :** `/top/playlist?limit=10&order=new` 515 | 516 | 返回数据如下图 : 517 | 518 | ![精选碟](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/top_playlist.png) 519 | ![对应位置](https://ws2.sinaimg.cn/large/006tKfTcgy1fr3wnpyg6jj317e0vcqdc.jpg) 520 | ![返回数据](https://ws4.sinaimg.cn/large/006tKfTcgy1fr3wqs5lw9j31ic1re4c4.jpg) 521 | 522 | ### 获取精品歌单 523 | 524 | 说明 : 调用此接口 , 可获取精品歌单 525 | 526 | **可选参数 :** `cat`: tag, 比如 " 华语 "、" 古风 " 、" 欧美 "、" 流行 ", 默认为 527 | "全部",可从歌单分类接口获取(/playlist/catlist) 528 | 529 | `limit`: 取出歌单数量 , 默认为 20 530 | 531 | **接口地址 :** `/top/playlist/highquality` 532 | 533 | **调用例子 :** `/top/playlist/highquality?limit=30` 534 | 535 | ### 相关歌单推荐 536 | 537 | 说明 : 调用此接口,传入歌单 id 可获取相关歌单(对应页面 [https://music.163.com/#/playlist?id=1](https://music.163.com/#/playlist?id=1)) 538 | 539 | **必选参数 :** `id` : 歌单 id 540 | 541 | **接口地址 :** `/related/playlist` 542 | 543 | **调用例子 :** `/related/playlist?id=1` 544 | 545 | 546 | ### 获取歌单详情 547 | 548 | 说明 : 歌单能看到歌单名字 , 但看不到具体歌单内容 , 调用此接口 , 传入歌单 id, 可 549 | 以获取对应歌单内的所有的音乐 550 | 551 | **必选参数 :** `id` : 歌单 id 552 | 553 | **可选参数 :** `s` : 歌单最近的 s 个收藏者 554 | 555 | **接口地址 :** `/playlist/detail` 556 | 557 | **调用例子 :** `/playlist/detail?id=24381616` 558 | 559 | 返回数据如下图 : 560 | ![歌单详情](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E6%AD%8C%E5%8D%95%E8%AF%A6%E6%83%85.png) 561 | 562 | ### 获取音乐 url 563 | 564 | 说明 : 使用歌单详情接口后 , 能得到的音乐的 id, 但不能得到的音乐 url, 调用此接口 565 | , 传入的音乐 id( 可多个 , 用逗号隔开 ), 可以获取对应的音乐的 url( 不需要登录 ) 566 | 567 | > 注 : 部分用户反馈获取的 url 会 403,[hwaphon](https://github.com/hwaphon)找到的 568 | > 解决方案是当获取到音乐的 id 后,将 569 | > https://music.163.com/song/media/outer/url?id=id.mp3 以 src 赋予 Audio 即可播放 570 | 571 | **必选参数 :** `id` : 音乐 id 572 | 573 | **可选参数 :** `br`: 码率,默认设置了 999000 即最大码率,如果要 320k 则可设置为 320000,其他类推 574 | 575 | **接口地址 :** `/music/url` 576 | 577 | **调用例子 :** `/music/url?id=33894312` `/music/url?id=405998841,33894312` 578 | 579 | 返回数据如下图 : 580 | ![音乐 url](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E9%9F%B3%E4%B9%90%20url.png) 581 | 582 | ### 音乐是否可用 583 | 584 | 说明: 调用此接口,传入歌曲 id, 可获取音乐是否可用,返回 `{ success: true, message: 'ok' }` 或者 `{ success: false, message: '亲爱的,暂无版权' }` 585 | 586 | **必选参数 :** `id` : 歌曲 id 587 | 588 | **可选参数** : `br`: 码率,默认设置了 999000 即最大码率,如果要 320k 则可设置为 320000,其他类推 589 | 590 | **接口地址 :** `/check/music` 591 | 592 | **调用例子 :** `/check/music?id=33894312` 593 | 594 | ### 搜索 595 | 596 | 说明 : 调用此接口 , 传入搜索关键词可以搜索该音乐 / 专辑 / 歌手 / 歌单 / 用户 , 597 | 关键词可以多个 , 以空格隔开 , 如 " 周杰伦 搁浅 "( 不需要登录 ), 搜索获取的 598 | mp3url 不能直接用 , 可通过 `/music/url` 接口传入歌曲 id 获取具体的播放链接 599 | 600 | **必选参数 :** `keywords` : 关键词 601 | 602 | **可选参数 :** `limit` : 返回数量 , 默认为 30 `offset` : 偏移数量,用于分页 , 如 603 | : 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 604 | 605 | `type`: 搜索类型;默认为 1 即单曲 , 取值意义 : 1: 单曲, 10: 专辑, 100: 歌手, 1000: 606 | 歌单, 1002: 用户, 1004: MV, 1006: 歌词, 1009: 电台, 1014: 视频 607 | 608 | **接口地址 :** `/search` 609 | 610 | **调用例子 :** `/search?keywords= 海阔天空` 611 | 612 | 返回数据如下图 : 613 | ![搜索音乐](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E6%90%9C%E7%B4%A2.png) 614 | 615 | ### 热搜 616 | 617 | 说明 : 调用此接口,可获取热门搜索列表 618 | 619 | **接口地址 :** `/search/hot` 620 | 621 | **调用例子 :** `/search/hot` 622 | 623 | ### 搜索建议 624 | 625 | 说明 : 调用此接口 , 传入搜索关键词可获得搜索建议 , 搜索结果同时包含单曲 , 歌手 , 626 | 歌单 ,mv 信息 627 | 628 | **必选参数 :** `keywords` : 关键词 629 | 630 | **可选参数 :** 631 | `limit` : 返回数量 , 默认为 30 632 | 633 | `offset` : 偏移数量,用于分页 , 如 634 | : 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 635 | 636 | `type`: 搜索类型;默认为 1 即单曲 , 取值意义 : 1: 单曲 10: 专辑 100: 歌手 1000: 637 | 歌单 1002: 用户 1004: MV 1006: 歌词 1009: 电台 638 | 639 | **接口地址 :** `/search/suggest` 640 | 641 | **调用例子 :** `/search/suggest?keywords= 海阔天空` 642 | 643 | ### 搜索多重匹配 644 | 645 | 说明 : 调用此接口 , 传入搜索关键词可获得搜索结果 646 | 647 | **必选参数 :** `keywords` : 关键词 648 | 649 | **接口地址 :** `/search/multimatch` 650 | 651 | **调用例子 :** `/search/multimatch?keywords= 海阔天空` 652 | 653 | ### 新建歌单 654 | 655 | 说明 : 调用此接口 , 传入歌单名字可新建歌单 656 | 657 | **必选参数 :** `name` : 歌单名 658 | 659 | **接口地址 :** `/playlist/create` 660 | 661 | **调用例子 :** `/playlist/create?name=测试歌单` 662 | 663 | 返回数据如下图: 664 | ![数据](https://ws1.sinaimg.cn/large/006tKfTcgy1fr3va885z5j31a617qwjy.jpg) 665 | 666 | ### 收藏/取消收藏歌单 667 | 668 | 说明 : 调用此接口 , 传入类型和歌单 id 可收藏歌单或者取消收藏歌单 669 | 670 | **必选参数 :** 671 | `t` : 类型,1:收藏,2:取消收藏 672 | `id` : 歌单 id 673 | 674 | **接口地址 :** `/playlist/subscribe` 675 | 676 | **调用例子 :** `/playlist/subscribe?t=1&id=106697785` `/playlist/subscribe?t=2&id=106697785` 677 | 678 | 返回数据如下图: 679 | ![数据](https://ws1.sinaimg.cn/large/006tKfTcgy1fr3vdwx0hvj30s405u74b.jpg) 680 | 681 | ### 对歌单添加或删除歌曲 682 | 683 | 说明 : 调用此接口 , 可以添加歌曲到歌单或者从歌单删除某首歌曲 ( 需要登录 ) 684 | 685 | **必选参数 :** 686 | `op`: 从歌单增加单曲为 add, 删除为 del 687 | 688 | `pid`: 歌单 id 689 | `tracks`: 歌曲 id,可多个,用逗号隔开 690 | 691 | **接口地址 :** `/playlist/tracks` 692 | 693 | **调用例子 :** `/playlist/tracks?op=add&pid=24381616&tracks=347231` ( 对应把歌曲添加到 ' 我 ' 的歌单 , 测试的时候请把这里的 pid 换成你自己的, id 和 tracks 不对可能会报 502 错误) 694 | 695 | ### 获取歌词 696 | 697 | 说明 : 调用此接口 , 传入音乐 id 可获得对应音乐的歌词 ( 不需要登录 ) 698 | 699 | **必选参数 :** `id`: 音乐 id 700 | 701 | **接口地址 :** `/lyric` 702 | 703 | **调用例子 :** `/lyric?id=33894312` 704 | 705 | 返回数据如下图 : 706 | ![获取歌词](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E6%AD%8C%E8%AF%8D.png) 707 | 708 | ### 歌曲评论 709 | 710 | 说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该音乐的所有评论 ( 不需要 711 | 登录 ) 712 | 713 | **必选参数 :** `id`: 音乐 id 714 | 715 | **可选参数 :** `limit`: 取出评论数量 , 默认为 20 716 | 717 | `offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*20, 其中 20 为 limit 的值 718 | 719 | **接口地址 :** `/comment/music` 720 | 721 | **调用例子 :** `/comment/music?id=186016&limit=1` 对应晴天评论 722 | 723 | 返回数据如下图 : 724 | ![获取评论](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/comment.png) 725 | 726 | ### 专辑评论 727 | 728 | 说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该专辑的所有评论 ( 不需要 729 | 登录 ) 730 | 731 | **必选参数 :** `id`: 专辑 id 732 | 733 | **可选参数 :** `limit`: 取出评论数量 , 默认为 20 734 | 735 | `offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*20, 其中 20 为 limit 的值 736 | 737 | **接口地址 :** `/comment/album` 738 | 739 | **调用例子 :** `/comment/album?id=32311` 740 | 741 | ### 歌单评论 742 | 743 | 说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该歌单的所有评论 ( 不需要 744 | 登录 ) 745 | 746 | **必选参数 :** `id`: 歌单 id 747 | 748 | **可选参数 :** `limit`: 取出评论数量 , 默认为 20 749 | 750 | `offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*20, 其中 20 为 limit 的值 751 | 752 | **接口地址 :** `/comment/playlist` 753 | 754 | **调用例子 :** `/comment/playlist?id=705123491` 755 | 756 | ### mv 评论 757 | 758 | 说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该 mv 的所有评论 ( 不需要 759 | 登录 ) 760 | 761 | **必选参数 :** `id`: mv id 762 | 763 | **可选参数 :** `limit`: 取出评论数量 , 默认为 20 764 | 765 | `offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*20, 其中 20 为 limit 的值 766 | 767 | **接口地址 :** `/comment/mv` 768 | 769 | **调用例子 :** `/comment/mv?id=5436712` 770 | 771 | ### 电台节目评论 772 | 773 | 说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该 电台节目 的所有评论 ( 774 | 不需要登录 ) 775 | 776 | **必选参数 :** `id`: 电台节目的 id 777 | 778 | **可选参数 :** `limit`: 取出评论数量 , 默认为 20 779 | 780 | `offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*20, 其中 20 为 limit 的值 781 | 782 | **接口地址 :** `/comment/dj` 783 | 784 | **调用例子 :** `/comment/dj?id=794062371` 785 | 786 | ### 视频评论 787 | 788 | 说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该 视频 的所有评论 ( 789 | 不需要登录 ) 790 | 791 | **必选参数 :** `id`: 视频的 id 792 | 793 | **可选参数 :** `limit`: 取出评论数量 , 默认为 20 794 | 795 | `offset`: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)\*20, 其中 20 为 limit 的值 796 | 797 | **接口地址 :** `/comment/video` 798 | 799 | **调用例子 :** `/comment/video?id=89ADDE33C0AAE8EC14B99F6750DB954D` 800 | 801 | ### 热门评论 802 | 803 | 说明 : 调用此接口 , 传入 type, 资源 id 可获得对应资源热门评论 ( 不需要登录 ) 804 | 805 | **必选参数 :** 806 | 807 | `id` : 资源 id 808 | 809 | `type`: 数字 , 资源类型 , 对应歌曲 , mv, 专辑 , 歌单 , 电台, 视频对应以下类型 810 | 811 | ``` 812 | 0: 歌曲 813 | 1: mv 814 | 2: 歌单 815 | 3: 专辑 816 | 4: 电台 817 | 5: 视频 818 | ``` 819 | 820 | **接口地址 :** `/comment/hot` 821 | 822 | **调用例子 :** `/comment/hot?id=186016&type=0` 823 | 824 | ### 给评论点赞 825 | 826 | 说明 : 调用此接口 , 传入 type, 资源 id, 和评论 id cid 和 是否点赞参数 t 即可给对 827 | 应评论点赞 ( 需要登录 ) 828 | 829 | **必选参数 :** `id` : 资源 id, 如歌曲 id,mv id 830 | 831 | `cid` : 评论 id 832 | 833 | `t` : 是否点赞 ,1 为点赞 ,0 为取消点赞 834 | 835 | `type`: 数字 , 资源类型 , 对应歌曲 , mv, 专辑 , 歌单 , 电台, 视频对应以下类型 836 | 837 | ``` 838 | 0: 歌曲 839 | 1: mv 840 | 2: 歌单 841 | 3: 专辑 842 | 4: 电台 843 | 5: 视频 844 | ``` 845 | 846 | **接口地址 :** `comment/like` 847 | 848 | **调用例子 :** `/comment/like?id=29178366&cid=12840183&t=1&type=0` 对应给 [https://music.163.com/#/song?id=29178366](https://music.163.com/#/song?id=29178366) 最热门的评论点赞 849 | 850 | ### 发送/删除评论 851 | 852 | 说明 : 调用此接口,可发送评论或者删除评论 853 | 854 | **接口地址 :** `/comment` 855 | 856 | 1. 发送评论 857 | 858 | **必选参数** 859 | `action`:1 发送 860 | 861 | `type`: 数字,资源类型,对应歌曲,mv,专辑,歌单,电台,视频对应以下类型 862 | 863 | ``` 864 | 0: 歌曲 865 | 1: mv 866 | 2: 歌单 867 | 3: 专辑 868 | 4: 电台 869 | 5: 视频 870 | ``` 871 | 872 | `id`:对应资源 id 873 | 874 | `content` :要发送的内容 875 | 876 | **调用例子** : `/comment?action=1&type=1&id=5436712&content=test` (往广岛之恋 mv 发送评论: test) 877 | 878 | 2. 删除评论 879 | 880 | **必选参数** 881 | `action`:0 删除 882 | 883 | `type`: 数字,资源类型,对应歌曲,mv,专辑,歌单,电台,视频对应以下类型 884 | 885 | ``` 886 | 0: 歌曲 887 | 1: mv 888 | 2: 歌单 889 | 3: 专辑 890 | 4: 电台 891 | 5: 视频 892 | ``` 893 | 894 | `id`:对应资源 id 895 | `content` :内容 id,可通过 `/comment/mv` 等接口获取 896 | 897 | **调用例子** : `/comment?action=0&type=1&id=5436712&commentId=1535550516319` (在广岛之恋 mv 删除评论) 898 | 899 | ### banner 900 | 901 | 说明 : 调用此接口 , 可获取 banner( 轮播图 ) 数据注 : 因参数未知 , 只能获取比较旧 902 | 的数据 , 如果有知道参数的小伙伴 , 可提交 PR 903 | 904 | **接口地址 :** `/banner` 905 | 906 | **调用例子 :** `/banner` 907 | 908 | ### 获取歌曲详情 909 | 910 | 说明 : 调用此接口 , 传入音乐 id, 可获得歌曲详情(注意:歌曲封面现在需要通过专辑内容接口获取) 911 | 912 | **必选参数 :** `ids`: 音乐 id, 如 `ids=347230` 913 | 914 | **接口地址 :** `/song/detail` 915 | 916 | **调用例子 :** `/song/detail?ids=347230` 917 | 918 | 返回数据如下图 : 919 | ![获取歌曲详情](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/songDetail.png) 920 | 921 | ### 获取专辑内容 922 | 923 | 说明 : 调用此接口 , 传入专辑 id, 可获得专辑内容 924 | 925 | **必选参数 :** `id`: 专辑 id 926 | 927 | **接口地址 :** `/album` 928 | 929 | **调用例子 :** `/album?id=32311` 930 | 931 | 返回数据如下图 : 932 | ![获取专辑内容](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E4%B8%93%E8%BE%91.png) 933 | 934 | ### 获取歌手单曲 935 | 936 | 说明 : 调用此接口 , 传入歌手 id, 可获得歌手部分信息和热门歌曲 937 | 938 | **必选参数 :** `id`: 歌手 id, 可由搜索接口获得 939 | 940 | **接口地址 :** `/artists` 941 | 942 | **调用例子 :** `/artists?id=6452` 943 | 944 | 返回数据如下图 : 945 | ![获取歌手单曲](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/artists.png) 946 | 947 | ### 获取歌手 mv 948 | 949 | 说明 : 调用此接口 , 传入歌手 id, 可获得歌手 mv 信息 , 具体 mv 播放地址可调 950 | 用`/mv`传入此接口获得的 mvid 来拿到 , 如 : 951 | `/artist/mv?id=6452`,`/mv?mvid=5461064` 952 | 953 | **必选参数 :** `id`: 歌手 id, 可由搜索接口获得 954 | 955 | **接口地址 :** `/artist/mv` 956 | 957 | **调用例子 :** `/artist/mv?id=6452` 958 | 959 | ### 获取歌手专辑 960 | 961 | 说明 : 调用此接口 , 传入歌手 id, 可获得歌手专辑内容 962 | 963 | **必选参数 :** `id`: 歌手 id 964 | 965 | **可选参数 :** `limit`: 取出数量 , 默认为 50 966 | 967 | `offset`: 偏移数量 , 用于分页 , 如 :( 页数 -1)\*50, 其中 50 为 limit 的值 , 默认 968 | 为 0 969 | 970 | **接口地址 :** `/artist/album` 971 | 972 | **调用例子 :** `/artist/album?id=6452&limit=30` ( 周杰伦 ) 973 | 974 | 返回数据如下图 : 975 | ![获取专辑内容](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/artist_album.png) 976 | 977 | ### 获取歌手描述 978 | 979 | 说明 : 调用此接口 , 传入歌手 id, 可获得歌手描述 980 | 981 | **必选参数 :** `id`: 歌手 id 982 | 983 | **接口地址 :** `/artist/desc` 984 | 985 | **调用例子 :** `/artist/desc?id=6452` ( 周杰伦 ) 986 | 987 | ### 获取相似歌手 988 | 989 | 说明 : 调用此接口 , 传入歌手 id, 可获得相似歌手 990 | 991 | **必选参数 :** `id`: 歌手 id 992 | 993 | **接口地址 :** `/simi/artist` 994 | 995 | **调用例子 :** `/simi/artist?id=6452` ( 对应和周杰伦相似歌手 ) 996 | 997 | ### 获取相似歌单 998 | 999 | 说明 : 调用此接口 , 传入歌曲 id, 可获得相似歌单 1000 | 1001 | **必选参数 :** `id`: 歌曲 id 1002 | 1003 | **接口地址 :** `/simi/playlist` 1004 | 1005 | **调用例子 :** `/simi/playlist?id=347230` ( 对应 ' 光辉岁月 ' 相似歌单 ) 1006 | 1007 | ### 相似 mv 1008 | 1009 | 说明 : 调用此接口 , 传入 `mvid` 可获取相似 mv 1010 | 1011 | **必选参数 :** `mvid`: mv id 1012 | 1013 | **接口地址 :** `/simi/mv` 1014 | 1015 | **调用例子 :** `/simi/mv?mvid=5436712` 1016 | 1017 | ### 获取相似音乐 1018 | 1019 | 说明 : 调用此接口 , 传入歌曲 id, 可获得相似歌曲 1020 | 1021 | **必选参数 :** `id`: 歌曲 id 1022 | 1023 | **接口地址 :** `/simi/song` 1024 | 1025 | **调用例子 :** `/simi/song?id=347230` ( 对应 ' 光辉岁月 ' 相似歌曲 ) 1026 | 1027 | ### 获取最近 5 个听了这首歌的用户 1028 | 1029 | 说明 : 调用此接口 , 传入歌曲 id, 最近 5 个听了这首歌的用户 1030 | 1031 | **必选参数 :** `id`: 歌曲 id 1032 | 1033 | **接口地址 :** `/simi/user` 1034 | 1035 | **调用例子 :** `/simi/user?id=347230` ( 对应 ' 光辉岁月 ' 相似歌曲 ) 1036 | 1037 | ### 获取每日推荐歌单 1038 | 1039 | 说明 : 调用此接口 , 可获得每日推荐歌单 ( 需要登录 ) 1040 | 1041 | **接口地址 :** `/recommend/resource` 1042 | 1043 | **调用例子 :** `/recommend/resource` 1044 | 1045 | 返回数据如下图 : 1046 | ![每日推荐歌单](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E6%8E%A8%E8%8D%90%E6%AD%8C%E5%8D%95.png) 1047 | 1048 | ### 获取每日推荐歌曲 1049 | 1050 | 说明 : 调用此接口 , 可获得每日推荐歌曲 ( 需要登录 ) 1051 | 1052 | **接口地址 :** `/recommend/songs` 1053 | 1054 | **调用例子 :** `/recommend/songs` 1055 | 1056 | 返回数据如下图 : 1057 | ![每日推荐歌曲](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E6%8E%A8%E8%8D%90%E6%AD%8C%E6%9B%B2.png) 1058 | 1059 | ### 私人 FM 1060 | 1061 | 说明 : 私人 FM( 需要登录 ) 1062 | 1063 | **接口地址 :** `/personal_fm` 1064 | 1065 | **调用例子 :** `/personal_fm` 1066 | 1067 | 返回数据如下图 : 1068 | 1069 | ![私人 FM](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/personal_fm.png) 1070 | 1071 | ### 签到 1072 | 1073 | 说明 : 调用此接口 , 传入签到类型 ( 可不传 , 默认安卓端签到 ), 可签到 ( 需要登录 1074 | ), 其中安卓端签到可获得 3 点经验 , web/PC 端签到可获得 2 点经验 1075 | 1076 | **可选参数 :** `type`: 签到类型 , 默认 0, 其中 0 为安卓端签到 ,1 为 web/PC 签到 1077 | 1078 | **接口地址 :** `/daily_signin` 1079 | 1080 | **调用例子 :** `/daily_signin` 1081 | 1082 | 返回数据如下图 : 1083 | 1084 | ![签到成功](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/signinSuccess.png) 1085 | 1086 | ![签到失败](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/signinError.png) 1087 | 1088 | ### 喜欢音乐 1089 | 1090 | 说明 : 调用此接口 , 传入音乐 id, 可喜欢该音乐 1091 | 1092 | **必选参数 :** `id`: 歌曲 id 1093 | 1094 | **可选参数 :** `like`: 布尔值 , 默认为 true 即喜欢 , 若传 false, 则取消喜欢 1095 | 1096 | **接口地址 :** `/like` 1097 | 1098 | **调用例子 :** `/like?id=347230` 1099 | 1100 | 返回数据如下图 : 1101 | 1102 | ![喜欢成功](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/like.png) 1103 | 1104 | 喜欢成功则返回数据的 code 为 200, 其余为失败 1105 | 1106 | ![喜欢成功截图](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/likeSuccess.png) 1107 | 1108 | ### 垃圾桶 1109 | 1110 | 说明 : 调用此接口 , 传入音乐 id, 可把该音乐从私人 FM 中移除至垃圾桶 1111 | 1112 | **必选参数 :** `id`: 歌曲 id 1113 | 1114 | **接口地址 :** `/fm_trash` 1115 | 1116 | **调用例子 :** `/fm_trash?id=347230` 1117 | 1118 | 返回数据如下图 : 1119 | 1120 | ![移除成功](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/fm_trash.png) 1121 | 1122 | ### 新碟上架 1123 | 1124 | 说明 : 调用此接口 , 可获取新碟上架列表 , 如需具体音乐信息需要调用获取专辑列表接 1125 | 口 `/album` , 然后传入 id, 如 `/album?id=32311&limit=30` 1126 | 1127 | **可选参数 :** `limit`: 取出数量 , 默认为 50 1128 | 1129 | `offset`: 偏移数量 , 用于分页 , 如 :( 页数 -1)\*50, 其中 50 为 limit 的值 , 默认 1130 | 为 0 1131 | 1132 | **接口地址 :** `/top/album` 1133 | 1134 | **调用例子 :** `/top/album?offset=0&limit=30` 1135 | 1136 | 返回数据如下图 : 1137 | 1138 | ![新碟上架](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/new_albums.png) 1139 | 1140 | ### 热门歌手 1141 | 1142 | 说明 : 调用此接口 , 可获取热门歌手数据 1143 | 1144 | **可选参数 :** `limit`: 取出数量 , 默认为 50 1145 | 1146 | `offset`: 偏移数量 , 用于分页 , 如 :( 页数 -1)\*50, 其中 50 为 limit 的值 , 默认 1147 | 为 0 1148 | 1149 | **接口地址 :** `/top/artists` 1150 | 1151 | **调用例子 :** `/top/artists?offset=0&limit=30` 1152 | 1153 | 返回数据如下图 : 1154 | 1155 | ![热门歌手](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/top_artists.png) 1156 | 1157 | ### 最新 mv 1158 | 1159 | 说明 : 调用此接口 , 可获取最新 mv 1160 | 1161 | **可选参数 :** `limit`: 取出数量 , 默认为 30 1162 | 1163 | **接口地址 :** `/mv/first` 1164 | 1165 | **调用例子 :** `/mv/first?limit=10` 1166 | 1167 | ### 推荐 mv 1168 | 1169 | 说明 : 调用此接口 , 可获取推荐 mv 1170 | 1171 | **接口地址 :** `/personalized/mv` 1172 | 1173 | **调用例子 :** `/personalized/mv` 1174 | 1175 | ### 推荐歌单 1176 | 1177 | 说明 : 调用此接口 , 可获取推荐歌单 1178 | 1179 | **接口地址 :** `/personalized` 1180 | 1181 | **调用例子 :** `/personalized` 1182 | 1183 | ### 推荐新音乐 1184 | 1185 | 说明 : 调用此接口 , 可获取推荐新音乐 1186 | 1187 | **接口地址 :** `/personalized/newsong` 1188 | 1189 | **调用例子 :** `/personalized/newsong` 1190 | 1191 | ### 推荐电台 1192 | 1193 | 说明 : 调用此接口 , 可获取推荐电台 1194 | 1195 | **接口地址 :** `/personalized/djprogram` 1196 | 1197 | **调用例子 :** `/personalized/djprogram` 1198 | 1199 | ### 推荐节目 1200 | 1201 | 说明 : 调用此接口 , 可获取推荐电台 1202 | 1203 | **接口地址 :** `/program/recommend` 1204 | 1205 | **调用例子 :** `/program/recommend` 1206 | 1207 | ### 独家放送 1208 | 1209 | 说明 : 调用此接口 , 可获取独家放送 1210 | 1211 | **接口地址 :** `/personalized/privatecontent` 1212 | 1213 | **调用例子 :** `/personalized/privatecontent` 1214 | 1215 | ### mv 排行 1216 | 1217 | 说明 : 调用此接口 , 可获取 mv 排行 1218 | 1219 | **可选参数 :** `limit`: 取出数量 , 默认为 30 1220 | 1221 | `offset`: 偏移数量 , 用于分页 , 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认 1222 | 为 0 1223 | 1224 | **接口地址 :** `top/mv` 1225 | 1226 | **调用例子 :** `top/mv?limit=10` 1227 | 1228 | ### 获取 mv 数据 1229 | 1230 | 说明 : 调用此接口 , 传入 mvid ( 在搜索音乐的时候传 type=1004 获得 ) , 可获取对应 1231 | MV 数据 , 数据包含 mv 名字 , 歌手 , 发布时间 , mv 视频地址等数据 , 其中 mv 视频 1232 | 网易做了防盗链处理 , 可能不能直接播放 , 需要播放的话需要调用 ' 播放 mv/视频' 接口 1233 | 1234 | **必选参数 :** `mvid`: mv 的 id 1235 | 1236 | **接口地址 :** `/mv` 1237 | 1238 | **调用例子 :** `/mv?mvid=5436712` 1239 | 1240 | 返回数据如下图 : 1241 | 1242 | ![热门歌手](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/mv.png) 1243 | 1244 | ### 获取视频数据 1245 | 1246 | 说明 : 调用此接口 , 传入视频的 id ( 在搜索音乐的时候传 type=1014 获得 ) , 可获取对应 1247 | 视频数据,其中视频网易做了防盗链处理 , 可能不能直接播放 , 需要播放的话需要调用 ' 播放 mv/视频' 接口 1248 | 1249 | **必选参数 :** `id`: 视频 的 id 1250 | 1251 | **接口地址 :** `/video` 1252 | 1253 | **调用例子 :** `/video?id=89ADDE33C0AAE8EC14B99F6750DB954D` 1254 | 1255 | 返回数据如下图 : 1256 | 1257 | ![视频数据](https://ws1.sinaimg.cn/large/006tNbRwgy1fuqdv10p5rj31kw0da76y.jpg) 1258 | 1259 | ### 播放 mv/视频 1260 | 1261 | 说明 : 调用此接口 , 传入 mv/视频 地址 , 可播放 mv/视频, 也可将接口嵌入 video 标签使用 , 由 1262 | 于使用了 'pipe', 进度条无法通过拖动进度条控制进度 , 如有解决方案可提出 PR 或者自 1263 | 行改造 1264 | 1265 | **可选参数 :** `url`: mv/视频 的 地址 1266 | 1267 | **接口地址 :** `/mv/url` 1268 | 1269 | **调用例子 :** 1270 | `/mv/url?url=http://v4.music.126.net/20170422034915/c98eab2f5e2c85fc8de2ab3f0f8ed1c6/web/cloudmusic/MjQ3NDQ3MjUw/89a6a279dc2acfcd068b45ce72b1f560/533e4183a709699d566180ed0cd9abe9.mp4` 1271 | 1272 | 如下图 : 1273 | 1274 | ![播放视频](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/play_mv.png) 1275 | 1276 | ### 排行榜 1277 | 1278 | 说明 : 调用此接口 , 传入数字 idx, 可获取不同排行榜 1279 | 1280 | **必选参数 :** `idx`: 对象 key, 对应以下排行榜 1281 | 1282 | ``` 1283 | "0": 云音乐新歌榜, 1284 | "1": 云音乐热歌榜, 1285 | "2": 网易原创歌曲榜, 1286 | "3": 云音乐飙升榜, 1287 | "4": 云音乐电音榜, 1288 | "5": UK排行榜周榜, 1289 | "6": 美国Billboard周榜 1290 | "7": KTV嗨榜, 1291 | "8": iTunes榜, 1292 | "9": Hit FM Top榜, 1293 | "10": 日本Oricon周榜 1294 | "11": 韩国Melon排行榜周榜, 1295 | "12": 韩国Mnet排行榜周榜, 1296 | "13": 韩国Melon原声周榜, 1297 | "14": 中国TOP排行榜(港台榜), 1298 | "15": 中国TOP排行榜(内地榜) 1299 | "16": 香港电台中文歌曲龙虎榜, 1300 | "17": 华语金曲榜, 1301 | "18": 中国嘻哈榜, 1302 | "19": 法国 NRJ EuroHot 30周榜, 1303 | "20": 台湾Hito排行榜, 1304 | "21": Beatport全球电子舞曲榜, 1305 | "22": 云音乐ACG音乐榜, 1306 | "23": 云音乐嘻哈榜 1307 | ``` 1308 | 1309 | **接口地址 :** `/top/list` 1310 | 1311 | **调用例子 :** `/top/list?idx=6` 1312 | 1313 | 返回数据如下图 : 1314 | 1315 | ![排行榜](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/top_list.png) 1316 | 1317 | ### 歌手榜 1318 | 1319 | 说明 : 调用此接口 , 可获取 PC 版排行榜中的歌手榜 1320 | 1321 | **接口地址 :** `/toplist/artist` 1322 | 1323 | **调用例子 :** `/toplist/artist` 1324 | 1325 | ### 云盘 1326 | 1327 | 说明 : 登录后调用此接口 , 可获取云盘数据 , 获取的数据没有对应 url, 需要再调用一 1328 | 次 `/music/url` 获取 url 1329 | 1330 | **接口地址 :** `/user/cloud` 1331 | 1332 | **调用例子 :** `/user/cloud` 1333 | 1334 | ### 电台 - 推荐 1335 | 1336 | 说明 : 登录后调用此接口 , 可获得推荐电台 1337 | 1338 | **接口地址 :** `/dj/recommend` 1339 | 1340 | **调用例子 :** `/dj/recommend` 1341 | 1342 | ### 电台 - 分类 1343 | 1344 | 说明 : 登录后调用此接口 , 可获得电台类型 1345 | 1346 | **接口地址 :** `/dj/catelist` 1347 | 1348 | **调用例子 :** `/dj/catelist` 1349 | 1350 | ### 电台 - 分类推荐 1351 | 1352 | 说明 : 登录后调用此接口 , 可获得推荐电台 1353 | 1354 | **必选参数 :** `type`: 电台类型 , 数字 , 可通过`/dj/catelist`获取 , 对应关系为 1355 | id 对应 此接口的 type, name 对应类型意义 1356 | 1357 | **接口地址 :** `/dj/recommend/type` 1358 | 1359 | **调用例子 :** `/dj/recommend/type?type=1` 1360 | 1361 | ### 电台 - 订阅 1362 | 1363 | 说明 : 登录后调用此接口 , 传入`rid`, 可订阅 dj,dj 的 `rid` 可通过搜索指定 1364 | type='1009' 获取其 id, 如`/search?keywords= 代码时间 &type=1009` 1365 | 1366 | **必选参数 :** `rid`: 电台 的 id 1367 | 1368 | **接口地址 :** `/dj/sub` 1369 | 1370 | **调用例子 :** `/dj/sub?rid=336355127&t=1` ( 对应关注 ' 代码时间 ') 1371 | `/dj/sub?rid=336355127&t=0` ( 对应取消关注 ' 代码时间 ') 1372 | 1373 | ### 电台的订阅列表 1374 | 1375 | 说明 : 登录后调用此接口 , 可获取订阅的电台列表 1376 | 1377 | **接口地址 :** `/dj/sublist` 1378 | 1379 | **调用例子 :** `/dj/sublist` 1380 | 1381 | ### 电台 - 付费精选 1382 | 1383 | 说明 : 可以获取付费精选的电台列表 , 传入 `limit` 和 `offset` 可以进行分页 1384 | 1385 | **接口地址 :** `/dj/paygift` 1386 | 1387 | **调用例子 :** `/dj/paygift?limit=10&offset=20` 1388 | 1389 | ### 电台 - 详情 1390 | 1391 | 说明 : 登录后调用此接口 , 传入`rid`, 可获得对应电台的详情介绍 1392 | 1393 | **必选参数 :** `rid`: 电台 的 id 1394 | 1395 | **接口地址 :** `/dj/detail?rid=336355127` 1396 | 1397 | **调用例子 :** `/dj/detail?rid=336355127` ( 对应 ' 代码时间 ' 的详情介绍 ) 1398 | 1399 | ### 电台 - 节目 1400 | 1401 | 说明 : 登录后调用此接口 , 传入`rid`, 可查看对应电台的电台节目以及对应的 id, 需要 1402 | 注意的是这个接口返回的 mp3Url 已经无效 , 都为 null, 但是通过调用 `/music/url` 这 1403 | 个接口 , 传入节目 mainTrackId 仍然能获取到节目音频 , 如 `/music/url?id=478446370` 获取代 1404 | 码时间的一个节目的音频 1405 | 1406 | **必选参数 :** `rid`: 电台 的 id 1407 | 1408 | **可选参数 :** 1409 | `limit` : 返回数量 , 默认为 30 1410 | 1411 | `offset` : 偏移数量,用于分页 , 如 1412 | : 如 :( 页数 -1)\*30, 其中 30 为 limit 的值 , 默认为 0 1413 | 1414 | **接口地址 :** `/dj/program` 1415 | 1416 | **调用例子 :** `/dj/program?rid=336355127&limit=40` ( 对应 ' 代码时间 ' 的节目列表 ) 1417 | 1418 | ## 离线访问此文档 1419 | 1420 | 此文档同时也是 Progressive Web Apps(PWA), 加入了 serviceWorker, 可离线访问 1421 | 1422 | ## 关于此文档 1423 | 1424 | 此文档由 [docsify](https://github.com/QingWei-Li/docsify/) 生成 docsify 是一个动 1425 | 态生成文档网站的工具。不同于 GitBook、Hexo 的地方是它不会生成将 .md 转成 .html 1426 | 文件,所有转换工作都是在运行时进行。 1427 | 1428 | ## License 1429 | 1430 | [The MIT License (MIT)](https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/LICENSE) 1431 | -------------------------------------------------------------------------------- /docs/开发指南.md: -------------------------------------------------------------------------------- 1 | # 写个开发者的开发指南 2 | 3 | ### 开发 4 | - 克隆项目 `git clone git@github.com:2061360308/NeteaseCloudMusic_PythonSDK.git` 5 | - 安装依赖 `pip install -r requirements.txt` 6 | - 目录/文件说明 7 | ``` 8 | ├── package 项目包根目录 9 | ├── test_gender 生成测试代码的脚本 10 | ├── test.py 手动测试/ 使用示例 11 | ``` 12 | 13 | #### 更新 14 | 项目使用towncrier自动生成更新日志 15 | 16 | 在 newsfragments 目录下,创建一个新的文本文件。这个文件的名字应该是一个唯一的编号,后缀是 .rst。 17 | 例如,如果你正在处理编号为 123 的问题,你可以创建一个名为 123.feature.rst 的文件。 18 | 19 | 注意在 towncrier 中,新闻片段的类型通常由文件名的后缀决定。以下是一些常见的新闻片段类型: 20 | - .feature: 用于描述新的特性或者功能。 21 | - .bugfix: 用于描述一个 bug 修复。 22 | - .doc: 用于描述文档的更改。 23 | - .removal: 用于描述移除的特性或者功能。 24 | - .misc: 用于描述其他类型的更改。 25 | - 26 | 在这个文件中,写下你的更改的描述。这个描述应该是简短的,通常只有一到两句话。 27 | 例如`Added support for the XYZ feature.` 28 | 29 | #### 发布新版本 30 | 自动: 31 | 运行 python publish.py 32 | 33 | 手动: 34 | 使用bumpversion自动更新版本号,提交并发布标签 35 | 你需要安装bumpversion然后执行 36 | ```bash 37 | bumpversion patch # for a patch level increase (e.g., 1.0.0 to 1.0.1) 38 | bumpversion minor # for a minor level increase (e.g., 1.0.0 to 1.1.0) 39 | bumpversion major # for a major level increase (e.g., 1.0.0 to 2.0.0) 40 | ``` 41 | 42 | 接下来会自动更新版本号并提交到远程仓库,然后发布一个新的标签 43 | workflow会依据标签自动发布相应资源并且发布到pypi -------------------------------------------------------------------------------- /example.py: -------------------------------------------------------------------------------- 1 | """ 2 | description: 网易云音乐API使用示例,这个示例引导你进行登录操作,然后下载一首歌曲 3 | author: LuTong 4 | date: 2020-10-07 10:00 5 | """ 6 | from pprint import pprint 7 | 8 | import requests 9 | 10 | from NeteaseCloudMusic import NeteaseCloudMusicApi, api_help, api_list 11 | 12 | netease_cloud_music_api = NeteaseCloudMusicApi() # 初始化API 13 | 14 | version_result = netease_cloud_music_api.request("inner_version") 15 | print( 16 | f'当前使用NeteaseCloudMusicApi版本号:{version_result["NeteaseCloudMusicApi"]}\n当前使用NeteaseCloudMusicApi_V8版本号:{version_result["NeteaseCloudMusicApi_V8"]}') # 退出登录 17 | 18 | 19 | 20 | def captcha_sent(_phone): 21 | response = netease_cloud_music_api.request("/captcha/sent", {"phone": f"{_phone}"}) 22 | return response 23 | 24 | 25 | def login_cellphone(_phone, _captcha): 26 | response = netease_cloud_music_api.request("/login/cellphone", {"phone": f"{_phone}", "captcha": f"{_captcha}"}) 27 | return response 28 | 29 | 30 | def song_url_v1(song_id): 31 | # 获取歌曲mp3地址 32 | response = netease_cloud_music_api.request("song_url_v1", {"id": song_id, "level": "exhigh"}) 33 | return response 34 | 35 | 36 | def song_detail(song_id): 37 | # 获取歌曲详情 38 | response = netease_cloud_music_api.request("song_detail", {"ids": str(song_id)}) 39 | # 这里记得传一个字符串,其实所有参数都传字符串就行,需要数字的话内部会自己转换的,但是它默认你传入的时候是字符串,所以你传数字他不会自动转字符串, 40 | # 这时如果遇到操作字符串的方法就会报错,所以最好都传字符串,避免出现意外 41 | return response 42 | 43 | 44 | def login_status(): 45 | response = netease_cloud_music_api.request("/login/status") 46 | return response 47 | 48 | 49 | # 登录 50 | if not netease_cloud_music_api.cookie: 51 | print("请设置cookie") 52 | phone = input("请输入手机号:") 53 | result = captcha_sent(phone) 54 | print(result) 55 | if result.get("code") == 200: 56 | print("验证码已发送,请查收") 57 | captcha = input("请输入验证码:") 58 | result = login_cellphone(phone, captcha) 59 | if result.get("code") == 200: 60 | print("登录成功") 61 | if netease_cloud_music_api.cookie: 62 | print("cookie已自动设置") 63 | else: 64 | print("登录失败") 65 | """ 66 | 调用登录接口后,会自动设置cookie,如果cookie失效,需要重新登录,登录过后api会在你的当前工作目录下创建cookie_storage文件保存你的cookie 67 | 在下次调用运行程序时,他会判断cookie是否过期,没有过期就自动读取cookie_storage文件中的cookie。 68 | 69 | 总的来说你不需要手动管理cookie,只需要调用登录接口,然后调用其他接口即可,cookie会自动设置,如果cookie过期,再次调用登录接口就好。 70 | 更好的办法是,在cookie还没有失效之前使用refresh_login接口刷新cookie,这样就不需要重新登录了(建议在你每次启动软件时都刷新,当然频繁重启调试的时候另算) 71 | 72 | 如果你想判断当前是否已经登录,if not netease_cloud_music_api.cookie 就可以了,或者调用/login/status接口 73 | """ 74 | 75 | # 获取登录状态 76 | login_status_result = login_status() 77 | # pprint(login_status_result) 78 | if login_status_result['data']['data']["code"] == 200: 79 | print(f'当前登录账号:{login_status_result["data"]["data"]["profile"]["nickname"]}') 80 | 81 | version_result = netease_cloud_music_api.request("inner_version") 82 | print( 83 | f'当前使用NeteaseCloudMusicApi版本号:{version_result["NeteaseCloudMusicApi"]}\n当前使用NeteaseCloudMusicApi_V8版本号:{version_result["NeteaseCloudMusicApi_V8"]}') # 退出登录 84 | 85 | # 获取歌曲mp3地址 86 | song_url_result = song_url_v1(33894312) 87 | if song_url_result.get("code") == 200: 88 | song_url = song_url_result['data']["data"][0]['url'] 89 | else: 90 | print("获取歌曲mp3地址失败") 91 | exit(1) 92 | # 获取歌曲详情 93 | song_detail_result = song_detail(33894312) 94 | if song_detail_result.get("code") == 200: 95 | song_name = song_detail_result['data']['songs'][0]['name'] 96 | song_artist = song_detail_result['data']['songs'][0]['ar'][0]['name'] 97 | else: 98 | print("获取歌曲详情失败") 99 | exit(1) 100 | # 下载歌曲mp3 101 | print(f"正在下载歌曲:{song_name} - {song_artist}") 102 | result = requests.get(song_url) 103 | with open(f"{song_name} - {song_artist}.mp3", "wb") as f: 104 | f.write(result.content) 105 | print("下载完成") 106 | 107 | """ 108 | 示例程序结束,如果你运行成功了,那么你的执行目录下应该有一个cookie_storage文件,里面保存了你的cookie,还有一个mp3文件,就是你下载的歌曲 109 | 有关其他API的使用方法请参考:https://docs.neteasecloudmusicapi.binaryify.com/ 110 | 111 | 再次注明一下,我之前也想过要不要将登录状态管理和cookie刷新等等封装到NeteaseCloudMusicApi类中, 112 | 但最后我想的是,这毕竟这是一个api接口类,就让他保持最原始简洁的状态就好,其他的留给大家去自由发挥吧! 113 | 114 | 友情提示:单个账户每天发送验证码的次数有限制,千万别一直调试登录接口。 115 | """ 116 | -------------------------------------------------------------------------------- /package/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2023 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. -------------------------------------------------------------------------------- /package/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md LICENSE NeteaseCloudMusic/NeteaseCloudMusicApi.js -------------------------------------------------------------------------------- /package/NeteaseCloudMusic.egg-info/PKG-INFO: -------------------------------------------------------------------------------- 1 | Metadata-Version: 2.1 2 | Name: NeteaseCloudMusic 3 | Version: 0.1.7 4 | Summary: 网易云音乐API NeteaseCloudMusicApi项目的 Python SDK 5 | Home-page: https://github.com/2061360308/NeteaseCloudMusic_PythonSDK 6 | Author: 盧瞳 7 | Author-email: 2061360308@qq.com 8 | License: MIT 9 | Classifier: License :: OSI Approved :: MIT License 10 | Classifier: Programming Language :: Python 11 | Classifier: Programming Language :: Python :: 3 12 | Classifier: Programming Language :: Python :: 3.6 13 | Classifier: Programming Language :: Python :: Implementation :: CPython 14 | Classifier: Programming Language :: Python :: Implementation :: PyPy 15 | Requires-Python: >=3.6.0 16 | Description-Content-Type: text/markdown 17 | License-File: LICENSE 18 | 19 | 20 | 21 | # NeteaseCloudMusic_PythonSDK 22 | > 基于 [ NeteaseCloudMusicApi](https://github.com/Binaryify/NeteaseCloudMusicApi) 封装的 Python SDK。 23 | > 网易云API Python版本。 24 | > 现已同步原项目接口且测试通过的有200多个 25 | > 已发布到PyPi,可直接使用pip安装 26 | > 项目地址:[GitHub](https://github.com/2061360308/NeteaseCloudMusic_PythonSDK) 27 | 28 | ![](https://img.shields.io/badge/py_mini_racer-@0.6.0-red.svg) 29 | ![License](https://img.shields.io/badge/license-MIT-yellow) 30 | 31 | ### 依赖于 32 | - [ NeteaseCloudMusicApi](https://github.com/Binaryify/NeteaseCloudMusicApi) 33 | - [ NeteaseCloudMusicApi_V8 ](https://github.com/2061360308/NeteaseCloudMusicApi_V8) 34 | 35 | ### 原理 36 | - 通过 `py_mini_racer` 调用 `NeteaseCloudMusicApi_V8` 的 `js` 方法。进一步进行了简单封装。 37 | 38 | ### 使用 39 | - 安装 `pip install NeteaseCloudMusic` 40 | - 导入API进行使用(具体查看`example.py`中的示例) 41 | ```python 42 | from NeteaseCloudMusic import NeteaseCloudMusicApi, api_help, api_list 43 | import os 44 | 45 | netease_cloud_music_api = NeteaseCloudMusicApi() # 初始化API 46 | netease_cloud_music_api.cookie = "你的cookie" # 设置cookie, 如果没有cookie需要先登录 具体见example.py 47 | response = netease_cloud_music_api.request("song_url_v1", {"id": 33894312, "level": "exhigh"}) # 调用API 48 | 49 | # 获取帮助 50 | print(api_help()) 51 | print(api_help('song_url_v1')) 52 | # 获取API列表 53 | print(api_list()) 54 | ``` 55 | 56 | > 注意: request(self, name, query=None) 的第一个参数为API名称,第二个参数为API参数,具体API名称和参数请参考 [NeteaseCloudMusicApi文档](https://docs.neteasecloudmusicapi.binaryify.com),name支持`/song/url/v1`和`song_url_v1`两种写法。 57 | 58 | > api已加入自动缓存,在测试接口时,如果频繁调用获取结果在query里应该加上timestamp参数来区分,例如 59 | > ```python 60 | > response = netease_cloud_music_api.request("song_url_v1", {"id": 33894312, "level": "exhigh", "timestamp": time.time()}) 61 | > ``` 62 | 63 | ### 开发 64 | - 克隆项目 `git clone git@github.com:2061360308/NeteaseCloudMusic_PythonSDK.git` 65 | - 安装依赖 `pip install -r requirements.txt` 66 | - 目录/文件说明 67 | ``` 68 | ├── package 项目包根目录 69 | ├── test_gender 生成测试代码的脚本 70 | ├── test.py 手动测试/ 使用示例 71 | ``` 72 | 73 | ### 更新 74 | 项目使用towncrier自动生成更新日志 75 | 76 | 在 newsfragments 目录下,创建一个新的文本文件。这个文件的名字应该是一个唯一的编号,后缀是 .rst。 77 | 例如,如果你正在处理编号为 123 的问题,你可以创建一个名为 123.feature.rst 的文件。 78 | 79 | 注意在 towncrier 中,新闻片段的类型通常由文件名的后缀决定。以下是一些常见的新闻片段类型: 80 | - .feature: 用于描述新的特性或者功能。 81 | - .bugfix: 用于描述一个 bug 修复。 82 | - .doc: 用于描述文档的更改。 83 | - .removal: 用于描述移除的特性或者功能。 84 | - .misc: 用于描述其他类型的更改。 85 | - 86 | 在这个文件中,写下你的更改的描述。这个描述应该是简短的,通常只有一到两句话。 87 | 例如`Added support for the XYZ feature.` 88 | 89 | ### 发布新版本 90 | 使用bumpversion自动更新版本号,提交并发布标签 91 | 你需要安装bumpversion然后执行 92 | ```bash 93 | bumpversion patch # for a patch level increase (e.g., 1.0.0 to 1.0.1) 94 | bumpversion minor # for a minor level increase (e.g., 1.0.0 to 1.1.0) 95 | bumpversion major # for a major level increase (e.g., 1.0.0 to 2.0.0) 96 | ``` 97 | 98 | 接下来会自动更新版本号并提交到远程仓库,然后发布一个新的标签 99 | workflow会依据标签自动发布相应资源并且发布到pypi 100 | 101 | ### 改进 102 | > 下列API未支持 103 | > 104 | - apicache.js 105 | - memory-cache.js 106 | - request_reference.js 107 | - avatar_upload.js 108 | - cloud.js 109 | - playlist_cover_update.js 110 | - voice_upload.js 111 | - register_anonimous.js 112 | - verify_getQr.js 113 | 114 | > 以下api未测试(这些接口测试起来比较繁琐) 115 | > 116 | - /user/replacephone 117 | - /audio/match 118 | - /rebind 119 | - /nickname/check 120 | - /activate/init/profile 121 | - /cellphone/existence/check 122 | - /register/cellphone 123 | - /captcha/verify 124 | - /captcha/sent 125 | - /login/refresh 126 | - /logout 127 | - /user/update 128 | - /pl/count 129 | - /playlist/update 130 | - /playlist/desc/update 131 | - /playlist/name/update 132 | - /playlist/tags/update 133 | - /event/forward 134 | - /event/del 135 | - /share/resource 136 | - /send/text 137 | - /send/playlist 138 | - /playlist/create 139 | - /playlist/tracks 140 | - /daily_signin 141 | - /fm_trash 142 | 143 | ### 欢迎提交PR 144 | 145 | 更正request库返回多个cookie时自动用分号拼接导致后续cookie不好解析的问题 146 | 添加了对cookie中Max-Age为0的处理 147 | 改进判断cookie是否过期的逻辑 148 | 添加了自动处理cookie的更新操作 149 | -------------------------------------------------------------------------------- /package/NeteaseCloudMusic.egg-info/SOURCES.txt: -------------------------------------------------------------------------------- 1 | LICENSE 2 | MANIFEST.in 3 | README.md 4 | setup.py 5 | NeteaseCloudMusic/NeteaseCloudMusicApi.js 6 | NeteaseCloudMusic/__init__.py 7 | NeteaseCloudMusic/config.json 8 | NeteaseCloudMusic/help.py 9 | NeteaseCloudMusic/main.py 10 | NeteaseCloudMusic/utils.py 11 | NeteaseCloudMusic.egg-info/PKG-INFO 12 | NeteaseCloudMusic.egg-info/SOURCES.txt 13 | NeteaseCloudMusic.egg-info/dependency_links.txt 14 | NeteaseCloudMusic.egg-info/requires.txt 15 | NeteaseCloudMusic.egg-info/top_level.txt -------------------------------------------------------------------------------- /package/NeteaseCloudMusic.egg-info/dependency_links.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /package/NeteaseCloudMusic.egg-info/requires.txt: -------------------------------------------------------------------------------- 1 | py_mini_racer 2 | requests 3 | diskcache 4 | -------------------------------------------------------------------------------- /package/NeteaseCloudMusic.egg-info/top_level.txt: -------------------------------------------------------------------------------- 1 | NeteaseCloudMusic 2 | -------------------------------------------------------------------------------- /package/NeteaseCloudMusic/__init__.py: -------------------------------------------------------------------------------- 1 | from .main import NeteaseCloudMusicApi 2 | from .help import api_help, api_list 3 | from .utils import format_cookie_str, prase_cookie_str 4 | 5 | __version__ = '0.1.10' 6 | -------------------------------------------------------------------------------- /package/NeteaseCloudMusic/help.py: -------------------------------------------------------------------------------- 1 | import json 2 | import pkg_resources 3 | 4 | # 载入配置 5 | resource_path = pkg_resources.resource_filename(__name__, 'config.json') 6 | 7 | # 不被支持的接口 8 | exclude = ["/request/reference", "/avatar/upload", "/cloud", "/playlist/cover/update", "/voice/upload", 9 | "/register/anonimous", "/verify/getQr"] 10 | 11 | with open(resource_path, 'r', encoding='utf-8') as f: 12 | config = json.loads(f.read()) 13 | 14 | 15 | def api_help(name: str = None) -> str: 16 | """ 17 | 获取接口帮助 18 | :param name: 接口名称 19 | :return: 20 | """ 21 | if name is None: 22 | result_str = ("from NeteaseCloudMusic import NeteaseCloudMusicApi, api_help, api_list\n\n" 23 | "netease_cloud_music_api = NeteaseCloudMusicApi() # 初始化API\n" 24 | "netease_cloud_music_api.cookie = YOUR_COOKIE # 设置cookie\n" 25 | "response = netease_cloud_music_api.request(apiName, queryDict) # 调用接口\n\n" 26 | "# Use ”help(apiName)“ to view detailed information about the interface\n" 27 | "# Use ”api_list()“ to view the interface list") 28 | elif name in api_list(): 29 | result_str = f'name: {name}\n {config[name]["name"]}\n {config[name]["explain"]}\n\n' 30 | 31 | result_str += "query example: \n" 32 | for example in config[name]["example"]: 33 | index = config[name]["example"].index(example) 34 | result_str += f'{json.dumps(config[name]["example"][index]["query"], indent=2, ensure_ascii=False)}\n\n' 35 | else: 36 | result_str = f'apiName: {name} not found,please use ”api_list()“ to view the interface list' 37 | 38 | return result_str 39 | 40 | 41 | def api_list(): 42 | """ 43 | 获取接口列表 44 | :return: 45 | """ 46 | return [item for item in list(config.keys()) if item not in exclude] 47 | -------------------------------------------------------------------------------- /package/NeteaseCloudMusic/main.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os.path 3 | import socket 4 | import time 5 | from pprint import pprint 6 | import http.cookies 7 | import datetime 8 | from diskcache import Cache 9 | 10 | import pkg_resources 11 | import requests 12 | from py_mini_racer import py_mini_racer 13 | from .help import api_list 14 | from .utils import format_cookie_str, prase_cookie_str 15 | import urllib.parse 16 | 17 | 18 | class NeteaseCloudMusicApi: 19 | __cookie = None 20 | __ip = None 21 | 22 | cache = Cache('cache', timeout=120) # 设置缓存目录和过期时间 23 | 24 | # cache = TTLCache(maxsize=100, ttl=120) # 设置缓存大小为100,缓存项的生存时间为120秒 25 | 26 | def __init__(self, debug=False, cache=False): 27 | self.DEBUG = debug # 是否开启调试模式 28 | self.CACHE = cache # 是否开启缓存 29 | 30 | self.special_api = {"/playlist/track/all": self.playlist_track_all, 31 | "/login/cellphone": self.login_cellphone, 32 | "/inner/version": self.inner_version, 33 | "/login/refresh": self.login_refresh} 34 | 35 | # 载入js代码 36 | resource_path = pkg_resources.resource_filename(__name__, 'NeteaseCloudMusicApi.js') 37 | 38 | with open(resource_path, 'r', encoding='utf-8') as file: 39 | js_code = file.read() 40 | self.ctx = py_mini_racer.MiniRacer() 41 | self.ctx.eval(js_code) 42 | 43 | def request(self, name: str, query: dict = None) -> dict: 44 | """ 45 | 调用接口 46 | 接口文档地址: https://docs.neteasecloudmusicapi.binaryify.com 47 | :param name: api名称 例如: song_url_v1, /song/url/v1 48 | :param query: 请求参数 49 | :return: 请求结果 示例:{"code": 200, "data": {}, "msg": "success"} 50 | """ 51 | 52 | special = { 53 | 'daily_signin': '/daily_signin', 54 | 'fm_trash': '/fm_trash', 55 | 'personal_fm': '/personal_fm', 56 | } 57 | 58 | yubei_special = {'/yunbei/tasks/receipt': '/yunbei/receipt', 59 | '/yunbei/tasks/expense': '/yunbei/expense'} # 这俩个接口准换的路由莫名奇妙 60 | 61 | # 测试name是否合法 62 | name.replace("\\", "/") 63 | if not name.startswith("/"): 64 | if name in special.keys(): 65 | name = special[name] 66 | else: 67 | name = "/" + name 68 | name = name.replace("_", "/") 69 | 70 | # 处理俩个云贝接口名称转换问题 71 | if name in yubei_special.keys(): 72 | name = yubei_special[name] 73 | # print("转换了个麻烦的路由", name) 74 | 75 | if name not in api_list(): 76 | if name not in yubei_special.values(): 77 | raise Exception(f"apiName: {name} not found,please use ”api_list()“ to view the interface list") 78 | 79 | # 生成一个唯一的键,用于在缓存中查找结果 80 | cache_key = (name, frozenset(query.items()) if query else None) 81 | 82 | if self.CACHE: 83 | # 检查缓存中是否已经有了结果 84 | if self.cache.get(cache_key): 85 | return self.cache.get(cache_key) 86 | 87 | if query is None: 88 | query = {} 89 | else: 90 | # 如果存在timestamp参数,那么删除它 91 | if query.get("timestamp"): 92 | del query["timestamp"] 93 | 94 | if query.get("cookie") is None: 95 | query["cookie"] = self.cookie 96 | 97 | if query.get("realIP") is None: 98 | query["realIP"] = self.ip 99 | else: 100 | query["realIP"] = query.get("realIP") 101 | 102 | # 特殊api处理 103 | if name in self.special_api.keys(): 104 | result = self.special_api[name](query) 105 | else: 106 | result = self.call_api(name, query) 107 | 108 | if self.CACHE: 109 | # 将结果存入缓存 110 | self.cache.set(cache_key, result) 111 | 112 | return result 113 | 114 | @staticmethod 115 | def get_local_ip(): 116 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 117 | try: 118 | # doesn't even have to be reachable 119 | s.connect(('10.255.255.255', 1)) 120 | IP = s.getsockname()[0] 121 | except Exception: 122 | print("get local ip error") 123 | IP = "116.25.146.177" 124 | finally: 125 | s.close() 126 | return IP 127 | 128 | @property 129 | def cookie(self): 130 | if self.__cookie is None: 131 | if os.path.isfile("cookie_storage"): 132 | with open("cookie_storage", "r", encoding='utf-8') as f: 133 | content = f.read() 134 | try: 135 | cookie_storage = json.loads(content) 136 | # 验证cookie是否过期 137 | create_time_stamp = cookie_storage['create_time_stamp'] 138 | 139 | if time.time() - create_time_stamp > 1296010: 140 | # cookie过期了 141 | self.__cookie = "" 142 | else: 143 | # 判断cookie生成时间是否超过1天 144 | if time.time() - create_time_stamp > 86400: 145 | # 更新cookie 146 | # Todo login_refresh接口返回cookie好像少一些值 147 | # self.request("/login/refresh", {"cookie": cookie_storage['cookie'], "timestamp": time.time()}) 148 | self.cookie = cookie_storage['cookie'] 149 | else: 150 | self.__cookie = cookie_storage['cookie'] 151 | except json.JSONDecodeError and KeyError: 152 | self.__cookie = "" 153 | else: 154 | self.__cookie = "" # 如果没有cookie文件,就设置为空 155 | 156 | return self.__cookie 157 | 158 | @cookie.setter 159 | def cookie(self, value): 160 | if value is None: 161 | self.__cookie = "" 162 | return 163 | 164 | "判断cookie是否合法, 简单检查一下关键的键" 165 | necessary_keys = ["__csrf", "MUSIC_A_T", "MUSIC_R_T"] 166 | cookie_dict = prase_cookie_str(value) 167 | for key in necessary_keys: 168 | if cookie_dict.get(key) is None: 169 | raise Exception(f"cookie is illegal, missing key: {key}.") 170 | 171 | self.__cookie = value 172 | with open("cookie_storage", "w+", encoding='utf-8') as f: 173 | f.write(json.dumps({"cookie": value, "create_time_stamp": time.time()}, indent=2, ensure_ascii=False)) 174 | 175 | @property 176 | def ip(self): 177 | if self.__ip is None: 178 | self.__ip = self.get_local_ip() 179 | return self.__ip 180 | 181 | def call_api(self, name, query): 182 | request_param = self.ctx.call('NeteaseCloudMusicApi.beforeRequest', name, query) # 拿到请求头和请求参数 183 | 184 | # print(request_param) 185 | 186 | # Todo 了解 py_mini_racer 返回没有自动编码 而 node可以 187 | # from urllib.parse import unquote 188 | # param_data = {} 189 | # if request_param["data"] != "": 190 | # for item in request_param["data"].split("&"): 191 | # # param_data[item.split("=")[0]] = urllib.parse.quote(item.split("=")[1], safe='') # 不需要编码后反而出错 192 | # param_data[item.split("=")[0]] = unquote(item.split("=")[1]) 193 | 194 | if request_param.get("method") == "GET": 195 | response = requests.get(request_param["url"], params=request_param['data'], headers=request_param["headers"]) 196 | else: 197 | response = requests.post(request_param["url"], data=request_param['data'], headers=request_param["headers"]) 198 | 199 | try: 200 | data = json.loads(response.text) 201 | except json.JSONDecodeError: 202 | data = response.text 203 | 204 | response_result = { 205 | "headers": dict(response.headers), 206 | "data": data, 207 | "status": response.status_code, 208 | } 209 | 210 | result = self.ctx.call('NeteaseCloudMusicApi.afterRequest', 211 | response_result, 212 | request_param.get('crypto', None), 213 | request_param['apiName']) # 拿到请求结果 214 | 215 | return result 216 | 217 | def playlist_track_all(self, query): 218 | """ 219 | 获取歌单全部歌曲 220 | :param query: 221 | :return: 222 | """ 223 | 224 | detail_query = {"id": query.get("id"), "cookie": query.get("cookie"), "realIP": query.get("realIP")} 225 | 226 | result = self.call_api("/playlist/detail", detail_query) 227 | 228 | track_all_query = {"detail_result": json.dumps(result), "cookie": query.get("cookie"), 229 | "realIP": query.get("realIP")} 230 | if query.get("limit"): 231 | track_all_query["limit"] = query.get("limit") 232 | if query.get("offset"): 233 | track_all_query["offset"] = query.get("offset") 234 | 235 | result = self.call_api("/playlist/track/all", track_all_query) 236 | return result 237 | 238 | def inner_version(self, query): 239 | """ 240 | 获取所使用的 NeteaseCloudMusicApi 和 NeteaseCloudMusicApi_V8 版本号 241 | :param query: 242 | :return: 243 | """ 244 | result = self.ctx.call('NeteaseCloudMusicApi.inner_version') 245 | return result 246 | 247 | def login_cellphone(self, query): 248 | """ 249 | 手机号登录 250 | :param query: 251 | :return: 252 | """ 253 | result = self.call_api("/login/cellphone", query) 254 | 255 | # 自动 更新cookie 256 | if result["code"] == 200: 257 | if result.get("data").get("cookie"): 258 | # cookie_str = format_cookie_str(result.get("data").get("cookie")) 259 | cookie_str = result.get("data").get("cookie") 260 | result["data"]["cookie"] = cookie_str 261 | self.cookie = cookie_str 262 | return result 263 | 264 | def login_refresh(self, query): 265 | """ 266 | 刷新登录状态 267 | :param query: 268 | :return: 269 | """ 270 | result = self.call_api("/login/refresh", query) 271 | 272 | # 自动 更新cookie 273 | # if result["code"] == 200: 274 | # if result.get("data").get("cookie"): 275 | # # cookie_str = format_cookie_str(result.get("data").get("cookie")) 276 | # cookie_str = result.get("data").get("cookie") 277 | # result["data"]["cookie"] = cookie_str 278 | # pprint(cookie_str) 279 | # self.cookie = cookie_str 280 | return result 281 | -------------------------------------------------------------------------------- /package/NeteaseCloudMusic/utils.py: -------------------------------------------------------------------------------- 1 | from pprint import pprint 2 | 3 | 4 | def format_cookie_str(cookie_str: str) -> str: 5 | """ 6 | 格式化cookie字符串 7 | 功能 8 | 处理以逗号分割的cookie字符串 9 | 删除max-age为0的cookie 10 | 注意: 11 | 传入cookie字符串必须是以 逗号+空格 或 分号+空格 分割的规范cookie字符串 12 | :param cookie_str: 13 | :return: 格式化后的cookie str 14 | """ 15 | 16 | if not cookie_str: 17 | return "" 18 | 19 | # 解析cookie字符串 20 | cookie_dict = prase_cookie_str(cookie_str) 21 | 22 | cookie_valid_dict = {} 23 | # 删除max-age为0的cookie 24 | for item in cookie_dict.keys(): 25 | max_age = cookie_dict[item].get("Max-Age") 26 | if max_age: 27 | max_age = int(max_age) 28 | if max_age != 0: 29 | cookie_valid_dict[item] = cookie_dict[item] 30 | 31 | # 重新拼接cookie字符串 32 | cookie = "" 33 | for item in cookie_valid_dict.keys(): 34 | cookie += item + "=" + cookie_valid_dict[item]["value"] + "; " 35 | for key in cookie_valid_dict[item].keys(): 36 | if key != "value": 37 | cookie += key + "=" + cookie_valid_dict[item][key] + "; " 38 | 39 | return cookie[: -2] 40 | 41 | 42 | def prase_cookie_str(cookie_str: str) -> dict: 43 | """ 44 | 解析cookie字符串 45 | 功能 46 | 处理以逗号分割的cookie字符串 47 | 注意: 48 | 传入cookie字符串必须是以 逗号+空格 或 分号+空格 分割的规范cookie字符串 49 | :param cookie_str: 50 | :return: cookie dict 51 | """ 52 | if not cookie_str: 53 | return {} 54 | 55 | # 解决用逗号分割的问题 56 | cookie_part = [] 57 | for item in cookie_str.split(", "): 58 | cookie_part.extend(item.split("; ")) 59 | 60 | cookies = [] 61 | for item in cookie_part: 62 | if "=" not in item: 63 | # 属于上一个cookie的一部分 64 | cookies[-1] = cookies[-1] + item 65 | else: 66 | cookies.append(item) 67 | 68 | cookie_dict = {} 69 | 70 | current_name = "" 71 | for cookie in cookies: 72 | # print(cookie) 73 | if cookie[-1] == "=": 74 | name = cookie[:-1] 75 | value = "" 76 | else: 77 | part = cookie.split("=") 78 | name = part[0] 79 | value = part[1] 80 | 81 | if name in ["Max-Age", "Expires", "Path", "Domain"]: 82 | cookie_dict[current_name][name] = value 83 | else: 84 | cookie_dict[name] = {"value": value} 85 | current_name = name 86 | 87 | return cookie_dict 88 | 89 | 90 | if __name__ == '__main__': 91 | cookie = ("MUSIC_R_T=1579622000495; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; " 92 | "Path=/openapi/clientlog; Domain=.music.163.com, MUSIC_A_T=1579621885297; Max-Age=2147483647; Expires=Wed, " 93 | "02 Jan 2092 11:39:38 GMT; Path=/wapi/feedback; Domain=.music.163.com, __remember_me=true; " 94 | "Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/; Domain=.music.163.com, " 95 | "MUSIC_A_T=1579621885297; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/api/feedback; " 96 | "Domain=.music.163.com, MUSIC_A_T=1579621885297; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; " 97 | "Path=/eapi/clientlog; Domain=.music.163.com, MUSIC_A_T=1579621885297; Max-Age=2147483647; Expires=Wed, " 98 | "02 Jan 2092 11:39:38 GMT; Path=/api/clientlog; Domain=.music.163.com, MUSIC_R_T=1579622000495; " 99 | "Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/wapi/feedback; Domain=.music.163.com, " 100 | "MUSIC_A_T=1579621885297; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/weapi/clientlog; " 101 | "Domain=.music.163.com, MUSIC_R_T=1579622000495; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; " 102 | "Path=/neapi/feedback; Domain=.music.163.com, MUSIC_R_T=1579622000495; Max-Age=2147483647; Expires=Wed, " 103 | "02 Jan 2092 11:39:38 GMT; Path=/eapi/clientlog; Domain=.music.163.com, MUSIC_R_T=1579622000495; " 104 | "Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/api/feedback; Domain=.music.163.com, " 105 | "MUSIC_A_T=1579621885297; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/weapi/feedback; " 106 | "Domain=.music.163.com, MUSIC_R_T=1579622000495; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; " 107 | "Path=/eapi/feedback; Domain=.music.163.com, MUSIC_A_T=1579621885297; Max-Age=2147483647; Expires=Wed, " 108 | "02 Jan 2092 11:39:38 GMT; Path=/neapi/clientlog; Domain=.music.163.com, MUSIC_R_T=1579622000495; " 109 | "Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/wapi/clientlog; Domain=.music.163.com, " 110 | "MUSIC_A_T=1579621885297; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/wapi/clientlog; " 111 | "Domain=.music.163.com, MUSIC_R_T=1579622000495; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; " 112 | "Path=/weapi/feedback; Domain=.music.163.com, NMTID=00OLqRn-wykrFFXdElLpZA3_-aaQtIAAAGMbJSp9A; " 113 | "Max-Age=315360000; Expires=Mon, 12 Dec 2033 08:25:31 GMT; Path=/; Domain=music.163.com, " 114 | "__csrf=4d5e515015723fd3d7edaa5b05f35b4d; Max-Age=1296010; Expires=Sat, 30 Dec 2023 08:25:41 GMT; Path=/; " 115 | "Domain=.music.163.com, MUSIC_R_T=1579622000495; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; " 116 | "Path=/neapi/clientlog; Domain=.music.163.com, MUSIC_A_T=1579621885297; Max-Age=2147483647; Expires=Wed, " 117 | "02 Jan 2092 11:39:38 GMT; Path=/openapi/clientlog; Domain=.music.163.com, MUSIC_A_T=1579621885297; " 118 | "Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/eapi/feedback; Domain=.music.163.com, " 119 | "MUSIC_R_T=1579622000495; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/weapi/clientlog; " 120 | "Domain=.music.163.com, MUSIC_R_T=1579622000495; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; " 121 | "Path=/api/clientlog; Domain=.music.163.com, MUSIC_SNS=; Max-Age=0; Expires=Fri, 15 Dec 2023 08:25:31 GMT; " 122 | "Path=/, " 123 | "MUSIC_U=00CCEEF2F7A9825637C9869A455B5CA8E009D905415134A7EDAC2E404A940B2D58BFF7129A413193E9A8FD6D1D497E1E8E9023611BA91D2CB28FA94B53DBE4C42699A30FF1448C8EFAF5B00E73ADD353C52F2E004C094AEAC4BA4D83C6FFBB4CD532DEEAEA8D5584E69AC78110BBA682829C263DA72F5AA290AD826A47F640CA3903AC652E4DDE946ACC4EB8A63E5853FA695B480A919CF84498B7084C5CA9A91297F2CF5AF45C2D545AC0D5C03A1641306BAC0FB6FFD57BC653A91F2483FB52BFE85DE39280B012BC036DF244883D9700480E5FDDCD5A417C60241AE08CD6AA84BFC1C8890AE4A08286144D9D1146E33C67CF7797CDB5A961C85DB5AC492B232601D80D4DB07E4F170F635ABC01E080B4D32408FA0698DAD95AD80CDB99F2F672638048F5116214319175B596BF68B2A7A0269746EABFD919D62C165353725E6B1253A7C5D6774D453DDDCC28524D3378; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/; Domain=.music.163.com, MUSIC_A_T=1579621885297; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/neapi/feedback; Domain=.music.163.com") 124 | pprint(prase_cookie_str(cookie)) 125 | -------------------------------------------------------------------------------- /package/README.md: -------------------------------------------------------------------------------- 1 | # NeteaseCloudMusic_PythonSDK 2 | > 基于 [ NeteaseCloudMusicApi](https://github.com/Binaryify/NeteaseCloudMusicApi) 封装的 Python SDK。 3 | > 网易云API Python版本。 4 | > 现已同步原项目接口且测试通过的有200多个 5 | > 已发布到PyPi,可直接使用pip安装 6 | > 项目地址:[GitHub](https://github.com/2061360308/NeteaseCloudMusic_PythonSDK) 7 | 8 | ![](https://img.shields.io/badge/py_mini_racer-@0.6.0-red.svg) 9 | ![License](https://img.shields.io/badge/license-MIT-yellow) 10 | 11 | ### 依赖于 12 | - [ NeteaseCloudMusicApi](https://github.com/Binaryify/NeteaseCloudMusicApi) 13 | - [ NeteaseCloudMusicApi_V8 ](https://github.com/2061360308/NeteaseCloudMusicApi_V8) 14 | 15 | ### 原理 16 | - 通过 `py_mini_racer` 调用 `NeteaseCloudMusicApi_V8` 的 `js` 方法。进一步进行了简单封装。 17 | 18 | ### 使用 19 | - 安装 `pip install NeteaseCloudMusic` 20 | - 导入API进行使用(具体查看`example.py`中的示例) 21 | ```python 22 | from NeteaseCloudMusic import NeteaseCloudMusicApi, api_help, api_list 23 | import os 24 | 25 | netease_cloud_music_api = NeteaseCloudMusicApi() # 初始化API 26 | netease_cloud_music_api.cookie = "你的cookie" # 设置cookie, 如果没有cookie需要先登录 具体见example.py 27 | response = netease_cloud_music_api.request("song_url_v1", {"id": 33894312, "level": "exhigh"}) # 调用API 28 | 29 | # 获取帮助 30 | print(api_help()) 31 | print(api_help('song_url_v1')) 32 | # 获取API列表 33 | print(api_list()) 34 | ``` 35 | 36 | > 注意: request(self, name, query=None) 的第一个参数为API名称,第二个参数为API参数,具体API名称和参数请参考 [NeteaseCloudMusicApi文档](https://docs.neteasecloudmusicapi.binaryify.com),name支持`/song/url/v1`和`song_url_v1`两种写法。 37 | 38 | > api已加入自动缓存,在测试接口时,如果频繁调用获取结果在query里应该加上timestamp参数来区分,例如 39 | > ```python 40 | > response = netease_cloud_music_api.request("song_url_v1", {"id": 33894312, "level": "exhigh", "timestamp": time.time()}) 41 | > ``` 42 | 43 | ### 开发 44 | - 克隆项目 `git clone git@github.com:2061360308/NeteaseCloudMusic_PythonSDK.git` 45 | - 安装依赖 `pip install -r requirements.txt` 46 | - 目录/文件说明 47 | ``` 48 | ├── package 项目包根目录 49 | ├── test_gender 生成测试代码的脚本 50 | ├── test.py 手动测试/ 使用示例 51 | ``` 52 | 53 | ### 更新 54 | 项目使用towncrier自动生成更新日志 55 | 56 | 在 newsfragments 目录下,创建一个新的文本文件。这个文件的名字应该是一个唯一的编号,后缀是 .rst。 57 | 例如,如果你正在处理编号为 123 的问题,你可以创建一个名为 123.feature.rst 的文件。 58 | 59 | 注意在 towncrier 中,新闻片段的类型通常由文件名的后缀决定。以下是一些常见的新闻片段类型: 60 | - .feature: 用于描述新的特性或者功能。 61 | - .bugfix: 用于描述一个 bug 修复。 62 | - .doc: 用于描述文档的更改。 63 | - .removal: 用于描述移除的特性或者功能。 64 | - .misc: 用于描述其他类型的更改。 65 | - 66 | 在这个文件中,写下你的更改的描述。这个描述应该是简短的,通常只有一到两句话。 67 | 例如`Added support for the XYZ feature.` 68 | 69 | ### 发布新版本 70 | 使用bumpversion自动更新版本号,提交并发布标签 71 | 你需要安装bumpversion然后执行 72 | ```bash 73 | bumpversion patch # for a patch level increase (e.g., 1.0.0 to 1.0.1) 74 | bumpversion minor # for a minor level increase (e.g., 1.0.0 to 1.1.0) 75 | bumpversion major # for a major level increase (e.g., 1.0.0 to 2.0.0) 76 | ``` 77 | 78 | 接下来会自动更新版本号并提交到远程仓库,然后发布一个新的标签 79 | workflow会依据标签自动发布相应资源并且发布到pypi 80 | 81 | ### 改进 82 | > 下列API未支持 83 | > 84 | - apicache.js 85 | - memory-cache.js 86 | - request_reference.js 87 | - avatar_upload.js 88 | - cloud.js 89 | - playlist_cover_update.js 90 | - voice_upload.js 91 | - register_anonimous.js 92 | - verify_getQr.js 93 | 94 | > 以下api未测试(这些接口测试起来比较繁琐) 95 | > 96 | - /user/replacephone 97 | - /audio/match 98 | - /rebind 99 | - /nickname/check 100 | - /activate/init/profile 101 | - /cellphone/existence/check 102 | - /register/cellphone 103 | - /captcha/verify 104 | - /captcha/sent 105 | - /login/refresh 106 | - /logout 107 | - /user/update 108 | - /pl/count 109 | - /playlist/update 110 | - /playlist/desc/update 111 | - /playlist/name/update 112 | - /playlist/tags/update 113 | - /event/forward 114 | - /event/del 115 | - /share/resource 116 | - /send/text 117 | - /send/playlist 118 | - /playlist/create 119 | - /playlist/tracks 120 | - /daily_signin 121 | - /fm_trash 122 | 123 | ### 欢迎提交PR 124 | 125 | 更正request库返回多个cookie时自动用分号拼接导致后续cookie不好解析的问题 126 | 添加了对cookie中Max-Age为0的处理 127 | 改进判断cookie是否过期的逻辑 128 | 添加了自动处理cookie的更新操作 129 | -------------------------------------------------------------------------------- /package/build/lib/NeteaseCloudMusic/__init__.py: -------------------------------------------------------------------------------- 1 | from .main import NeteaseCloudMusicApi 2 | from .help import api_help, api_list 3 | from .utils import format_cookie_str, prase_cookie_str 4 | 5 | __version__ = '0.1.7' 6 | -------------------------------------------------------------------------------- /package/build/lib/NeteaseCloudMusic/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "/user/detail": { 3 | "name": "获取用户详情", 4 | "explain": "说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户详情", 5 | "example": [ 6 | { 7 | "query": { 8 | "uid": "32953014" 9 | } 10 | } 11 | ] 12 | }, 13 | "/user/account": { 14 | "name": "获取账号信息", 15 | "explain": "说明 : 登录后调用此接口 ,可获取用户账号信息", 16 | "example": [ 17 | { 18 | "query": {} 19 | } 20 | ] 21 | }, 22 | "/user/subcount": { 23 | "name": "获取用户信息 , 歌单,收藏,mv, dj 数量", 24 | "explain": "说明 : 登录后调用此接口 , 可以获取用户信息", 25 | "example": [ 26 | { 27 | "query": {} 28 | } 29 | ] 30 | }, 31 | "/user/level": { 32 | "name": "获取用户等级信息", 33 | "explain": "说明 : 登录后调用此接口 , 可以获取用户等级信息,包含当前登录天数,听歌次数,下一等级需要的登录天数和听歌次数,当前等级进度,对应 ", 34 | "example": [ 35 | { 36 | "query": {} 37 | } 38 | ] 39 | }, 40 | "/user/binding": { 41 | "name": "获取用户绑定信息", 42 | "explain": "说明 : 登录后调用此接口 , 可以获取用户绑定信息", 43 | "example": [ 44 | { 45 | "query": { 46 | "uid": "32953014" 47 | } 48 | } 49 | ] 50 | }, 51 | "/user/playlist": { 52 | "name": "获取用户歌单", 53 | "explain": "说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户歌单", 54 | "example": [ 55 | { 56 | "query": { 57 | "uid": "32953014" 58 | } 59 | } 60 | ] 61 | }, 62 | "/playlist/order/update": { 63 | "name": "调整歌单顺序", 64 | "explain": "说明 : 登录后调用此接口,可以根据歌单 id 顺序调整歌单顺序", 65 | "example": [ 66 | { 67 | "query": { 68 | "ids": "[111,222]" 69 | } 70 | } 71 | ] 72 | }, 73 | "/song/order/update": { 74 | "name": "调整歌曲顺序", 75 | "explain": "说明 : 登录后调用此接口,可以根据歌曲 id 顺序调整歌曲顺序", 76 | "example": [ 77 | { 78 | "query": { 79 | "pid": "2039116066", 80 | "ids": "[5268328,1219871]" 81 | } 82 | } 83 | ] 84 | }, 85 | "/user/comment/history": { 86 | "name": "获取用户历史评论", 87 | "explain": "说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户历史评论", 88 | "example": [ 89 | { 90 | "query": { 91 | "uid": "32953014" 92 | } 93 | }, 94 | { 95 | "query": { 96 | "uid": "32953014", 97 | "limit": "1", 98 | "time": "1616217577564" 99 | } 100 | } 101 | ] 102 | }, 103 | "/user/dj": { 104 | "name": "获取用户电台", 105 | "explain": "说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户电台", 106 | "example": [ 107 | { 108 | "query": { 109 | "uid": "32953014" 110 | } 111 | } 112 | ] 113 | }, 114 | "/user/follows": { 115 | "name": "获取用户关注列表", 116 | "explain": "说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户关注列表", 117 | "example": [ 118 | { 119 | "query": { 120 | "uid": "32953014" 121 | } 122 | } 123 | ] 124 | }, 125 | "/user/followeds": { 126 | "name": "获取用户粉丝列表", 127 | "explain": "说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户粉丝列表", 128 | "example": [ 129 | { 130 | "query": { 131 | "uid": "32953014" 132 | } 133 | }, 134 | { 135 | "query": { 136 | "uid": "416608258", 137 | "limit": "1" 138 | } 139 | }, 140 | { 141 | "query": { 142 | "uid": "416608258", 143 | "limit": "1", 144 | "offset": "1" 145 | } 146 | } 147 | ] 148 | }, 149 | "/user/event": { 150 | "name": "获取用户动态", 151 | "explain": "说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户动态", 152 | "example": [ 153 | { 154 | "query": { 155 | "uid": "32953014" 156 | } 157 | }, 158 | { 159 | "query": { 160 | "uid": "32953014", 161 | "limit": "1", 162 | "lasttime": "1558011138743" 163 | } 164 | } 165 | ] 166 | }, 167 | "/comment/event": { 168 | "name": "获取动态评论", 169 | "explain": "说明 : 登录后调用此接口 , 可以获取动态下评论", 170 | "example": [ 171 | { 172 | "query": { 173 | "threadId": "A_EV_2_6559519868_32953014" 174 | } 175 | } 176 | ] 177 | }, 178 | "/follow": { 179 | "name": "关注/取消关注用户", 180 | "explain": "说明 : 登录后调用此接口 , 传入用户 id, 和操作 t,可关注/取消关注用户", 181 | "example": [ 182 | { 183 | "query": { 184 | "id": "32953014", 185 | "t": "1" 186 | } 187 | } 188 | ] 189 | }, 190 | "/user/record": { 191 | "name": "获取用户播放记录", 192 | "explain": "说明 : 登录后调用此接口 , 传入用户 id, 可获取用户播放记录", 193 | "example": [ 194 | { 195 | "query": { 196 | "uid": "32953014", 197 | "type": "1" 198 | } 199 | } 200 | ] 201 | }, 202 | "/hot/topic": { 203 | "name": "获取热门话题", 204 | "explain": "说明 : 调用此接口 , 可获取热门话题", 205 | "example": [ 206 | { 207 | "query": { 208 | "limit": "30", 209 | "offset": "30" 210 | } 211 | } 212 | ] 213 | }, 214 | "/topic/detail": { 215 | "name": "获取话题详情", 216 | "explain": "说明 : 调用此接口 , 可获取话题详情", 217 | "example": [ 218 | { 219 | "query": { 220 | "actid": "111551188" 221 | } 222 | } 223 | ] 224 | }, 225 | "/topic/detail/event/hot": { 226 | "name": "获取话题详情热门动态", 227 | "explain": "说明 : 调用此接口 , 可获取话题详情热门动态", 228 | "example": [ 229 | { 230 | "query": { 231 | "actid": "111551188" 232 | } 233 | } 234 | ] 235 | }, 236 | "/playmode/intelligence/list": { 237 | "name": "心动模式/智能播放", 238 | "explain": "说明 : 登录后调用此接口 , 可获取心动模式/智能播放列表\n", 239 | "example": [ 240 | { 241 | "query": { 242 | "id": "33894312", 243 | "pid": "24381616" 244 | } 245 | }, 246 | { 247 | "query": { 248 | "id": "33894312", 249 | "pid": "24381616", 250 | "sid": "36871368" 251 | } 252 | } 253 | ] 254 | }, 255 | "/event": { 256 | "name": "获取动态消息", 257 | "explain": "说明 : 调用此接口 , 可获取各种动态 , 对应网页版网易云,朋友界面里的各种动态消息\n,如分享的视频,音乐,照片等!", 258 | "example": [ 259 | { 260 | "query": { 261 | "pagesize": "30", 262 | "lasttime": "1556740526369" 263 | } 264 | } 265 | ] 266 | }, 267 | "/artist/list": { 268 | "name": "歌手分类列表", 269 | "explain": "说明 : 调用此接口,可获取歌手分类列表", 270 | "example": [ 271 | { 272 | "query": { 273 | "type": "1", 274 | "area": "96", 275 | "initial": "b" 276 | } 277 | }, 278 | { 279 | "query": { 280 | "type": "2", 281 | "area": "2", 282 | "initial": "b" 283 | } 284 | } 285 | ] 286 | }, 287 | "/artist/sub": { 288 | "name": "收藏/取消收藏歌手", 289 | "explain": "说明 : 调用此接口,可收藏歌手", 290 | "example": [ 291 | { 292 | "query": { 293 | "id": "6452", 294 | "t": "1" 295 | } 296 | } 297 | ] 298 | }, 299 | "/artist/top/song": { 300 | "name": "歌手热门 50 首歌曲", 301 | "explain": "说明 : 调用此接口,可获取歌手热门 50 首歌曲", 302 | "example": [ 303 | { 304 | "query": { 305 | "id": "6452" 306 | } 307 | } 308 | ] 309 | }, 310 | "/artist/songs": { 311 | "name": "歌手全部歌曲", 312 | "explain": "说明 : 调用此接口,可获取歌手全部歌曲\n", 313 | "example": [ 314 | { 315 | "query": { 316 | "id": "6452" 317 | } 318 | } 319 | ] 320 | }, 321 | "/artist/sublist": { 322 | "name": "收藏的歌手列表", 323 | "explain": "说明 : 调用此接口,可获取收藏的歌手列表 ", 324 | "example": [ 325 | { 326 | "query": {} 327 | } 328 | ] 329 | }, 330 | "/topic/sublist": { 331 | "name": "收藏的专栏", 332 | "explain": "说明 : 调用此接口,可获取收藏的专栏", 333 | "example": [ 334 | { 335 | "query": { 336 | "limit": "2", 337 | "offset": "1" 338 | } 339 | } 340 | ] 341 | }, 342 | "/video/sub": { 343 | "name": "收藏视频", 344 | "explain": "说明 : 调用此接口,可收藏视频", 345 | "example": [ 346 | { 347 | "query": { 348 | "id": "5659C0B60C6D1C63662BC698C603D961", 349 | "t": 1 350 | } 351 | } 352 | ] 353 | }, 354 | "/mv/sub": { 355 | "name": "收藏/取消收藏 MV", 356 | "explain": "说明 : 调用此接口,可收藏/取消收藏 MV", 357 | "example": [ 358 | { 359 | "query": { 360 | "mvid": "5344234", 361 | "t": 1 362 | } 363 | } 364 | ] 365 | }, 366 | "/mv/sublist": { 367 | "name": "收藏的 MV 列表", 368 | "explain": "说明 : 调用此接口,可获取收藏的 MV 列表", 369 | "example": [ 370 | { 371 | "query": {} 372 | } 373 | ] 374 | }, 375 | "/playlist/catlist": { 376 | "name": "歌单分类", 377 | "explain": "说明 : 调用此接口,可获取歌单分类,包含 category 信息", 378 | "example": [ 379 | { 380 | "query": {} 381 | } 382 | ] 383 | }, 384 | "/playlist/hot": { 385 | "name": "热门歌单分类", 386 | "explain": "说明 : 调用此接口,可获取歌单分类,包含 category 信息", 387 | "example": [ 388 | { 389 | "query": {} 390 | } 391 | ] 392 | }, 393 | "/top/playlist": { 394 | "name": "歌单 ( 网友精选碟 )", 395 | "explain": "说明 : 调用此接口 , 可获取网友精选碟歌单", 396 | "example": [ 397 | { 398 | "query": { 399 | "limit": "10" 400 | } 401 | } 402 | ] 403 | }, 404 | "/playlist/highquality/tags": { 405 | "name": "精品歌单标签列表", 406 | "explain": "说明 : 调用此接口 , 可获取精品歌单标签列表", 407 | "example": [ 408 | { 409 | "query": {} 410 | } 411 | ] 412 | }, 413 | "/top/playlist/highquality": { 414 | "name": "获取精品歌单", 415 | "explain": "说明 : 调用此接口 , 可获取精品歌单", 416 | "example": [ 417 | { 418 | "query": { 419 | "before": "1503639064232", 420 | "limit": "3" 421 | } 422 | } 423 | ] 424 | }, 425 | "/related/playlist": { 426 | "name": "相关歌单推荐", 427 | "explain": "说明 : 调用此接口,传入歌单 id 可获取相关歌单(对应页面 ", 428 | "example": [ 429 | { 430 | "query": { 431 | "id": "1" 432 | } 433 | } 434 | ] 435 | }, 436 | "/playlist/detail": { 437 | "name": "获取歌单详情", 438 | "explain": "说明 : 歌单能看到歌单名字, 但看不到具体歌单内容 , 调用此接口 , 传入歌单 id, 可\n以获取对应歌单内的所有的音乐(未登录状态只能获取不完整的歌单,登录后是完整的),但是返回的 trackIds 是完整的,tracks 则是不完整的,可拿全部 trackIds 请求一次 ", 439 | "example": [ 440 | { 441 | "query": { 442 | "id": "24381616" 443 | } 444 | } 445 | ] 446 | }, 447 | "/playlist/track/all": { 448 | "name": "获取歌单所有歌曲", 449 | "explain": "说明 : 由于网易云接口限制,歌单详情只会提供 10 首歌,通过调用此接口,传入对应的歌单", 450 | "example": [ 451 | { 452 | "query": { 453 | "id": "24381616", 454 | "limit": "10", 455 | "offset": "1" 456 | } 457 | } 458 | ] 459 | }, 460 | "/playlist/detail/dynamic": { 461 | "name": "歌单详情动态", 462 | "explain": "说明 : 调用后可获取歌单详情动态部分,如评论数,是否收藏,播放数", 463 | "example": [ 464 | { 465 | "query": { 466 | "id": "24381616" 467 | } 468 | } 469 | ] 470 | }, 471 | "/playlist/update/playcount": { 472 | "name": "歌单更新播放量", 473 | "explain": "说明 : 调用后可更新歌单播放量", 474 | "example": [ 475 | { 476 | "query": { 477 | "id": "24381616" 478 | } 479 | } 480 | ] 481 | }, 482 | "/song/url/v1": { 483 | "name": "获取音乐 url - 新版", 484 | "explain": "说明 : 使用歌单详情接口后 , 能得到的音乐的 id, 但不能得到的音乐 url, 调用此接口, 传入的音乐 id( 可多个 , 用逗号隔开 ), 可以获取对应的音乐的 url,未登录状态或者非会员返回试听片段(返回字段包含被截取的正常歌曲的开始时间和结束时间)", 485 | "example": [ 486 | { 487 | "query": { 488 | "id": "33894312", 489 | "level": "exhigh" 490 | } 491 | }, 492 | { 493 | "query": { 494 | "id": "405998841,33894312", 495 | "level": "lossless" 496 | } 497 | } 498 | ] 499 | }, 500 | "/check/music": { 501 | "name": "音乐是否可用", 502 | "explain": "说明: 调用此接口,传入歌曲 id, 可获取音乐是否可用,返回 ", 503 | "example": [ 504 | { 505 | "query": { 506 | "id": "33894312" 507 | } 508 | } 509 | ] 510 | }, 511 | "/cloudsearch": { 512 | "name": "搜索", 513 | "explain": "说明 : 调用此接口 , 传入搜索关键词可以搜索该音乐 / 专辑 / 歌手 / 歌单 / 用户 ,\n关键词可以多个 , 以空格隔开 , 如 \" 周杰伦 搁浅 \"( 不需要登录 ), 可通过 ", 514 | "example": [ 515 | { 516 | "query": { 517 | "keywords": "海阔天空" 518 | } 519 | }, 520 | { 521 | "query": { 522 | "keywords": "海阔天空" 523 | } 524 | } 525 | ] 526 | }, 527 | "/search/hot": { 528 | "name": "热搜列表(简略)", 529 | "explain": "说明 : 调用此接口,可获取热门搜索列表", 530 | "example": [ 531 | { 532 | "query": {} 533 | } 534 | ] 535 | }, 536 | "/search/hot/detail": { 537 | "name": "热搜列表(详细)", 538 | "explain": "说明 : 调用此接口,可获取热门搜索列表", 539 | "example": [ 540 | { 541 | "query": {} 542 | } 543 | ] 544 | }, 545 | "/search/suggest": { 546 | "name": "搜索建议", 547 | "explain": "说明 : 调用此接口 , 传入搜索关键词可获得搜索建议 , 搜索结果同时包含单曲 , 歌手 , 歌单信息", 548 | "example": [ 549 | { 550 | "query": { 551 | "keywords": "海阔天空" 552 | } 553 | }, 554 | { 555 | "query": { 556 | "keywords": "海阔天空", 557 | "type": "mobile" 558 | } 559 | } 560 | ] 561 | }, 562 | "/search/multimatch": { 563 | "name": "搜索多重匹配", 564 | "explain": "说明 : 调用此接口 , 传入搜索关键词可获得搜索结果", 565 | "example": [ 566 | { 567 | "query": { 568 | "keywords": "海阔天空" 569 | } 570 | } 571 | ] 572 | }, 573 | "/playlist/delete": { 574 | "name": "删除歌单", 575 | "explain": "说明 : 调用此接口 , 传入歌单 id 可删除歌单", 576 | "example": [ 577 | { 578 | "query": { 579 | "id": "2947311456" 580 | } 581 | }, 582 | { 583 | "query": { 584 | "id": "5013464397,5013427772" 585 | } 586 | } 587 | ] 588 | }, 589 | "/playlist/subscribe": { 590 | "name": "收藏/取消收藏歌单", 591 | "explain": "说明 : 调用此接口 , 传入类型和歌单 id 可收藏歌单或者取消收藏歌单", 592 | "example": [ 593 | { 594 | "query": { 595 | "t": "1", 596 | "id": "106697785" 597 | } 598 | }, 599 | { 600 | "query": { 601 | "t": "2", 602 | "id": "106697785" 603 | } 604 | } 605 | ] 606 | }, 607 | "/playlist/subscribers": { 608 | "name": "歌单收藏者", 609 | "explain": "说明 : 调用此接口 , 传入歌单 id 可获取歌单的所有收藏者", 610 | "example": [ 611 | { 612 | "query": { 613 | "id": "544215255", 614 | "limit": "30" 615 | } 616 | } 617 | ] 618 | }, 619 | "/playlist/track/add": { 620 | "name": "收藏视频到视频歌单", 621 | "explain": "说明 : 调用此接口 , 可收藏视频到视频歌单 ( 需要登录 )", 622 | "example": [ 623 | { 624 | "query": { 625 | "pid": "5271999357", 626 | "ids": "186041" 627 | } 628 | } 629 | ] 630 | }, 631 | "/playlist/track/delete": { 632 | "name": "删除视频歌单里的视频", 633 | "explain": "说明 : 调用此接口 , 可删除视频歌单里的视频 ( 需要登录 )\n", 634 | "example": [ 635 | { 636 | "query": { 637 | "pid": "5271999357", 638 | "ids": "186041" 639 | } 640 | } 641 | ] 642 | }, 643 | "/playlist/video/recent": { 644 | "name": "最近播放的视频", 645 | "explain": "说明 : 调用此接口 , 可获取最近播放的视频 ( 需要登录 )", 646 | "example": [ 647 | { 648 | "query": {} 649 | } 650 | ] 651 | }, 652 | "/lyric": { 653 | "name": "获取歌词", 654 | "explain": "说明 : 调用此接口 , 传入音乐 id 可获得对应音乐的歌词 ( 不需要登录 )", 655 | "example": [ 656 | { 657 | "query": { 658 | "id": "33894312" 659 | } 660 | } 661 | ] 662 | }, 663 | "/lyric/new": { 664 | "name": "获取逐字歌词", 665 | "explain": "说明 : 此接口的 ", 666 | "example": [ 667 | { 668 | "query": { 669 | "id": "1824020871" 670 | } 671 | } 672 | ] 673 | }, 674 | "/top/song": { 675 | "name": "新歌速递", 676 | "explain": "说明 : 调用此接口 , 可获取新歌速递", 677 | "example": [ 678 | { 679 | "query": { 680 | "type": "96" 681 | } 682 | } 683 | ] 684 | }, 685 | "/comment/music": { 686 | "name": "歌曲评论", 687 | "explain": "说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该音乐的所有评论 ( 不需要登录 )", 688 | "example": [ 689 | { 690 | "query": { 691 | "id": "186016", 692 | "limit": "1" 693 | } 694 | } 695 | ] 696 | }, 697 | "/comment/floor": { 698 | "name": "楼层评论", 699 | "explain": "说明 : 调用此接口 , 传入资源 parentCommentId 和资源类型 type 和资源 id 参数, 可获得该资源的歌曲楼层评论", 700 | "example": [ 701 | { 702 | "query": { 703 | "parentCommentId": "1438569889", 704 | "id": "29764564", 705 | "type": "0" 706 | } 707 | } 708 | ] 709 | }, 710 | "/comment/album": { 711 | "name": "专辑评论", 712 | "explain": "说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该专辑的所有评论 ( 不需要\n登录 )", 713 | "example": [ 714 | { 715 | "query": { 716 | "id": "32311" 717 | } 718 | } 719 | ] 720 | }, 721 | "/comment/playlist": { 722 | "name": "歌单评论", 723 | "explain": "说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该歌单的所有评论 ( 不需要\n登录 )", 724 | "example": [ 725 | { 726 | "query": { 727 | "id": "705123491" 728 | } 729 | } 730 | ] 731 | }, 732 | "/comment/mv": { 733 | "name": "mv 评论", 734 | "explain": "说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该 mv 的所有评论 ( 不需要\n登录 )", 735 | "example": [ 736 | { 737 | "query": { 738 | "id": "5436712" 739 | } 740 | } 741 | ] 742 | }, 743 | "/comment/dj": { 744 | "name": "电台节目评论", 745 | "explain": "说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该 电台节目 的所有评论 (\n不需要登录 )", 746 | "example": [ 747 | { 748 | "query": { 749 | "id": "794062371" 750 | } 751 | } 752 | ] 753 | }, 754 | "/comment/video": { 755 | "name": "视频评论", 756 | "explain": "说明 : 调用此接口 , 传入音乐 id 和 limit 参数 , 可获得该 视频 的所有评论 (\n不需要登录 )", 757 | "example": [ 758 | { 759 | "query": { 760 | "id": "89ADDE33C0AAE8EC14B99F6750DB954D" 761 | } 762 | } 763 | ] 764 | }, 765 | "/comment/hot": { 766 | "name": "热门评论", 767 | "explain": "说明 : 调用此接口 , 传入 type, 资源 id 可获得对应资源热门评论 ( 不需要登录 )", 768 | "example": [ 769 | { 770 | "query": { 771 | "id": "186016", 772 | "type": "0" 773 | } 774 | } 775 | ] 776 | }, 777 | "/comment/new": { 778 | "name": "新版评论接口", 779 | "explain": "说明 : 调用此接口 , 传入资源类型和资源 id,以及排序方式,可获取对应资源的评论", 780 | "example": [ 781 | { 782 | "query": { 783 | "type": "0", 784 | "id": "1407551413", 785 | "sortType": "3" 786 | } 787 | }, 788 | { 789 | "query": { 790 | "type": "0", 791 | "id": "1407551413", 792 | "sortType": "3", 793 | "cursor": "1602072870260", 794 | "pageSize": "20", 795 | "pageNo": "2" 796 | } 797 | } 798 | ] 799 | }, 800 | "/comment/like": { 801 | "name": "给评论点赞", 802 | "explain": "说明 : 调用此接口 , 传入 type, 资源 id, 和评论 id cid 和 是否点赞参数 t 即可给对\n应评论点赞 ( 需要登录 )", 803 | "example": [ 804 | { 805 | "query": { 806 | "id": "29178366", 807 | "cid": "12840183", 808 | "t": "1", 809 | "type": "0" 810 | } 811 | } 812 | ] 813 | }, 814 | "/hug/comment": { 815 | "name": "抱一抱评论", 816 | "explain": "说明 : 调用此接口,可抱一抱评论", 817 | "example": [ 818 | { 819 | "query": { 820 | "uid": "285516405", 821 | "cid": "1167145843", 822 | "sid": "863481066" 823 | } 824 | } 825 | ] 826 | }, 827 | "/comment/hug/list": { 828 | "name": "评论抱一抱列表", 829 | "explain": "说明 : 调用此接口,可获取评论抱一抱列表", 830 | "example": [ 831 | { 832 | "query": { 833 | "uid": "285516405", 834 | "cid": "1167145843", 835 | "sid": "863481066", 836 | "pageSize": "2", 837 | "page": "1" 838 | } 839 | } 840 | ] 841 | }, 842 | "/banner": { 843 | "name": "banner", 844 | "explain": "说明 : 调用此接口 , 可获取 banner( 轮播图 ) 数据", 845 | "example": [ 846 | { 847 | "query": {} 848 | }, 849 | { 850 | "query": { 851 | "type": "2" 852 | } 853 | } 854 | ] 855 | }, 856 | "/resource/like": { 857 | "name": "资源点赞( MV,电台,视频)", 858 | "explain": "说明 : 调用此接口 , 可对 MV,电台,视频点赞", 859 | "example": [ 860 | { 861 | "query": { 862 | "t": "1", 863 | "type": "1", 864 | "id": "5436712" 865 | } 866 | } 867 | ] 868 | }, 869 | "/playlist/mylike": { 870 | "name": "获取点赞过的视频", 871 | "explain": "说明 : 调用此接口, 可获取获取点赞过的视频", 872 | "example": [ 873 | { 874 | "query": {} 875 | } 876 | ] 877 | }, 878 | "/song/detail": { 879 | "name": "获取歌曲详情", 880 | "explain": "说明 : 调用此接口 , 传入音乐 id(支持多个 id, 用 ", 881 | "example": [ 882 | { 883 | "query": { 884 | "ids": "347230" 885 | } 886 | }, 887 | { 888 | "query": { 889 | "ids": "347230,347231" 890 | } 891 | } 892 | ] 893 | }, 894 | "/album": { 895 | "name": "获取专辑内容", 896 | "explain": "说明 : 调用此接口 , 传入专辑 id, 可获得专辑内容", 897 | "example": [ 898 | { 899 | "query": { 900 | "id": "32311" 901 | } 902 | } 903 | ] 904 | }, 905 | "/album/detail/dynamic": { 906 | "name": "专辑动态信息", 907 | "explain": "说明 : 调用此接口 , 传入专辑 id, 可获得专辑动态信息,如是否收藏,收藏数,评论数,分享数", 908 | "example": [ 909 | { 910 | "query": { 911 | "id": "32311" 912 | } 913 | } 914 | ] 915 | }, 916 | "/album/sub": { 917 | "name": "收藏/取消收藏专辑", 918 | "explain": "说明 : 调用此接口,可收藏/取消收藏专辑", 919 | "example": [ 920 | { 921 | "query": { 922 | "id": "147779282", 923 | "t": "1" 924 | } 925 | }, 926 | { 927 | "query": { 928 | "id": "147779282", 929 | "t": "0" 930 | } 931 | } 932 | ] 933 | }, 934 | "/album/sublist": { 935 | "name": "获取已收藏专辑列表", 936 | "explain": "说明 : 调用此接口 , 可获得已收藏专辑列表", 937 | "example": [ 938 | { 939 | "query": {} 940 | } 941 | ] 942 | }, 943 | "/artists": { 944 | "name": "获取歌手单曲", 945 | "explain": "说明 : 调用此接口 , 传入歌手 id, 可获得歌手部分信息和热门歌曲", 946 | "example": [ 947 | { 948 | "query": { 949 | "id": "6452" 950 | } 951 | } 952 | ] 953 | }, 954 | "/artist/mv": { 955 | "name": "获取歌手 mv", 956 | "explain": "说明 : 调用此接口 , 传入歌手 id, 可获得歌手 mv 信息 , 具体 mv 播放地址可调\n用", 957 | "example": [ 958 | { 959 | "query": { 960 | "id": "6452" 961 | } 962 | } 963 | ] 964 | }, 965 | "/artist/album": { 966 | "name": "获取歌手专辑", 967 | "explain": "说明 : 调用此接口 , 传入歌手 id, 可获得歌手专辑内容", 968 | "example": [ 969 | { 970 | "query": { 971 | "id": "6452", 972 | "limit": "5" 973 | } 974 | } 975 | ] 976 | }, 977 | "/artist/desc": { 978 | "name": "获取歌手描述", 979 | "explain": "说明 : 调用此接口 , 传入歌手 id, 可获得歌手描述", 980 | "example": [ 981 | { 982 | "query": { 983 | "id": "6452" 984 | } 985 | } 986 | ] 987 | }, 988 | "/artist/detail": { 989 | "name": "获取歌手详情", 990 | "explain": "说明 : 调用此接口 , 传入歌手 id, 可获得获取歌手详情", 991 | "example": [ 992 | { 993 | "query": { 994 | "id": "11972054" 995 | } 996 | } 997 | ] 998 | }, 999 | "/simi/artist": { 1000 | "name": "获取相似歌手", 1001 | "explain": "说明 : 调用此接口 , 传入歌手 id, 可获得相似歌手", 1002 | "example": [ 1003 | { 1004 | "query": { 1005 | "id": "6452" 1006 | } 1007 | } 1008 | ] 1009 | }, 1010 | "/simi/playlist": { 1011 | "name": "获取相似歌单", 1012 | "explain": "说明 : 调用此接口 , 传入歌曲 id, 可获得相似歌单", 1013 | "example": [ 1014 | { 1015 | "query": { 1016 | "id": "347230" 1017 | } 1018 | } 1019 | ] 1020 | }, 1021 | "/simi/mv": { 1022 | "name": "相似 mv", 1023 | "explain": "说明 : 调用此接口 , 传入 ", 1024 | "example": [ 1025 | { 1026 | "query": { 1027 | "mvid": "5436712" 1028 | } 1029 | } 1030 | ] 1031 | }, 1032 | "/simi/song": { 1033 | "name": "获取相似音乐", 1034 | "explain": "说明 : 调用此接口 , 传入歌曲 id, 可获得相似歌曲", 1035 | "example": [ 1036 | { 1037 | "query": { 1038 | "id": "347230" 1039 | } 1040 | } 1041 | ] 1042 | }, 1043 | "/simi/user": { 1044 | "name": "获取最近 5 个听了这首歌的用户", 1045 | "explain": "说明 : 调用此接口 , 传入歌曲 id, 最近 5 个听了这首歌的用户", 1046 | "example": [ 1047 | { 1048 | "query": { 1049 | "id": "347230" 1050 | } 1051 | } 1052 | ] 1053 | }, 1054 | "/recommend/resource": { 1055 | "name": "获取每日推荐歌单", 1056 | "explain": "说明 : 调用此接口 , 可获得每日推荐歌单 ( 需要登录 )", 1057 | "example": [ 1058 | { 1059 | "query": {} 1060 | } 1061 | ] 1062 | }, 1063 | "/recommend/songs": { 1064 | "name": "获取每日推荐歌曲", 1065 | "explain": "说明 : 调用此接口 , 可获得每日推荐歌曲 ( 需要登录 )", 1066 | "example": [ 1067 | { 1068 | "query": {} 1069 | } 1070 | ] 1071 | }, 1072 | "/recommend/songs/dislike": { 1073 | "name": "每日推荐歌曲-不感兴趣", 1074 | "explain": "说明 : 日推歌曲标记为不感兴趣( 同时会返回一个新推荐歌曲, 需要登录 )", 1075 | "example": [ 1076 | { 1077 | "query": { 1078 | "id": "168091" 1079 | } 1080 | } 1081 | ] 1082 | }, 1083 | "/history/recommend/songs": { 1084 | "name": "获取历史日推可用日期列表", 1085 | "explain": "说明 : 调用此接口 , 可获得历史日推可用日期列表", 1086 | "example": [ 1087 | { 1088 | "query": {} 1089 | } 1090 | ] 1091 | }, 1092 | "/history/recommend/songs/detail": { 1093 | "name": "获取历史日推详情数据", 1094 | "explain": "说明 : 调用此接口 ,传入当日日期, 可获得当日历史日推数据", 1095 | "example": [ 1096 | { 1097 | "query": { 1098 | "date": "2020-06-21" 1099 | } 1100 | } 1101 | ] 1102 | }, 1103 | "/personal_fm": { 1104 | "name": "私人 FM", 1105 | "explain": "说明 : 私人 FM( 需要登录 )", 1106 | "example": [ 1107 | { 1108 | "query": {} 1109 | } 1110 | ] 1111 | }, 1112 | "/like": { 1113 | "name": "喜欢音乐", 1114 | "explain": "说明 : 调用此接口 , 传入音乐 id, 可喜欢该音乐", 1115 | "example": [ 1116 | { 1117 | "query": { 1118 | "id": "347230" 1119 | } 1120 | } 1121 | ] 1122 | }, 1123 | "/likelist": { 1124 | "name": "喜欢音乐列表", 1125 | "explain": "说明 : 调用此接口 , 传入用户 id, 可获取已喜欢音乐 id 列表(id 数组)", 1126 | "example": [ 1127 | { 1128 | "query": { 1129 | "uid": "32953014" 1130 | } 1131 | } 1132 | ] 1133 | }, 1134 | "/top/album": { 1135 | "name": "新碟上架", 1136 | "explain": "说明 : 调用此接口 , 可获取新碟上架列表 , 如需具体音乐信息需要调用获取专辑列表接\n口 ", 1137 | "example": [ 1138 | { 1139 | "query": { 1140 | "offset": "0", 1141 | "limit": "30", 1142 | "year": "2019", 1143 | "month": "6" 1144 | } 1145 | } 1146 | ] 1147 | }, 1148 | "/album/new": { 1149 | "name": "全部新碟", 1150 | "explain": "说明 : 登录后调用此接口 ,可获取全部新碟", 1151 | "example": [ 1152 | { 1153 | "query": { 1154 | "area": "KR", 1155 | "limit": "10" 1156 | } 1157 | } 1158 | ] 1159 | }, 1160 | "/album/newest": { 1161 | "name": "最新专辑", 1162 | "explain": "说明 : 调用此接口 ,获取云音乐首页新碟上架数据", 1163 | "example": [ 1164 | { 1165 | "query": {} 1166 | } 1167 | ] 1168 | }, 1169 | "/scrobble": { 1170 | "name": "听歌打卡", 1171 | "explain": "说明 : 调用此接口 , 传入音乐 id, 来源 id,歌曲时间 time,更新听歌排行数据", 1172 | "example": [ 1173 | { 1174 | "query": { 1175 | "id": "518066366", 1176 | "sourceid": "36780169", 1177 | "time": "291" 1178 | } 1179 | } 1180 | ] 1181 | }, 1182 | "/top/artists": { 1183 | "name": "热门歌手", 1184 | "explain": "说明 : 调用此接口 , 可获取热门歌手数据", 1185 | "example": [ 1186 | { 1187 | "query": { 1188 | "offset": "0", 1189 | "limit": "30" 1190 | } 1191 | } 1192 | ] 1193 | }, 1194 | "/mv/all": { 1195 | "name": "全部 mv", 1196 | "explain": "说明 : 调用此接口 , 可获取全部 mv", 1197 | "example": [ 1198 | { 1199 | "query": { 1200 | "area": "港台" 1201 | } 1202 | } 1203 | ] 1204 | }, 1205 | "/mv/first": { 1206 | "name": "最新 mv", 1207 | "explain": "说明 : 调用此接口 , 可获取最新 mv", 1208 | "example": [ 1209 | { 1210 | "query": { 1211 | "limit": "10" 1212 | } 1213 | } 1214 | ] 1215 | }, 1216 | "/mv/exclusive/rcmd": { 1217 | "name": "网易出品 mv", 1218 | "explain": "说明 : 调用此接口 , 可获取网易出品 mv", 1219 | "example": [ 1220 | { 1221 | "query": { 1222 | "limit": "10" 1223 | } 1224 | } 1225 | ] 1226 | }, 1227 | "/personalized/mv": { 1228 | "name": "推荐 mv", 1229 | "explain": "说明 : 调用此接口 , 可获取推荐 mv", 1230 | "example": [ 1231 | { 1232 | "query": {} 1233 | } 1234 | ] 1235 | }, 1236 | "/personalized": { 1237 | "name": "推荐歌单", 1238 | "explain": "说明 : 调用此接口 , 可获取推荐歌单", 1239 | "example": [ 1240 | { 1241 | "query": { 1242 | "limit": "1" 1243 | } 1244 | } 1245 | ] 1246 | }, 1247 | "/personalized/newsong": { 1248 | "name": "推荐新音乐", 1249 | "explain": "说明 : 调用此接口 , 可获取推荐新音乐", 1250 | "example": [ 1251 | { 1252 | "query": {} 1253 | } 1254 | ] 1255 | }, 1256 | "/personalized/djprogram": { 1257 | "name": "推荐电台", 1258 | "explain": "说明 : 调用此接口 , 可获取推荐电台", 1259 | "example": [ 1260 | { 1261 | "query": {} 1262 | } 1263 | ] 1264 | }, 1265 | "/program/recommend": { 1266 | "name": "推荐节目", 1267 | "explain": "说明 : 调用此接口 , 可获取推荐电台", 1268 | "example": [ 1269 | { 1270 | "query": { 1271 | "limit": "5" 1272 | } 1273 | } 1274 | ] 1275 | }, 1276 | "/personalized/privatecontent": { 1277 | "name": "独家放送(入口列表)", 1278 | "explain": "说明 : 调用此接口 , 可获取独家放送", 1279 | "example": [ 1280 | { 1281 | "query": {} 1282 | } 1283 | ] 1284 | }, 1285 | "/personalized/privatecontent/list": { 1286 | "name": "独家放送列表", 1287 | "explain": "说明 : 调用此接口 , 可获取独家放送列表", 1288 | "example": [ 1289 | { 1290 | "query": { 1291 | "limit": "1", 1292 | "offset": "2" 1293 | } 1294 | } 1295 | ] 1296 | }, 1297 | "/top/mv": { 1298 | "name": "mv 排行", 1299 | "explain": "说明 : 调用此接口 , 可获取 mv 排行", 1300 | "example": [ 1301 | { 1302 | "query": { 1303 | "limit": "10" 1304 | } 1305 | } 1306 | ] 1307 | }, 1308 | "/mv/detail": { 1309 | "name": "获取 mv 数据", 1310 | "explain": "说明 : 调用此接口 , 传入 mvid ( 在搜索音乐的时候传 type=1004 获得 ) , 可获取对应\nMV 数据 , 数据包含 mv 名字 , 歌手 , 发布时间 , mv 视频地址等数据 , 其中 mv 视频\n网易做了防盗链处理 , 可能不能直接播放 , 需要播放的话需要调用 ' mv 地址' 接口", 1311 | "example": [ 1312 | { 1313 | "query": { 1314 | "mvid": "5436712" 1315 | } 1316 | } 1317 | ] 1318 | }, 1319 | "/mv/detail/info": { 1320 | "name": "获取 mv 点赞转发评论数数据", 1321 | "explain": "说明 : 调用此接口 , 传入 mvid ( 在搜索音乐的时候传 type=1004 获得 ) , 可获取对应\nMV 点赞转发评论数数据", 1322 | "example": [ 1323 | { 1324 | "query": { 1325 | "mvid": "5436712" 1326 | } 1327 | } 1328 | ] 1329 | }, 1330 | "/video/group/list": { 1331 | "name": "获取视频标签列表", 1332 | "explain": "说明 : 调用此接口 , 可获取视频标签列表", 1333 | "example": [ 1334 | { 1335 | "query": {} 1336 | } 1337 | ] 1338 | }, 1339 | "/video/category/list": { 1340 | "name": "获取视频分类列表", 1341 | "explain": "说明 : 调用此接口 , 可获取视频分类列表", 1342 | "example": [ 1343 | { 1344 | "query": {} 1345 | } 1346 | ] 1347 | }, 1348 | "/video/group": { 1349 | "name": "获取视频标签/分类下的视频", 1350 | "explain": "说明 : 调用此接口 , 传入标签/分类", 1351 | "example": [ 1352 | { 1353 | "query": { 1354 | "id": "9104" 1355 | } 1356 | } 1357 | ] 1358 | }, 1359 | "/video/timeline/all": { 1360 | "name": "获取全部视频列表", 1361 | "explain": "说明 : 调用此接口,可获取视频分类列表,分页参数只能传入 offset", 1362 | "example": [ 1363 | { 1364 | "query": {} 1365 | } 1366 | ] 1367 | }, 1368 | "/video/timeline/recommend": { 1369 | "name": "获取推荐视频", 1370 | "explain": "说明 : 调用此接口, 可获取推荐视频,分页参数只能传入 offset", 1371 | "example": [ 1372 | { 1373 | "query": { 1374 | "offset": "10" 1375 | } 1376 | } 1377 | ] 1378 | }, 1379 | "/related/allvideo": { 1380 | "name": "相关视频", 1381 | "explain": "说明 : 调用此接口 , 可获取相关视频", 1382 | "example": [ 1383 | { 1384 | "query": { 1385 | "id": "89ADDE33C0AAE8EC14B99F6750DB954D" 1386 | } 1387 | } 1388 | ] 1389 | }, 1390 | "/video/detail": { 1391 | "name": "视频详情", 1392 | "explain": "说明 : 调用此接口 , 可获取视频详情", 1393 | "example": [ 1394 | { 1395 | "query": { 1396 | "id": "89ADDE33C0AAE8EC14B99F6750DB954D" 1397 | } 1398 | } 1399 | ] 1400 | }, 1401 | "/video/detail/info": { 1402 | "name": "获取视频点赞转发评论数数据", 1403 | "explain": "说明 : 调用此接口 , 传入 vid ( 视频 id ) , 可获取对应视频点赞转发评论数数据\n", 1404 | "example": [ 1405 | { 1406 | "query": { 1407 | "vid": "89ADDE33C0AAE8EC14B99F6750DB954D" 1408 | } 1409 | } 1410 | ] 1411 | }, 1412 | "/video/url": { 1413 | "name": "获取视频播放地址", 1414 | "explain": "说明 : 调用此接口 , 传入视频 id,可获取视频播放地址", 1415 | "example": [ 1416 | { 1417 | "query": { 1418 | "id": "89ADDE33C0AAE8EC14B99F6750DB954D" 1419 | } 1420 | } 1421 | ] 1422 | }, 1423 | "/toplist": { 1424 | "name": "所有榜单", 1425 | "explain": "说明 : 调用此接口,可获取所有榜单\n", 1426 | "example": [ 1427 | { 1428 | "query": {} 1429 | } 1430 | ] 1431 | }, 1432 | "/toplist/detail": { 1433 | "name": "所有榜单内容摘要", 1434 | "explain": "说明 : 调用此接口,可获取所有榜单内容摘要", 1435 | "example": [ 1436 | { 1437 | "query": {} 1438 | } 1439 | ] 1440 | }, 1441 | "/toplist/artist": { 1442 | "name": "歌手榜", 1443 | "explain": "说明 : 调用此接口 , 可获取排行榜中的歌手榜", 1444 | "example": [ 1445 | { 1446 | "query": {} 1447 | } 1448 | ] 1449 | }, 1450 | "/user/cloud": { 1451 | "name": "云盘", 1452 | "explain": "说明 : 登录后调用此接口 , 可获取云盘数据 , 获取的数据没有对应 url, 需要再调用一\n次 ", 1453 | "example": [ 1454 | { 1455 | "query": {} 1456 | } 1457 | ] 1458 | }, 1459 | "/user/cloud/detail": { 1460 | "name": "云盘数据详情", 1461 | "explain": "说明 : 登录后调用此接口 , 传入云盘歌曲 id,可获取云盘数据详情", 1462 | "example": [ 1463 | { 1464 | "query": { 1465 | "id": "5374627" 1466 | } 1467 | } 1468 | ] 1469 | }, 1470 | "/user/cloud/del": { 1471 | "name": "云盘歌曲删除", 1472 | "explain": "说明 : 登录后调用此接口 , 可删除云盘歌曲", 1473 | "example": [ 1474 | { 1475 | "query": {} 1476 | } 1477 | ] 1478 | }, 1479 | "/cloud": { 1480 | "name": "云盘上传", 1481 | "explain": "说明 : 登录后调用此接口,使用", 1482 | "example": [ 1483 | { 1484 | "query": {} 1485 | } 1486 | ] 1487 | }, 1488 | "/cloud/match": { 1489 | "name": "云盘歌曲信息匹配纠正", 1490 | "explain": "说明 : 登录后调用此接口,可对云盘歌曲信息匹配纠正,如需取消匹配,asid 需要传 0", 1491 | "example": [ 1492 | { 1493 | "query": { 1494 | "uid": "32953014", 1495 | "sid": "aaa", 1496 | "asid": "bbb" 1497 | } 1498 | }, 1499 | { 1500 | "query": { 1501 | "uid": "32953014", 1502 | "sid": "bbb", 1503 | "asid": "0" 1504 | } 1505 | } 1506 | ] 1507 | }, 1508 | "/dj/banner": { 1509 | "name": "电台 banner", 1510 | "explain": "说明 : 调用此接口,可获取电台 banner", 1511 | "example": [ 1512 | { 1513 | "query": {} 1514 | } 1515 | ] 1516 | }, 1517 | "/dj/personalize/recommend": { 1518 | "name": "电台个性推荐", 1519 | "explain": "说明 : 调用此接口,可获取电台个性推荐列表\n", 1520 | "example": [ 1521 | { 1522 | "query": { 1523 | "limit": "5" 1524 | } 1525 | } 1526 | ] 1527 | }, 1528 | "/dj/subscriber": { 1529 | "name": "电台订阅者列表", 1530 | "explain": "说明 : 调用此接口,可获取电台订阅者列表\n", 1531 | "example": [ 1532 | { 1533 | "query": { 1534 | "id": "335425050" 1535 | } 1536 | }, 1537 | { 1538 | "query": { 1539 | "id": "335425050", 1540 | "time": "1602761825390" 1541 | } 1542 | } 1543 | ] 1544 | }, 1545 | "/user/audio": { 1546 | "name": "用户电台", 1547 | "explain": "说明 : 调用此接口, 传入用户 id 可获取用户创建的电台", 1548 | "example": [ 1549 | { 1550 | "query": { 1551 | "uid": "32953014" 1552 | } 1553 | } 1554 | ] 1555 | }, 1556 | "/dj/hot": { 1557 | "name": "热门电台", 1558 | "explain": "说明 : 调用此接口,可获取热门电台", 1559 | "example": [ 1560 | { 1561 | "query": {} 1562 | } 1563 | ] 1564 | }, 1565 | "/dj/program/toplist": { 1566 | "name": "电台 - 节目榜", 1567 | "explain": "说明 : 登录后调用此接口 , 可获得电台节目榜", 1568 | "example": [ 1569 | { 1570 | "query": { 1571 | "limit": "1" 1572 | } 1573 | } 1574 | ] 1575 | }, 1576 | "/dj/toplist/pay": { 1577 | "name": "电台 - 付费精品", 1578 | "explain": "说明 : 调用此接口,可获取付费精品电台", 1579 | "example": [ 1580 | { 1581 | "query": { 1582 | "limit": "30" 1583 | } 1584 | } 1585 | ] 1586 | }, 1587 | "/dj/program/toplist/hours": { 1588 | "name": "电台 - 24 小时节目榜", 1589 | "explain": "说明 : 调用此接口,可获取 24 小时节目榜", 1590 | "example": [ 1591 | { 1592 | "query": { 1593 | "limit": "1" 1594 | } 1595 | } 1596 | ] 1597 | }, 1598 | "/dj/toplist/hours": { 1599 | "name": "电台 - 24 小时主播榜", 1600 | "explain": "说明 : 调用此接口,可获取 24 小时主播榜", 1601 | "example": [ 1602 | { 1603 | "query": { 1604 | "limit": "30" 1605 | } 1606 | } 1607 | ] 1608 | }, 1609 | "/dj/toplist/newcomer": { 1610 | "name": "电台 - 主播新人榜", 1611 | "explain": "说明 : 调用此接口,可获取主播新人榜", 1612 | "example": [ 1613 | { 1614 | "query": { 1615 | "limit": "30" 1616 | } 1617 | } 1618 | ] 1619 | }, 1620 | "/dj/toplist/popular": { 1621 | "name": "电台 - 最热主播榜", 1622 | "explain": "说明 : 调用此接口,可获取最热主播榜", 1623 | "example": [ 1624 | { 1625 | "query": { 1626 | "limit": "30" 1627 | } 1628 | } 1629 | ] 1630 | }, 1631 | "/dj/toplist": { 1632 | "name": "电台 - 新晋电台榜/热门电台榜", 1633 | "explain": "说明 : 登录后调用此接口 , 可获得新晋电台榜/热门电台榜", 1634 | "example": [ 1635 | { 1636 | "query": { 1637 | "type": "hot" 1638 | } 1639 | }, 1640 | { 1641 | "query": { 1642 | "type": "new", 1643 | "limit": "1" 1644 | } 1645 | } 1646 | ] 1647 | }, 1648 | "/dj/radio/hot": { 1649 | "name": "电台 - 类别热门电台", 1650 | "explain": "电台 - 类别热门电台", 1651 | "example": [ 1652 | { 1653 | "query": { 1654 | "cateId": "2001" 1655 | } 1656 | }, 1657 | { 1658 | "query": { 1659 | "cateId": "10002" 1660 | } 1661 | } 1662 | ] 1663 | }, 1664 | "/dj/recommend": { 1665 | "name": "电台 - 推荐", 1666 | "explain": "说明 : 登录后调用此接口 , 可获得推荐电台", 1667 | "example": [ 1668 | { 1669 | "query": {} 1670 | } 1671 | ] 1672 | }, 1673 | "/dj/catelist": { 1674 | "name": "电台 - 分类", 1675 | "explain": "说明 : 登录后调用此接口 , 可获得电台类型", 1676 | "example": [ 1677 | { 1678 | "query": {} 1679 | } 1680 | ] 1681 | }, 1682 | "/dj/recommend/type": { 1683 | "name": "电台 - 分类推荐", 1684 | "explain": "说明 : 登录后调用此接口 , 传入分类,可获得对应类型电台列表", 1685 | "example": [ 1686 | { 1687 | "query": { 1688 | "type": "1" 1689 | } 1690 | }, 1691 | { 1692 | "query": { 1693 | "type": "2001" 1694 | } 1695 | } 1696 | ] 1697 | }, 1698 | "/dj/sub": { 1699 | "name": "电台 - 订阅", 1700 | "explain": "说明 : 登录后调用此接口 , 传入", 1701 | "example": [ 1702 | { 1703 | "query": { 1704 | "rid": "336355127", 1705 | "t": "1" 1706 | } 1707 | }, 1708 | { 1709 | "query": { 1710 | "rid": "336355127", 1711 | "t": "0" 1712 | } 1713 | } 1714 | ] 1715 | }, 1716 | "/dj/sublist": { 1717 | "name": "电台的订阅列表", 1718 | "explain": "说明 : 登录后调用此接口 , 可获取订阅的电台列表", 1719 | "example": [ 1720 | { 1721 | "query": {} 1722 | } 1723 | ] 1724 | }, 1725 | "/dj/paygift": { 1726 | "name": "电台 - 付费精选", 1727 | "explain": "说明 : 可以获取付费精选的电台列表 , 传入 ", 1728 | "example": [ 1729 | { 1730 | "query": { 1731 | "limit": "10", 1732 | "offset": "20" 1733 | } 1734 | } 1735 | ] 1736 | }, 1737 | "/dj/category/excludehot": { 1738 | "name": "电台 - 非热门类型", 1739 | "explain": "说明 : 登录后调用此接口, 可获得电台非热门类型", 1740 | "example": [ 1741 | { 1742 | "query": {} 1743 | } 1744 | ] 1745 | }, 1746 | "/dj/category/recommend": { 1747 | "name": "电台 - 推荐类型", 1748 | "explain": "说明 : 登录后调用此接口, 可获得电台推荐类型", 1749 | "example": [ 1750 | { 1751 | "query": {} 1752 | } 1753 | ] 1754 | }, 1755 | "/dj/today/perfered": { 1756 | "name": "电台 - 今日优选", 1757 | "explain": "说明 : 登录后调用此接口, 可获得电台今日优选", 1758 | "example": [ 1759 | { 1760 | "query": {} 1761 | } 1762 | ] 1763 | }, 1764 | "/dj/detail": { 1765 | "name": "电台 - 详情", 1766 | "explain": "说明 : 登录后调用此接口 , 传入", 1767 | "example": [ 1768 | { 1769 | "query": { 1770 | "rid": "336355127" 1771 | } 1772 | } 1773 | ] 1774 | }, 1775 | "/dj/program": { 1776 | "name": "电台 - 节目", 1777 | "explain": "说明 : 登录后调用此接口 , 传入", 1778 | "example": [ 1779 | { 1780 | "query": { 1781 | "rid": "336355127", 1782 | "limit": "40" 1783 | } 1784 | } 1785 | ] 1786 | }, 1787 | "/dj/program/detail": { 1788 | "name": "电台 - 节目详情", 1789 | "explain": "说明 : 调用此接口传入电台节目 id,可获得电台节目详情", 1790 | "example": [ 1791 | { 1792 | "query": { 1793 | "id": "1367665101" 1794 | } 1795 | } 1796 | ] 1797 | }, 1798 | "/msg/private": { 1799 | "name": "通知 - 私信", 1800 | "explain": "说明 : 登录后调用此接口 ,可获取私信", 1801 | "example": [ 1802 | { 1803 | "query": { 1804 | "limit": "3" 1805 | } 1806 | } 1807 | ] 1808 | }, 1809 | "/send/song": { 1810 | "name": "发送私信(带歌曲)", 1811 | "explain": "说明 : 登录后调用此接口 , 传入用户 id 和要发送的信息,音乐 id, 可以发送音乐私信,返回内容为历史私信", 1812 | "example": [ 1813 | { 1814 | "query": { 1815 | "user_ids": "1", 1816 | "id": "351318", 1817 | "msg": "测试" 1818 | } 1819 | } 1820 | ] 1821 | }, 1822 | "/send/album": { 1823 | "name": "发送私信(带专辑)", 1824 | "explain": "说明 : 登录后调用此接口 , 传入用户 id 和要发送的信息,专辑 id, 可以发送专辑私信,返回内容为消息 id", 1825 | "example": [ 1826 | { 1827 | "query": { 1828 | "user_ids": "1", 1829 | "id": "351318", 1830 | "msg": "测试" 1831 | } 1832 | } 1833 | ] 1834 | }, 1835 | "/msg/recentcontact": { 1836 | "name": "最近联系人", 1837 | "explain": "说明 : 登录后调用此接口 ,可获取最接近联系人", 1838 | "example": [ 1839 | { 1840 | "query": {} 1841 | } 1842 | ] 1843 | }, 1844 | "/msg/private/history": { 1845 | "name": "私信内容", 1846 | "explain": "说明 : 登录后调用此接口 , 可获取私信内容", 1847 | "example": [ 1848 | { 1849 | "query": { 1850 | "uid": "9003" 1851 | } 1852 | } 1853 | ] 1854 | }, 1855 | "/msg/comments": { 1856 | "name": "通知 - 评论", 1857 | "explain": "说明 : 登录后调用此接口 ,可获取评论", 1858 | "example": [ 1859 | { 1860 | "query": { 1861 | "uid": "32953014" 1862 | } 1863 | } 1864 | ] 1865 | }, 1866 | "/msg/forwards": { 1867 | "name": "通知 - @我", 1868 | "explain": "说明 : 登录后调用此接口 ,可获取@我数据", 1869 | "example": [ 1870 | { 1871 | "query": { 1872 | "limit": "3" 1873 | } 1874 | } 1875 | ] 1876 | }, 1877 | "/msg/notices": { 1878 | "name": "通知 - 通知", 1879 | "explain": "说明 : 登录后调用此接口 ,可获取通知", 1880 | "example": [ 1881 | { 1882 | "query": { 1883 | "limit": "3" 1884 | } 1885 | } 1886 | ] 1887 | }, 1888 | "/setting": { 1889 | "name": "设置", 1890 | "explain": "说明 : 登录后调用此接口 ,可获取用户设置", 1891 | "example": [ 1892 | { 1893 | "query": {} 1894 | } 1895 | ] 1896 | }, 1897 | "/album/list": { 1898 | "name": "数字专辑-新碟上架", 1899 | "explain": "说明 : 调用此接口 ,可获取数字专辑-新碟上架", 1900 | "example": [ 1901 | { 1902 | "query": { 1903 | "limit": "10" 1904 | } 1905 | } 1906 | ] 1907 | }, 1908 | "/album/songsaleboard": { 1909 | "name": "数字专辑&数字单曲-榜单", 1910 | "explain": "说明 : 调用此接口 ,可获取数字专辑&数字单曲-榜单", 1911 | "example": [ 1912 | { 1913 | "query": { 1914 | "type": "year", 1915 | "year": "2020", 1916 | "albumType": "0" 1917 | } 1918 | } 1919 | ] 1920 | }, 1921 | "/album/list/style": { 1922 | "name": "数字专辑-语种风格馆", 1923 | "explain": "说明 : 调用此接口 ,可获取语种风格馆数字专辑列表", 1924 | "example": [ 1925 | { 1926 | "query": { 1927 | "area": "Z_H", 1928 | "offset": "2" 1929 | } 1930 | } 1931 | ] 1932 | }, 1933 | "/digitalAlbum/detail": { 1934 | "name": "数字专辑详情", 1935 | "explain": "说明 : 调用此接口 , 传入专辑 id, 可获取数字专辑信息", 1936 | "example": [ 1937 | { 1938 | "query": { 1939 | "id": "120605500" 1940 | } 1941 | } 1942 | ] 1943 | }, 1944 | "/digitalAlbum/purchased": { 1945 | "name": "我的数字专辑", 1946 | "explain": "说明 : 登录后调用此接口 ,可获取我的数字专辑", 1947 | "example": [ 1948 | { 1949 | "query": { 1950 | "limit": "10" 1951 | } 1952 | } 1953 | ] 1954 | }, 1955 | "/digitalAlbum/ordering": { 1956 | "name": "购买数字专辑", 1957 | "explain": "说明 : 登录后调用此接口 ,可获取购买数字专辑的地址,把地址生成二维码后,可扫描购买专辑", 1958 | "example": [ 1959 | { 1960 | "query": { 1961 | "id": "86286082", 1962 | "payment": "3", 1963 | "quantity": "1" 1964 | } 1965 | } 1966 | ] 1967 | }, 1968 | "/calendar": { 1969 | "name": "音乐日历", 1970 | "explain": "说明 : 登录后调用此接口,传入开始和结束时间,可获取音乐日历", 1971 | "example": [ 1972 | { 1973 | "query": { 1974 | "startTime": "1606752000000", 1975 | "endTime": "1609430399999" 1976 | } 1977 | } 1978 | ] 1979 | }, 1980 | "/yunbei": { 1981 | "name": "云贝", 1982 | "explain": "说明 : 登录后调用此接口可获取云贝签到信息(连续签到天数,第二天全部可获得的云贝)", 1983 | "example": [ 1984 | { 1985 | "query": {} 1986 | } 1987 | ] 1988 | }, 1989 | "/yunbei/today": { 1990 | "name": "云贝今日签到信息", 1991 | "explain": "说明 : 登录后调用此接口可获取云贝今日签到信息(今日签到获取的云贝数)", 1992 | "example": [ 1993 | { 1994 | "query": {} 1995 | } 1996 | ] 1997 | }, 1998 | "/yunbei/sign": { 1999 | "name": "云贝签到", 2000 | "explain": "说明 : 登录后调用此接口可进行云贝签到", 2001 | "example": [ 2002 | { 2003 | "query": {} 2004 | } 2005 | ] 2006 | }, 2007 | "/yunbei/info": { 2008 | "name": "云贝账户信息", 2009 | "explain": "说明 :登录后调用此接口可获取云贝账户信息(账户云贝数)", 2010 | "example": [ 2011 | { 2012 | "query": {} 2013 | } 2014 | ] 2015 | }, 2016 | "/yunbei/tasks": { 2017 | "name": "云贝所有任务", 2018 | "explain": "说明 :登录后调用此接口可获取云贝所有任务", 2019 | "example": [ 2020 | { 2021 | "query": {} 2022 | } 2023 | ] 2024 | }, 2025 | "/yunbei/tasks/todo": { 2026 | "name": "云贝 todo 任务", 2027 | "explain": "说明 :登录后调用此接口可获取云贝 todo 任务", 2028 | "example": [ 2029 | { 2030 | "query": {} 2031 | } 2032 | ] 2033 | }, 2034 | "/yunbei/task/finish": { 2035 | "name": "云贝完成任务", 2036 | "explain": "云贝完成任务", 2037 | "example": [ 2038 | { 2039 | "query": { 2040 | "userTaskId": "5146243240", 2041 | "depositCode": "0" 2042 | } 2043 | } 2044 | ] 2045 | }, 2046 | "/yunbei/tasks/receipt": { 2047 | "name": "云贝收入", 2048 | "explain": "说明 :登录后调用此接口可获取云贝收入", 2049 | "example": [ 2050 | { 2051 | "query": { 2052 | "limit": "1" 2053 | } 2054 | } 2055 | ] 2056 | }, 2057 | "/yunbei/tasks/expense": { 2058 | "name": "云贝支出", 2059 | "explain": "说明 :登录后调用此接口可获取云贝支出", 2060 | "example": [ 2061 | { 2062 | "query": { 2063 | "limit": "1" 2064 | } 2065 | } 2066 | ] 2067 | }, 2068 | "/artist/new/song": { 2069 | "name": "关注歌手新歌", 2070 | "explain": "说明 :登录后调用此接口可获取关注歌手新歌", 2071 | "example": [ 2072 | { 2073 | "query": { 2074 | "limit": "1" 2075 | } 2076 | }, 2077 | { 2078 | "query": { 2079 | "limit": "1", 2080 | "before": "1602777625000" 2081 | } 2082 | } 2083 | ] 2084 | }, 2085 | "/artist/new/mv": { 2086 | "name": "关注歌手新 MV", 2087 | "explain": "说明 :登录后调用此接口可获取关注歌手新 MV", 2088 | "example": [ 2089 | { 2090 | "query": { 2091 | "limit": "1" 2092 | } 2093 | }, 2094 | { 2095 | "query": { 2096 | "limit": "1", 2097 | "before": "1602777625000" 2098 | } 2099 | } 2100 | ] 2101 | }, 2102 | "/yunbei/rcmd/song": { 2103 | "name": "云贝推歌", 2104 | "explain": "说明 : 登录后调用此接口 , 传入歌曲 id, 可以进行云贝推歌", 2105 | "example": [ 2106 | { 2107 | "query": { 2108 | "id": "65528" 2109 | } 2110 | }, 2111 | { 2112 | "query": { 2113 | "id": "65528", 2114 | "reason": "人间好声音推荐给你听" 2115 | } 2116 | } 2117 | ] 2118 | }, 2119 | "/yunbei/rcmd/song/history": { 2120 | "name": "云贝推歌历史记录", 2121 | "explain": "说明 : 登录后调用此接口 , 可以获得云贝推歌历史记录", 2122 | "example": [ 2123 | { 2124 | "query": { 2125 | "size": "10" 2126 | } 2127 | } 2128 | ] 2129 | }, 2130 | "/song/purchased": { 2131 | "name": "已购单曲", 2132 | "explain": "说明 :登录后调用此接口可获取已购买的单曲", 2133 | "example": [ 2134 | { 2135 | "query": { 2136 | "limit": "10" 2137 | } 2138 | } 2139 | ] 2140 | }, 2141 | "/mlog/url": { 2142 | "name": "获取 mlog 播放地址", 2143 | "explain": "说明 : 调用此接口 , 传入 mlog id, 可获取 mlog 播放地址", 2144 | "example": [ 2145 | { 2146 | "query": { 2147 | "id": "a1qOVPTWKS1ZrK8" 2148 | } 2149 | } 2150 | ] 2151 | }, 2152 | "/mlog/to/video": { 2153 | "name": "将 mlog id 转为视频 id", 2154 | "explain": "说明 : 调用此接口 , 传入 mlog id, 可获取 video id,然后通过", 2155 | "example": [ 2156 | { 2157 | "query": { 2158 | "id": "a1qOVPTWKS1ZrK8" 2159 | } 2160 | } 2161 | ] 2162 | }, 2163 | "/vip/growthpoint": { 2164 | "name": "vip 成长值", 2165 | "explain": "说明 : 登录后调用此接口 , 可获取当前会员成长值", 2166 | "example": [ 2167 | { 2168 | "query": {} 2169 | } 2170 | ] 2171 | }, 2172 | "/vip/growthpoint/details": { 2173 | "name": "vip 成长值获取记录", 2174 | "explain": "说明 :登录后调用此接口可获取会员成长值领取记录", 2175 | "example": [ 2176 | { 2177 | "query": { 2178 | "limit": "10" 2179 | } 2180 | } 2181 | ] 2182 | }, 2183 | "/vip/tasks": { 2184 | "name": "vip 任务", 2185 | "explain": "说明 : 登录后调用此接口 , 可获取会员任务", 2186 | "example": [ 2187 | { 2188 | "query": {} 2189 | } 2190 | ] 2191 | }, 2192 | "/vip/growthpoint/get": { 2193 | "name": "领取 vip 成长值", 2194 | "explain": "说明 : 登录后调用此接口 , 可获取已完成的会员任务的成长值奖励", 2195 | "example": [ 2196 | { 2197 | "query": { 2198 | "ids": "7043206830_7" 2199 | } 2200 | }, 2201 | { 2202 | "query": { 2203 | "ids": "8613118351_1,8607552957_1" 2204 | } 2205 | } 2206 | ] 2207 | }, 2208 | "/artist/fans": { 2209 | "name": "歌手粉丝", 2210 | "explain": "说明 : 调用此接口 , 传入歌手 id, 可获取歌手粉丝\n", 2211 | "example": [ 2212 | { 2213 | "query": { 2214 | "id": "2116", 2215 | "limit": "10", 2216 | "offset": "0" 2217 | } 2218 | } 2219 | ] 2220 | }, 2221 | "/artist/follow/count": { 2222 | "name": "歌手粉丝数量", 2223 | "explain": "说明 : 调用此接口 , 传入歌手 id, 可获取歌手粉丝数量", 2224 | "example": [ 2225 | { 2226 | "query": { 2227 | "id": "2116" 2228 | } 2229 | } 2230 | ] 2231 | }, 2232 | "/digitalAlbum/sales": { 2233 | "name": "数字专辑销量", 2234 | "explain": "说明 : 调用此接口 , 传入专辑 id, 可获取数字专辑销量", 2235 | "example": [ 2236 | { 2237 | "query": { 2238 | "ids": "120605500" 2239 | } 2240 | }, 2241 | { 2242 | "query": { 2243 | "ids": "120605500,125080528" 2244 | } 2245 | } 2246 | ] 2247 | }, 2248 | "/musician/data/overview": { 2249 | "name": "音乐人数据概况", 2250 | "explain": "说明 : 音乐人登录后调用此接口 , 可获取统计数据概况", 2251 | "example": [ 2252 | { 2253 | "query": {} 2254 | } 2255 | ] 2256 | }, 2257 | "/musician/play/trend": { 2258 | "name": "音乐人播放趋势", 2259 | "explain": "说明 : 音乐人登录后调用此接口 , 可获取歌曲播放趋势", 2260 | "example": [ 2261 | { 2262 | "query": { 2263 | "startTime": "2021-05-24", 2264 | "endTime": "2021-05-30" 2265 | } 2266 | } 2267 | ] 2268 | }, 2269 | "/musician/tasks": { 2270 | "name": "音乐人任务", 2271 | "explain": "说明 : 音乐人登录后调用此接口 , 可获取音乐人任务。返回的数据中", 2272 | "example": [ 2273 | { 2274 | "query": {} 2275 | } 2276 | ] 2277 | }, 2278 | "/musician/tasks/new": { 2279 | "name": "音乐人任务(新)", 2280 | "explain": "说明 : 音乐人登录后调用此接口 , 可获取音乐人任务。返回的数据中", 2281 | "example": [ 2282 | { 2283 | "query": {} 2284 | } 2285 | ] 2286 | }, 2287 | "/musician/cloudbean": { 2288 | "name": "账号云豆数", 2289 | "explain": "说明 : 音乐人登录后调用此接口 , 可获取账号云豆数", 2290 | "example": [ 2291 | { 2292 | "query": {} 2293 | } 2294 | ] 2295 | }, 2296 | "/musician/cloudbean/obtain": { 2297 | "name": "领取云豆", 2298 | "explain": "说明 : 音乐人登录后调用此接口 , 可领取已完成的音乐人任务的云豆奖励", 2299 | "example": [ 2300 | { 2301 | "query": { 2302 | "id": "7036416928", 2303 | "period": "1" 2304 | } 2305 | } 2306 | ] 2307 | }, 2308 | "/vip/info": { 2309 | "name": "获取 VIP 信息", 2310 | "explain": "说明: 登录后调用此接口,可获取当前 VIP 信息。", 2311 | "example": [ 2312 | { 2313 | "query": {} 2314 | }, 2315 | { 2316 | "query": { 2317 | "uid": "32953014" 2318 | } 2319 | } 2320 | ] 2321 | }, 2322 | "/vip/info/v2": { 2323 | "name": "获取 VIP 信息(app端)", 2324 | "explain": "说明: 登录后调用此接口,可获取当前 VIP 信息。", 2325 | "example": [ 2326 | { 2327 | "query": {} 2328 | }, 2329 | { 2330 | "query": { 2331 | "uid": "32953014" 2332 | } 2333 | } 2334 | ] 2335 | }, 2336 | "/musician/sign": { 2337 | "name": "音乐人签到", 2338 | "explain": "说明: 音乐人登录后调用此接口,可以完成“登录音乐人中心”任务,然后通过", 2339 | "example": [ 2340 | { 2341 | "query": {} 2342 | } 2343 | ] 2344 | }, 2345 | "/artist/video": { 2346 | "name": "获取歌手视频", 2347 | "explain": "说明 : 调用此接口 , 传入歌手 id, 可获得歌手视频", 2348 | "example": [ 2349 | { 2350 | "query": { 2351 | "id": "2116" 2352 | } 2353 | } 2354 | ] 2355 | }, 2356 | "/record/recent/song": { 2357 | "name": "最近播放-歌曲", 2358 | "explain": "说明 : 调用此接口 , 可获得最近播放-歌曲", 2359 | "example": [ 2360 | { 2361 | "query": { 2362 | "limit": "1" 2363 | } 2364 | } 2365 | ] 2366 | }, 2367 | "/record/recent/video": { 2368 | "name": "最近播放-视频", 2369 | "explain": "说明 : 调用此接口 , 可获得最近播放-视频", 2370 | "example": [ 2371 | { 2372 | "query": { 2373 | "limit": "1" 2374 | } 2375 | } 2376 | ] 2377 | }, 2378 | "/record/recent/voice": { 2379 | "name": "最近播放-声音", 2380 | "explain": "说明 : 调用此接口 , 可获得最近播放-声音", 2381 | "example": [ 2382 | { 2383 | "query": { 2384 | "limit": "1" 2385 | } 2386 | } 2387 | ] 2388 | }, 2389 | "/record/recent/playlist": { 2390 | "name": "最近播放-歌单", 2391 | "explain": "说明 : 调用此接口 , 可获得最近播放-歌单", 2392 | "example": [ 2393 | { 2394 | "query": { 2395 | "limit": "1" 2396 | } 2397 | } 2398 | ] 2399 | }, 2400 | "/record/recent/album": { 2401 | "name": "最近播放-专辑", 2402 | "explain": "说明 : 调用此接口 , 可获得最近播放-专辑", 2403 | "example": [ 2404 | { 2405 | "query": { 2406 | "limit": "1" 2407 | } 2408 | } 2409 | ] 2410 | }, 2411 | "/record/recent/dj": { 2412 | "name": "最近播放-播客", 2413 | "explain": "说明 : 调用此接口 , 可获得最近播放-播客", 2414 | "example": [ 2415 | { 2416 | "query": { 2417 | "limit": "1" 2418 | } 2419 | } 2420 | ] 2421 | }, 2422 | "/signin/progress": { 2423 | "name": "签到进度", 2424 | "explain": "说明 : 调用此接口 , 可获得签到进度", 2425 | "example": [ 2426 | { 2427 | "query": { 2428 | "moduleId": "1207signin-1207signin" 2429 | } 2430 | } 2431 | ] 2432 | }, 2433 | "/inner/version": { 2434 | "name": "内部版本接口", 2435 | "explain": "说明 : 调用此接口 , 可获得内部版本号(从package.json读取)", 2436 | "example": [ 2437 | { 2438 | "query": {} 2439 | } 2440 | ] 2441 | }, 2442 | "/vip/timemachine": { 2443 | "name": "黑胶时光机", 2444 | "explain": "说明 : 调用此接口 , 可获得黑胶时光机数据", 2445 | "example": [ 2446 | { 2447 | "query": {} 2448 | }, 2449 | { 2450 | "query": { 2451 | "startTime": "1638288000000", 2452 | "endTime": "1640966399999", 2453 | "limit": "10" 2454 | } 2455 | }, 2456 | { 2457 | "query": { 2458 | "startTime": "1609430400", 2459 | "endTime": "1640966399999", 2460 | "limit": "60" 2461 | } 2462 | } 2463 | ] 2464 | }, 2465 | "/song/wiki/summary": { 2466 | "name": "音乐百科 - 简要信息", 2467 | "explain": "说明: 调用此接口可以获取歌曲的音乐百科简要信息", 2468 | "example": [ 2469 | { 2470 | "query": { 2471 | "id": "1958384591" 2472 | } 2473 | } 2474 | ] 2475 | }, 2476 | "/sheet/list": { 2477 | "name": "乐谱列表", 2478 | "explain": "说明: 调用此接口可以获取歌曲的乐谱列表", 2479 | "example": [ 2480 | { 2481 | "query": { 2482 | "id": "1815684465" 2483 | } 2484 | } 2485 | ] 2486 | }, 2487 | "/sheet/preview": { 2488 | "name": "乐谱内容", 2489 | "explain": "说明: 登录后调用此接口获取乐谱的内容", 2490 | "example": [ 2491 | { 2492 | "query": { 2493 | "id": "143190" 2494 | } 2495 | } 2496 | ] 2497 | }, 2498 | "/style/list": { 2499 | "name": "曲风列表", 2500 | "explain": "说明: 调用此接口获取曲风列表及其对应的 ", 2501 | "example": [ 2502 | { 2503 | "query": {} 2504 | } 2505 | ] 2506 | }, 2507 | "/style/preference": { 2508 | "name": "曲风偏好", 2509 | "explain": "说明: 登录后调用此接口获取我的曲风偏好", 2510 | "example": [ 2511 | { 2512 | "query": {} 2513 | } 2514 | ] 2515 | }, 2516 | "/style/detail": { 2517 | "name": "曲风详情", 2518 | "explain": "说明: 调用此接口可以获取该曲风的描述信息", 2519 | "example": [ 2520 | { 2521 | "query": { 2522 | "tagId": "1000" 2523 | } 2524 | } 2525 | ] 2526 | }, 2527 | "/style/song": { 2528 | "name": "曲风-歌曲", 2529 | "explain": "说明: 调用此接口可以获取该曲风对应的歌曲", 2530 | "example": [ 2531 | { 2532 | "query": { 2533 | "tagId": "1000" 2534 | } 2535 | }, 2536 | { 2537 | "query": { 2538 | "tagId": "1010", 2539 | "sort": "1" 2540 | } 2541 | } 2542 | ] 2543 | }, 2544 | "/style/album": { 2545 | "name": "曲风-专辑", 2546 | "explain": "说明: 调用此接口可以获取该曲风对应的专辑", 2547 | "example": [ 2548 | { 2549 | "query": { 2550 | "tagId": "1000" 2551 | } 2552 | }, 2553 | { 2554 | "query": { 2555 | "tagId": "1010", 2556 | "sort": "1" 2557 | } 2558 | } 2559 | ] 2560 | }, 2561 | "/style/playlist": { 2562 | "name": "曲风-歌单", 2563 | "explain": "说明: 调用此接口可以获取该曲风对应的歌单", 2564 | "example": [ 2565 | { 2566 | "query": { 2567 | "tagId": "1000" 2568 | } 2569 | } 2570 | ] 2571 | }, 2572 | "/style/artist": { 2573 | "name": "曲风-歌手", 2574 | "explain": "说明: 调用此接口可以获取该曲风对应的歌手", 2575 | "example": [ 2576 | { 2577 | "query": { 2578 | "tagId": "1000" 2579 | } 2580 | } 2581 | ] 2582 | }, 2583 | "/get/userids": { 2584 | "name": "根据nickname获取userid", 2585 | "explain": "说明: 使用此接口,传入用户昵称,可获取对应的用户id,支持批量获取,多个昵称用", 2586 | "example": [ 2587 | { 2588 | "query": { 2589 | "nicknames": "binaryify" 2590 | } 2591 | }, 2592 | { 2593 | "query": { 2594 | "nicknames": "binaryify;binaryify2" 2595 | } 2596 | } 2597 | ] 2598 | }, 2599 | "/ugc/album/get": { 2600 | "name": "专辑简要百科信息", 2601 | "explain": "说明: 登录后调用此接口,使用此接口,传入专辑id,可获取对应的专辑简要百科信息", 2602 | "example": [ 2603 | { 2604 | "query": { 2605 | "id": "168223858" 2606 | } 2607 | } 2608 | ] 2609 | }, 2610 | "/ugc/song/get": { 2611 | "name": "歌曲简要百科信息", 2612 | "explain": "说明: 登录后调用此接口,使用此接口,传入歌曲id,可获取对应的歌曲简要百科信息", 2613 | "example": [ 2614 | { 2615 | "query": { 2616 | "id": "2058263032" 2617 | } 2618 | } 2619 | ] 2620 | }, 2621 | "/ugc/artist/get": { 2622 | "name": "歌手简要百科信息", 2623 | "explain": "说明: 登录后调用此接口,使用此接口,传入歌手id,可获取对应的歌手简要百科信息", 2624 | "example": [ 2625 | { 2626 | "query": { 2627 | "id": "15396" 2628 | } 2629 | } 2630 | ] 2631 | }, 2632 | "/ugc/mv/get": { 2633 | "name": "mv简要百科信息", 2634 | "explain": "说明: 登录后调用此接口,使用此接口,传入mv id,可获取对应的mv简要百科信息", 2635 | "example": [ 2636 | { 2637 | "query": { 2638 | "id": "14572641" 2639 | } 2640 | } 2641 | ] 2642 | }, 2643 | "/ugc/artist/search": { 2644 | "name": "搜索歌手", 2645 | "explain": "说明: 登录后调用此接口,使用此接口,传入歌手名关键字或者歌手id,可获取搜索到的歌手信息", 2646 | "example": [ 2647 | { 2648 | "query": { 2649 | "keyword": "sasakure" 2650 | } 2651 | } 2652 | ] 2653 | }, 2654 | "/ugc/detail": { 2655 | "name": "用户贡献内容", 2656 | "explain": "说明: 登录后调用此接口,使用此接口,可获取当前登录用户贡献内容", 2657 | "example": [ 2658 | { 2659 | "query": {} 2660 | } 2661 | ] 2662 | }, 2663 | "/ugc/user/devote": { 2664 | "name": "用户贡献条目、积分、云贝数量", 2665 | "explain": "说明: 登录后调用此接口,使用此接口,可获取当前登录用户贡献条目、积分、云贝数量", 2666 | "example": [ 2667 | { 2668 | "query": {} 2669 | } 2670 | ] 2671 | }, 2672 | "/summary/annual": { 2673 | "name": "年度听歌报告", 2674 | "explain": "说明: 登录后调用此接口,使用此接口,可获取当前登录用户年度听歌报告,目前支持2017-2022年的报告", 2675 | "example": [ 2676 | { 2677 | "query": { 2678 | "year": "2022" 2679 | } 2680 | } 2681 | ] 2682 | }, 2683 | "/login/cellphone": { 2684 | "name": "手机登录", 2685 | "explain": "说明 : 验证码,使用 /captcha/sent接口传入手机号获取验证码,调用此接口传入验证码,可使用验证码登录,传入后 password 参数将失效", 2686 | "example": [ 2687 | { 2688 | "query": { 2689 | "phone": "13xxx", 2690 | "captcha": "1234" 2691 | } 2692 | } 2693 | ] 2694 | }, 2695 | "/user/replacephone": { 2696 | "name": "用户绑定手机", 2697 | "explain": "说明 : 登录后调用此接口 , 可以更换绑定手机", 2698 | "example": [ 2699 | { 2700 | "query": { 2701 | "phone": "xxx", 2702 | "captcha": "1234", 2703 | "oldcaptcha": "2345" 2704 | } 2705 | } 2706 | ] 2707 | }, 2708 | "/audio/match": { 2709 | "name": "听歌识曲", 2710 | "explain": "说明: 使用此接口,上传音频文件或者麦克风采集声音可识别对应歌曲信息,具体调用例子参考 ", 2711 | "example": [] 2712 | }, 2713 | "/rebind": { 2714 | "name": "更换绑定手机", 2715 | "explain": "说明 : 调用此接口 ,可更换绑定手机(流程:先发送验证码到原手机号码,再发送验证码到新手机号码然后再调用此接口)", 2716 | "example": [ 2717 | { 2718 | "query": { 2719 | "phone": "xxx", 2720 | "oldcaptcha": "1234", 2721 | "captcha": "5678" 2722 | } 2723 | } 2724 | ] 2725 | }, 2726 | "/nickname/check": { 2727 | "name": "重复昵称检测", 2728 | "explain": "说明 : 调用此接口 ,可检测昵称是否重复,并提供备用昵称\n", 2729 | "example": [ 2730 | { 2731 | "query": { 2732 | "nickname": "binaryify" 2733 | } 2734 | } 2735 | ] 2736 | }, 2737 | "/activate/init/profile": { 2738 | "name": "初始化昵称", 2739 | "explain": "说明 : 刚注册的账号(需登录),调用此接口 ,可初始化昵称", 2740 | "example": [ 2741 | { 2742 | "query": { 2743 | "nickname": "testUser2019" 2744 | } 2745 | } 2746 | ] 2747 | }, 2748 | "/cellphone/existence/check": { 2749 | "name": "检测手机号码是否已注册", 2750 | "explain": "说明 : 调用此接口 ,可检测手机号码是否已注册", 2751 | "example": [ 2752 | { 2753 | "query": { 2754 | "phone": "13xxx" 2755 | } 2756 | } 2757 | ] 2758 | }, 2759 | "/register/cellphone": { 2760 | "name": "注册(修改密码)", 2761 | "explain": "说明 : 调用此接口 ,传入手机号码和验证码,密码,昵称, 可注册网易云音乐账号(同时可修改密码)", 2762 | "example": [ 2763 | { 2764 | "query": { 2765 | "phone": "13xxx", 2766 | "password": "xxxxx", 2767 | "captcha": "1234", 2768 | "nickname": "binary1345" 2769 | } 2770 | } 2771 | ] 2772 | }, 2773 | "/captcha/verify": { 2774 | "name": "验证验证码", 2775 | "explain": "说明 : 调用此接口 ,传入手机号码和验证码, 可校验验证码是否正确", 2776 | "example": [ 2777 | { 2778 | "query": { 2779 | "phone": "13xxx", 2780 | "captcha": "1597" 2781 | } 2782 | } 2783 | ] 2784 | }, 2785 | "/captcha/sent": { 2786 | "name": "发送验证码", 2787 | "explain": "说明 : 调用此接口 ,传入手机号码, 可发送验证码", 2788 | "example": [ 2789 | { 2790 | "query": { 2791 | "phone": "13xxx" 2792 | } 2793 | } 2794 | ] 2795 | }, 2796 | "/login/refresh": { 2797 | "name": "刷新登录", 2798 | "explain": "说明 : 调用此接口 , 可刷新登录状态,返回内容包含新的cookie(不支持刷新二维码登录的cookie)", 2799 | "example": [ 2800 | { 2801 | "query": {} 2802 | } 2803 | ] 2804 | }, 2805 | "/logout": { 2806 | "name": "退出登录", 2807 | "explain": "说明 : 调用此接口 , 可退出登录", 2808 | "example": [ 2809 | { 2810 | "query": {} 2811 | } 2812 | ] 2813 | }, 2814 | "/user/update": { 2815 | "name": "更新用户信息", 2816 | "explain": "说明 : 登录后调用此接口 , 传入相关信息,可以更新用户信息", 2817 | "example": [ 2818 | { 2819 | "query": { 2820 | "gender": "0", 2821 | "signature": "测试签名", 2822 | "city": "440300", 2823 | "nickname": "binary", 2824 | "birthday": "1525918298004", 2825 | "province": "440000" 2826 | } 2827 | } 2828 | ] 2829 | }, 2830 | "/avatar/upload": { 2831 | "name": "更新头像", 2832 | "explain": "说明 : 登录后调用此接口,使用", 2833 | "example": [ 2834 | { 2835 | "query": { 2836 | "imgSize": "200" 2837 | } 2838 | } 2839 | ] 2840 | }, 2841 | "/pl/count": { 2842 | "name": "私信和通知接口", 2843 | "explain": "说明 : 登录后调用此接口,可获取私信和通知数量信息", 2844 | "example": [ 2845 | { 2846 | "query": {} 2847 | } 2848 | ] 2849 | }, 2850 | "/playlist/update": { 2851 | "name": "更新歌单", 2852 | "explain": "说明 : 登录后调用此接口,可以更新用户歌单", 2853 | "example": [ 2854 | { 2855 | "query": { 2856 | "id": "24381616", 2857 | "name": "新歌单", 2858 | "desc": "描述", 2859 | "tags": "欧美" 2860 | } 2861 | } 2862 | ] 2863 | }, 2864 | "/playlist/desc/update": { 2865 | "name": "更新歌单描述", 2866 | "explain": "说明 : 登录后调用此接口,可以单独更新用户歌单描述", 2867 | "example": [ 2868 | { 2869 | "query": { 2870 | "id": "24381616", 2871 | "desc": "描述" 2872 | } 2873 | } 2874 | ] 2875 | }, 2876 | "/playlist/name/update": { 2877 | "name": "更新歌单名", 2878 | "explain": "说明 : 登录后调用此接口,可以单独更新用户歌单名", 2879 | "example": [ 2880 | { 2881 | "query": { 2882 | "id": "24381616", 2883 | "name": "歌单名" 2884 | } 2885 | } 2886 | ] 2887 | }, 2888 | "/playlist/tags/update": { 2889 | "name": "更新歌单标签", 2890 | "explain": "说明 : 登录后调用此接口,可以单独更新用户歌单标签", 2891 | "example": [ 2892 | { 2893 | "query": { 2894 | "id": "24381616", 2895 | "tags": "学习" 2896 | } 2897 | } 2898 | ] 2899 | }, 2900 | "/playlist/cover/update": { 2901 | "name": "歌单封面上传", 2902 | "explain": "说明 : 登录后调用此接口,使用", 2903 | "example": [ 2904 | { 2905 | "query": { 2906 | "id": "3143833470", 2907 | "imgSize": "200" 2908 | } 2909 | } 2910 | ] 2911 | }, 2912 | "/event/forward": { 2913 | "name": "转发用户动态", 2914 | "explain": "说明 : 登录后调用此接口 ,可以转发用户动态", 2915 | "example": [ 2916 | { 2917 | "query": { 2918 | "evId": "6712917601", 2919 | "uid": "32953014", 2920 | "forwards": "测试内容" 2921 | } 2922 | } 2923 | ] 2924 | }, 2925 | "/event/del": { 2926 | "name": "删除用户动态", 2927 | "explain": "说明 : 登录后调用此接口 ,可以删除用户动态", 2928 | "example": [ 2929 | { 2930 | "query": { 2931 | "evId": "6712917601" 2932 | } 2933 | } 2934 | ] 2935 | }, 2936 | "/share/resource": { 2937 | "name": "分享文本、歌曲、歌单、mv、电台、电台节目到动态", 2938 | "explain": "说明 : 登录后调用此接口 ,可以分享文本、歌曲、歌单、mv、电台、电台节目,专辑到动态", 2939 | "example": [ 2940 | { 2941 | "query": { 2942 | "id": "1297494209", 2943 | "msg": "测试" 2944 | } 2945 | }, 2946 | { 2947 | "query": { 2948 | "type": "djradio", 2949 | "id": "336355127" 2950 | } 2951 | }, 2952 | { 2953 | "query": { 2954 | "type": "djprogram", 2955 | "id": "2061034798" 2956 | } 2957 | }, 2958 | { 2959 | "query": { 2960 | "type": "djprogram", 2961 | "id": "2061034798", 2962 | "msg": "测试@binaryify 测试" 2963 | } 2964 | }, 2965 | { 2966 | "query": { 2967 | "type": "noresource", 2968 | "msg": "测试" 2969 | } 2970 | } 2971 | ] 2972 | }, 2973 | "/send/text": { 2974 | "name": "发送私信", 2975 | "explain": "说明 : 登录后调用此接口 , 传入用户 id 和要发送的信息, 可以发送私信,返回内容为历史私信,包含带歌单的私信信息(注:不能发送私信给自己)", 2976 | "example": [ 2977 | { 2978 | "query": { 2979 | "user_ids": "32953014", 2980 | "msg": "test" 2981 | } 2982 | }, 2983 | { 2984 | "query": { 2985 | "user_ids": "32953014,475625142", 2986 | "msg": "test" 2987 | } 2988 | } 2989 | ] 2990 | }, 2991 | "/send/playlist": { 2992 | "name": "发送私信(带歌单)", 2993 | "explain": "说明 : 登录后调用此接口 , 传入用户 id 和要发送的信息和歌单 id, 可以发送带歌单的私信(注:不能发送重复的歌单)", 2994 | "example": [ 2995 | { 2996 | "query": { 2997 | "msg": "test", 2998 | "user_ids": "475625142", 2999 | "playlist": "705123491" 3000 | } 3001 | }, 3002 | { 3003 | "query": { 3004 | "msg": "test2", 3005 | "user_ids": "475625142,32953014", 3006 | "playlist": "705123493" 3007 | } 3008 | } 3009 | ] 3010 | }, 3011 | "/playlist/create": { 3012 | "name": "新建歌单", 3013 | "explain": "说明 : 调用此接口 , 传入歌单名字可新建歌单", 3014 | "example": [ 3015 | { 3016 | "query": { 3017 | "name": "测试歌单" 3018 | } 3019 | }, 3020 | { 3021 | "query": { 3022 | "name": "test", 3023 | "type": "VIDEO" 3024 | } 3025 | } 3026 | ] 3027 | }, 3028 | "/playlist/tracks": { 3029 | "name": "对歌单添加或删除歌曲", 3030 | "explain": "说明 : 调用此接口 , 可以添加歌曲到歌单或者从歌单删除某首歌曲 ( 需要登录 )", 3031 | "example": [ 3032 | { 3033 | "query": { 3034 | "op": "add", 3035 | "pid": "24381616", 3036 | "tracks": "347231" 3037 | } 3038 | } 3039 | ] 3040 | }, 3041 | "/daily_signin": { 3042 | "name": "签到", 3043 | "explain": "说明 : 调用此接口 , 传入签到类型 ( 可不传 , 默认安卓端签到 ), 可签到 ( 需要登录\n), 其中安卓端签到可获得 3 点经验 , web/PC 端签到可获得 2 点经验", 3044 | "example": [ 3045 | { 3046 | "query": {} 3047 | } 3048 | ] 3049 | }, 3050 | "/fm_trash": { 3051 | "name": "垃圾桶", 3052 | "explain": "说明 : 调用此接口 , 传入音乐 id, 可把该音乐从私人 FM 中移除至垃圾桶", 3053 | "example": [ 3054 | { 3055 | "query": { 3056 | "id": "347230" 3057 | } 3058 | } 3059 | ] 3060 | }, 3061 | "/login/status": { 3062 | "name": "登录状态", 3063 | "explain": "说明 : 调用此接口,可获取登录状态", 3064 | "example": [ 3065 | { 3066 | "query": {} 3067 | } 3068 | ] 3069 | } 3070 | } -------------------------------------------------------------------------------- /package/build/lib/NeteaseCloudMusic/help.py: -------------------------------------------------------------------------------- 1 | import json 2 | import pkg_resources 3 | 4 | # 载入配置 5 | resource_path = pkg_resources.resource_filename(__name__, 'config.json') 6 | 7 | # 不被支持的接口 8 | exclude = ["/request/reference", "/avatar/upload", "/cloud", "/playlist/cover/update", "/voice/upload", 9 | "/register/anonimous", "/verify/getQr"] 10 | 11 | with open(resource_path, 'r', encoding='utf-8') as f: 12 | config = json.loads(f.read()) 13 | 14 | 15 | def api_help(name: str = None) -> str: 16 | """ 17 | 获取接口帮助 18 | :param name: 接口名称 19 | :return: 20 | """ 21 | if name is None: 22 | result_str = ("from NeteaseCloudMusic import NeteaseCloudMusicApi, api_help, api_list\n\n" 23 | "netease_cloud_music_api = NeteaseCloudMusicApi() # 初始化API\n" 24 | "netease_cloud_music_api.cookie = YOUR_COOKIE # 设置cookie\n" 25 | "response = netease_cloud_music_api.request(apiName, queryDict) # 调用接口\n\n" 26 | "# Use ”help(apiName)“ to view detailed information about the interface\n" 27 | "# Use ”api_list()“ to view the interface list") 28 | elif name in api_list(): 29 | result_str = f'name: {name}\n {config[name]["name"]}\n {config[name]["explain"]}\n\n' 30 | 31 | result_str += "query example: \n" 32 | for example in config[name]["example"]: 33 | index = config[name]["example"].index(example) 34 | result_str += f'{json.dumps(config[name]["example"][index]["query"], indent=2, ensure_ascii=False)}\n\n' 35 | else: 36 | result_str = f'apiName: {name} not found,please use ”api_list()“ to view the interface list' 37 | 38 | return result_str 39 | 40 | 41 | def api_list(): 42 | """ 43 | 获取接口列表 44 | :return: 45 | """ 46 | return [item for item in list(config.keys()) if item not in exclude] 47 | -------------------------------------------------------------------------------- /package/build/lib/NeteaseCloudMusic/main.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os.path 3 | import socket 4 | import time 5 | from pprint import pprint 6 | import http.cookies 7 | import datetime 8 | from diskcache import Cache 9 | 10 | import pkg_resources 11 | import requests 12 | from py_mini_racer import py_mini_racer 13 | from .help import api_list 14 | from .utils import format_cookie_str, prase_cookie_str 15 | import urllib.parse 16 | 17 | 18 | class NeteaseCloudMusicApi: 19 | __cookie = None 20 | __ip = None 21 | 22 | cache = Cache('cache', timeout=120) # 设置缓存目录和过期时间 23 | 24 | # cache = TTLCache(maxsize=100, ttl=120) # 设置缓存大小为100,缓存项的生存时间为120秒 25 | 26 | def __init__(self, debug=False, cache=False): 27 | self.DEBUG = debug # 是否开启调试模式 28 | self.CACHE = cache # 是否开启缓存 29 | 30 | self.special_api = {"/playlist/track/all": self.playlist_track_all, 31 | "/login/cellphone": self.login_cellphone, 32 | "/inner/version": self.inner_version, 33 | "/login/refresh": self.login_refresh} 34 | 35 | # 载入js代码 36 | resource_path = pkg_resources.resource_filename(__name__, 'NeteaseCloudMusicApi.js') 37 | 38 | with open(resource_path, 'r', encoding='utf-8') as file: 39 | js_code = file.read() 40 | self.ctx = py_mini_racer.MiniRacer() 41 | self.ctx.eval(js_code) 42 | 43 | def request(self, name: str, query: dict = None) -> dict: 44 | """ 45 | 调用接口 46 | 接口文档地址: https://docs.neteasecloudmusicapi.binaryify.com 47 | :param name: api名称 例如: song_url_v1, /song/url/v1 48 | :param query: 请求参数 49 | :return: 请求结果 示例:{"code": 200, "data": {}, "msg": "success"} 50 | """ 51 | 52 | special = { 53 | 'daily_signin': '/daily_signin', 54 | 'fm_trash': '/fm_trash', 55 | 'personal_fm': '/personal_fm', 56 | } 57 | 58 | yubei_special = {'/yunbei/tasks/receipt': '/yunbei/receipt', 59 | '/yunbei/tasks/expense': '/yunbei/expense'} # 这俩个接口准换的路由莫名奇妙 60 | 61 | # 测试name是否合法 62 | name.replace("\\", "/") 63 | if not name.startswith("/"): 64 | if name in special.keys(): 65 | name = special[name] 66 | else: 67 | name = "/" + name 68 | name = name.replace("_", "/") 69 | 70 | # 处理俩个云贝接口名称转换问题 71 | if name in yubei_special.keys(): 72 | name = yubei_special[name] 73 | # print("转换了个麻烦的路由", name) 74 | 75 | if name not in api_list(): 76 | if name not in yubei_special.values(): 77 | raise Exception(f"apiName: {name} not found,please use ”api_list()“ to view the interface list") 78 | 79 | # 生成一个唯一的键,用于在缓存中查找结果 80 | cache_key = (name, frozenset(query.items()) if query else None) 81 | 82 | if self.CACHE: 83 | # 检查缓存中是否已经有了结果 84 | if self.cache.get(cache_key): 85 | return self.cache.get(cache_key) 86 | 87 | if query is None: 88 | query = {} 89 | else: 90 | # 如果存在timestamp参数,那么删除它 91 | if query.get("timestamp"): 92 | del query["timestamp"] 93 | 94 | if query.get("cookie") is None: 95 | query["cookie"] = self.cookie 96 | 97 | if query.get("realIP") is None: 98 | query["realIP"] = self.ip 99 | else: 100 | query["realIP"] = query.get("realIP") 101 | 102 | # 特殊api处理 103 | if name in self.special_api.keys(): 104 | result = self.special_api[name](query) 105 | else: 106 | result = self.call_api(name, query) 107 | 108 | if self.CACHE: 109 | # 将结果存入缓存 110 | self.cache.set(cache_key, result) 111 | 112 | return result 113 | 114 | @staticmethod 115 | def get_local_ip(): 116 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 117 | try: 118 | # doesn't even have to be reachable 119 | s.connect(('10.255.255.255', 1)) 120 | IP = s.getsockname()[0] 121 | except Exception: 122 | print("get local ip error") 123 | IP = "116.25.146.177" 124 | finally: 125 | s.close() 126 | return IP 127 | 128 | @property 129 | def cookie(self): 130 | if self.__cookie is None: 131 | if os.path.isfile("cookie_storage"): 132 | with open("cookie_storage", "r", encoding='utf-8') as f: 133 | content = f.read() 134 | try: 135 | cookie_storage = json.loads(content) 136 | # 验证cookie是否过期 137 | create_time_stamp = cookie_storage['create_time_stamp'] 138 | 139 | if time.time() - create_time_stamp > 1296010: 140 | # cookie过期了 141 | self.__cookie = "" 142 | else: 143 | # 判断cookie生成时间是否超过1天 144 | if time.time() - create_time_stamp > 86400: 145 | # 更新cookie 146 | # Todo login_refresh接口返回cookie好像少一些值 147 | # self.request("/login/refresh", {"cookie": cookie_storage['cookie'], "timestamp": time.time()}) 148 | self.cookie = cookie_storage['cookie'] 149 | else: 150 | self.__cookie = cookie_storage['cookie'] 151 | except json.JSONDecodeError and KeyError: 152 | self.__cookie = "" 153 | else: 154 | self.__cookie = "" # 如果没有cookie文件,就设置为空 155 | 156 | return self.__cookie 157 | 158 | @cookie.setter 159 | def cookie(self, value): 160 | if value is None: 161 | self.__cookie = "" 162 | return 163 | 164 | "判断cookie是否合法, 简单检查一下关键的键" 165 | necessary_keys = ["__csrf", "MUSIC_A_T", "MUSIC_R_T"] 166 | cookie_dict = prase_cookie_str(value) 167 | for key in necessary_keys: 168 | if cookie_dict.get(key) is None: 169 | raise Exception(f"cookie is illegal, missing key: {key}.") 170 | 171 | self.__cookie = value 172 | with open("cookie_storage", "w+", encoding='utf-8') as f: 173 | f.write(json.dumps({"cookie": value, "create_time_stamp": time.time()}, indent=2, ensure_ascii=False)) 174 | 175 | @property 176 | def ip(self): 177 | if self.__ip is None: 178 | self.__ip = self.get_local_ip() 179 | return self.__ip 180 | 181 | def call_api(self, name, query): 182 | request_param = self.ctx.call('NeteaseCloudMusicApi.beforeRequest', name, query) # 拿到请求头和请求参数 183 | 184 | # Todo 了解 py_mini_racer 返回没有自动编码 而 node可以 185 | param_data = {} 186 | if request_param["data"] != "": 187 | for item in request_param["data"].split("&"): 188 | # param_data[item.split("=")[0]] = urllib.parse.quote(item.split("=")[1], safe='') # 不需要编码后反而出错 189 | param_data[item.split("=")[0]] = item.split("=")[1] 190 | 191 | if request_param.get("method") == "GET": 192 | response = requests.get(request_param["url"], params=param_data, headers=request_param["headers"]) 193 | else: 194 | response = requests.post(request_param["url"], data=param_data, headers=request_param["headers"]) 195 | 196 | try: 197 | data = json.loads(response.text) 198 | except json.JSONDecodeError: 199 | data = response.text 200 | 201 | response_result = { 202 | "headers": dict(response.headers), 203 | "data": data, 204 | "status": response.status_code, 205 | } 206 | 207 | result = self.ctx.call('NeteaseCloudMusicApi.afterRequest', 208 | json.dumps(response_result), 209 | request_param.get('crypto', None), 210 | request_param['apiName']) # 拿到请求结果 211 | 212 | return result 213 | 214 | def playlist_track_all(self, query): 215 | """ 216 | 获取歌单全部歌曲 217 | :param query: 218 | :return: 219 | """ 220 | 221 | detail_query = {"id": query.get("id"), "cookie": query.get("cookie"), "realIP": query.get("realIP")} 222 | 223 | result = self.call_api("/playlist/detail", detail_query) 224 | 225 | track_all_query = {"detail_result": json.dumps(result), "cookie": query.get("cookie"), 226 | "realIP": query.get("realIP")} 227 | if query.get("limit"): 228 | track_all_query["limit"] = query.get("limit") 229 | if query.get("offset"): 230 | track_all_query["offset"] = query.get("offset") 231 | 232 | result = self.call_api("/playlist/track/all", track_all_query) 233 | return result 234 | 235 | def inner_version(self, query): 236 | """ 237 | 获取所使用的 NeteaseCloudMusicApi 和 NeteaseCloudMusicApi_V8 版本号 238 | :param query: 239 | :return: 240 | """ 241 | result = self.ctx.call('NeteaseCloudMusicApi.inner_version') 242 | return result 243 | 244 | def login_cellphone(self, query): 245 | """ 246 | 手机号登录 247 | :param query: 248 | :return: 249 | """ 250 | result = self.call_api("/login/cellphone", query) 251 | 252 | # 自动 更新cookie 253 | if result["code"] == 200: 254 | if result.get("data").get("cookie"): 255 | # cookie_str = format_cookie_str(result.get("data").get("cookie")) 256 | cookie_str = result.get("data").get("cookie") 257 | result["data"]["cookie"] = cookie_str 258 | self.cookie = cookie_str 259 | return result 260 | 261 | def login_refresh(self, query): 262 | """ 263 | 刷新登录状态 264 | :param query: 265 | :return: 266 | """ 267 | result = self.call_api("/login/refresh", query) 268 | 269 | # 自动 更新cookie 270 | # if result["code"] == 200: 271 | # if result.get("data").get("cookie"): 272 | # # cookie_str = format_cookie_str(result.get("data").get("cookie")) 273 | # cookie_str = result.get("data").get("cookie") 274 | # result["data"]["cookie"] = cookie_str 275 | # pprint(cookie_str) 276 | # self.cookie = cookie_str 277 | return result 278 | -------------------------------------------------------------------------------- /package/build/lib/NeteaseCloudMusic/utils.py: -------------------------------------------------------------------------------- 1 | from pprint import pprint 2 | 3 | 4 | def format_cookie_str(cookie_str: str) -> str: 5 | """ 6 | 格式化cookie字符串 7 | 功能 8 | 处理以逗号分割的cookie字符串 9 | 删除max-age为0的cookie 10 | 注意: 11 | 传入cookie字符串必须是以 逗号+空格 或 分号+空格 分割的规范cookie字符串 12 | :param cookie_str: 13 | :return: 格式化后的cookie str 14 | """ 15 | 16 | if not cookie_str: 17 | return "" 18 | 19 | # 解析cookie字符串 20 | cookie_dict = prase_cookie_str(cookie_str) 21 | 22 | cookie_valid_dict = {} 23 | # 删除max-age为0的cookie 24 | for item in cookie_dict.keys(): 25 | max_age = cookie_dict[item].get("Max-Age") 26 | if max_age: 27 | max_age = int(max_age) 28 | if max_age != 0: 29 | cookie_valid_dict[item] = cookie_dict[item] 30 | 31 | # 重新拼接cookie字符串 32 | cookie = "" 33 | for item in cookie_valid_dict.keys(): 34 | cookie += item + "=" + cookie_valid_dict[item]["value"] + "; " 35 | for key in cookie_valid_dict[item].keys(): 36 | if key != "value": 37 | cookie += key + "=" + cookie_valid_dict[item][key] + "; " 38 | 39 | return cookie[: -2] 40 | 41 | 42 | def prase_cookie_str(cookie_str: str) -> dict: 43 | """ 44 | 解析cookie字符串 45 | 功能 46 | 处理以逗号分割的cookie字符串 47 | 注意: 48 | 传入cookie字符串必须是以 逗号+空格 或 分号+空格 分割的规范cookie字符串 49 | :param cookie_str: 50 | :return: cookie dict 51 | """ 52 | if not cookie_str: 53 | return {} 54 | 55 | # 解决用逗号分割的问题 56 | cookie_part = [] 57 | for item in cookie_str.split(", "): 58 | cookie_part.extend(item.split("; ")) 59 | 60 | cookies = [] 61 | for item in cookie_part: 62 | if "=" not in item: 63 | # 属于上一个cookie的一部分 64 | cookies[-1] = cookies[-1] + item 65 | else: 66 | cookies.append(item) 67 | 68 | cookie_dict = {} 69 | 70 | current_name = "" 71 | for cookie in cookies: 72 | # print(cookie) 73 | if cookie[-1] == "=": 74 | name = cookie[:-1] 75 | value = "" 76 | else: 77 | part = cookie.split("=") 78 | name = part[0] 79 | value = part[1] 80 | 81 | if name in ["Max-Age", "Expires", "Path", "Domain"]: 82 | cookie_dict[current_name][name] = value 83 | else: 84 | cookie_dict[name] = {"value": value} 85 | current_name = name 86 | 87 | return cookie_dict 88 | 89 | 90 | if __name__ == '__main__': 91 | cookie = ("MUSIC_R_T=1579622000495; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; " 92 | "Path=/openapi/clientlog; Domain=.music.163.com, MUSIC_A_T=1579621885297; Max-Age=2147483647; Expires=Wed, " 93 | "02 Jan 2092 11:39:38 GMT; Path=/wapi/feedback; Domain=.music.163.com, __remember_me=true; " 94 | "Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/; Domain=.music.163.com, " 95 | "MUSIC_A_T=1579621885297; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/api/feedback; " 96 | "Domain=.music.163.com, MUSIC_A_T=1579621885297; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; " 97 | "Path=/eapi/clientlog; Domain=.music.163.com, MUSIC_A_T=1579621885297; Max-Age=2147483647; Expires=Wed, " 98 | "02 Jan 2092 11:39:38 GMT; Path=/api/clientlog; Domain=.music.163.com, MUSIC_R_T=1579622000495; " 99 | "Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/wapi/feedback; Domain=.music.163.com, " 100 | "MUSIC_A_T=1579621885297; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/weapi/clientlog; " 101 | "Domain=.music.163.com, MUSIC_R_T=1579622000495; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; " 102 | "Path=/neapi/feedback; Domain=.music.163.com, MUSIC_R_T=1579622000495; Max-Age=2147483647; Expires=Wed, " 103 | "02 Jan 2092 11:39:38 GMT; Path=/eapi/clientlog; Domain=.music.163.com, MUSIC_R_T=1579622000495; " 104 | "Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/api/feedback; Domain=.music.163.com, " 105 | "MUSIC_A_T=1579621885297; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/weapi/feedback; " 106 | "Domain=.music.163.com, MUSIC_R_T=1579622000495; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; " 107 | "Path=/eapi/feedback; Domain=.music.163.com, MUSIC_A_T=1579621885297; Max-Age=2147483647; Expires=Wed, " 108 | "02 Jan 2092 11:39:38 GMT; Path=/neapi/clientlog; Domain=.music.163.com, MUSIC_R_T=1579622000495; " 109 | "Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/wapi/clientlog; Domain=.music.163.com, " 110 | "MUSIC_A_T=1579621885297; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/wapi/clientlog; " 111 | "Domain=.music.163.com, MUSIC_R_T=1579622000495; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; " 112 | "Path=/weapi/feedback; Domain=.music.163.com, NMTID=00OLqRn-wykrFFXdElLpZA3_-aaQtIAAAGMbJSp9A; " 113 | "Max-Age=315360000; Expires=Mon, 12 Dec 2033 08:25:31 GMT; Path=/; Domain=music.163.com, " 114 | "__csrf=4d5e515015723fd3d7edaa5b05f35b4d; Max-Age=1296010; Expires=Sat, 30 Dec 2023 08:25:41 GMT; Path=/; " 115 | "Domain=.music.163.com, MUSIC_R_T=1579622000495; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; " 116 | "Path=/neapi/clientlog; Domain=.music.163.com, MUSIC_A_T=1579621885297; Max-Age=2147483647; Expires=Wed, " 117 | "02 Jan 2092 11:39:38 GMT; Path=/openapi/clientlog; Domain=.music.163.com, MUSIC_A_T=1579621885297; " 118 | "Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/eapi/feedback; Domain=.music.163.com, " 119 | "MUSIC_R_T=1579622000495; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/weapi/clientlog; " 120 | "Domain=.music.163.com, MUSIC_R_T=1579622000495; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; " 121 | "Path=/api/clientlog; Domain=.music.163.com, MUSIC_SNS=; Max-Age=0; Expires=Fri, 15 Dec 2023 08:25:31 GMT; " 122 | "Path=/, " 123 | "MUSIC_U=00CCEEF2F7A9825637C9869A455B5CA8E009D905415134A7EDAC2E404A940B2D58BFF7129A413193E9A8FD6D1D497E1E8E9023611BA91D2CB28FA94B53DBE4C42699A30FF1448C8EFAF5B00E73ADD353C52F2E004C094AEAC4BA4D83C6FFBB4CD532DEEAEA8D5584E69AC78110BBA682829C263DA72F5AA290AD826A47F640CA3903AC652E4DDE946ACC4EB8A63E5853FA695B480A919CF84498B7084C5CA9A91297F2CF5AF45C2D545AC0D5C03A1641306BAC0FB6FFD57BC653A91F2483FB52BFE85DE39280B012BC036DF244883D9700480E5FDDCD5A417C60241AE08CD6AA84BFC1C8890AE4A08286144D9D1146E33C67CF7797CDB5A961C85DB5AC492B232601D80D4DB07E4F170F635ABC01E080B4D32408FA0698DAD95AD80CDB99F2F672638048F5116214319175B596BF68B2A7A0269746EABFD919D62C165353725E6B1253A7C5D6774D453DDDCC28524D3378; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/; Domain=.music.163.com, MUSIC_A_T=1579621885297; Max-Age=2147483647; Expires=Wed, 02 Jan 2092 11:39:38 GMT; Path=/neapi/feedback; Domain=.music.163.com") 124 | pprint(prase_cookie_str(cookie)) 125 | -------------------------------------------------------------------------------- /package/dist/NeteaseCloudMusic-0.1.7-py2.py3-none-any.whl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2061360308/NeteaseCloudMusic_PythonSDK/02a34af715dc3a25ea370fb3b0f69f3978b6960f/package/dist/NeteaseCloudMusic-0.1.7-py2.py3-none-any.whl -------------------------------------------------------------------------------- /package/dist/NeteaseCloudMusic-0.1.7.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2061360308/NeteaseCloudMusic_PythonSDK/02a34af715dc3a25ea370fb3b0f69f3978b6960f/package/dist/NeteaseCloudMusic-0.1.7.tar.gz -------------------------------------------------------------------------------- /package/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Note: To use the 'upload' functionality of this file, you must: 5 | # $ pipenv install twine --dev 6 | 7 | import io 8 | import json 9 | import os 10 | import sys 11 | from shutil import rmtree 12 | 13 | from setuptools import find_packages, setup, Command 14 | 15 | # Package meta-data. 16 | NAME = 'NeteaseCloudMusic' 17 | DESCRIPTION = '网易云音乐API NeteaseCloudMusicApi项目的 Python SDK' 18 | URL = 'https://github.com/2061360308/NeteaseCloudMusic_PythonSDK' 19 | EMAIL = '2061360308@qq.com' 20 | AUTHOR = '盧瞳' 21 | REQUIRES_PYTHON = '>=3.6.0' 22 | VERSION = '0.1.10' 23 | UPDATA_INFO = ('修复了初次使用时没有cookie导致的一系列问题\n' 24 | '修复了NeteaseCloudMusicApi.js没有更新的问题\n' 25 | '添加了对于cookie的判断,现在可以正常判断cookie是否过期了') 26 | 27 | # What packages are required for this module to be executed? 28 | REQUIRED = [ 29 | 'py_mini_racer', 'requests', 'diskcache' 30 | # 'requests', 'maya', 'records', 31 | ] 32 | 33 | # What packages are optional? 34 | EXTRAS = { 35 | # 'fancy feature': ['django'], 36 | } 37 | 38 | # The rest you shouldn't have to touch too much :) 39 | # ------------------------------------------------ 40 | # Except, perhaps the License and Trove Classifiers! 41 | # If you do change the License, remember to change the Trove Classifier for that! 42 | 43 | here = os.path.abspath(os.path.dirname(__file__)) 44 | 45 | print("copy README.md start") 46 | with open(os.path.join(here, '../README.md'), 'r', encoding='utf-8') as f: 47 | README = f.read() 48 | with open(os.path.join(here, 'README.md'), 'w+', encoding='utf-8') as f: 49 | f.write(README) 50 | print("copy README.md end") 51 | 52 | try: 53 | if os.path.exists(os.path.join(here, '../release_notes.txt')): 54 | # 优先读取release_notes.txt(工作流自动生成的当前版本的更新内容) 55 | with open(os.path.join(here, '../release_notes.txt'), 'r', encoding='utf-8') as f: 56 | changelog = f.read() 57 | else: 58 | with io.open(os.path.join(here, '../CHANGELOG.md'), encoding='utf-8') as f: 59 | changelog = f.read() 60 | except FileNotFoundError: 61 | changelog = '' 62 | 63 | # Import the README and use it as the long-description. 64 | # Note: this will only work if 'README.md' is present in your MANIFEST.in file! 65 | try: 66 | with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f: 67 | long_description = '\n' + "# 更新信息" + "\n" + changelog + '\n' + f.read() 68 | except FileNotFoundError: 69 | long_description = DESCRIPTION 70 | 71 | # print("long_description:", long_description) 72 | 73 | print("copy config.json start") 74 | with open(os.path.join(here, '../config.json'), 'r', encoding='utf-8') as f: 75 | config = json.loads(f.read()) 76 | 77 | for key in config: 78 | for example in config[key]['example']: 79 | if 'result' in example: 80 | del example['result'] 81 | with open(os.path.join(here, 'NeteaseCloudMusic/config.json'), 'w+', encoding='utf-8') as f: 82 | f.write(json.dumps(config, indent=2, ensure_ascii=False)) 83 | print("copy config.json end") 84 | 85 | # Load the package's __version__.py module as a dictionary. 86 | about = {} 87 | if not VERSION: 88 | project_slug = NAME.lower().replace("-", "_").replace(" ", "_") 89 | with open(os.path.join(here, project_slug, '__version__.py')) as f: 90 | exec(f.read(), about) 91 | else: 92 | about['__version__'] = VERSION 93 | 94 | 95 | class UploadCommand(Command): 96 | """Support setup.py upload.""" 97 | 98 | description = 'Build and publish the package.' 99 | user_options = [] 100 | 101 | @staticmethod 102 | def status(s): 103 | """Prints things in bold.""" 104 | print('\033[1m{0}\033[0m'.format(s)) 105 | 106 | def initialize_options(self): 107 | pass 108 | 109 | def finalize_options(self): 110 | pass 111 | 112 | def run(self): 113 | try: 114 | self.status('Removing previous builds…') 115 | rmtree(os.path.join(here, 'dist')) 116 | except OSError: 117 | pass 118 | 119 | self.status('Building Source and Wheel (universal) distribution…') 120 | os.system('{0} setup.py sdist bdist_wheel --universal'.format(sys.executable)) 121 | 122 | sys.exit() 123 | 124 | 125 | class BuildCommand(Command): 126 | """Support setup.py build.""" 127 | 128 | description = 'Build the package.' 129 | user_options = [] 130 | 131 | @staticmethod 132 | def status(s): 133 | """Prints things in bold.""" 134 | print('\033[1m{0}\033[0m'.format(s)) 135 | 136 | def initialize_options(self): 137 | pass 138 | 139 | def finalize_options(self): 140 | pass 141 | 142 | def run(self): 143 | try: 144 | self.status('Removing previous builds…') 145 | rmtree(os.path.join(here, 'dist')) 146 | except OSError: 147 | pass 148 | 149 | self.status('Building Source and Wheel (universal) distribution…') 150 | os.system('{0} setup.py sdist bdist_wheel --universal'.format(sys.executable)) 151 | 152 | sys.exit() 153 | 154 | 155 | # Where the magic happens: 156 | setup( 157 | name=NAME, 158 | version=about['__version__'], 159 | description=DESCRIPTION, 160 | long_description=long_description, 161 | long_description_content_type='text/markdown', 162 | author=AUTHOR, 163 | author_email=EMAIL, 164 | python_requires=REQUIRES_PYTHON, 165 | url=URL, 166 | packages=find_packages(exclude=["tests", "*.tests", "*.tests.*", "tests.*"]), 167 | # If your package is a single module, use this instead of 'packages': 168 | # py_modules=['mypackage'], 169 | 170 | # entry_points={ 171 | # 'console_scripts': ['mycli=mymodule:cli'], 172 | # }, 173 | install_requires=REQUIRED, 174 | extras_require=EXTRAS, 175 | include_package_data=True, 176 | license='MIT', 177 | classifiers=[ 178 | # Trove classifiers 179 | # Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers 180 | 'License :: OSI Approved :: MIT License', 181 | 'Programming Language :: Python', 182 | 'Programming Language :: Python :: 3', 183 | 'Programming Language :: Python :: 3.6', 184 | 'Programming Language :: Python :: Implementation :: CPython', 185 | 'Programming Language :: Python :: Implementation :: PyPy' 186 | ], 187 | package_data={ 188 | '': ['*.js'], # 包含所有的.js文件 189 | '': ['*.json'], # 包含所有的.json文件 190 | }, 191 | # $ setup.py publish support. 192 | cmdclass={ 193 | 'upload': UploadCommand, 194 | }, 195 | ) 196 | -------------------------------------------------------------------------------- /publish.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | 4 | # Bump version 5 | print('Bumping version...') 6 | subprocess.check_call(['bumpversion', 'patch']) 7 | 8 | # Push changes to remote 9 | print('Pushing changes to remote...') 10 | subprocess.check_call(['git', 'push']) 11 | subprocess.check_call(['git', 'push', '--tags']) 12 | 13 | # Run towncrier 14 | print('Running towncrier...') 15 | subprocess.check_call(['towncrier', '--yes']) 16 | 17 | print("Created newsfragments directory") 18 | if not os.path.isdir('./newsfragments'): 19 | os.mkdir('./newsfragments') 20 | 21 | print("Done!") -------------------------------------------------------------------------------- /pytest.yml: -------------------------------------------------------------------------------- 1 | name: Python package 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Set up Python 3.8 17 | uses: actions/setup-python@v2 18 | with: 19 | python-version: 3.8 20 | - name: Install dependencies 21 | run: | 22 | python -m pip install --upgrade pip 23 | pip install pytest 24 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi 25 | - name: Install pytest_html 26 | run: | 27 | pip install pytest_html 28 | - name: Run tests with pytest 29 | env: 30 | COOKIE: ${{ secrets.COOKIE }} 31 | run: | 32 | pytest 33 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2061360308/NeteaseCloudMusic_PythonSDK/02a34af715dc3a25ea370fb3b0f69f3978b6960f/requirements.txt -------------------------------------------------------------------------------- /static/Python.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2061360308/NeteaseCloudMusic_PythonSDK/02a34af715dc3a25ea370fb3b0f69f3978b6960f/static/Python.jpg -------------------------------------------------------------------------------- /static/Qt.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2061360308/NeteaseCloudMusic_PythonSDK/02a34af715dc3a25ea370fb3b0f69f3978b6960f/static/Qt.jpg -------------------------------------------------------------------------------- /static/idea.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2061360308/NeteaseCloudMusic_PythonSDK/02a34af715dc3a25ea370fb3b0f69f3978b6960f/static/idea.jpg -------------------------------------------------------------------------------- /static/javascript.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2061360308/NeteaseCloudMusic_PythonSDK/02a34af715dc3a25ea370fb3b0f69f3978b6960f/static/javascript.jpg -------------------------------------------------------------------------------- /static/wish.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2061360308/NeteaseCloudMusic_PythonSDK/02a34af715dc3a25ea370fb3b0f69f3978b6960f/static/wish.jpg -------------------------------------------------------------------------------- /static/网易云.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2061360308/NeteaseCloudMusic_PythonSDK/02a34af715dc3a25ea370fb3b0f69f3978b6960f/static/网易云.png -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | # 使用示例 2 | 3 | import json 4 | import os 5 | import time 6 | from enum import Enum 7 | from pprint import pprint 8 | import dotenv 9 | 10 | from package.NeteaseCloudMusic import NeteaseCloudMusicApi, api_help, api_list 11 | 12 | # from NeteaseCloudMusic import NeteaseCloudMusicApi, api_help, api_list 13 | 14 | dotenv.load_dotenv() # 从.env文件中加载环境变量 15 | 16 | netease_cloud_music_api = NeteaseCloudMusicApi() # 初始化API 17 | # netease_cloud_music_api.cookie = os.getenv("COOKIE") # 设置cookie 18 | netease_cloud_music_api.DEBUG = True # 开启调试模式 19 | 20 | 21 | def song_url_v1_test(): 22 | # 获取歌曲详情 23 | response = netease_cloud_music_api.request("song_url_v1", {"id": '1880562045', "level": "exhigh"}) 24 | pprint(response) 25 | 26 | 27 | def search_test(): 28 | # 搜索 29 | response = netease_cloud_music_api.request("search", {"keywords": "海阔天空"}) 30 | # print("|", response.text, "|") 31 | pprint(response) 32 | 33 | 34 | def search_default_test(): 35 | # 搜索 36 | response = netease_cloud_music_api.request("search_default") 37 | pprint(response) 38 | 39 | 40 | def user_account_test(): 41 | # 获取用户账号信息 42 | response = netease_cloud_music_api.request("user_account", query={"timestamp": time.time()}) 43 | pprint(response) 44 | 45 | 46 | def comment_new_test(): 47 | response = netease_cloud_music_api.request("comment_new", { 48 | "type": "0", 49 | "id": "1407551413", 50 | "sortType": 3, 51 | "cursor": 1602072870260, 52 | "pageSize": 20, 53 | "pageNo": 2, 54 | "realIP": "116.25.146.177", 55 | }) 56 | pprint(response) 57 | 58 | 59 | def toplist_detail_test(): 60 | # 获取用户账号信息 61 | response = netease_cloud_music_api.request("toplist_detail") 62 | pprint(response) 63 | 64 | 65 | def playlist_detail_test(): 66 | # 获取用户账号信息 67 | response = netease_cloud_music_api.request("playlist_detail", {"id": 19723756}) 68 | pprint(response) 69 | 70 | 71 | def top_playlist_highquality_test(): 72 | response = netease_cloud_music_api.request("/top/playlist/highquality") 73 | pprint(response) 74 | 75 | 76 | def captcha_sent_test(): 77 | response = netease_cloud_music_api.request("/captcha/sent", {"phone": "15234941791", "timestamp": time.time()}) 78 | pprint(response) 79 | 80 | 81 | def login_cellphone_test(): 82 | response = netease_cloud_music_api.request("/login/cellphone", 83 | { 84 | "phone": "15234941791", 85 | "captcha": "9159", 86 | "timestamp": time.time() 87 | }) 88 | pprint(response) 89 | 90 | 91 | def personalized_djprogram_test(): 92 | response = netease_cloud_music_api.request("personalized_djprogram") 93 | pprint(response) 94 | 95 | 96 | def top_mv_test(): 97 | response = netease_cloud_music_api.request("top_mv", {'limit': 6}) 98 | pprint(response) 99 | 100 | 101 | def playlist_track_all_test(): 102 | response = netease_cloud_music_api.request("playlist_track_all", {'id': '592179800'}) 103 | pprint(response) 104 | 105 | 106 | def login_refresh(): 107 | response = netease_cloud_music_api.request("login_refresh", {"timestamp": time.time()}) 108 | pprint(response) 109 | 110 | 111 | def login_status(): 112 | response = netease_cloud_music_api.request("login_status") 113 | pprint(response) 114 | 115 | 116 | if __name__ == '__main__': 117 | pass 118 | # print(api_list()) 119 | # print(api_help()) 120 | # song_url_v1_test() 121 | # top_mv_test() 122 | search_test() 123 | # search_default_test() 124 | # comment_new_test() 125 | # toplist_detail_test() 126 | # playlist_detail_test() 127 | # top_playlist_highquality_test() 128 | # captcha_sent_test() 129 | # login_cellphone_test() 130 | # user_account_test() 131 | # playlist_track_all_test() 132 | # login_refresh() 133 | # login_status() 134 | -------------------------------------------------------------------------------- /test_gender/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2061360308/NeteaseCloudMusic_PythonSDK/02a34af715dc3a25ea370fb3b0f69f3978b6960f/test_gender/__init__.py -------------------------------------------------------------------------------- /test_gender/generator.py: -------------------------------------------------------------------------------- 1 | # 生成测试文件 2 | 3 | import json 4 | from pprint import pprint 5 | 6 | with open("../package/NeteaseCloudMusic/config.json", 'r', encoding='utf-8') as f: 7 | config = json.loads(f.read()) 8 | 9 | with open("template", 'r', encoding='utf-8') as f: 10 | template = f.read() 11 | 12 | 13 | def pathToName(path): 14 | if path[0] == "/": 15 | path = path[1:] 16 | return path.replace("/", "_") 17 | 18 | 19 | tests = "" 20 | 21 | # 不被支持的接口 22 | exclude = ["/request/reference", "/avatar/upload", "/cloud", "/playlist/cover/update", "/voice/upload", 23 | "/register/anonimous", "/verify/getQr"] 24 | 25 | # 忽略一些接口的测试 26 | ignore = ['/login/cellphone', 27 | '/user/replacephone', 28 | '/audio/match', 29 | '/rebind', 30 | '/nickname/check', 31 | '/activate/init/profile', 32 | '/cellphone/existence/check', 33 | '/register/cellphone', 34 | '/captcha/verify', 35 | '/captcha/sent', 36 | '/login/refresh', 37 | '/logout', 38 | '/user/update', 39 | '/avatar/upload', 40 | '/pl/count', 41 | '/playlist/update', 42 | '/playlist/desc/update', 43 | '/playlist/name/update', 44 | '/playlist/tags/update', 45 | '/playlist/cover/update', 46 | '/event/forward', 47 | '/event/del', 48 | '/share/resource', 49 | '/send/text', 50 | '/send/playlist', 51 | '/playlist/create', 52 | '/playlist/tracks', 53 | '/daily_signin', 54 | '/fm_trash'] 55 | 56 | for apiPath, value in config.items(): 57 | apiName = pathToName(apiPath) 58 | 59 | if (apiName + ".js") in exclude: 60 | continue 61 | 62 | if apiPath in ignore: 63 | continue 64 | 65 | apiExplain = value["explain"] 66 | 67 | apiExample = [] 68 | 69 | for item in value["example"]: 70 | apiExample.append(item["query"]) 71 | 72 | content = (template.replace("{{apiName}}", apiName) 73 | .replace("{{explain}}", apiExplain) 74 | .replace("{{example}}", json.dumps(apiExample))) 75 | 76 | if apiPath == "/song/order/update": 77 | content = content.replace(" == 200", " in [200, 401]") 78 | elif apiPath == "/follow": 79 | content = content.replace(" == 200", " in [200, 400, -462]") 80 | elif apiPath == "/user/record": 81 | content = content.replace(" == 200", " in [200, 400]") 82 | elif apiPath == "/artist/sub": 83 | content = content.replace(" == 200", " in [200, 400, -462]") 84 | elif apiPath == "/video/sub": 85 | content = content.replace(" == 200", " in [200, 408]") 86 | elif apiPath == "/playlist/subscribe": 87 | content = content.replace(" == 200", " in [200, 408, 501]") 88 | elif apiPath == "/playlist/track/add": 89 | content = content.replace(" == 200", " in [200, 404]") 90 | elif apiPath == "/playlist/track/delete": 91 | content = content.replace(" == 200", " in [200, 400]") 92 | elif apiPath == "/album/sub": 93 | content = content.replace(" == 200", " in [200, 401, 404]") 94 | elif apiPath == "/artist/detail": 95 | content = content.replace(" == 200", " in [200, 400, -460]") 96 | elif apiPath == "/recommend/songs/dislike": 97 | content = content.replace(" == 200", " in [200, 432]") 98 | elif apiPath == "/user/cloud/del": 99 | content = content.replace(" == 200", " in [200, 404]") 100 | elif apiPath == "/cloud/match": 101 | content = content.replace(" == 200", " in [200, 400]") 102 | elif apiPath == "/send/song": 103 | content = content.replace(" == 200", " in [200, 401]") 104 | elif apiPath == "/send/album": 105 | content = content.replace(" == 200", " in [200, 404]") 106 | elif apiPath == "/msg/comments": 107 | content = content.replace(" == 200", " in [200, 400]") 108 | elif apiPath == "/yunbei/rcmd/song": 109 | content = content.replace(" == 200", " in [200, 400]") 110 | elif apiPath == "/vip/growthpoint": 111 | content = content.replace(" == 200", " in [200, 400, 1000]") 112 | elif apiPath == "/vip/growthpoint/get": 113 | content = content.replace(" == 200", " in [200, 400, 1000]") 114 | elif apiPath == "/artist/fans": 115 | content = content.replace(" == 200", " in [200, 400, -460]") 116 | elif apiPath == "/inner/version": 117 | content = content.replace("assert (response[\"code\"] == 200 or response[\"data\"][\"code\"] == 200)", 118 | "assert (response is not None)") 119 | elif "musician" in apiPath: 120 | content = content.replace(" == 200", " in [200, 400, 600, 10000, 500, 404]") 121 | 122 | tests += content + "\n\n\n" 123 | 124 | with open("../api_test.py", 'w+', encoding='utf-8') as f: 125 | tests = ("from pytest_html import extras\n" 126 | "import json\n" 127 | "import os\n" 128 | "from pprint import pprint\n" 129 | "import dotenv\n" 130 | "from package.NeteaseCloudMusic import NeteaseCloudMusicApi, api_help, api_list\n" 131 | "dotenv.load_dotenv() # 从.env文件中加载环境变量\n" 132 | "netease_cloud_music_api = NeteaseCloudMusicApi() # 初始化API\n" 133 | "netease_cloud_music_api.cookie = os.getenv('COOKIE') # 设置cookie\n" 134 | "netease_cloud_music_api.DEBUG = True # 开启调试模式") + "\n\n\n" + tests 135 | f.write(tests) 136 | -------------------------------------------------------------------------------- /test_gender/some.txt: -------------------------------------------------------------------------------- 1 | user_cloud_detail 2 | user_audio 3 | search_suggest 4 | search_multimatch 5 | resource_like 6 | related_allvideo 7 | playlist_update_playcount 8 | playlist_order_update 9 | playlist_delete 10 | comment_like 11 | -------------------------------------------------------------------------------- /test_gender/template: -------------------------------------------------------------------------------- 1 | def test_{{apiName}}(extra): 2 | """ 3 | {{explain}} 4 | """ 5 | 6 | example = {{example}} 7 | for query in example: 8 | response = netease_cloud_music_api.request("{{apiName}}", query) 9 | extra.append(extras.json(response, name="response")) 10 | assert (response["code"] == 200 or response["data"]["code"] == 200) -------------------------------------------------------------------------------- /towncrier.toml: -------------------------------------------------------------------------------- 1 | [tool.towncrier] 2 | version = "0.1.10" 3 | filename = "CHANGELOG.md" 4 | directory = "newsfragments" --------------------------------------------------------------------------------