01Virex/dsh-status-rotator ↗★ 82
dsh-status-rotator
将状态文本替换为可编辑多主题短语轮播与动态展示 适合想定制界面状态文案与氛围的用户,需保留配置文件并支持页面实时刷新
安裝
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:01Virex/dsh-status-rotator說明文件
閱讀完整 README ↗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 bynode 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, restartdsh webonce 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
}
| Key | Default | Description |
|---|---|---|
intervalMs | 10000 | Rotation interval (ms) |
typeSpeedMs | 30 | Typewriter delay per character (ms), 0 disables the typewriter |
longAfterMs | 60000 | Threshold for entering the long phase |
reloadIntervalMs | 15000 | Interval for auto re-reading config.json while the page is open (ms), 0 disables |
liveTickMs | 1000 | Refresh interval for live placeholders ({elapsed} / {date} / {time} / {tps}…) in phrases and titles (ms), 0 disables |
weightedRandom | true | Weighted random picking. false = fully uniform over phrases. Phrase entries may be "text" or { "text": "...", "weight": 3 } (weight > 0, capped at 1000, invalid/missing = 1) |
debug | false | Console 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) |
gradient | see above | Rainbow gradient: false / true / {enabled, colors, speed} |
title | see above | Tab title rotation: false / {enabled, templates, idleTemplate, intervalMs} |
danmaku | see above | Bullet-screen comments: false / {enabled, intervalMs, speedMs, fontSizeMin, fontSizeMax, rainbow, colors, color, opacity, maxCount, zIndex, scope, marginTop, marginBottom} |
phrases | from config file | The phrases (Chinese/English × three phases; partial entries allowed, missing ones fall back to other sources) |
packs | none | Modular phrase packs: [{ id, label?, phrases? }], merged into the effective bank in order (deduped by text) |
enabledPacks | null (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 |
presets | none | Named phrase banks, each with optional config / phrases |
activePreset | null | Which preset is active (null = use the top-level config/phrases) |
schedule | none | Time 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:
- localStorage single-text override
dsh-status-rotator.texts[.]/texts; - localStorage full config
dsh-status-rotator.config(paste JSON, applies after refresh); - External JSON:
dsh-status-rotator.url>EXTERNAL_URLconstant > local auto-load (/plugins/dsh-status-rotator/config.json); - Built-in defaults: only
DEFAULT_CONFIGat the top oflib/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.