major bug fixes

This commit is contained in:
Forrest 2026-08-04 19:29:58 -04:00
parent 9728906556
commit d6144c4483
39 changed files with 483 additions and 53 deletions

View file

@ -48,6 +48,17 @@ class SubsonicClient {
final String _password;
final Dio _dio;
/// Auth params reused for asset URLs (cover art) so the URL is *stable*
/// across rebuilds. The per-request random salt in [_authParams] otherwise
/// makes every build produce a fresh cover-art URL, which defeats Flutter's
/// URL-keyed image cache and refetches the art on each rebuild — seen as a
/// flickering album cover, especially while mirroring a fast remote-state
/// stream (bug #4). Reusing one salt is safe under Subsonic's token scheme:
/// salt+token only prove password knowledge; the server treats neither as a
/// nonce. Computed once per client, so a credential change (new client)
/// still rotates it.
late final Map<String, String> _assetAuth = _authParams();
static const String apiVersion = '1.16.1';
static const String clientName = 'timbre';
static const String _saltAlphabet =
@ -299,8 +310,16 @@ class SubsonicClient {
});
/// Signed cover-art URL. [size] is clamped to Subsonic's 32–2048 range.
Uri coverArtUri(String id, {int? size}) => _uri('getCoverArt', {
'id': id,
if (size != null) 'size': '${size.clamp(32, 2048)}',
});
///
/// Uses the stable [_assetAuth] params (not the per-request salt) so the same
/// (id, size) always yields the same URL — required for the image cache to
/// hit and the art to hold steady across rebuilds (bug #4).
Uri coverArtUri(String id, {int? size}) =>
Uri.parse('$baseUrl/rest/getCoverArt').replace(
queryParameters: {
..._assetAuth,
'id': id,
if (size != null) 'size': '${size.clamp(32, 2048)}',
},
);
}