mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-21 22:15:40 +00:00
exp(orbit): host merge, guest queue view, settings popover, i18n
Guest suggestions now auto-merge into the host's play queue at random positions inside the upcoming range, so they actually surface alongside host-picked tracks instead of piling up at the end. Per-item dedupe via addedBy:addedAt:trackId keys survives reshuffles. Guests get a read-only mirror of the session in place of their queue panel — live-card for the host's current track, suggestion list with submitter attribution, and a footer reminding them the host owns playback. Track metadata is resolved lazily and cached locally. New host-only settings popover (gear in the bar) with auto-approve and auto-shuffle toggles plus a "Shuffle now" action. Settings live in the OrbitState blob and push immediately to Navidrome; missing fields on older blobs default to "both on". 15-min shuffle now touches the real playerStore queue via a new shuffleUpcomingQueue action — previous behaviour only reshuffled the guest-facing suggestion history. A manual shuffle is available from the settings popover so the interval can be verified without waiting. Start-modal reworked into a single step: share-link is visible and copy-able from the start, auto-copied on Start if the host hasn't already hit Copy. Link carries a live name-derived slug (parser strips it, SID is authoritative). LAN/remote-server hint above the facts. Random session-name suggester pulls from three pattern pools for ~10k unique combinations. All user-visible Orbit strings moved to a dedicated orbit i18n namespace (en + de); other locales fall back to en via i18next. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import React, { useState, useRef, useMemo, useEffect } from 'react';
|
||||
import { Track, usePlayerStore, songToTrack } from '../store/playerStore';
|
||||
import { Play, Music, Star, X, Trash2, Save, FolderOpen, Shuffle, Infinity, Waves, MicVocal, ListMusic, Check, ListPlus, ArrowUpToLine, Radio, HardDrive, ChevronDown, Info, Share2, Orbit as OrbitIcon } from 'lucide-react';
|
||||
import OrbitStartModal from './OrbitStartModal';
|
||||
import { useOrbitStore } from '../store/orbitStore';
|
||||
import OrbitGuestQueue from './OrbitGuestQueue';
|
||||
import { Play, Music, Star, X, Trash2, Save, FolderOpen, Shuffle, Infinity, Waves, MicVocal, ListMusic, Check, ListPlus, ArrowUpToLine, Radio, HardDrive, ChevronDown, Info, Share2 } from 'lucide-react';
|
||||
import { buildCoverArtUrl, coverArtCacheKey, getAlbum, getPlaylists, getPlaylist, updatePlaylist, deletePlaylist, SubsonicPlaylist } from '../api/subsonic';
|
||||
import { usePlaylistStore } from '../store/playlistStore';
|
||||
import { useCachedUrl } from './CachedImage';
|
||||
@@ -201,9 +201,6 @@ function QueueHeader({ queue, queueIndex, showRemainingTime, setShowRemainingTim
|
||||
|
||||
const dur = showRemainingTime ? `-${fmt(Math.floor(remainingSecs))}` : fmt(Math.floor(totalSecs));
|
||||
|
||||
const orbitRole = useOrbitStore(s => s.role);
|
||||
const [startOpen, setStartOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="queue-header">
|
||||
<div style={{ display: "flex", flexDirection: "column", minWidth: 0, flex: 1 }}>
|
||||
@@ -230,23 +227,23 @@ function QueueHeader({ queue, queueIndex, showRemainingTime, setShowRemainingTim
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{orbitRole === null && (
|
||||
<button
|
||||
type="button"
|
||||
className="queue-header-orbit-btn"
|
||||
onClick={() => setStartOpen(true)}
|
||||
data-tooltip="Start a session"
|
||||
aria-label="Start a session"
|
||||
>
|
||||
<OrbitIcon size={14} />
|
||||
</button>
|
||||
)}
|
||||
{startOpen && <OrbitStartModal onClose={() => setStartOpen(false)} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function QueuePanel() {
|
||||
const orbitRole = useOrbitStore(s => s.role);
|
||||
if (orbitRole === 'guest') {
|
||||
return (
|
||||
<aside className="queue-panel queue-panel--orbit-guest">
|
||||
<OrbitGuestQueue />
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
return <QueuePanelHostOrSolo />;
|
||||
}
|
||||
|
||||
function QueuePanelHostOrSolo() {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const queue = usePlayerStore(s => s.queue);
|
||||
|
||||
Reference in New Issue
Block a user