spotify-clone/frontend/services/library.ts
Khoa Vo dd788db786 feat: Add new logo, PWA service worker, and background audio support
- New modern audio wave 'A' logo (192x192 and 512x512 icons)
- PWA service worker for offline support and installability
- Wake Lock API for background audio on FiiO/Android devices
- Visibility change handling to prevent audio pause on screen off
- Updated manifest.json with music categories and proper PWA config
- Media Session API lock screen controls (already present)
- Renamed app to 'Audiophile Web Player'
2026-01-14 10:27:29 +07:00

76 lines
2.4 KiB
TypeScript

import { Track } from "./db";
export interface StaticPlaylist {
id: string;
title: string;
description: string;
cover_url: string;
tracks: Track[];
type: 'Album' | 'Artist' | 'Playlist';
creator?: string;
}
// Helper to fetch from backend
const apiFetch = async (endpoint: string) => {
const res = await fetch(`/api${endpoint}`);
if (!res.ok) throw new Error(`API Error: ${res.statusText}`);
return res.json();
};
export const libraryService = {
async getLibrary(): Promise<StaticPlaylist> {
// Fetch "Liked Songs" or main library from backend
// Assuming backend has an endpoint or we treat "Trending" as default
return await apiFetch('/browse'); // Simplified fallback
},
async _generateMockContent(): Promise<void> {
// No-op in API mode
},
async getBrowseContent(): Promise<Record<string, StaticPlaylist[]>> {
return await apiFetch('/browse');
},
async getPlaylist(id: string): Promise<StaticPlaylist | null> {
try {
return await apiFetch(`/playlists/${id}`);
} catch (e) {
console.error("Failed to fetch playlist", id, e);
return null;
}
},
async getRecommendations(seedTrackId?: string): Promise<Track[]> {
// Use trending as recommendations for now
const data = await apiFetch('/trending');
return data.tracks || [];
},
async getRecommendedAlbums(seedArtist?: string): Promise<StaticPlaylist[]> {
const data = await apiFetch('/browse');
// Flatten all albums from categories
const albums: StaticPlaylist[] = [];
Object.values(data).forEach((list: any) => {
if (Array.isArray(list)) albums.push(...list);
});
return albums.slice(0, 8);
},
async search(query: string): Promise<Track[]> {
try {
return await apiFetch(`/search?q=${encodeURIComponent(query)}`);
} catch (e) {
return [];
}
},
// UTILITIES FOR DYNAMIC UPDATES
updateTrackCover(trackId: string, newUrl: string) {
console.log("Dynamic updates not implemented in Backend Mode");
},
updateAlbumCover(albumId: string, newUrl: string) {
console.log("Dynamic updates not implemented in Backend Mode");
}
};