mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 04:52:50 +08:00
feat: make Jellyfin an optional source instead of the default
Revert the jellyfin-only default introduced by PR #123 so upgrading users keep their online sources; Jellyfin becomes opt-in: - default enabledProviders is now the online set (netease/qq/bilibili/ youtube/kugou); defaultPlatform() uses a fixed priority order (netease -> qq -> kugou -> jellyfin -> bilibili -> youtube) instead of jellyfin-first, so chat/REST/WebUI default to netease again - Settings: Jellyfin card is always visible with a new enable toggle (its enabled bit is enabledProviders membership); guards against clobbering other providers before the list loads - Setup wizard: saving the Jellyfin step auto-enables the source when a server URL was entered - Search/player store fallbacks flip from jellyfin to netease; !help no longer hardcodes Jellyfin lines - tests: update default-platform assertions, add coverage for the new default set, legacy configs without enabledProviders, priority order, and explicit jellyfin-only configs - README: reframe Jellyfin as optional (badges, command table, quality tiers, dedicated section, changelog), document the enabledProviders default and the v1.10.0 jellyfin-only window fix, credit @ItsEricRao Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3841fa80d3
commit
750ad9b1cc
12 files changed
+270
-72
No files matched your search
+45
-1
@@ -10,7 +10,7 @@ import {
|
||||
renameSync,
|
||||
} from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { getDefaultConfig, loadConfig, saveConfig, migrateLegacyConfig } from "./config.js";
|
||||
import { getDefaultConfig, loadConfig, saveConfig, migrateLegacyConfig, defaultPlatform } from "./config.js";
|
||||
|
||||
// Wrap the fs functions config.ts uses in call-through spies so the atomic-write
|
||||
// and transient-read-error paths can be observed/forced. Everything else (mkdtemp,
|
||||
@@ -48,6 +48,50 @@ describe("config", () => {
|
||||
expect(config).toEqual(getDefaultConfig());
|
||||
});
|
||||
|
||||
it("defaults to the online sources with jellyfin as opt-in (disabled)", () => {
|
||||
const config = getDefaultConfig();
|
||||
expect(config.enabledProviders).toEqual(["netease", "qq", "bilibili", "youtube", "kugou"]);
|
||||
expect(config.enabledProviders).not.toContain("jellyfin");
|
||||
});
|
||||
|
||||
it("keeps pre-gating behavior for legacy configs without enabledProviders", () => {
|
||||
const dir = makeTmpDir();
|
||||
const path = join(dir, "config.json");
|
||||
// A config written before enabledProviders existed: no such field.
|
||||
writeFileSync(path, JSON.stringify({ webPort: 4000 }));
|
||||
const config = loadConfig(path);
|
||||
expect(config.enabledProviders).toEqual(["netease", "qq", "bilibili", "youtube", "kugou"]);
|
||||
expect(defaultPlatform(config)).toBe("netease");
|
||||
});
|
||||
|
||||
it("defaultPlatform follows the fixed priority order", () => {
|
||||
const config = getDefaultConfig();
|
||||
expect(defaultPlatform(config)).toBe("netease");
|
||||
|
||||
// Jellyfin ranks after the online music platforms…
|
||||
config.enabledProviders = ["netease", "jellyfin"];
|
||||
expect(defaultPlatform(config)).toBe("netease");
|
||||
// …but ahead of the video sites…
|
||||
config.enabledProviders = ["bilibili", "jellyfin", "youtube"];
|
||||
expect(defaultPlatform(config)).toBe("jellyfin");
|
||||
// …and is the default when it is the only enabled source.
|
||||
config.enabledProviders = ["jellyfin"];
|
||||
expect(defaultPlatform(config)).toBe("jellyfin");
|
||||
// Nothing enabled → netease fallback (the gate then reports it disabled).
|
||||
config.enabledProviders = [];
|
||||
expect(defaultPlatform(config)).toBe("netease");
|
||||
});
|
||||
|
||||
it("respects an explicit jellyfin-only enabledProviders from disk", () => {
|
||||
const dir = makeTmpDir();
|
||||
const path = join(dir, "config.json");
|
||||
// e.g. a config persisted by the short-lived jellyfin-by-default builds.
|
||||
writeFileSync(path, JSON.stringify({ enabledProviders: ["jellyfin"] }));
|
||||
const config = loadConfig(path);
|
||||
expect(config.enabledProviders).toEqual(["jellyfin"]);
|
||||
expect(defaultPlatform(config)).toBe("jellyfin");
|
||||
});
|
||||
|
||||
it("creates config file on save", () => {
|
||||
const dir = makeTmpDir();
|
||||
const path = join(dir, "sub", "config.json");
|
||||
|
||||
+14
-11
@@ -62,13 +62,15 @@ export function isProviderEnabled(config: BotConfig, platform: string): boolean
|
||||
|
||||
/**
|
||||
* The default platform for !play/!add/!playlist/!album and all REST/WebUI calls:
|
||||
* jellyfin when enabled, otherwise the first enabled provider in a fixed
|
||||
* priority order. Falls back to "netease" when nothing is enabled so callers
|
||||
* always get a provider — the enabled-gate then produces the friendly error.
|
||||
* the first enabled provider in a fixed priority order (netease with the default
|
||||
* config; jellyfin ranks after the online music platforms because it is an
|
||||
* opt-in source, but ahead of the video sites for users who run it as their
|
||||
* only music library). Falls back to "netease" when nothing is enabled so
|
||||
* callers always get a provider — the enabled-gate then produces the friendly
|
||||
* error.
|
||||
*/
|
||||
export function defaultPlatform(config: BotConfig): GateableProvider {
|
||||
if (config.enabledProviders.includes("jellyfin")) return "jellyfin";
|
||||
for (const p of ["netease", "qq", "kugou", "bilibili", "youtube"] as const) {
|
||||
for (const p of ["netease", "qq", "kugou", "jellyfin", "bilibili", "youtube"] as const) {
|
||||
if (config.enabledProviders.includes(p)) return p;
|
||||
}
|
||||
return "netease";
|
||||
@@ -102,9 +104,10 @@ export interface BotConfig {
|
||||
jellyfin: JellyfinConfig;
|
||||
/**
|
||||
* Which gateable providers are active (see GATEABLE_PROVIDERS). Default is
|
||||
* jellyfin-only: the legacy NetEase/QQ/Bilibili/YouTube/Kugou sources keep
|
||||
* compiling but stay disabled — their embedded sidecar API servers must not
|
||||
* start (or bind ports 3001/3200) unless listed here.
|
||||
* the online sources (NetEase/QQ/Bilibili/YouTube/Kugou); jellyfin is an
|
||||
* opt-in extra that must be listed here (Settings → Jellyfin 音乐库 toggles
|
||||
* it). Sources not listed stay disabled — the NetEase/QQ embedded sidecar
|
||||
* API servers must not start (or bind ports 3001/3200) unless enabled.
|
||||
*/
|
||||
enabledProviders: GateableProvider[];
|
||||
}
|
||||
@@ -159,7 +162,7 @@ export function getDefaultConfig(): BotConfig {
|
||||
apiKey: "",
|
||||
userId: "",
|
||||
},
|
||||
enabledProviders: ["jellyfin"],
|
||||
enabledProviders: ["netease", "qq", "bilibili", "youtube", "kugou"],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -306,8 +309,8 @@ export function loadConfig(path: string): BotConfig {
|
||||
};
|
||||
|
||||
// enabledProviders → known providers only; a non-array falls back to the
|
||||
// default (["jellyfin"]). An explicitly-empty array is respected (operator
|
||||
// chose to disable every gateable source).
|
||||
// default (online sources, jellyfin off). An explicitly-empty array is
|
||||
// respected (operator chose to disable every gateable source).
|
||||
const enabledProviders = Array.isArray(partial.enabledProviders)
|
||||
? partial.enabledProviders.filter((p): p is GateableProvider =>
|
||||
(GATEABLE_PROVIDERS as readonly string[]).includes(p as string),
|
||||
|
||||
Reference in new issue
Block a user