Files
wehub-resource-sync 2114b14ee0
Sync main into demo / sync (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:35:26 +08:00

138 lines
5.8 KiB
TypeScript

import type { SpotifyTrack } from '../types';
import { resolveSpotifyAssetsDeep } from './assets';
export type CategoryDataMap = Record<string, any>;
export type PlaylistTracksMap = Record<string, SpotifyTrack[]>;
// ─── 离线 iTunes 数据类型 ─────────────────────────────────────────────────────
export interface ArtistTrackEntry extends SpotifyTrack {
album?: string;
}
export type ArtistTracksMap = Record<string, ArtistTrackEntry[]>; // key: lowercase artist name
export interface SearchResultEntry {
songs: SpotifyTrack[];
artists: { artistId: string; artistName: string; artworkUrl100: string }[];
albums: { collectionId: string; collectionName: string; artistName: string; artworkUrl100: string }[];
}
export type SearchResultsMap = Record<string, SearchResultEntry>; // key: lowercase search term
export interface AlbumCacheEntry {
playlist: { id: string; title: string; subtitle: string; cover: string; type: string };
tracks: SpotifyTrack[];
albumInfo: { title: string; trackCount: number; year: string };
}
export type AlbumTracksMap = Record<string, AlbumCacheEntry>; // key: iTunes collectionId string
let categoryCache: CategoryDataMap | null = null;
let categoryInflight: Promise<CategoryDataMap> | null = null;
let playlistTracksCache: PlaylistTracksMap | null = null;
let playlistTracksInflight: Promise<PlaylistTracksMap> | null = null;
export async function loadCategories(): Promise<CategoryDataMap> {
if (categoryCache) return categoryCache;
if (categoryInflight) return categoryInflight;
categoryInflight = (async () => {
const url = new URL('./categories.json', import.meta.url).href;
const res = await fetch(url);
if (!res.ok) throw new Error(`[Spotify] 加载 categories.json 失败:${res.status} ${res.statusText}`);
const json = resolveSpotifyAssetsDeep((await res.json()) as CategoryDataMap);
categoryCache = json;
return json;
})().catch(err => { categoryInflight = null; throw err; });
return categoryInflight;
}
export function getCategoriesSync(): CategoryDataMap | null {
return categoryCache;
}
export async function loadPlaylistTracks(): Promise<PlaylistTracksMap> {
if (playlistTracksCache) return playlistTracksCache;
if (playlistTracksInflight) return playlistTracksInflight;
playlistTracksInflight = (async () => {
const url = new URL('./playlistTracks.json', import.meta.url).href;
const res = await fetch(url);
if (!res.ok) throw new Error(`[Spotify] 加载 playlistTracks.json 失败:${res.status} ${res.statusText}`);
const json = resolveSpotifyAssetsDeep((await res.json()) as PlaylistTracksMap);
playlistTracksCache = json;
return json;
})().catch(err => { playlistTracksInflight = null; throw err; });
return playlistTracksInflight;
}
export function getPlaylistTracksSync(): PlaylistTracksMap | null {
return playlistTracksCache;
}
export function clearCache() {
categoryCache = null;
categoryInflight = null;
playlistTracksCache = null;
playlistTracksInflight = null;
artistTracksCache = null;
artistTracksInflight = null;
searchResultsCache = null;
searchResultsInflight = null;
albumTracksCache = null;
albumTracksInflight = null;
}
// ─── 离线 iTunes 数据加载 ─────────────────────────────────────────────────────
let artistTracksCache: ArtistTracksMap | null = null;
let artistTracksInflight: Promise<ArtistTracksMap> | null = null;
export async function loadArtistTracks(): Promise<ArtistTracksMap> {
if (artistTracksCache) return artistTracksCache;
if (artistTracksInflight) return artistTracksInflight;
artistTracksInflight = (async () => {
const url = new URL('./artistTracks.json', import.meta.url).href;
const res = await fetch(url);
if (!res.ok) throw new Error(`[Spotify] 加载 artistTracks.json 失败:${res.status}`);
artistTracksCache = resolveSpotifyAssetsDeep(await res.json() as ArtistTracksMap);
return artistTracksCache;
})().catch(err => { artistTracksInflight = null; throw err; });
return artistTracksInflight;
}
let searchResultsCache: SearchResultsMap | null = null;
let searchResultsInflight: Promise<SearchResultsMap> | null = null;
export async function loadSearchResults(): Promise<SearchResultsMap> {
if (searchResultsCache) return searchResultsCache;
if (searchResultsInflight) return searchResultsInflight;
searchResultsInflight = (async () => {
const url = new URL('./searchResults.json', import.meta.url).href;
const res = await fetch(url);
if (!res.ok) throw new Error(`[Spotify] 加载 searchResults.json 失败:${res.status}`);
searchResultsCache = resolveSpotifyAssetsDeep(await res.json() as SearchResultsMap);
return searchResultsCache;
})().catch(err => { searchResultsInflight = null; throw err; });
return searchResultsInflight;
}
let albumTracksCache: AlbumTracksMap | null = null;
let albumTracksInflight: Promise<AlbumTracksMap> | null = null;
export async function loadAlbumTracks(): Promise<AlbumTracksMap> {
if (albumTracksCache) return albumTracksCache;
if (albumTracksInflight) return albumTracksInflight;
albumTracksInflight = (async () => {
const url = new URL('./albumTracks.json', import.meta.url).href;
const res = await fetch(url);
if (!res.ok) throw new Error(`[Spotify] 加载 albumTracks.json 失败:${res.status}`);
albumTracksCache = resolveSpotifyAssetsDeep(await res.json() as AlbumTracksMap);
return albumTracksCache;
})().catch(err => { albumTracksInflight = null; throw err; });
return albumTracksInflight;
}
export async function preload(): Promise<void> {
await Promise.all([loadCategories(), loadPlaylistTracks()]);
}