Files
mcma-webui/src/api/endpoints/lyrics.ts
T
Цвылев Александр Вадимович 9d88d70be0 feat(player): Now Playing overlay + synced lyrics panel (A1/A11, §6.7)
Full-screen overlay expanded from the persistent player: big artwork or a
Lyrics tab. Synced (LRC) lyrics highlight the active line by playback position,
auto-scroll, and seek on tap; plain text is the fallback; missing lyrics offers
a re-fetch. Adds lyrics endpoint + LRC parser + isNowPlayingOpen player state.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 21:04:39 +03:00

50 lines
1.5 KiB
TypeScript

import { api } from '../index';
import type { Lyrics } from '../types';
// `GET /tracks/{id}/lyrics` — cached lyrics for the Now Playing panel (§6.7).
// A miss is a normal 200 with `status: 'not_found'`, not an error.
interface RawLyrics {
track_id: string;
status: string;
source: string | null;
synced: string | null;
plain: string | null;
synced_available: boolean;
}
const toLyrics = (r: RawLyrics): Lyrics => ({
trackId: r.track_id,
status: r.status as Lyrics['status'],
source: r.source ?? undefined,
synced: r.synced ?? undefined,
plain: r.plain ?? undefined,
syncedAvailable: r.synced_available,
});
export const lyricsApi = api.injectEndpoints({
endpoints: (build) => ({
getLyrics: build.query<Lyrics, string>({
query: (trackId) => `/tracks/${trackId}/lyrics`,
transformResponse: (raw: RawLyrics) => toLyrics(raw),
}),
refetchLyrics: build.mutation<Lyrics, string>({
query: (trackId) => ({
url: `/tracks/${trackId}/lyrics/refetch`,
method: 'POST',
}),
transformResponse: (raw: RawLyrics) => toLyrics(raw),
// Push the fresh result straight into the getLyrics cache for this track.
async onQueryStarted(trackId, { dispatch, queryFulfilled }) {
const { data } = await queryFulfilled;
dispatch(
lyricsApi.util.upsertQueryData('getLyrics', trackId, data),
);
},
}),
}),
overrideExisting: false,
});
export const { useGetLyricsQuery, useRefetchLyricsMutation } = lyricsApi;