4.4 KiB
Executable File
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Overview
A modular CommonJS Node.js CLI for downloading music from NetEase Cloud Music (网易云音乐), with lyrics, cover art, and ID3 tag embedding. 163_music_downloader.js owns CLI argument handling and the interactive menu; reusable logic lives under lib/. There is no package.json — the script runs on Node built-ins only (https, http, fs, path, readline, child_process). The UI, comments, and console output are entirely in Chinese.
Running
# Interactive menu (TTY required for pause hotkey)
node 163_music_downloader.js
# Command-line batch mode (bypasses the menu entirely)
node 163_music_downloader.js <songId> <songId> ...
node 163_music_downloader.js --playlist=<playlistId>
# Flags (batch mode only)
--level=lossless # override quality; see QUALITY_LEVELS
--retries=5 # download retry count (default 3)
--no-lyric # skip .lrc download
--no-cover # skip cover/tag embedding
There are no tests, linter, or build step. Verify changes by running the script.
External dependencies (all optional / runtime-detected)
api.chksz.com— third-party API (APIobject inlib/config.js) for song URLs, search, lyrics, and playlists (requiresapikey). This is the core download source.music.163.com— queried directly (fetchNeteaseSongDetail,fetchNeteaseAlbumDetail) for rich metadata (album, publish date, popularity). RequiresCookie: os=pcheader.node-id3(npm) — preferred for MP3 tag/lyric/cover embedding.required lazily viahasNodeID3(); absent by default.ffmpeg(system) — fallback embedder for non-MP3 (FLAC etc.) and when node-id3 is missing. Detected viahasFFmpeg().- Audio players (
mpv,ffplay,play,cvlc,aplay) — for the preview/play features, detected viawhich. Note:whichis Unix-only, so preview won't find players on Windows even if installed.
If a dependency is missing the relevant feature degrades gracefully (skips embedding, prints the URL, etc.).
Architecture
163_music_downloader.js drives batch mode or the interactive menu loop, while lib/ contains feature modules:
lib/network.js—fetchJSON,downloadFile(streams with a live progress bar, follows redirects), anddownloadBuffer.lib/downloader.js— the core retry/download pipeline: resolves the URL, handles existing files, writes audio and lyrics, embeds cover/tags, then records history.lib/lyrics.js— lyric fetching, translation merging, credit parsing, and standalone.lrcsaving.lib/metadata.js— NetEase song/album metadata, album directory naming, andcover.jpgsaving.lib/tagging.js— node-id3/ffmpeg detection and audio tag embedding.lib/config.js,history.js,pause.js,quality.js,catalog.js,utils.js— configuration, persistence, batch state, quality selection, search, and shared helpers.- Persistence (all JSON in the script's
__dirname, not the download dir):download_history.json— capped at 500 entries, newest-first (addHistory).downloader_config.json— key/value config, currently only thelevelquality setting (getConfig/setConfig).
- Output layout — audio +
.lrcfiles go todownloads/. Deletes move files to.trash/(not permanent). ZIP packaging uses.tmp_zip/. Thecmenu option cleans these up.
Conventions & gotchas
- Quality levels —
QUALITY_LEVELSarray is the source of truth;DEFAULT_LEVEL = 'jymaster'. The chksz API may return a loweractualLevelthan requested. - Filenames — always
sanitize(${artist} - ${name})(strips/\:*?"<>|). Lyric/rename logic depends on this exact"artist - name"shape when parsing filenames back out. - Menu dispatch — adding a feature means adding a
casein themain()switch AND a line in bothprintMenu()and thehhelp text. Note the switch currently has a duplicatedcase 'p'/'P'block (the second is unreachable) and the keypress listener is registered twice — mirror the existing style rather than assuming it's clean. - Pause —
lib/pause.jsowns pause state;waitIfPaused()gates batch loops and thephotkey toggles it in interactive TTY mode. - Batch loops sleep ~300–500ms between songs to avoid hammering the API — preserve this when editing download loops.