From 9d8d04cbeb105a411c1b393d85c54a708afc2ddf Mon Sep 17 00:00:00 2001 From: Matthieu Serrepuy Date: Tue, 22 Sep 2026 16:59:42 +0200 Subject: [PATCH] Fix album art on Music Assistant 2.10+ MA 2.10 replaced /imageproxy?path=&provider= with /imageproxy/ and removed the old form, so every artwork request returned HTTP 400. Use proxy_id when the server sends it and keep the legacy query form as a fallback for pre-2.10 servers. Sizes are rounded up to the set MA accepts (80/160/256/512/1024), since callers also ask for 128. The two places that re-point an MA-built image URL at the configured server now keep the original path instead of only its query string. --- lib/providers/music_assistant_provider.dart | 10 ++++++++-- lib/services/music_assistant_api.dart | 21 ++++++++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/lib/providers/music_assistant_provider.dart b/lib/providers/music_assistant_provider.dart index 282d3e36..2fd9b81f 100644 --- a/lib/providers/music_assistant_provider.dart +++ b/lib/providers/music_assistant_provider.dart @@ -2915,7 +2915,10 @@ class MusicAssistantProvider with ChangeNotifier { if (baseUrl.endsWith('/')) { baseUrl = baseUrl.substring(0, baseUrl.length - 1); } - finalImageUrl = '$baseUrl/imageproxy?$queryString'; + // Keep the original path: on MA 2.10+ it carries the proxy id + final imgPath = imgUri.path.isEmpty ? '/imageproxy' : imgUri.path; + finalImageUrl = + queryString.isEmpty ? '$baseUrl$imgPath' : '$baseUrl$imgPath?$queryString'; } catch (e) { // Use original URL } @@ -3155,7 +3158,10 @@ class MusicAssistantProvider with ChangeNotifier { if (baseUrl.endsWith('/')) { baseUrl = baseUrl.substring(0, baseUrl.length - 1); } - imageUrl = '$baseUrl/imageproxy?$queryString'; + // Keep the original path: on MA 2.10+ it carries the proxy id + final imgPath = imgUri.path.isEmpty ? '/imageproxy' : imgUri.path; + imageUrl = + queryString.isEmpty ? '$baseUrl$imgPath' : '$baseUrl$imgPath?$queryString'; } catch (e) { if (imageUrl != null && imageUrl.startsWith('http://')) { imageUrl = imageUrl.replaceFirst('http://', 'https://'); diff --git a/lib/services/music_assistant_api.dart b/lib/services/music_assistant_api.dart index 08c30a59..fde07bb7 100644 --- a/lib/services/music_assistant_api.dart +++ b/lib/services/music_assistant_api.dart @@ -3250,6 +3250,18 @@ class MusicAssistantAPI { return streamUrl; } + // MA only accepts a fixed set of imageproxy sizes, so round up to the + // nearest supported one rather than letting the request 400 (0 = original). + static const _imageProxySizes = [80, 160, 256, 512, 1024]; + + int _imageProxySize(int size) { + if (size <= 0) return 0; + for (final supported in _imageProxySizes) { + if (size <= supported) return supported; + } + return _imageProxySizes.last; + } + // Get image URL String? getImageUrl(MediaItem item, {int size = 256}) { // Images are in metadata.images as an array @@ -3315,8 +3327,15 @@ class MusicAssistantAPI { baseUrl = '${uri.scheme}://${uri.host}:${uri.port}'; } + // MA 2.10 replaced the path+provider query form with /imageproxy/ + // and dropped the old one, so prefer proxy_id whenever the server sends it. + final proxyId = selectedImage['proxy_id'] as String?; + if (proxyId != null && proxyId.isNotEmpty) { + return '$baseUrl/imageproxy/$proxyId?size=${_imageProxySize(size)}&fmt=jpeg'; + } + final provider = selectedImage['provider'] as String?; - // Use the imageproxy endpoint + // Pre-2.10 servers don't expose proxy_id; fall back to the legacy endpoint return '$baseUrl/imageproxy?provider=${Uri.encodeComponent(provider ?? "")}&size=$size&fmt=jpeg&path=${Uri.encodeComponent(imagePath)}'; }