mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 15:25:46 +00:00
a451509d94
* feat(discord): allow the server cover source in the store again DiscordCoverSource gains 'server' back. The rehydrate migration that forced any persisted 'server' preference to 'none' is dropped — that coercion only made sense while the source didn't exist. * feat(discord): resolve server covers via credential-free album-info URLs Add a resolver that fetches cover art for the Discord 'server' source through the standard Subsonic getAlbumInfo2 endpoint, never through an authenticated getCoverArt URL (that was the leak fixed in #1246). - sanitizeDiscordCoverUrl rejects anything unfit to publish: non-https, embedded userinfo, auth-shaped query params (u/t/s/apiKey/jwt/token/...), LAN/loopback hosts - resolveServerCoverForDiscord takes only an album id and a share-base string, never a server profile or credentials, and session-caches results (including negative ones) per album - rewrites a LAN-scoped album-info response to the profile's public share address, keeping path + query, so the app being connected over LAN doesn't hide an otherwise-public /share/img/<jwt> link - discordPresence.ts wires the 'server' branch in with a staleness guard so a slow resolve can't overwrite a newer track's presence * feat(discord): add the server option back to the cover-source picker Three-way segmented control again: none / server / apple. The cover description now discloses that server covers reveal the server's public address to anyone viewing the presence (no credentials). Restores discordCoverServer in all 14 locales — the Italian locale already carried an unused copy of the key from before it existed at removal time, now wired up instead of left dead. * fix(discord): reject non-publishable image URLs before they reach Discord is_publishable_image_url is a backstop applied to every artwork_url (cover_art_url param and the iTunes result alike) right before it can become a large_image asset: https only, no userinfo, no auth-shaped query params. This is the layer a future frontend refactor can't silently bypass — the failure mode that turned the original credential-free server-cover design (#462) into the leak fixed in #1246 was exactly that kind of regression, on the frontend only. * docs(changelog): note Discord server cover source restoration (#1299) * fix(discord): close the LAN-host gap in the Rust publish backstop is_publishable_image_url checked scheme/userinfo/credential params but not host locality, despite its doc comment claiming parity with the TS sanitizer's isLanUrl check — a self-review found the gap. Reuses psysonic-core::log_sanitize's existing is_lan_host (now pub) instead of a second hand-written LAN-detection copy. * fix(discord): don't silently resurrect a pre-#1246 'server' preference The rehydrate migration that forced any persisted 'server' cover source to 'none' was dropped in the initial revival commit, which meant a user skipping straight from a pre-#1246 build to this one would have gotten it silently reactivated without ever seeing the new opt-in disclosure. Restored as a one-time, sentinel-gated migration: it still catches that stale value exactly once, but never coerces a deliberate post-revival choice back. * fix(discord): harden the server-cover sync against races and cross-server tracks - Staleness guard on the async resolve now also rechecks discordRichPresence/discordCoverSource, not just the track id, so a slow resolve can't revive presence after it was disabled or the cover source was switched away from 'server' while in flight. - Skip server-cover resolution (fall back to the app icon) when the playing track isn't from the active server — getAlbumInfo2 always queries the active server, so a mixed-server queue could otherwise ask the wrong server for an album id. - The change-detection gate now also reacts to the active server profile's share-base changing (e.g. adding a public address), not only to track/play-state/cover-source/template changes. - Server profile/shareBase is now computed once per sync and reused, instead of a second useAuthStore.getState() call inside the branch. * fix(discord): preserve reverse-proxy paths and TTL the server-cover cache - rewriteOriginToShareBase only swapped protocol/hostname/port, so a server reachable behind a reverse-proxy subpath (shareBase carrying a path prefix) lost that prefix and produced a 404ing URL. The prefix is now preserved. - serverCoverCache entries (including negative ones) no longer live forever — a 1h TTL, matching the existing Rust iTunes-artwork cache, means a transient resolve failure doesn't hide an album's cover for the rest of the session.