{"id":35180698,"url":"https://github.com/dsy4567/neteasecloudmusicapi-hook","last_synced_at":"2026-04-28T10:07:22.802Z","repository":{"id":275432136,"uuid":"924076968","full_name":"dsy4567/NeteaseCloudMusicApi-hook","owner":"dsy4567","description":"让 NeteaseCloudMusicApi 用根正苗红的浏览器请求 weapi 接口","archived":false,"fork":false,"pushed_at":"2025-02-05T12:34:31.000Z","size":47,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-31T16:53:47.528Z","etag":null,"topics":["api","cloudmusic","hooks","netease-cloud-music","neteasecloud","neteasecloudmusicapi","nodejs"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dsy4567.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-01-29T11:26:17.000Z","updated_at":"2025-02-05T12:34:35.000Z","dependencies_parsed_at":"2025-02-02T14:24:21.787Z","dependency_job_id":null,"html_url":"https://github.com/dsy4567/NeteaseCloudMusicApi-hook","commit_stats":null,"previous_names":["dsy4567/neteasecloudmusicapi-hook"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dsy4567/NeteaseCloudMusicApi-hook","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dsy4567%2FNeteaseCloudMusicApi-hook","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dsy4567%2FNeteaseCloudMusicApi-hook/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dsy4567%2FNeteaseCloudMusicApi-hook/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dsy4567%2FNeteaseCloudMusicApi-hook/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dsy4567","download_url":"https://codeload.github.com/dsy4567/NeteaseCloudMusicApi-hook/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dsy4567%2FNeteaseCloudMusicApi-hook/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32375788,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-28T09:24:15.638Z","status":"ssl_error","status_checked_at":"2026-04-28T09:24:15.071Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","cloudmusic","hooks","netease-cloud-music","neteasecloud","neteasecloudmusicapi","nodejs"],"created_at":"2025-12-29T01:19:11.103Z","updated_at":"2026-04-28T10:07:22.797Z","avatar_url":"https://github.com/dsy4567.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NeteaseCloudMusicApi-hook\n\n让 [NeteaseCloudMusicApi](https://gitlab.com/Binaryify/neteasecloudmusicapi) 用根正苗红的浏览器请求网易云音乐的 weapi 接口。\n\n本项目基于 NeteaseCloudMusicApi 4.25.0 编写。\n\n\n## 原理\u0026优缺点\n\n本项目通过使用类似于临时替换 [util/request.js](https://gitlab.com/Binaryify/neteasecloudmusicapi/-/blob/main/util/request.js) 的方式来拦截请求，\n并**将请求转交给**事先要求用户**在浏览器内运行的**，特别编写的**JS**。发起请求的一般大致流程如下：\n\n```\nhook 前\n\n你的项目\n  |^\n  ||\n  v|\nNeteaseCloudMusicApi\n  |^\n  ||https\n  v|\nmusic.163.com\n```\n\n```\nhook 后\n\n（你已引导用户在浏览器上登录网易云，并在控制台执行特定代码）\n\n你的项目\n  |^\n  ||\n  v|\nNeteaseCloudMusicApi\n  |^\n  ||\n  v|\nNeteaseCloudMusicApi-hook\n  |^\n  ||\n  v|\nlocal server\n  |^\n  ||WebSocket\n  v|\nbrowser\n  |^\n  ||https\n  v|\nmusic.163.com\n```\n\n优点：\n\n- 请求在浏览器发出，可以**绕过多数风控手段**（过环境检测、允许用户手动解决人机验证等）；\n- 不必费尽心思模拟浏览器的行为。\n\n缺点：\n\n- ~~肯定有人认为本项目在画蛇添足~~；\n- 根据项目自身设计，迁移至本项目存在不同大小的难度；\n- 部分返回结果**有异于**原 NeteaseCloudMusicApi（如返回结果里的 `cookie[]` 数组始终为空）；\n- 每次运行都需要引导用户在控制台执行特定代码，**麻烦且增加了**现有应用的**使用门槛**（可以指定固定的 `connectionToken` + 油猴脚本/折腾无头浏览器来解决）；\n- **只能本地使用**，不建议（也很难）在线部署（可以在线应用调访客设备上部署的接口）。\n\n\n## 安装\u0026快速上手\n\n```bash\ngit clone https://gitlab.com/Binaryify/neteasecloudmusicapi NeteaseCloudMusicApi\ngit clone https://github.com/dsy4567/NeteaseCloudMusicApi-hook NeteaseCloudMusicApi-hook\n\ncd NeteaseCloudMusicApi\nnpm i\ncd ../NeteaseCloudMusicApi-hook\nnpm i\n```\n\n一般用法请参见示例代码 [example.js](./example.js)。\n\n更多详细用法请见 [types/index.d.ts](types/index.d.ts)。\n\n\n## 迁移\n\n\u003e **定义**：如无特别说明，\n\u003e\n\u003e `ncmApiHook` 即 `require(\"./path/to/NeteaseCloudMusicApi-hook\")`；\n\u003e\n\u003e `ncmApi` 即 `require('NeteaseCloudMusicApi')` 或 `ncmApiHook.getExports()`。\n\n对于一些项目，只需要改变登录逻辑即可，甚至只需要加几行代码就行；对于另一些项目，则可能需要不同程度的大改。\n\n尽管本项目尽力减少与 NeteaseCloudMusicApi 的行为差异，迁移到 NeteaseCloudMusicApi-hook 仍需要注意以下几点：\n\n- 本项目设计之初是供**本地应用**（而不是在线应用）使用，你的项目**不能**连同本项目**在线部署**，也**不要**尝试将本项目的服务**公开至公网**；\n- 注意默认情况下，本项目会**自行决定请求去向**，详见“常见问题 \u003e 如何判断请求走浏览器还是 NeteaseCloudMusicApi”；\n- 你需要**自行引导用户**在浏览器上登录网易云，并在控制台**执行特定代码**；\n- 本项目**不支持**所有**非 weapi 接口**，直接调用它们时，将自动转到原 NeteaseCloudMusicApi（见 常见问题 ）；\n- 未连接浏览器时，调用任何 api 亦会走原 NeteaseCloudMusicApi（除非在 `ncmApiHook.init()` 指定 `{ forceConnection: true }`，未连接浏览器将拒绝所有请求 ）；\n- 如果请求将要走浏览器（尤其浏览器端已登录时），调用 weapi 不必带上 cookie（即使带上也会忽略）。\n\n\n## 常见问题\n\n### 如何在线部署？\n\n- ~~在**访客**的设备上部署用到本项目的简易服务，然后让你的在线应用访问**访客设备上的服务**~~；\n- 放弃这个想法。\n\n\n### 如何登录？\n\n请求走浏览器，需提前引导用户在浏览器打开 [music.163.com](https://music.163.com/) 并正常完成登录流程，然后在控制台执行以下代码；无需在 `ncmApi.foo_bar()` 指定 `{ cookie: \"MUSIC_U=xxx;\" }`（即使指定也会忽略）。\n\n```js\n// 详见 example.js\n\n(() =\u003e {\n    let s = document.createElement(\"script\");\n    s.dataset.connectionToken = \"REPLACE_THIS\"\n    s.src = \"REPLACE_THIS\";\n    document.head.append(s);\n})();\n```\n\n请求走 NeteaseCloudMusicApi，在 `ncmApi.foo_bar()` 指定 `{ cookie: \"MUSIC_U=xxx;\" }` 即可；\n\n如需获取浏览器内部分 cookies，使用 `ncmApiHook.loginStatus.get()` 即可。\n\n\n### 我从 `ncmApiHook.loginStatus.get()` 获得的 `MUSIC_U` 为空字符串怎么办？\n\n在浏览器中的网易云音乐网页版，cookie `MUSIC_U` 是“HttpOnly”的。手动在开发者工具 \u003e 应用 \u003e Cookie 中取消勾选对应复选框即可。\n\n\n### 如何强制使用 weapi 加密接口？\n\n以下方法任选其一：\n\n- 在 `ncmApiHook.init()` 指定 `{ forceWeapi: true }` 来强制使用 weapi 接口；\n  ```js\n  ncmApiHook.init({ forceWeapi: true });\n  ```\n- 调用 api 时，像原来那样指定 `{ crypto: \"weapi\" }` ）；\n  ```js\n  ncmApi.like({ id: 114514, like: true, crypto: \"weapi\" });\n  ```\n\n\n### 如何判断请求走浏览器还是 NeteaseCloudMusicApi?\n\n**实际情况请以在 `ncmApiHook.init()` 指定 `{ debug: true }` 后的日志为准。**\n\n\u003e 你可以结合阅读 [src/hooks/request.js](src/hooks/request.js) （不到 100 行）来理解下面的说明。\n\n满足和以下条件之一，任何请求必定**走浏览器或被拒绝**：\n\n- 在 `ncmApiHook.init()` 指定了 `{ forceWeapi: true, forceConnection: true }`；\n- 在表达式 `!!ncmApiHook.server.getServerStatus()._wsConnection === true` （即：已连接浏览器）和以下条件之一成立时。\n  - 在 `ncmApiHook.init()` 指定了 `{ forceWeapi: true }`；\n  - 在 `ncmApi.foo_bar()` 指定了 `{ crypto: \"weapi\" }`；\n  - 其他最终会请求 weapi 的情况。\n\n满足以下条件之一，任何请求必定**走 NeteaseCloudMusicApi 或被拒绝**：\n\n- 调用了 `ncmApiHook.unhook()`，随后从未调用 `ncmApiHook.hook()`；\n- 在表达式 `!!ncmApiHook.server.getServerStatus()._wsConnection === false` （即：未连接浏览器）和以下条件之一成立时；\n  - 在 `ncmApiHook.init()` 指定了 `{ forceConnection: false }`（默认值）。\n- 表达式 `!!ncmApiHook.server.getServerStatus()._wsConnection === true` （即：已连接浏览器）成立，且在 `ncmApiHook.init()` 指定了 `{ forceWeapi: false }`（默认值），且以下条件之一成立时。\n  - 在 `ncmApi.foo_bar()` 指定了 `{ crypto: \"eapi\" | \"api\" | \"linuxapi\" }`（即：使用非 weapi 加密）；\n- 其他最终会请求**非** weapi 的情况。\n\n\n### 尝试将服务公开到内网以供其他设备上的浏览器使用，浏览器连接时报错怎么办？\n\n如果报错信息与 HTTPS 相关，可能由于网易云网站设置的浏览器安全策略，使发往本项目服务（非 `127.0.0.1` / `localhost` 等本机环回地址）的 HTTP 请求自动强制升级为 HTTPS，可通过本机运行反向代理等方法解决，例如，可在浏览器端的设备上执行以下操作：\n\n1. 安装 [mitmproxy](https://mitmproxy.org/)；\n2. 执行以下命令：\n  ```bash\n  mitmdump --mode reverse:http://\u003c运行本项目服务设备的 IP 地址\u003e:\u003c端口（默认 16333）\u003e --set listen_port=16333\n  ```\n\n如果是其他问题，请见“常见问题 \u003e 浏览器与 NeteaseCloudMusicApi-hook 的服务器意外断连怎么办？”或提交 issue。\n\n\n### 浏览器与 NeteaseCloudMusicApi-hook 的服务器意外断连怎么办？\n\n在浏览器端打开开发者工具，并筛选 `[NeteaseCloudMusicApi-hook]`。\n\n如果找到“非正常断连，x 秒后重试”的日志，可等待重连；\n\n如果找到“重连次数过多”的日志，请尝试重启你的应用或检查网络连接（局域网）；\n\n如果以上操作没有效果，请准备好你应用的日志、浏览器控制台的日志，以及浏览器开发者工具 \u003e “网络”选项卡 \u003e 与本项目相关的 WebSocket 连接的**所有脱敏消息**，然后提交 issue。\n\n\n### 本项目和 NeteaseCloudMusicApi 有哪些返回结果上的差异？\n\n已知明显差异如下：\n\n- 执行 `ncmApi.foo_bar()` 后返回的结果中，`cookie[]` 数组始终为空；\n- 返回结果中的状态码，少数情况下可能不同于 NeteaseCloudMusicApi（如你认为有必要，可提交 issue 讨论）。\n\n\n### 每次都要要求用户在控制台执行代码太麻烦，有没有更方便的方法？\n\n1. 在 `ncmApiHook.init()` 指定 `{ connectionToken: \"\u003c固定值\u003e\" }`；\n2. 适当修改 [src/browser/inject.js](./src/browser/inject.js)，并将其以油猴脚本/浏览器扩展的形式提供给用户。\n\n或者，折腾无头浏览器。\n\n### 是否支持多用户？\n\n请求走浏览器时，除非不断更换连接的浏览器（同一 NeteaseCloudMusicApi-hook 实例同一时间只能接受一个连接），或者合理使用 `ncmApiHook.unhook()`，否则一个实例**只支持一名用户**；\n\n请求走 NeteaseCloudMusicApi 时，取决于你的应用是否支持多用户。\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdsy4567%2Fneteasecloudmusicapi-hook","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdsy4567%2Fneteasecloudmusicapi-hook","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdsy4567%2Fneteasecloudmusicapi-hook/lists"}