feat(player): stream at the chosen quality + per-track optimize (§6.6)

The Playback quality setting now drives streaming: getStreamUrl appends
?quality= and useAudioPlayer feeds the server-synced streamQuality, so the
backend transcodes on demand (miss → original). Adds an optimizeTrack mutation
and an Optimize action in the metadata editor to warm a track's rendition.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Цвылев Александр Вадимович
2026-07-28 21:22:59 +03:00
parent 9d88d70be0
commit e45ef785cf
6 changed files with 98 additions and 4 deletions
+13
View File
@@ -201,6 +201,18 @@ export const libraryApi = api.injectEndpoints({
}),
invalidatesTags: (_r, _e, trackId) => [{ type: 'Track', id: trackId }],
}),
// Enqueue a transcode to a cached Opus + HLS rendition (§6.6). Fire-and-
// forget: the worker does the work, playback keeps using the original.
optimizeTrack: build.mutation<
{ status: string; job_id: string; quality: string },
{ trackId: string; quality?: string }
>({
query: ({ trackId, quality = 'high' }) => ({
url: `/tracks/${trackId}/optimize`,
method: 'POST',
params: { quality },
}),
}),
}),
overrideExisting: false,
});
@@ -219,4 +231,5 @@ export const {
useLazyGetMetadataMatchesQuery,
useApplyMetadataMutation,
useEnrichTrackMutation,
useOptimizeTrackMutation,
} = libraryApi;
+10 -2
View File
@@ -5,9 +5,17 @@ import { getApiBaseUrl } from '../../config/runtime-config';
* param because `<audio>` can't send an `Authorization` header; the backend
* accepts `?token=` on `GET /stream/{id}` for exactly this reason.
*/
export function getStreamUrl(trackId: string, token: string): string {
export function getStreamUrl(
trackId: string,
token: string,
quality?: string,
): string {
const base = getApiBaseUrl();
return `${base}/stream/${trackId}?token=${encodeURIComponent(token)}`;
const q =
quality && quality !== 'original'
? `&quality=${encodeURIComponent(quality)}`
: '';
return `${base}/stream/${trackId}?token=${encodeURIComponent(token)}${q}`;
}
export function getCoverUrl(artUrl: string | undefined): string | undefined {