mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 04:52:50 +08:00
Three small reliability fixes from re-auditing: 1. Playlist.vue used Promise.all, so a flaky /detail endpoint would blank out the whole page even though /songs returned just fine. Switch to allSettled and synthesize a stub playlist header from the song list when only detail fails. User can still play the playlist; just loses the description/cover. 2. sourceTabs.readAll: typeof null === 'object' AND typeof [] === 'object', so a corrupted localStorage value (e.g. an array) would be treated as a record and its missing keys would silently fall back. Reject explicitly so the failure mode is "clean defaults" instead of "wrong shape that almost works". 3. Settings.vue loadProfileConfig: a 200 response with empty/wrong body would set profileConfigs[botId] to a falsy/wrong-shape value, leaving the row stuck on "加载中..." (because the v-if uses !profileConfigs[id]). Validate the shape; surface "响应格式异常" so the retry link is reachable. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
43 lines
1.2 KiB
TypeScript
43 lines
1.2 KiB
TypeScript
import type { Source } from './player.js';
|
|
|
|
const STORAGE_KEY = 'source-tabs';
|
|
|
|
export type TabKey =
|
|
| 'home.recommend'
|
|
| 'home.daily'
|
|
| 'home.user'
|
|
| 'library.user';
|
|
|
|
function readAll(): Partial<Record<TabKey, Source>> {
|
|
try {
|
|
const raw = localStorage.getItem(STORAGE_KEY);
|
|
if (!raw) return {};
|
|
const parsed = JSON.parse(raw);
|
|
// typeof null === 'object' and typeof [] === 'object' — both pass a
|
|
// naive check but neither is a valid record. Reject explicitly so a
|
|
// corrupted / manipulated value can't smuggle wrong shapes through.
|
|
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
return {};
|
|
}
|
|
return parsed as Partial<Record<TabKey, Source>>;
|
|
} catch {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
export function loadTabSource(key: TabKey, fallback: Source = 'netease'): Source {
|
|
const all = readAll();
|
|
const v = all[key];
|
|
return v === 'netease' || v === 'qq' ? v : fallback;
|
|
}
|
|
|
|
export function saveTabSource(key: TabKey, value: Source): void {
|
|
try {
|
|
const all = readAll();
|
|
all[key] = value;
|
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(all));
|
|
} catch {
|
|
// localStorage may be unavailable (private browsing); silently no-op
|
|
}
|
|
}
|