fix(runtime): harden application service boundaries
This commit is contained in:
@@ -42,49 +42,44 @@ mixin _JellyfinPlaylistMethods on MediaServerCacheMixin {
|
||||
final offset = start ?? 0;
|
||||
final pageSize = size ?? _playlistsPageSize;
|
||||
final requestedType = playlistType.toLowerCase();
|
||||
final items = <MediaPlaylist>[];
|
||||
var rawOffset = 0;
|
||||
var filteredSeen = 0;
|
||||
int? rawTotal;
|
||||
var rawFinished = false;
|
||||
|
||||
while (items.length < pageSize && !rawFinished) {
|
||||
final response = await _http.get(
|
||||
'/Items',
|
||||
queryParameters: {
|
||||
'userId': connection.userId,
|
||||
'IncludeItemTypes': 'Playlist',
|
||||
'Recursive': 'true',
|
||||
'StartIndex': rawOffset.toString(),
|
||||
'Limit': pageSize.toString(),
|
||||
'Fields': 'Overview,DateCreated,DateLastSaved,ChildCount,Tags',
|
||||
...jellyfinImageQueryParameters,
|
||||
},
|
||||
abort: abort,
|
||||
);
|
||||
throwIfHttpError(response);
|
||||
final rawItems = _itemsArray(response.data);
|
||||
final rawTotalValue = response.data is Map<String, dynamic>
|
||||
? (response.data as Map<String, dynamic>)['TotalRecordCount']
|
||||
: null;
|
||||
if (rawTotalValue is int) rawTotal = rawTotalValue;
|
||||
|
||||
for (final item in rawItems.map(_playlistFromJson)) {
|
||||
if (!_matchesPlaylistFilters(item, requestedType: requestedType, smart: smart)) continue;
|
||||
if (filteredSeen >= offset && items.length < pageSize) {
|
||||
items.add(item);
|
||||
}
|
||||
filteredSeen++;
|
||||
}
|
||||
|
||||
rawOffset += rawItems.length;
|
||||
rawFinished = rawItems.isEmpty || rawItems.length < pageSize || (rawTotal != null && rawOffset >= rawTotal);
|
||||
final mediaType = switch (requestedType) {
|
||||
'' => null,
|
||||
'video' => 'Video',
|
||||
'audio' => 'Audio',
|
||||
'photo' => 'Photo',
|
||||
'book' => 'Book',
|
||||
'unknown' => 'Unknown',
|
||||
_ => '',
|
||||
};
|
||||
if (mediaType == '') {
|
||||
return LibraryPage<MediaPlaylist>(items: const [], totalCount: 0, offset: offset);
|
||||
}
|
||||
|
||||
final fallbackTotal = rawFinished
|
||||
? filteredSeen
|
||||
: fallbackPageTotal(offset: offset, itemCount: items.length, requestedSize: pageSize);
|
||||
return LibraryPage<MediaPlaylist>(items: items, totalCount: fallbackTotal, offset: offset);
|
||||
final response = await _http.get(
|
||||
'/Items',
|
||||
queryParameters: {
|
||||
'userId': connection.userId,
|
||||
'IncludeItemTypes': 'Playlist',
|
||||
'Recursive': 'true',
|
||||
'MediaTypes': ?mediaType,
|
||||
'StartIndex': offset.toString(),
|
||||
'Limit': pageSize.toString(),
|
||||
'Fields': 'Overview,DateCreated,DateLastSaved,ChildCount,Tags',
|
||||
...jellyfinImageQueryParameters,
|
||||
},
|
||||
abort: abort,
|
||||
);
|
||||
throwIfHttpError(response);
|
||||
final items = _itemsArray(response.data).map(_playlistFromJson).toList();
|
||||
final rawTotal = response.data is Map<String, dynamic>
|
||||
? (response.data as Map<String, dynamic>)['TotalRecordCount']
|
||||
: null;
|
||||
final fallbackTotal = fallbackPageTotal(offset: offset, itemCount: items.length, requestedSize: pageSize);
|
||||
return LibraryPage<MediaPlaylist>(
|
||||
items: items,
|
||||
totalCount: rawTotal is int ? rawTotal : fallbackTotal,
|
||||
offset: offset,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -201,7 +196,7 @@ mixin _JellyfinPlaylistMethods on MediaServerCacheMixin {
|
||||
return false;
|
||||
}
|
||||
if (item.playlistItemId == null) {
|
||||
appLogger.e('movePlaylistItem: item ${item.id} ("${item.title}") has no playlistItemId');
|
||||
appLogger.e('Jellyfin movePlaylistItem failed: missing playlist entry ID');
|
||||
return false;
|
||||
}
|
||||
final response = await _http.post(
|
||||
@@ -218,7 +213,7 @@ mixin _JellyfinPlaylistMethods on MediaServerCacheMixin {
|
||||
return false;
|
||||
}
|
||||
if (item.playlistItemId == null) {
|
||||
appLogger.e('removeFromPlaylist: item ${item.id} ("${item.title}") has no playlistItemId');
|
||||
appLogger.e('Jellyfin removeFromPlaylist failed: missing playlist entry ID');
|
||||
return false;
|
||||
}
|
||||
final response = await _http.delete(
|
||||
@@ -253,12 +248,6 @@ mixin _JellyfinPlaylistMethods on MediaServerCacheMixin {
|
||||
return 'video';
|
||||
}
|
||||
|
||||
bool _matchesPlaylistFilters(MediaPlaylist playlist, {required String requestedType, required bool? smart}) {
|
||||
if (requestedType.isNotEmpty && playlist.playlistType.toLowerCase() != requestedType) return false;
|
||||
if (smart != null && playlist.smart != smart) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
String? _imageTagPath(String id, Object? tags) {
|
||||
if (tags is! Map<String, dynamic>) return null;
|
||||
final tag = tags['Primary'];
|
||||
|
||||
Reference in New Issue
Block a user