Files
mcma-webui/src/api/endpoints/streaming.ts
T
Цвылев Александр Вадимович e45ef785cf 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>
2026-07-28 21:22:59 +03:00

58 lines
1.8 KiB
TypeScript

import { getApiBaseUrl } from '../../config/runtime-config';
/**
* Audio stream URL for the `<audio>` element. The access token rides as a query
* 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,
quality?: string,
): string {
const base = getApiBaseUrl();
const q =
quality && quality !== 'original'
? `&quality=${encodeURIComponent(quality)}`
: '';
return `${base}/stream/${trackId}?token=${encodeURIComponent(token)}${q}`;
}
export function getCoverUrl(artUrl: string | undefined): string | undefined {
if (!artUrl) return undefined;
if (artUrl.startsWith('http://') || artUrl.startsWith('https://'))
return artUrl;
const base = getApiBaseUrl();
return `${base}${artUrl}`;
}
/**
* Cover image URL for a track, served by `GET /tracks/{id}/cover`. Like the
* audio stream, an `<img>` can't send an `Authorization` header, so the access
* token rides as `?token=`. Returns undefined when the track has no cover.
*/
export function getTrackCoverUrl(
trackId: string,
token: string,
hasCover: boolean,
): string | undefined {
if (!hasCover) return undefined;
const base = getApiBaseUrl();
return `${base}/tracks/${trackId}/cover?token=${encodeURIComponent(token)}`;
}
/**
* Cover image URL for an album, served by `GET /albums/{id}/cover`. Same
* `?token=` rationale as the track cover. Returns undefined when the album has
* no cover (so callers fall back to generated tile art).
*/
export function getAlbumCoverUrl(
albumId: string,
token: string,
hasCover: boolean,
): string | undefined {
if (!hasCover) return undefined;
const base = getApiBaseUrl();
return `${base}/albums/${albumId}/cover?token=${encodeURIComponent(token)}`;
}