mirror of
https://github.com/Boof2015/astra-mobile.git
synced 2026-08-19 20:20:18 +02:00
178 lines
6.8 KiB
TypeScript
178 lines
6.8 KiB
TypeScript
// Lyrics orchestrator — local-first lookup with an in-flight Map for request
|
|
// deduplication and a persistent cache for embedded/online results. Source order:
|
|
// sidecar → embedded → cache → xlrcdb → lrclib.
|
|
|
|
import Constants from 'expo-constants';
|
|
import { clearLyricsCache, deleteLyricsCache, getLyricsCache, putLyricsCache } from '@/db/lyricsQueries';
|
|
import { sha1Hex } from '@/lib/hash';
|
|
import type { Track } from '@/types/audio';
|
|
import { resolveEmbeddedLyrics, resolveSidecarLyrics } from './local';
|
|
import type { LyricsLookupResult, LyricsPayload, LyricsTrackQuery } from './types';
|
|
import { resolveLyricsWithDependencies, resultFromLyricsCache } from './resolver';
|
|
import { LrclibLookupCoordinator, createLrclibClientConfig, normalizeLrclibMetadataText } from '@/services/lyrics/lrclib';
|
|
import { XlrcdbLookupCoordinator, createXlrcdbClientConfig } from '@/services/lyrics/xlrcdb';
|
|
import { safeNormalize } from '@/services/lyrics/unicode';
|
|
import { CacheInvalidationGate } from '@/lib/cacheInvalidation';
|
|
|
|
export interface GetLyricsOptions {
|
|
forceRefresh?: boolean;
|
|
onlineEnabled?: boolean;
|
|
}
|
|
|
|
const APP_VERSION = Constants.expoConfig?.version ?? '0.1.0';
|
|
|
|
let xlrcdbProvider: XlrcdbLookupCoordinator | null = null;
|
|
let lrclibProvider: LrclibLookupCoordinator | null = null;
|
|
const cacheGate = new CacheInvalidationGate();
|
|
|
|
function getXlrcdb(): XlrcdbLookupCoordinator {
|
|
if (!xlrcdbProvider) xlrcdbProvider = new XlrcdbLookupCoordinator(createXlrcdbClientConfig());
|
|
return xlrcdbProvider;
|
|
}
|
|
|
|
function getLrclib(): LrclibLookupCoordinator {
|
|
if (!lrclibProvider) lrclibProvider = new LrclibLookupCoordinator(createLrclibClientConfig({ appVersion: APP_VERSION }));
|
|
return lrclibProvider;
|
|
}
|
|
|
|
function normalizeDurationSeconds(value: unknown): number | null {
|
|
if (typeof value === 'number' && Number.isFinite(value) && value >= 0) return Math.round(value);
|
|
return null;
|
|
}
|
|
|
|
/** Stable, Hermes-safe signature normalize — only needs consistency across runs. */
|
|
function normalizeSignatureText(value: string): string {
|
|
return safeNormalize(value.trim(), 'NFKC').toLocaleLowerCase().replace(/\s+/g, ' ').trim();
|
|
}
|
|
|
|
function createMetadataSignature(query: LyricsTrackQuery): string {
|
|
const title = normalizeSignatureText(query.title);
|
|
const artist = normalizeSignatureText(query.artist);
|
|
const album = normalizeSignatureText(query.album ?? '');
|
|
const duration = normalizeDurationSeconds(query.durationSeconds) ?? -1;
|
|
return sha1Hex(`${title} |