01Virex/dsh-status-rotator ↗★ 82

dsh-status-rotator

Turn the DSH Web status line into a 1063-phrase meme machine: phase-aware phrases, typewriter, rainbow gradient, danmaku and 12 theme packs, all editable from the settings page. 适合想定制界面状态文案与氛围的用户,需保留配置文件并支持页面实时刷新

패키지
dsh-status-rotator
호환성
미검증
Cordis peer 범위
*
버전
0.17.3
라이선스
MIT
최근 업데이트
2026. 9. 14.

설치

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:01Virex/dsh-status-rotator

Configuration

Phrases are fully separated from the source code and live in JSON config files. There are two config files at the project root:

  • config.example.json — the complete template committed to the repo: default config + all phrases (bilingual, split into three phases);
  • config.json — your local personalized config, initialized by node gen-config.cjs (only created when missing, never overwrites your changes). It's in .gitignore, so edit freely without polluting git.

Auto-loading (default): the plugin's node half registers an HTTP route (/plugins/dsh-status-rotator/config.json) that serves the config.json next to the plugin (read from disk on every request). The browser fetches it automatically by default, and while the page stays open it re-reads every reloadIntervalMs, plus immediately when you switch back to the tab, so as long as config.json sits in the plugin directory, phrase edits take effect without a refresh or restart. The only restart of dsh web needed is on first install.

Persistent storage since v0.6.1: saved edits are written into the official dsh settings store ($DSH_HOME/settings.yaml, namespace status-rotator) — the same store the rest of dsh uses for its settings, which survives plugin upgrades. Upgrading via npm or a release package will no longer wipe your gradient/phrases/presets (previously config.json lived inside the plugin directory and was deleted on upgrade). The plugin-directory config.json remains as a compatibility mirror and fallback; a one-time import migrates an existing config.json into the settings store on first start.

Version history lives in CHANGELOG.md (including the 0.16.1 fix for a silent settingsNamespace() regression). After upgrading the plugin, restart dsh web once so the node half picks up the new code; the client half only needs a page refresh.

{
    "config": { "intervalMs": 10000, "typeSpeedMs": 30, "longAfterMs": 60000, "reloadIntervalMs": 15000, "liveTickMs": 1000, "weightedRandom": true, "debug": false, "fontWeight": "inherit", "gradient": { "enabled": true, "colors": ["#ff5f6d", "#ffc371", "#ffdd55", "#7dff7d", "#5fd4ff", "#a78bfa", "#ff8adb"], "speed": 4 }, "title": { "enabled": false, "templates": ["⏳ {phaseLabel} {elapsed}", "🤔 {phaseLabel}… {elapsed}"], "idleTemplate": "💤 dsh 空闲", "intervalMs": 8000 }, "danmaku": { "enabled": true, "intervalMs": 2500, "speedMs": 18000, "fontSizeMin": 14, "fontSizeMax": 30, "rainbow": true, "colors": ["#ff5f6d", "#ffc371", "#ffdd55", "#7dff7d", "#5fd4ff", "#a78bfa", "#ff8adb"], "color": "#ffffff", "opacity": 0.3, "maxCount": 12, "zIndex": -1, "scope": "all", "marginTop": 16, "marginBottom": 160 } },
    "phrases": { "zh": { "thinking": ["…"], "running": ["…"], "long": ["…"] }, "en": { "thinking": ["…"], "running": ["…"], "long": ["…"] } },
    "packs": [],            // optional, see "Phrase Packs" (default config ships 12 theme packs)
    "enabledPacks": null,   // null/absent = all packs; the shipped default pins the ten non-star ids
    "presets": [],          // optional, see "Presets & Scheduling"
    "activePreset": null,   // optional preset id
    "schedule": []          // optional time rules
}
KeyDefaultDescription
intervalMs10000Rotation interval (ms)
typeSpeedMs30Typewriter delay per character (ms), 0 disables the typewriter
longAfterMs60000Threshold for entering the long phase
reloadIntervalMs15000Interval for auto re-reading config.json while the page is open (ms), 0 disables
liveTickMs1000Refresh interval for live placeholders ({elapsed} / {date} / {time} / {tps}…) in phrases and titles (ms), 0 disables
weightedRandomtrueWeighted random picking. false = fully uniform over phrases. Phrase entries may be "text" or { "text": "...", "weight": 3 } (weight > 0, capped at 1000, invalid/missing = 1)
debugfalseConsole diagnostic logs
fontWeight"inherit"Font weight of the status text and the danmaku: a number (1–1000; typical 100–900) or a CSS keyword (normal/bold/bolder/lighter); "inherit" follows the UI (default; danmaku keeps its built-in 600)
gradientsee aboveRainbow gradient: false / true / {enabled, colors, speed}
titlesee aboveTab title rotation: false / {enabled, templates, idleTemplate, intervalMs}
danmakusee aboveBullet-screen comments: false / {enabled, intervalMs, speedMs, fontSizeMin, fontSizeMax, rainbow, colors, color, opacity, maxCount, zIndex, scope, marginTop, marginBottom}
phrasesfrom config fileThe phrases (Chinese/English × three phases; partial entries allowed, missing ones fall back to other sources)
packsnoneModular phrase packs: [{ id, label?, phrases? }], merged into the effective bank in order (deduped by text)
enabledPacksnull (all)Which packs are enabled; null/absent = all, [] = core bank only. The shipped default lists the ten non-star ids, so star-ask / star-route start off
presetsnoneNamed phrase banks, each with optional config / phrases
activePresetnullWhich preset is active (null = use the top-level config/phrases)
schedulenoneTime rules that switch the active preset automatically

Value guards: numeric fields are clamped on both save and load (rotation interval ≥ 250 ms, typewriter ≤ 1000 ms/char, danmaku spawn interval ≥ 200 ms, concurrent bullets ≤ 60, layer ±1000 …); colors accept only #rrggbb / rgb() / hsl() / CSS color names, and invalid values are dropped and flagged in the settings page. Colors are interpolated into an injected `` and numbers feed setInterval directly — that is why the guards exist.

Same-origin writes only: PUT/POST /plugins/dsh-status-rotator/config.json requires content-type: application/json and an origin matching Host (sec-fetch-site must be same-origin / none); cross-site requests get 403. Without this, any web page could rewrite your local config.

Phrase source priority, highest first:

  1. localStorage single-text override dsh-status-rotator.texts[.] / texts;
  2. localStorage full config dsh-status-rotator.config (paste JSON, applies after refresh);
  3. External JSON: dsh-status-rotator.url > EXTERNAL_URL constant > local auto-load (/plugins/dsh-status-rotator/config.json);
  4. Built-in defaults: only DEFAULT_CONFIG at the top of lib/client.js (no phrases).

If a localStorage override matches, the external config.json is silently suppressed; the new version logs a [status-rotator] ⚠ localStorage override active warning in the browser console — when you see it, clear the corresponding key.

Old phrase-only external JSON ({ "zh": [...], "en": [...] } or { "thinking": [...] }) is still supported and treated as a "phrases-only config" (a flat array lands in the thinking group).

Phrases switch live between Chinese and English following Settings → Language; unknown languages fall back to Chinese.