Files
root a91188ca68 s
2026-05-17 14:06:06 +00:00

60 lines
1.7 KiB
TypeScript

export type QuickLinkMap = Record<string, string>;
export type NekoBrowserLink = {
id: number;
key: string;
label: string;
url: string;
port: string;
};
const NEKO_KEY_RE = /^neko_browser(?:_(\d+))?$/i;
function parsePort(url: string): string {
try {
return new URL(url, "http://127.0.0.1").port || "";
} catch {
return "";
}
}
export function extractNekoBrowserLinks(quickLinks?: QuickLinkMap | null): NekoBrowserLink[] {
const picked = new Map<number, NekoBrowserLink>();
for (const [key, rawUrl] of Object.entries(quickLinks ?? {})) {
const match = key.match(NEKO_KEY_RE);
const url = rawUrl.trim();
if (!match || !url) continue;
const id = key === "neko_browser" ? 1 : Number(match[1] || 1);
const next: NekoBrowserLink = {
id,
key,
label: `Neko ${id}`,
url,
port: parsePort(url),
};
const current = picked.get(id);
const preferNext = key !== "neko_browser";
if (!current || preferNext) picked.set(id, next);
}
return Array.from(picked.values()).sort((a, b) => a.id - b.id);
}
export function resolveNekoBrowserLink(
links: NekoBrowserLink[],
preferredIndex: number,
): { link: NekoBrowserLink | null; fallback: boolean } {
if (!links.length) return { link: null, fallback: false };
if (!Number.isInteger(preferredIndex) || preferredIndex < 0) {
return { link: links[0], fallback: false };
}
if (preferredIndex < links.length) {
return { link: links[preferredIndex], fallback: false };
}
return { link: links[0], fallback: true };
}
export function formatNekoPorts(links: NekoBrowserLink[]): string {
const ports = links.map((item) => item.port).filter(Boolean);
return ports.length ? ports.map((port) => `:${port}`).join(" / ") : "";
}