# Chaunsin Netease Cloud Music Netease Cloud Music

> ncmctl Development Guide

- Skill: `tomevault-io/chaunsin-netease-cloud-music-netease-cloud-music` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/chaunsin-netease-cloud-music-netease-cloud-music`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/chaunsin-netease-cloud-music-netease-cloud-music/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/chaunsin-netease-cloud-music-netease-cloud-music

---

# ncmctl Development Guide

ncmctl is a Go CLI tool for NetEase Cloud Music providing login, daily tasks, music download, cloud upload, and NCM file decryption.

## Project Structure

```
cmd/ncmctl/main.go       # CLI entry point
internal/ncmctl/          # CLI command implementations (cobra commands)
api/                      # API client layer
  ├── api.go              # Core Client: HTTP, encryption, cookie persistence
  ├── weapi/              # Web/Mini-program API (recommended, most complete)
  ├── eapi/               # PC/Mobile API
  ├── linux/              # Linux client API
  └── types/              # Shared request/response types
pkg/
  ├── crypto/             # AES-CBC/ECB, RSA, weapi/eapi encryption
  ├── cookie/             # Cookie persistence and sync
  ├── cookiecloud/        # CookieCloud browser extension support
  ├── ncm/                # NCM file decryption + audio tag handling
  ├── database/           # Badger key-value store wrapper
  ├── log/                # Structured logging (lumberjack rotation)
  └── utils/              # General utilities
config/                   # Config structs + default config.yaml
```

## Build & Test

```bash
make build                # Build binary → ./ncmctl
make install              # Install to $GOPATH/bin
go test -v ./...          # Run all tests
go test -v -run TestName ./example/  # Run single test
make build-image          # Build Docker image
```

Requires Go >= 1.24. Tests needing login require cookie file or should be skipped.

## CLI Commands

| Command      | Login | Description                            |
| ------------ | ----- | -------------------------------------- |
| `login`    | No    | Phone/Cookie/CookieCloud/QR code login |
| `logout`   | No    | Clear stored credentials               |
| `task`     | Yes   | Run all daily tasks on cron schedule   |
| `sign`     | Yes   | YunBei + VIP daily check-in            |
| `partner`  | Yes   | Music partner auto-evaluation          |
| `scrobble` | Yes   | Scrobble 300 songs daily               |
| `download` | Yes   | Download songs/albums/playlists        |
| `cloud`    | Yes   | Upload music to cloud disk             |
| `ncm`      | No    | Decrypt .ncm → .mp3/.flac             |
| `crypto`   | No    | Encrypt/decrypt API parameters         |
| `curl`     | No    | Invoke API methods directly            |

## Adding a New CLI Command

1. Create `internal/ncmctl/<command>.go` implementing a struct with `root`, `cmd`, `opts`, `l` fields
2. Implement `New<Command>(root *Root, l *log.Logger)` constructor
3. Define cobra command with `Use`, `Short`, `Example`
4. Add flags via `addFlags()` method
5. Implement `validate()` and `execute(ctx, args)` methods
6. For login-required commands: create API client, check `request.NeedLogin(ctx)`, defer `request.TokenRefresh(ctx, &weapi.TokenRefreshReq{})`
7. Register in `internal/ncmctl/ncmctl.go`: `c.Add(New<Command>(c, c.l).Command())`

Pattern for login-required commands:

```go
cli, err := api.NewClient(c.root.Cfg.Network, c.l)
if err != nil { return fmt.Errorf("NewClient: %w", err) }
defer cli.Close(ctx)
request := weapi.New(cli)
if request.NeedLogin(ctx) { return fmt.Errorf("need login") }
defer func() {
    refresh, err := request.TokenRefresh(ctx, &weapi.TokenRefreshReq{})
    if err != nil || refresh.Code != 200 {
        log.Warn("TokenRefresh resp:%+v err: %s", refresh, err)
    }
}()
```

## Adding a New API Endpoint

1. Create file in `api/weapi/` or `api/eapi/`
2. Define request/response structs (request fields use json tags)
3. Implement method on API struct calling `a.client.Request(ctx, url, req, resp, opts...)`
4. Set correct `CryptoMode` via option: `api.WithCryptoMode(api.CryptoModeWEAPI)`
5. Default crypto mode is weapi; eapi uses `CryptoModeEAPI`

API call flow:

```go
cli := api.New(cfg)
weapiClient := weapi.New(cli)
resp, err := weapiClient.SomeMethod(ctx, &weapi.SomeMethodReq{...})
cli.Close(ctx)
```

## Encryption Modes

| Mode                | Algorithm                    | Use Case         |
| ------------------- | ---------------------------- | ---------------- |
| `CryptoModeWEAPI` | AES-CBC double encrypt + RSA | Web/Mini-program |
| `CryptoModeEAPI`  | AES-ECB                      | PC/Mobile        |
| `CryptoModeLinux` | AES-ECB                      | Linux client     |
| `CryptoModeAPI`   | None                         | Basic API        |

Core functions in `pkg/crypto/crypto.go`: `WeApiEncrypt()`, `EApiEncrypt()`, `LinuxApiEncrypt()`, `EApiDecrypt()`.

## Configuration

- Config file: `~/.ncmctl/config.yaml` (optional, uses defaults if absent)
- Cookie storage: `~/.ncmctl/cookie.json` (auto-persisted, 3s interval)
- Database: `~/.ncmctl/database/badger/` (scrobble dedup records)
- Logs: `~/.ncmctl/log/ncm.log`
- Env var prefix: `NCmctl_` (e.g., `NCmctl_Network_Debug=true`)
- Magic variable: `${HOME}` replaced at runtime

## Download Quality Levels

| Level    | Aliases | Format  |
| -------- | ------- | ------- |
| standard | 128     | 128kbps |
| higher   | 192     | 192kbps |
| exhigh   | HQ, 320 | 320kbps |
| lossless | SQ      | FLAC    |
| hires    | HR      | Hi-Res  |

## Key Dependencies

| Package                 | Purpose           |
| ----------------------- | ----------------- |
| `spf13/cobra`         | CLI framework     |
| `go-resty/resty/v2`   | HTTP client       |
| `dgraph-io/badger/v4` | Local KV database |
| `robfig/cron/v3`      | Cron scheduling   |
| `spf13/viper`         | Config management |

## Important Notes

- Cookie persistence is interval-based (3s); unclean shutdown may lose recent cookies
- Scrobble dedup data in `~/.ncmctl/database/` should not be deleted
- Directory depth limit is 3 for cloud upload and NCM decryption
- Cloud upload max file size: 500MB
- Download parallelism max: 20; Cloud upload parallelism max: 10
- The `task` command runs as a long-lived service; use Ctrl+C to stop
- Sign-in reward auto-claim (`--sign.automatic`) has ban risk, disabled by default
- Scrobble (刷歌) currently has high risk of account ban due to strict risk control

For detailed command usage and API reference, read `references/commands.md` and `references/api-guide.md`.

---
> Source: [chaunsin/netease-cloud-music](https://github.com/chaunsin/netease-cloud-music) — distributed by [TomeVault](https://tomevault.io).
<!-- tomevault:4.0:skill_md:2026-06-30 -->

