Files
Psychotoxical-psysonic/src/utils/orbit.ts
T
cucadmuh e8e41752a7 feat(playback): global speed with three strategies (#852)
* feat(playback): global speed with three strategies

Add Settings → Audio and player-bar controls for global playback speed
(speed with auto pitch correction as default, varispeed, manual pitch shift).
Time-stretch runs on a background worker; Orbit sessions force 1.0× passthrough.

* fix(playback): align seekbar, seek, and progress on content timeline

Unify UI timebase across varispeed and preserve strategies: full-track
duration, speed-scaled progress for DSP paths, and content-timeline seeks
without varispeed scaling. Reset the sample counter after seek so clicks
land correctly; restart playback on strategy/enable changes instead of
fragile hot-switching.

* fix(ui): anchor playback speed popover like volume controls

Replace the centered EQ-style modal with a player-bar popover (outside
click, Escape, reposition on scroll). Show compact controls in the bar
and overflow menu; keep strategy hints and labels in Settings only.

* docs(release): CHANGELOG and credits for playback speed (PR #852)

* docs(changelog): add playback speed entry for PR #852

* fix(clippy): simplify raw_counter_samples branch for CI

Collapse duplicate if branches flagged by clippy::if-same-then-else.

* fix(ui): wheel on pitch slider adjusts pitch in speed popover

In compact player-bar controls, scroll over the pitch row changes pitch;
elsewhere in the panel changes speed. Stop propagation so overflow menu
wheel does not tweak volume.

* fix(playback): address PR #852 review and drop ineffective dynamic imports

Translate playback-rate strings for de/fr/es/zh/nb/nl/ro; restamp sample
counter on live preserve-path speed changes; use neutral rate atomics for
radio progress; static-import playerStore in playListenSession (move preview
volume sync to previewPlayerVolumeSync side-effect module).

* fix(i18n): translate playback-rate strategy labels in all locales

Replace leftover English Varispeed/Pitch strings in ru and other non-en
settings blocks so popover strategy buttons and hints read natively.

* fix(i18n): refine German varispeed label to "Tonhöhe folgt dem Tempo"

---------

Co-authored-by: Psychotoxical <171614930+Psychotoxical@users.noreply.github.com>
2026-05-22 18:59:28 +02:00

79 lines
2.3 KiB
TypeScript

/**
* Orbit — multi-user listen-together feature.
*
* This file is a re-export shim. Implementation lives under `utils/orbit/`:
*
* - `constants.ts` — cadence + TTL ms values.
* - `helpers.ts` — pure utilities (id gen, serialisation, key fns).
* - `stateMath.ts` — pure state transforms (shuffle, drift, sweep merge).
* - `remote.ts` — Navidrome playlist comment I/O.
* - `shareLink.ts` — invite magic-string encode/decode.
* - `host.ts` — host session lifecycle (start, end, settings, enqueue).
* - `moderation.ts` — host kicks / soft-removes / mutes.
* - `guest.ts` — guest join/leave + suggestion pipeline + host
* approve/decline reactions.
* - `sweep.ts` — host-side outbox sweep loop.
* - `cleanup.ts` — app-start orphan playlist sweep.
*
* Importers everywhere else in the codebase keep using `'../utils/orbit'`;
* this shim re-exports every public symbol unchanged.
*/
export {
ORBIT_HEARTBEAT_ALIVE_MS,
ORBIT_ORPHAN_TTL_MS,
ORBIT_REMOVED_TTL_MS,
ORBIT_SHUFFLE_INTERVAL_MS,
} from './orbit/constants';
export {
generateSessionId,
OrbitStateTooLarge,
serialiseOrbitState,
suggestionKey,
} from './orbit/helpers';
export { isOrbitPlaybackSyncActive } from './orbit/sessionActive';
export {
applyOutboxSnapshotsToState,
computeOrbitDriftMs,
effectiveShuffleIntervalMs,
maybeShuffleQueue,
patchOrbitState,
} from './orbit/stateMath';
export {
findSessionPlaylistId,
readOrbitState,
writeOrbitHeartbeat,
writeOrbitState,
} from './orbit/remote';
export {
buildOrbitShareLink,
parseOrbitShareLink,
type OrbitShareLink,
} from './orbit/shareLink';
export {
endOrbitSession,
hostEnqueueToOrbit,
startOrbitSession,
triggerOrbitShuffleNow,
updateOrbitSettings,
type StartOrbitArgs,
} from './orbit/host';
export {
kickOrbitParticipant,
removeOrbitParticipant,
setOrbitSuggestionBlocked,
} from './orbit/moderation';
export {
approveOrbitSuggestion,
declineOrbitSuggestion,
evaluateOrbitSuggestGate,
joinOrbitSession,
leaveOrbitSession,
OrbitJoinError,
OrbitSuggestBlockedError,
suggestOrbitTrack,
type OrbitSuggestGateReason,
} from './orbit/guest';
export { sweepGuestOutboxes } from './orbit/sweep';
export { cleanupOrphanedOrbitPlaylists } from './orbit/cleanup';