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
+7 -2
View File
@@ -10,6 +10,7 @@ import {
import { nextTrack, prevTrack } from '../store/slices/queue';
import { play } from '../store/slices/player';
import { getStreamUrl, getCoverUrl } from '../api/endpoints/streaming';
import { useGetSettingsQuery } from '../api/endpoints/settings';
let audioElement: HTMLAudioElement | null = null;
@@ -26,6 +27,10 @@ export function useAudioPlayer() {
const player = useAppSelector((s) => s.player);
const queue = useAppSelector((s) => s.queue);
const accessToken = useAppSelector((s) => s.auth.accessToken);
// Default stream quality (server-synced §A10) → the backend transcodes to it
// on demand; a cache miss transparently falls back to the original.
const { data: settings } = useGetSettingsQuery();
const streamQuality = settings?.streamQuality;
const isSetup = useRef(false);
// `ended` is registered once below; read the latest loop flag through a ref
// so the listener doesn't need to be re-bound on every queue change.
@@ -63,7 +68,7 @@ export function useAudioPlayer() {
useEffect(() => {
if (!player.currentTrackId || !accessToken) return;
const audio = getAudio();
const url = getStreamUrl(player.currentTrackId, accessToken);
const url = getStreamUrl(player.currentTrackId, accessToken, streamQuality);
if (audio.src !== url) {
audio.src = url;
audio.load();
@@ -73,7 +78,7 @@ export function useAudioPlayer() {
} else {
audio.pause();
}
}, [player.currentTrackId, player.isPlaying, accessToken]);
}, [player.currentTrackId, player.isPlaying, accessToken, streamQuality]);
useEffect(() => {
const audio = getAudio();