网易云音乐播放器:用 ETAF/Ebox 搭的 Emacs 文本应用客户端(NetEase Cloud Music player built with ETAF and Ebox)
  • Emacs Lisp 90.1%
  • Python 9.4%
  • Makefile 0.4%
Find a file
Kinneyzhang ef59186247
Some checks are pending
Repository structure / structure (push) Waiting to run
feat(ncm): pause the library refresh when it cannot help
The player's background refresh reports success and failure codes to ETAF's
list cache, so an expired login pauses it until a load succeeds and other
failures back off; a player whose buffer no window shows pauses the refresh
until it is shown again.  The backend's error code is kept beside the human
message.

Validation: make check (51 acceptance tests including the new pause/resume and
hidden-buffer scenarios, 51 public API declarations).
2026-10-02 18:08:47 +08:00
.githooks feat(ncm): add the ETAF NetEase Cloud Music player 2026-09-30 01:27:23 +08:00
.github/workflows feat(ncm): add the ETAF NetEase Cloud Music player 2026-09-30 01:27:23 +08:00
benchmarks fix(ncm): keep the playing second on retained hosts 2026-10-02 17:44:50 +08:00
docs feat(ncm): pause the library refresh when it cannot help 2026-10-02 18:08:47 +08:00
examples feat(ncm): add the ETAF NetEase Cloud Music player 2026-09-30 01:27:23 +08:00
lisp feat(ncm): pause the library refresh when it cannot help 2026-10-02 18:08:47 +08:00
scripts test(ncm): use the shared row-height and canvas checks 2026-10-02 06:51:28 +08:00
tests feat(ncm): pause the library refresh when it cannot help 2026-10-02 18:08:47 +08:00
.editorconfig feat(ncm): add the ETAF NetEase Cloud Music player 2026-09-30 01:27:23 +08:00
.gitignore feat(ncm): add the ETAF NetEase Cloud Music player 2026-09-30 01:27:23 +08:00
CHANGELOG.md fix(ncm): keep the playing second on retained hosts 2026-10-02 17:44:50 +08:00
etaf-ncm.el feat(ncm): pause the library refresh when it cannot help 2026-10-02 18:08:47 +08:00
Makefile feat(ncm): add the ETAF NetEase Cloud Music player 2026-09-30 01:27:23 +08:00
README.md feat(ncm): show whole libraries and a scrolling queue 2026-10-01 19:30:42 +08:00

ETAF NCM

ETAF NCM is a NetEase Cloud Music client for Emacs. It renders the signed-in account's music library, playback and lyric as one ETAF view: a sidebar of libraries, a paginated song list, a panel with the synchronized lyric or the queue, and a playback bar. mpv keeps playing; the player is the interface over the netease-music backend.

The player mounted in a dark palette

Capabilities

  • Libraries: daily recommendation, private FM, liked songs, playlists, saved albums and artists, charts, podcasts, recent plays.
  • Search by song, with a playlist scope; results behave like any library.
  • Playback: play a row or a whole list, pause, skip, stop, volume, relative seek, shuffle, repeat, like and unlike.
  • Queue: a window that follows the playing song, wheel through every loaded entry, jump to any of them, append songs.
  • Lyric: LRC parsed into timed lines, current line highlighted, translation shown next to it when the backend has one.
  • Two palettes (dark and light) with one key, published as :ui-* theme tokens so the shared ETAF UI controls follow the same colours.
  • Headless sessions for scripts and tests: no buffer, no timer and a scripted client are all supported.
  • Window layouts: three columns on a wide frame, a glyph-only rail with one pane on a medium one, and a phone-like stacked layout on a narrow one.

Prerequisites

Emacs 29.1 or newer, the etaf, etaf-ui, ebox and ecss repositories on load-path, and the netease-music backend skill with Node.js and mpv signed in to the account.

Installation

(add-to-list 'load-path "/path/to/etaf")
(add-to-list 'load-path "/path/to/etaf-ui")
(add-to-list 'load-path "/path/to/ebox")
(add-to-list 'load-path "/path/to/ecss")
(add-to-list 'load-path "/path/to/etaf-ncm")
(require 'etaf-ncm)

(global-set-key (kbd "C-c m") #'etaf-ncm-open)

M-x etaf-ncm-open mounts the player; M-x etaf-ncm-close closes it. etaf-ncm-skill-directory and etaf-ncm-state-directory point at the backend skill and its login/queue state; etaf-ncm-theme-mode selects the palette.

Minimal example

(require 'etaf-ncm)

(let* ((player (etaf-ncm-create))          ; headless session
       (client (etaf-ncm-make-client)))
  (plist-put player :client client)
  (etaf-ncm-refresh player)                ; library, status, queue, account
  (while (plist-get (etaf-ncm-state player) :loading)
    (sit-for 0.05))
  (etaf-ncm-move-selection player 4)
  (etaf-ncm-activate-selection player)     ; plays the fifth row
  (plist-get (etaf-ncm-state player) :status))

Runnable demo

M-x etaf-ncm-demo-open mounts the complete player on a scripted library, so it needs no network, login or mpv. M-x etaf-ncm-demo-live opens the same player against the installed backend. From a checkout with sibling providers:

cd etaf-ncm
emacs -Q -L ../../ecss -L ../../ebox -L ../../etaf -L ../../etaf-ui \
  -L . -l examples/etaf-ncm-demo.el -f etaf-ncm-demo-open

Documentation

  • The manual: keys, libraries, playback, lyric, theming, scripting, custom backends and troubleshooting.
  • Architecture: module responsibilities, data flow and invariants.
  • The root entry Commentary: the authoritative list of supported functions, variables, the app Component and the error type.

Checks

make check runs the structure checker, byte compilation with warnings as errors, the acceptance suite and the API boundary checker. The acceptance scenarios drive a scripted backend, so they need no network, mpv or frame:

make compile   # byte compilation, warnings are errors
make test      # the public acceptance scenarios
make check     # structure + compile + acceptance + API boundary