109 lines
3.3 KiB
TypeScript
109 lines
3.3 KiB
TypeScript
import type { FriendMode, OverlaySettings } from "./types.ts";
|
|
|
|
/** Keys accepted in overlay.toml (snake_case). */
|
|
export interface OverlayToml {
|
|
chat_request_database?: string;
|
|
cover?: boolean;
|
|
map_info?: boolean;
|
|
time?: boolean;
|
|
score?: boolean;
|
|
friends?: boolean;
|
|
friend_mode?: string;
|
|
bsr?: boolean;
|
|
beatleader_player_id?: string;
|
|
right?: boolean;
|
|
bottom?: boolean;
|
|
scale?: number;
|
|
fade?: number;
|
|
}
|
|
|
|
export interface OverlayConfigApiBody {
|
|
defaults: Partial<OverlaySettings>;
|
|
}
|
|
|
|
const FRIEND_MODES = new Set<FriendMode>(["mutual", "following", "followers"]);
|
|
|
|
/** Merge `/api/overlay-config` into the object used as `defaults` before applying the URL hash. */
|
|
export function mergeOverlayConfigResponse(
|
|
target: OverlaySettings,
|
|
body: { defaults?: Partial<OverlaySettings> },
|
|
): void {
|
|
const d = body.defaults;
|
|
if (!d) return;
|
|
const out = target as unknown as Record<string, unknown>;
|
|
for (const key of Object.keys(d) as (keyof OverlaySettings)[]) {
|
|
const v = d[key];
|
|
if (v !== undefined) out[key as string] = v;
|
|
}
|
|
}
|
|
|
|
function asBool(v: unknown): boolean | undefined {
|
|
if (typeof v === "boolean") return v;
|
|
return undefined;
|
|
}
|
|
|
|
function asNum(v: unknown): number | undefined {
|
|
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
return undefined;
|
|
}
|
|
|
|
/**
|
|
* Maps parsed TOML (snake_case) to overlay defaults. Collects warnings for invalid values.
|
|
*/
|
|
export function overlayTomlToDefaults(toml: OverlayToml): {
|
|
chatRequestDatabase: string | undefined;
|
|
defaults: Partial<OverlaySettings>;
|
|
beatleaderPlayerIdConfigured: boolean;
|
|
warnings: string[];
|
|
} {
|
|
const warnings: string[] = [];
|
|
const defaults: Partial<OverlaySettings> = {};
|
|
|
|
const db = typeof toml.chat_request_database === "string" ? toml.chat_request_database.trim() : "";
|
|
const chatRequestDatabase = db || undefined;
|
|
|
|
const bCover = asBool(toml.cover);
|
|
if (bCover !== undefined) defaults.cover = bCover;
|
|
const bMap = asBool(toml.map_info);
|
|
if (bMap !== undefined) defaults.mapInfo = bMap;
|
|
const bTime = asBool(toml.time);
|
|
if (bTime !== undefined) defaults.time = bTime;
|
|
const bScore = asBool(toml.score);
|
|
if (bScore !== undefined) defaults.score = bScore;
|
|
const bFriends = asBool(toml.friends);
|
|
if (bFriends !== undefined) defaults.friends = bFriends;
|
|
const bBsr = asBool(toml.bsr);
|
|
if (bBsr !== undefined) defaults.bsr = bBsr;
|
|
const bRight = asBool(toml.right);
|
|
if (bRight !== undefined) defaults.right = bRight;
|
|
const bBottom = asBool(toml.bottom);
|
|
if (bBottom !== undefined) defaults.bottom = bBottom;
|
|
|
|
if (toml.friend_mode !== undefined) {
|
|
const raw = String(toml.friend_mode).trim().toLowerCase();
|
|
if (FRIEND_MODES.has(raw as FriendMode)) defaults.friendMode = raw as FriendMode;
|
|
else {
|
|
warnings.push(
|
|
`overlay.toml: invalid friend_mode "${toml.friend_mode}" (expected mutual, following, or followers)`,
|
|
);
|
|
}
|
|
}
|
|
|
|
const scale = asNum(toml.scale);
|
|
if (scale !== undefined) defaults.scale = scale;
|
|
|
|
const fade = asNum(toml.fade);
|
|
if (fade !== undefined) defaults.fade = fade;
|
|
|
|
let beatleaderPlayerIdConfigured = false;
|
|
if (typeof toml.beatleader_player_id === "string") {
|
|
const id = toml.beatleader_player_id.trim();
|
|
if (id) {
|
|
defaults.beatLeaderId = id;
|
|
beatleaderPlayerIdConfigured = true;
|
|
}
|
|
}
|
|
|
|
return { chatRequestDatabase, defaults, beatleaderPlayerIdConfigured, warnings };
|
|
}
|