diff --git a/MANIFEST.json b/MANIFEST.json new file mode 100644 index 0000000..aae6f9d --- /dev/null +++ b/MANIFEST.json @@ -0,0 +1,406 @@ +{ + "manifest_version": 1, + "name": "netease-music", + "summary": "网易云音乐遥控器:一句话对上云里的内容(每日推荐 / 歌单 / 榜单 / 收藏 / FM / 最近 / 播客)并放出来;播放侧管好本机队列现场(快照 / back / 追加)", + "tier": 1, + "status": "stable", + "version": "fb22dd2", + "source": { + "path": "skills/netease-music", + "commit": "fb22dd2", + "describe": "fb22dd2", + "dirty": false, + "packed_at": "2026-10-01T23:34:48.413Z" + }, + "platforms": [ + "darwin" + ], + "entry": { + "path": "scripts/netease-music.sh" + }, + "commands": [ + "daily", + "play", + "play-ids", + "search", + "cover", + "artist", + "album", + "albums", + "liked", + "liked-ids", + "myplaylists", + "pause", + "resume", + "toggle", + "next", + "prev", + "stop", + "clear", + "volume", + "seek", + "queue", + "jump", + "remove", + "status", + "lyric", + "like", + "unlike", + "shuffle", + "repeat", + "login", + "setup", + "check", + "playlist", + "playlists", + "charts", + "chart", + "myalbums", + "myartists", + "fm", + "dislike", + "recent", + "replay", + "podcasts", + "podcast", + "episode", + "queues", + "queue-save", + "queue-load", + "back", + "add" + ], + "errors": [ + "usage", + "deps", + "auth", + "notfound", + "timeout", + "external", + "internal" + ], + "aliases": [ + "netease", + "netease-music" + ], + "admin": [ + "scripts/install-cli.sh" + ], + "depends_on": [], + "requires": [ + { + "kind": "runtime", + "name": "node", + "check": "which node", + "note": "接口客户端与 mpv 控制都是 node 脚本,零 npm 依赖" + }, + { + "kind": "runtime", + "name": "python3", + "check": "which python3" + }, + { + "kind": "binary", + "name": "mpv", + "install": "brew install mpv", + "check": "which mpv", + "note": "真正的播放器(常驻 + unix socket 控制)" + }, + { + "kind": "binary", + "name": "qrencode", + "install": "brew install qrencode", + "check": "which qrencode", + "note": "只在扫码登录时用" + } + ], + "config": [ + { + "key": "cookie", + "desc": "登录 cookie(MUSIC_U=…),由 login 命令扫码写入", + "type": "string", + "secret": true, + "required": true, + "ask": "扫码登录一次:pi-skill netease-music login", + "note": "只存本机 local/skills/netease-music/config.json,不进共享仓库" + }, + { + "key": "quality", + "desc": "音质级别:standard/higher/exhigh/lossless/hires", + "type": "enum", + "values": [ + "standard", + "higher", + "exhigh", + "lossless", + "hires" + ], + "default": "lossless" + } + ], + "external_imports": [], + "contract": { + "version": 1, + "skill": "netease-music", + "tier": 1, + "platforms": [ + "darwin" + ], + "commands": { + "add": { + "destructive": false + }, + "album": { + "destructive": false + }, + "albums": { + "destructive": false + }, + "artist": { + "destructive": false + }, + "back": { + "destructive": false + }, + "chart": { + "destructive": false + }, + "charts": { + "destructive": false + }, + "check": { + "destructive": false + }, + "clear": { + "destructive": false + }, + "cover": { + "destructive": false + }, + "daily": { + "destructive": false + }, + "dislike": { + "destructive": false + }, + "episode": { + "destructive": false + }, + "fm": { + "destructive": false + }, + "jump": { + "destructive": false + }, + "like": { + "destructive": false + }, + "liked": { + "destructive": false + }, + "liked-ids": { + "destructive": false + }, + "login": { + "destructive": false + }, + "lyric": { + "destructive": false + }, + "myalbums": { + "destructive": false + }, + "myartists": { + "destructive": false + }, + "myplaylists": { + "destructive": false + }, + "next": { + "destructive": false + }, + "pause": { + "destructive": false + }, + "play": { + "destructive": false + }, + "play-ids": { + "destructive": false + }, + "playlist": { + "destructive": false + }, + "playlists": { + "destructive": false + }, + "podcast": { + "destructive": false + }, + "podcasts": { + "destructive": false + }, + "prev": { + "destructive": false + }, + "queue": { + "destructive": false + }, + "queue-load": { + "destructive": false + }, + "queue-save": { + "destructive": false + }, + "queues": { + "destructive": false + }, + "recent": { + "destructive": false + }, + "remove": { + "destructive": false + }, + "repeat": { + "destructive": false + }, + "replay": { + "destructive": false + }, + "resume": { + "destructive": false + }, + "search": { + "destructive": false + }, + "seek": { + "destructive": false + }, + "setup": { + "destructive": false + }, + "shuffle": { + "destructive": false + }, + "status": { + "destructive": false + }, + "stop": { + "destructive": false + }, + "toggle": { + "destructive": false + }, + "unlike": { + "destructive": false + }, + "volume": { + "destructive": false + } + }, + "errors": [ + "auth", + "deps", + "external", + "internal", + "notfound", + "timeout", + "usage" + ], + "aliases": [ + "netease", + "netease-music" + ], + "adminAliases": [] + }, + "files": [ + { + "path": "REFERENCE.md", + "bytes": 32599, + "sha256": "d17e12c8754a504c" + }, + { + "path": "SKILL.md", + "bytes": 8951, + "sha256": "e3ae9ecca8057749" + }, + { + "path": "VERSION", + "bytes": 6, + "sha256": "80447316529fc620" + }, + { + "path": "contract.lock.json", + "bytes": 2809, + "sha256": "7a2a0c59facbfb43" + }, + { + "path": "interface.json", + "bytes": 9260, + "sha256": "ddd1274a65b4dfd3" + }, + { + "path": "scripts/install-cli.sh", + "bytes": 1312, + "sha256": "083687332848a7f6" + }, + { + "path": "scripts/lib/build-queue.py", + "bytes": 3167, + "sha256": "4424f575185c91fd" + }, + { + "path": "scripts/lib/mpv-map.py", + "bytes": 4541, + "sha256": "f675cb36eb16b10b" + }, + { + "path": "scripts/lib/queue-append.py", + "bytes": 1658, + "sha256": "9205defd26585355" + }, + { + "path": "scripts/lib/queue-edit.py", + "bytes": 2368, + "sha256": "cb17631b2b87092c" + }, + { + "path": "scripts/lib/snapshot.py", + "bytes": 4220, + "sha256": "bde00b57fde45e3d" + }, + { + "path": "scripts/mpv-ctl.mjs", + "bytes": 11912, + "sha256": "dd01e858a705a8c5" + }, + { + "path": "scripts/netease-api.mjs", + "bytes": 34669, + "sha256": "716e15d585f6fc04" + }, + { + "path": "scripts/netease-music.sh", + "bytes": 62184, + "sha256": "e29d22d0084c3053" + }, + { + "path": "scripts/refresh-urls.sh", + "bytes": 4687, + "sha256": "234202fe6846ed04" + } + ], + "leak_scan": { + "errors": 0, + "warnings": 1, + "findings": [ + { + "level": "warn", + "kind": "email", + "file": "interface.json", + "line": 286, + "excerpt": "git@gitea.gklazycat" + } + ] + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..833cb7a --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# netease-music-cli + +网易云音乐遥控器:一句话对上云里的内容(每日推荐 / 歌单 / 榜单 / 收藏 / FM / 最近 / 播客)并放出来;播放侧管好本机队列现场(快照 / back / 追加) + +由 Pi 技能 `netease-music` 发布,当前版本 v0.1.1。命令名是 `netease-music`(仓库名带 `-cli`,命令不带)。 + +## 安装 + +```sh +./scripts/install-cli.sh # 链接到 ~/.local/bin/netease-music 并检查 node/mpv/python3 +netease-music check # 自检:依赖 / 登录 +netease-music login # 未登录时(手机扫码) +netease-music help # 完整命令面 +``` + +消费方契约(JSON 字段 / 环境变量 / 状态目录 / 退出码)见 [REFERENCE.md](REFERENCE.md)。 + +## 许可 + +见仓库内的许可声明(与 Pi 技能 `netease-music` 相同)。 diff --git a/REFERENCE.md b/REFERENCE.md index f453a2e..88f4edd 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -309,8 +309,8 @@ mpv --idle=yes --no-video --force-window=no --audio-display=no --no-terminal \ ## 6. 对外契约(CLI 消费者) 本技能目录同时是一个可独立使用的 CLI:入口 `scripts/netease-music.sh`,standalone 安装用 -`scripts/install-cli.sh`(链接成 `netease-music` 并查 node/mpv/python3),发布镜像用 -`scripts/publish.sh`。**命名规范**:公开镜像仓叫 `<工具>-cli`(这里是 +`scripts/install-cli.sh`(链接成 `netease-music` 并查 node/mpv/python3),发布用共享的 +`skill-publish`(声明在 interface.json 的 `publish`,见 skill-interface 的 REFERENCE §12)。**命名规范**:公开镜像仓叫 `<工具>-cli`(这里是 `netease-music-cli`),装出来的命令仍叫 `<工具>`(`netease-music`)——仓名标交付物类型, 命令名只管好敲。消费者(Emacs 包 etaf-ncm、其他脚本)只依赖本节与 `--json` 输出, 不读实现、不读状态文件。 diff --git a/VERSION b/VERSION index 6e8bf73..17e51c3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0 +0.1.1 diff --git a/interface.json b/interface.json index bbe96db..b3080b3 100644 --- a/interface.json +++ b/interface.json @@ -278,11 +278,12 @@ "path": "scripts/install-cli.sh", "runner": "sh", "summary": "standalone 安装:不需要 Pi,把入口链接成 netease-music 并检查 node/mpv/python3" - }, - { - "path": "scripts/publish.sh", - "runner": "sh", - "summary": "发布公开镜像:测试门禁通过后把技能目录整体覆盖到 gitea 镜像仓(生成物,不在镜像仓手改)" } - ] + ], + "publish": { + "repo": "https://gitea.vhkd.top/geekinney/netease-music-cli.git", + "mirrors": [ + "git@gitea.gklazycat.heiyu.space:geekinney/netease-music-cli.git" + ] + } } diff --git a/scripts/publish.sh b/scripts/publish.sh deleted file mode 100755 index 1d43a98..0000000 --- a/scripts/publish.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/sh -# 发布镜像:把本技能目录整体发布成公开仓库(生成物,整体覆盖;不要在镜像仓手工改)。 -# 用法:scripts/publish.sh [--dry-run] -# 远端:NETEASE_MUSIC_PUBLISH_REMOTES(空格分隔);默认两个 gitea 远端。 -set -eu -here="$(cd "$(dirname "$0")/.." && pwd)" -version="$(cat "$here/VERSION")" -dry=0 -ok=0; failed=0 -[ "${1:-}" = "--dry-run" ] && dry=1 -remotes="${NETEASE_MUSIC_PUBLISH_REMOTES:-git@gitea.gklazycat.heiyu.space:geekinney/netease-music-cli.git https://gitea.vhkd.top/geekinney/netease-music-cli.git}" -# 门禁:先过测试再发布。 -(cd "$here" && node --test tests/*.test.mjs >/dev/null) -for remote in $remotes; do - work="$(mktemp -d)" - if git clone --quiet "$remote" "$work/repo" 2>/dev/null; then - cd "$work/repo" - else - mkdir -p "$work/repo"; cd "$work/repo"; git init -q; git remote add origin "$remote" - fi - rsync -a --delete --exclude '.git' --exclude '__pycache__' --exclude 'tests/.runtime-*' "$here/" "$work/repo/" - git add -A - if git diff --cached --quiet; then - printf 'no changes for %s\n' "$remote" - else - git commit -q -m "release v$version" - fi - if [ "$dry" = 1 ]; then - printf 'dry-run: would push %s\n' "$remote" - elif git push -q origin HEAD:main 2>/dev/null || git push -q --set-upstream origin HEAD:main 2>/dev/null; then - printf 'published v%s -> %s\n' "$version" "$remote" - ok=$((ok + 1)) - else - printf 'push failed: %s(仓库没建?凭据?)\n' "$remote" - failed=$((failed + 1)) - fi - cd "$here"; rm -rf "$work" -done -[ "$ok" -gt 0 ] || exit 1 -printf 'remotes ok=%s failed=%s\n' "$ok" "$failed"