Preface¶
Building a floating window interface to play music in DSH (DeepSeek Harness) usually brings the ncm-player series to mind. Earlier versions had a recurring issue: if the playlist contained delisted or copyright-free songs, the player would only pop up a single sentence “Playback Error (possibly no copyright or needs membership)” and stop, requiring manual clicking of “Next”. The longer the playlist and the more such songs it contains, the more manual interactions are required.
ncm-player5 is a fork maintained by doctorpancode. Based on ncm-player4 1.3.1, it makes only one functional change: detecting unplayable songs and automatically skipping to the next one. Below is an introduction to its positioning, inherited capabilities, skip logic, and installation methods.
What is this?¶
One-sentence positioning: A NetEase Cloud Music floating window player for DSH (DeepSeek Harness), fully inheriting ncm-player4 with the addition of auto-skipping inaudible songs. Maintained by doctorpancode, categorized as a client-side plugin.
The upstream is WolfGenerals/ncm-player. The README traces the fork history as a complete linear commit history with three tags:
upstream-1.2.0: Import of upstreamWolfGenerals/ncm-player@mainas-is, 18 files identical byte-for-byte, serving as a public reference point for 1.2.0.ncm-player4-v1.3.1: ncm-player4 1.3.1, deriving from 1.2.0 with features like click-outside-to-close, auto-exit on idle, playback heartbeat, long-press drag, and silent repair.ncm-player5-v1.4.1: Current version of this plugin. The only functional change from 1.3.1 is auto-skipping, plus package name scope adjustment.
This means you can execute git diff ncm-player4-v1.3.1 main to directly review all changes of this plugin relative to the baseline. The current version is 1.4.1, package name @doctor-pan-code/ncm-player5 (Early versions used the upstream @wolfgenerals/ scope, but that scope belongs to the upstream author and this plugin has never been published to npm, so it was changed back to the submitter’s own scope starting from 1.4.1), cordis load id remains ncm-player5.
Inherited Capabilities from ncm-player4¶
The following capabilities are consistent with ncm-player4 1.3.1, all existing features listed in the README:
- Playback: Play/Pause, Previous/Next, progress dragging, volume and mute; three modes: Order, Repeat One, Random.
- Discovery: Search for singles/playlists/albums, hot playlist recommendations; after login, you can view “My” playlists and favorited albums.
- Lyrics: Line-by-line sync highlighting, click to jump, lyrics translation; Mini mode displays current lyrics, scrolls horizontally for very long lyrics, font size adjustable.
- Queue: Add, remove, clear, auto-persistence, restore queue, progress, playback mode, and volume after restart.
- Account: NetEase App QR code login, or paste Cookie.
- Floating Window: Three states: Expand / Mini-bar / Hide; all draggable; color follows DSH theme.
- Settings: Audio quality, lyrics translation, mini lyrics toggle/scroll/font size, auto-exit on idle, auto-skip inaudible songs.
Existing interaction details: Clicking outside the player window collapses it to a mini-bar; if no mouse click or movement occurs within 3 seconds of collapse, it automatically exits to the note button in the bottom right corner without interrupting playback; this button bounces with the music’s low-frequency beats during playback; the icon in the bottom right supports left-click long-press drag, and the position is automatically remembered.
ncm-player5 New Feature: Auto-skip¶
The skip determination has two stages, with the main criterion during the address fetching phase:
- Address Fetching Phase (Main Criterion): The
hostcalls/api/song/enhance/player/url. NetEase returnsurl: nullandcode: -110for unplayable songs. Thehostforwards this signal to the frontend.songUrlreturns{ url, playable, reason, code }, and introduces a newsongStatusop. Whenplayable === falseandreason === 'copyright', it is judged as no copyright/delisted and skipped directly without initiating any audio requests. - Multi-tier Quality Degradation: To avoid misjudging “just no high quality” as “cannot play”,
songUrlimplements multi-tier quality degradation: Request bitrate → 320k → 192k → 128k → 96k. If an address is not obtained at a tier, it automatically tries a lower bitrate; all fail to count as unplayable. - Playback Error Phase (Fallback): Inside the
<audio>errorevent, the original two retry branches are tried first (Web Audio takeover replaces the element, CORS fallback reloads once). Only when retries are exhausted, or the error code isMEDIA_ERR_SRC_NOT_SUPPORTED(4)/MEDIA_ERR_DECODE(3), is it judged as unplayable and skipped.
Network exceptions are not considered unplayable: When the interface itself fails (timeout/disconnect/parsing failure), it is handled as “Unknown” and the song is not skipped; only the usual notification is popped up.
Skip Rules:
- Advance according to the current playback mode: In Order mode, go to the next song; when reaching the end, loop back to the start to find a playable one. In Random mode, switch to a random song avoiding the current one. In Repeat One mode, encountering a bad song also skips to the next to avoid constantly replaying the same song.
- Notification: When skipping, display “Skipped 《Song Name》: No copyright/Delisted”, and it disappears automatically after 2.8 seconds.
- Prevent Infinite Loops: If the number of consecutive skips reaches the queue length (upper limit 30) and still no song is playable, stop playback and only show the notification “No playable songs in the queue” once; when there is only 1 bad song in the queue, stop directly without repeated retries.
- Toggle: Located in Settings → Playback → “Auto-skip inaudible songs”, enabled by default; when disabled, behavior is identical to ncm-player4.
- Caching: The determination result is cached for 5 minutes on the host side to avoid repeatedly requesting the same song during consecutive skips.
Installation and Enablement¶
Package name @doctor-pan-code/ncm-player5, cordis load id is ncm-player5.
Note: This plugin cannot be enabled simultaneously with ncm-player2/3/4. The host side registers routes with the /ncm/api prefix. Enabling both will cause conflicts; you should disable ncm-player4 when installing this plugin.
Install from GitHub:
dsh plugin add Doctor-Pan-code/ncm-player5
Local / Manual Installation (link method) is consistent with other local plugins in the profile. First, put the directory in the plugins directory, e.g., $DSH_HOME/plugins/ncm-player5, then:
- Declare the dependency in
$DSH_HOME/profiles/<profile>/package.jsonand append the bundle todsh.profile.bundles:
"dependencies": { "@doctor-pan-code/ncm-player5": "link:C:/Users/<you>/.dsh/plugins/ncm-player5" }
- Append insertions and disablings in
$DSH_HOME/profiles/<profile>/cordis.patch.yml:
- insert:
- id: ncm-player5
name: '@doctor-pan-code/ncm-player5'
- id: ncm-player4
disabled: true
- Completely exit and restart DSH.
Data Persistence and Upgrade Compatibility¶
Login state and playback queue are stored in the local browser’s localStorage, key remains ncmply2-settings; the position key for the note button in the bottom right remains ncmply4-disc-pos. Therefore, upgrading from ncm-player4 to ncm-player5 automatically inherits the login state, playback queue, various settings, and icon position; no need to re-login or re-drag the icon.
ncm-player5 adds a new field autoSkip (default true) to state. The overall shape is as follows:
{
"account": { "cookie": "...", "uid": 123, "nickname": "..." },
"state": {
"queue": [ { "id": 1, "name": "...", "artists": "...", "album": "...", "cover": "...", "duration": 0 } ],
"index": -1, "mode": "order", "vol": 0.8, "quality": 320000, "time": 0,
"showTrans": true, "showMiniLrc": true, "miniLrcScroll": true, "miniLrcSize": 11,
"autoExit": true, "autoSkip": true
}
}
New Host-side APIs¶
This plugin adds two ops to the host side; other behaviors like search / playlistDetail / albumDetail / lyric / like / login-related / saveState are identical to ncm-player4.
| op | Input | Return |
|---|---|---|
songUrl |
{ id, br } |
{ url, playable, reason, code }; tries multiple bitrates sequentially; if all fail, url still falls back to song/media/outer/url behavior to be compatible with old frontends |
songStatus |
{ id, br } |
{ playable, reason, code, fee, freeTrial }; pure query, no address returned, result cached for 5 minutes |
reason values: copyright (code -110, no copyright/delisted), error (code -200), unavailable (other), null (playable or unknown).
Applicable Scenarios and Notes¶
Suitable for those who want to mount a NetEase Cloud Music floating window in DSH and want the playlist to play through as automatically as possible. The plugin depends on a locally available Node.js runtime and a network accessible to music.163.com. Login Cookie is only used for requests to music.163.com and is not sent to any third party. Favorites (heart icon ❤) are affected by NetEase account risk control; a prompt will appear upon failure, which is a normal phenomenon. For personal study only; must comply with NetEase Cloud Music’s terms of service and local laws and regulations.
A few notes:
- VIP-exclusive songs return
-110when not logged in or non-VIP, so they will be skipped as unplayable; these songs can play normally after logging in with a VIP account. - The plugin runs with the permissions of the current dsh process; you should check the source code and license before installing (this plugin is MIT License).
- This repository is a community fork; there is no official affiliation with DeepSeek / Hypothesis.
Summary¶
ncm-player5 did not rewrite the player but added the long-standing pain point of “automatically skipping delisted/no copyright songs” on top of the mature ncm-player4 baseline. It handles skip criteria, quality degradation, mode progression, and anti-infinite-loop processing quite clearly, while retaining ncm-player4’s floating window interactions and all existing features. Directory page and repository are below:
- Directory page: https://www.skillhub.cn/plugins/doctorpancode/ncm-player5
- GitHub: https://github.com/doctorpancode/ncm-player5