Something went wrong. Try again.
Experiment to rebuild Diffuse using web applets.
Something went wrong. Try again.
4.1 kB · 157 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158import { SubsonicAPI, type Child } from "subsonic-api";import * as IDB from "idb-keyval";import * as URI from "uri-js";import QS from "query-string";
import type { Server } from "./types";import { IDB_SERVERS, SCHEME } from "./constants";import type { Track } from "@applets/core/types";
////////////////////////////////////////////// 🛠️////////////////////////////////////////////export function autoTypeToTrackKind(type: Child["type"]): Track["kind"] { switch (type?.toLowerCase()) { case "audiobook": return "audiobook";
case "music": return "music";
case "podcast": return "podcast";
default: return "miscellaneous"; }}
export function buildURI(server: Server, args: { songId: string; path?: string }) { return URI.serialize({ scheme: SCHEME, userinfo: server.apiKey ? URI.escapeComponent(server.apiKey) : `${URI.escapeComponent(server.username || "")}:${URI.escapeComponent(server.password || "")}`, host: server.host.replace(/^https?:\/\//, ""), path: args.path, query: QS.stringify({ songId: args.songId, tls: server.tls ? "t" : "f", }), });}
export async function consultServer(server: Server) { const client = createClient(server); const resp = await client.ping().catch(() => undefined);
return resp?.status?.toLowerCase() === "ok";}
export function createClient(server: Server) { return new SubsonicAPI({ url: `http${server.tls ? "s" : ""}://${server.host}`, auth: server.apiKey ? { apiKey: URI.unescapeComponent(server.apiKey) } : { username: URI.unescapeComponent(server.username || ""), password: URI.unescapeComponent(server.password || ""), }, });}
export function groupTracksByServer(tracks: Track[]) { const acc: Record<string, { server: Server; tracks: Track[] }> = {};
tracks.forEach((track: Track) => { const parsed = parseURI(track.uri); if (!parsed) return;
const id = serverId(parsed.server);
if (acc[id]) { acc[id].tracks.push(track); } else { acc[id] = { server: parsed.server, tracks: [track] }; } });
return acc;}
export async function loadServers(): Promise<Record<string, Server>> { const i = await IDB.get(IDB_SERVERS); return i ? i : {};}
export function parseURI( uriString: string,): { path: string | undefined; server: Server; songId: string | undefined } | undefined { const uri = URI.parse(uriString); if (uri.scheme !== SCHEME) return undefined; if (!uri.host) return undefined;
let apiKey: string | undefined = undefined; let username: string | undefined = undefined; let password: string | undefined = undefined;
if (uri.userinfo?.includes(":")) { // Username + Password const [u, p] = uri.userinfo.split(":"); username = u; password = p; if (!username || !password) return undefined; } else { // API key apiKey = uri.userinfo; if (!apiKey) return undefined; }
const qs = QS.parse(uri.query || "");
const server = { apiKey, host: uri.port ? `${uri.host}:${uri.port}` : uri.host, password, tls: qs.tls === "f" ? false : true, username, };
const path = uri.path; const songId = typeof qs.songId === "string" ? qs.songId : undefined;
return { path, server, songId };}
export async function saveServers(items: Record<string, Server>) { await IDB.set(IDB_SERVERS, items);}
export function serversFromTracks(tracks: Track[]) { const acc: Record<string, Server> = {};
tracks.forEach((track: Track) => { const parsed = parseURI(track.uri); if (!parsed) return;
const id = serverId(parsed.server); if (acc[id]) return;
acc[id] = parsed.server; });
return acc;}
export function serverId(server: Server) { const parts = { host: server.host, query: `tls=${server.tls ? "t" : "f"}`, };
const uri = server.apiKey ? URI.serialize({ ...parts, userinfo: server.apiKey }) : URI.serialize({ ...parts, userinfo: `${server.username}:${server.password}` });
return btoa(uri);}