mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-22 14:35:41 +00:00
feat(orbit): per-guest suggestion mute + global pending-cap setting
Two anti-spam knobs the host can dial during a live session: 1. Per-guest suggestion mute — Mic / MicOff toggle next to the kick/ban buttons in the participants popover. Symmetric (re-enable later). State lives in OrbitState.suggestionBlocked: string[]; the guest reads it and disables its own Suggest controls so the user sees a clear "muted" state instead of silent failures. Host-side sweep also drops their outbox entries as a safety net. 2. Max pending approvals cap — number input in the session-settings popover, default 0 (= unlimited so existing sessions are unaffected). When set, the host sweep stops folding new outbox entries into the approval list once the cap is reached. The OrbitQueueHead surfaces "X / Y pending" so guests can see when they're getting close. State changes are additive on the wire — both fields are optional, with parseOrbitState defaulting them, so older clients keep working. evaluateOrbitSuggestGate() centralises the guest-side allow/block check shared between useOrbitSongRowBehavior and the ContextMenu Add-to-Session items, plus suggestOrbitTrack as a defensive last line. i18n: en + de + fr + nl + zh + nb + ru + es. Also fixes an earlier dedupe-key collision: the (user, trackId) cache keys were missing their separator (NULL byte slipped in during the previous patch), so two tracks could share a key and one of them silently overwrite the other. Restored the space separator. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -100,6 +100,12 @@ export interface OrbitState {
|
||||
ended?: boolean;
|
||||
/** Host-settable session rules; absent on older clients — treat missing as all-defaults. */
|
||||
settings?: OrbitSettings;
|
||||
/**
|
||||
* Usernames muted by the host: their outbox is still polled (so heartbeats
|
||||
* keep them visible as participants) but new track suggestions are dropped
|
||||
* before they reach the approval list. Symmetric — host can re-enable.
|
||||
*/
|
||||
suggestionBlocked?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,6 +127,13 @@ export interface OrbitSettings {
|
||||
* field fall back to 15 via `effectiveShuffleIntervalMs`.
|
||||
*/
|
||||
shuffleIntervalMin?: OrbitShuffleIntervalMin;
|
||||
/**
|
||||
* Cap on simultaneously-pending guest suggestions. 0 = unlimited.
|
||||
* When the cap is reached, the host's outbox sweep drops new suggestions
|
||||
* until existing ones are approved or declined; the guest UI surfaces
|
||||
* the count so users know to wait.
|
||||
*/
|
||||
maxPending?: number;
|
||||
}
|
||||
|
||||
export const ORBIT_DEFAULT_SETTINGS: OrbitSettings = {
|
||||
@@ -128,6 +141,8 @@ export const ORBIT_DEFAULT_SETTINGS: OrbitSettings = {
|
||||
autoApprove: false,
|
||||
autoShuffle: true,
|
||||
shuffleIntervalMin: 15,
|
||||
// 0 = unlimited; host opts in via the session-settings popover.
|
||||
maxPending: 0,
|
||||
};
|
||||
|
||||
/** What the guest's outbox-playlist comment holds (heartbeat only, for now). */
|
||||
@@ -176,6 +191,7 @@ export function makeInitialOrbitState(args: {
|
||||
participants: [],
|
||||
kicked: [],
|
||||
removed: [],
|
||||
suggestionBlocked: [],
|
||||
playQueue: [],
|
||||
playQueueTotal: 0,
|
||||
settings: { ...ORBIT_DEFAULT_SETTINGS },
|
||||
@@ -201,6 +217,8 @@ export function parseOrbitState(raw: unknown): OrbitState | null {
|
||||
// the attribution UI, not correctness.
|
||||
// `removed` is optional (older hosts won't write it); coerce to [] if absent or malformed.
|
||||
if (!Array.isArray(s.removed)) s.removed = [];
|
||||
// `suggestionBlocked` is optional too — older hosts predate the mute feature.
|
||||
if (!Array.isArray(s.suggestionBlocked)) s.suggestionBlocked = [];
|
||||
// `playQueue` / `playQueueTotal` are optional (older hosts won't write them).
|
||||
if (!Array.isArray(s.playQueue)) s.playQueue = [];
|
||||
if (typeof s.playQueueTotal !== 'number') s.playQueueTotal = (s.playQueue?.length ?? 0);
|
||||
|
||||
Reference in New Issue
Block a user