mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 07:15:47 +00:00
feat(home): broaden Because-you-like seed pool + tidy orphan card at 1080p (#493)
* feat(home): mix recently-played + starred into Because-you-like anchor pool Anchor pool was sourced only from getAlbumList(frequent), so the rotation cursor walked the same eight top-played artists no matter how varied the rest of the listening history was. Round-robin merge of mostPlayed, recentlyPlayed and starred (dedup by artistId) means each mount can land on a different listening *mode* — heavy rotation, current focus, or explicit favorites — instead of stepping through the same top-played sequence. Pool size 8 -> 12 to let the cursor visit all three modes before wrapping. Visibility guard widened so the rail still renders when the server has no frequent-play data yet but starred or recent items exist. Zero new API calls — all three lists are already in Home's initial fetch. * fix(home): drop orphan 3rd Because-card in 2-col range, keep all 3 stacked on mobile auto-fit grid wraps to 2 cols between 696-1051px container width, which left the third card alone on a second row at 1080p. Container query hides the 3rd card only inside that 2-col band; on wider screens the full 3-up row stays, on narrow viewports (single column) all three cards stack vertically as expected. * docs(changelog): Because-you-listened seed pool + 1080p layout polish (PR #493) * docs(changelog): fold PR #493 refinements into the existing Because-you-listened entry Drop the separate Changed section entry — the feature is in the same 1.46.0 release window as PR #489, so readers want a single description of the final behaviour, not "added X, then changed X" for the same release. PR reference becomes "PRs #489, #493".
This commit is contained in:
committed by
GitHub
parent
b01e76df9c
commit
d75670ec4b
@@ -16,7 +16,7 @@ import { useAuthStore } from '../store/authStore';
|
||||
import { playAlbum } from '../utils/playAlbum';
|
||||
|
||||
const ANCHOR_KEY_PREFIX = 'psysonic_because_anchor:';
|
||||
const TOP_ARTIST_POOL = 8;
|
||||
const TOP_ARTIST_POOL = 12;
|
||||
const SIMILAR_FETCH = 12;
|
||||
const SIMILAR_PICK = 6;
|
||||
const SHOW_COUNT = 3;
|
||||
@@ -38,17 +38,27 @@ interface Anchor {
|
||||
|
||||
interface Props {
|
||||
mostPlayed: SubsonicAlbum[];
|
||||
recentlyPlayed?: SubsonicAlbum[];
|
||||
starred?: SubsonicAlbum[];
|
||||
disableArtwork?: boolean;
|
||||
}
|
||||
|
||||
function buildAnchorPool(albums: SubsonicAlbum[], limit: number): Anchor[] {
|
||||
/** Round-robin merge of multiple album sources, dedup by artistId.
|
||||
* Cycling sources (most-played, recently-played, starred) means the per-mount
|
||||
* rotation cursor visits a different listening *mode* each visit instead of
|
||||
* walking only down the top-played list. */
|
||||
function buildAnchorPool(sources: SubsonicAlbum[][], limit: number): Anchor[] {
|
||||
const seen = new Set<string>();
|
||||
const out: Anchor[] = [];
|
||||
for (const a of albums) {
|
||||
if (!a.artistId || seen.has(a.artistId)) continue;
|
||||
seen.add(a.artistId);
|
||||
out.push({ id: a.artistId, name: a.artist });
|
||||
if (out.length >= limit) break;
|
||||
const maxLen = sources.reduce((m, s) => Math.max(m, s.length), 0);
|
||||
for (let i = 0; i < maxLen && out.length < limit; i++) {
|
||||
for (const src of sources) {
|
||||
if (out.length >= limit) break;
|
||||
const a = src[i];
|
||||
if (!a || !a.artistId || seen.has(a.artistId)) continue;
|
||||
seen.add(a.artistId);
|
||||
out.push({ id: a.artistId, name: a.artist });
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -82,10 +92,18 @@ function rotateAnchor(pool: Anchor[], serverId: string | null): Anchor | null {
|
||||
return pool[(idx + 1) % pool.length];
|
||||
}
|
||||
|
||||
export default function BecauseYouLikeRail({ mostPlayed, disableArtwork = false }: Props) {
|
||||
export default function BecauseYouLikeRail({
|
||||
mostPlayed,
|
||||
recentlyPlayed,
|
||||
starred,
|
||||
disableArtwork = false,
|
||||
}: Props) {
|
||||
const { t } = useTranslation();
|
||||
const activeServerId = useAuthStore(s => s.activeServerId);
|
||||
const pool = useMemo(() => buildAnchorPool(mostPlayed, TOP_ARTIST_POOL), [mostPlayed]);
|
||||
const pool = useMemo(
|
||||
() => buildAnchorPool([mostPlayed, recentlyPlayed ?? [], starred ?? []], TOP_ARTIST_POOL),
|
||||
[mostPlayed, recentlyPlayed, starred],
|
||||
);
|
||||
const [anchor, setAnchor] = useState<Anchor | null>(null);
|
||||
const [recs, setRecs] = useState<SubsonicAlbum[]>([]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user