fix: Improve null handling when parsing image urls (#228)

Co-authored-by: PartyDonut <PartyDonut@users.noreply.github.com>
This commit is contained in:
PartyDonut 2025-02-16 11:58:53 +01:00 committed by GitHub
parent 06c4af81e7
commit a34f8fe2f4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 100 additions and 188 deletions

View file

@ -12,7 +12,6 @@ import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart' as enums;
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto;
import 'package:fladder/providers/image_provider.dart';
import 'package:fladder/util/custom_cache_manager.dart';
import 'package:fladder/util/jelly_id.dart';
class ImagesData {
final ImageData? primary;
@ -35,74 +34,80 @@ class ImagesData {
ImageData? get randomBackDrop => (backDrop?..shuffle())?.firstOrNull ?? primary;
factory ImagesData.fromBaseItem(
static ImagesData? fromBaseItem(
dto.BaseItemDto item,
Ref ref, {
Size backDrop = const Size(2000, 2000),
Size logo = const Size(1000, 1000),
Size primary = const Size(600, 600),
bool getOriginalSize = false,
int quality = 90,
int quality = 95,
}) {
final itemid = item.id;
if (itemid == null) return null;
final imageProvider = ref.read(imageUtilityProvider);
final newImgesData = ImagesData(
primary: item.imageTags?['Primary'] != null
? ImageData(
path: getOriginalSize
? ref.read(imageUtilityProvider).getItemsOrigImageUrl(
item.id!,
type: enums.ImageType.primary,
)
: ref.read(imageUtilityProvider).getItemsImageUrl(
(item.id!),
type: enums.ImageType.primary,
maxHeight: primary.height.toInt(),
maxWidth: primary.width.toInt(),
quality: quality,
),
? imageProvider.getItemsOrigImageUrl(
itemid,
type: enums.ImageType.primary,
)
: imageProvider.getItemsImageUrl(
itemid,
type: enums.ImageType.primary,
maxHeight: primary.height.toInt(),
maxWidth: primary.width.toInt(),
quality: quality,
),
key: item.imageTags?['Primary'],
hash: item.imageBlurHashes?.primary?[item.imageTags?['Primary']] as String? ?? "",
hash: item.imageBlurHashes?.primary?[item.imageTags?['Primary']] ?? "",
)
: null,
logo: item.imageTags?['Logo'] != null
? ImageData(
path: getOriginalSize
? ref.read(imageUtilityProvider).getItemsOrigImageUrl(
item.id!,
type: enums.ImageType.logo,
)
: ref.read(imageUtilityProvider).getItemsImageUrl(
(item.id!),
type: enums.ImageType.logo,
maxHeight: logo.height.toInt(),
maxWidth: logo.width.toInt(),
quality: quality,
),
key: item.imageTags?['Logo'],
hash: item.imageBlurHashes?.logo?[item.imageTags?['Logo']] as String? ?? "")
: null,
backDrop: (item.backdropImageTags ?? []).mapIndexed(
(index, backdrop) {
final image = ImageData(
path: getOriginalSize
? ref.read(imageUtilityProvider).getBackdropOrigImage(
item.id!,
index,
backdrop,
? imageProvider.getItemsOrigImageUrl(
itemid,
type: enums.ImageType.logo,
)
: ref.read(imageUtilityProvider).getBackdropImage(
(item.id!),
index,
backdrop,
maxHeight: backDrop.height.toInt(),
maxWidth: backDrop.width.toInt(),
: imageProvider.getItemsImageUrl(
itemid,
type: enums.ImageType.logo,
maxHeight: logo.height.toInt(),
maxWidth: logo.width.toInt(),
quality: quality,
),
key: backdrop,
hash: item.imageBlurHashes?.backdrop?[backdrop] ?? jellyId,
);
return image;
},
).toList(),
key: item.imageTags?['Logo'],
hash: item.imageBlurHashes?.logo?[item.imageTags?['Logo']] ?? "")
: null,
backDrop: (item.backdropImageTags ?? [])
.mapIndexed(
(index, backdrop) {
final image = ImageData(
path: getOriginalSize
? imageProvider.getBackdropOrigImage(
itemid,
index,
backdrop,
)
: imageProvider.getBackdropImage(
itemid,
index,
backdrop,
maxHeight: backDrop.height.toInt(),
maxWidth: backDrop.width.toInt(),
quality: quality,
),
key: backdrop,
hash: item.imageBlurHashes?.backdrop?[backdrop] ?? "",
);
return image;
},
)
.nonNulls
.toList(),
);
return newImgesData;
}
@ -113,51 +118,59 @@ class ImagesData {
Size backDrop = const Size(2000, 2000),
Size logo = const Size(1000, 1000),
Size primary = const Size(600, 600),
int quality = 90,
int quality = 95,
}) {
if (item.seriesId == null && item.parentId == null) return null;
final imageProvider = ref.read(imageUtilityProvider);
final newImgesData = ImagesData(
primary: (item.seriesPrimaryImageTag != null)
? ImageData(
path: ref.read(imageUtilityProvider).getItemsImageUrl(
(item.seriesId!),
type: enums.ImageType.primary,
maxHeight: primary.height.toInt(),
maxWidth: primary.width.toInt(),
quality: quality,
),
path: imageProvider.getItemsImageUrl(
item.seriesId,
type: enums.ImageType.primary,
maxHeight: primary.height.toInt(),
maxWidth: primary.width.toInt(),
quality: quality,
),
key: item.seriesPrimaryImageTag ?? "",
hash: item.imageBlurHashes?.primary?[item.seriesPrimaryImageTag] as String? ?? "")
hash: item.imageBlurHashes?.primary?[item.seriesPrimaryImageTag] ?? "")
: null,
logo: (item.parentLogoImageTag != null)
? ImageData(
path: ref.read(imageUtilityProvider).getItemsImageUrl(
(item.seriesId!),
type: enums.ImageType.logo,
maxHeight: logo.height.toInt(),
maxWidth: logo.width.toInt(),
quality: quality,
),
path: imageProvider.getItemsImageUrl(
item.seriesId,
type: enums.ImageType.logo,
maxHeight: logo.height.toInt(),
maxWidth: logo.width.toInt(),
quality: quality,
),
key: item.parentLogoImageTag ?? "",
hash: item.imageBlurHashes?.logo?[item.parentLogoImageTag] as String? ?? "")
hash: item.imageBlurHashes?.logo?[item.parentLogoImageTag] ?? "")
: null,
backDrop: (item.backdropImageTags ?? []).mapIndexed(
(index, backdrop) {
final image = ImageData(
path: ref.read(imageUtilityProvider).getBackdropImage(
((item.seriesId ?? item.parentId)!),
backDrop: (item.backdropImageTags ?? [])
.mapIndexed(
(index, backdrop) {
final itemId = item.seriesId ?? item.parentId;
if (itemId == null) return null;
final image = ImageData(
path: imageProvider.getBackdropImage(
itemId,
index,
backdrop,
maxHeight: backDrop.height.toInt(),
maxWidth: backDrop.width.toInt(),
quality: quality,
),
key: backdrop,
hash: item.imageBlurHashes?.backdrop?[backdrop],
);
return image;
},
).toList(),
key: backdrop,
hash: item.imageBlurHashes?.backdrop?[backdrop] ?? "",
);
return image;
},
)
.nonNulls
.toList(),
);
return newImgesData;
}
@ -168,7 +181,7 @@ class ImagesData {
Size backDrop = const Size(2000, 2000),
Size logo = const Size(1000, 1000),
Size primary = const Size(2000, 2000),
int quality = 90,
int quality = 95,
}) {
return ImagesData(
primary: (item.primaryImageTag != null && item.imageBlurHashes != null)
@ -181,7 +194,7 @@ class ImagesData {
quality: quality,
),
key: item.primaryImageTag ?? "",
hash: item.imageBlurHashes?.primary?[item.primaryImageTag] as String? ?? jellyId)
hash: item.imageBlurHashes?.primary?[item.primaryImageTag] ?? '')
: null,
logo: null,
backDrop: null,

View file

@ -187,7 +187,7 @@ class Person {
return Person(
id: item.id ?? "",
name: item.name ?? "",
image: ImagesData.fromBaseItem(item, ref).primary,
image: ImagesData.fromBaseItem(item, ref)?.primary,
);
}
@ -274,107 +274,3 @@ class Studio {
@override
int get hashCode => id.hashCode ^ name.hashCode;
}
// class UserData {
// final bool isFavourite;
// final int playCount;
// final int? unPlayedItemCount;
// final int playbackPositionTicks;
// final double progress;
// final bool played;
// UserData({
// this.isFavourite = false,
// this.playCount = 0,
// this.unPlayedItemCount,
// this.playbackPositionTicks = 0,
// this.progress = 0,
// this.played = false,
// });
// factory UserData.fromDto(dto.UserItemDataDto? dto) {
// if (dto == null) {
// return UserData();
// }
// return UserData(
// isFavourite: dto.isFavorite ?? false,
// playCount: dto.playCount ?? 0,
// playbackPositionTicks: dto.playbackPositionTicks ?? 0,
// played: dto.played ?? false,
// unPlayedItemCount: dto.unplayedItemCount ?? 0,
// progress: dto.playedPercentage ?? 0,
// );
// }
// Duration get playBackPosition => Duration(milliseconds: playbackPositionTicks ~/ 10000);
// @override
// String toString() {
// return 'UserData(isFavourite: $isFavourite, playCount: $playCount, unPlayedItemCount: $unPlayedItemCount, playbackPositionTicks: $playbackPositionTicks, progress: $progress, played: $played)';
// }
// UserData copyWith({
// bool? isFavourite,
// int? playCount,
// int? unPlayedItemCount,
// int? playbackPositionTicks,
// double? progress,
// bool? played,
// }) {
// return UserData(
// isFavourite: isFavourite ?? this.isFavourite,
// playCount: playCount ?? this.playCount,
// unPlayedItemCount: unPlayedItemCount ?? this.unPlayedItemCount,
// playbackPositionTicks: playbackPositionTicks ?? this.playbackPositionTicks,
// progress: progress ?? this.progress,
// played: played ?? this.played,
// );
// }
// Map<String, dynamic> toMap() {
// return <String, dynamic>{
// 'isFavourite': isFavourite,
// 'playCount': playCount,
// 'unPlayedItemCount': unPlayedItemCount,
// 'playbackPositionTicks': playbackPositionTicks,
// 'progress': progress,
// 'played': played,
// };
// }
// factory UserData.fromMap(Map<String, dynamic> map) {
// return UserData(
// isFavourite: (map['isFavourite'] ?? false) as bool,
// playCount: (map['playCount'] ?? 0) as int,
// unPlayedItemCount: (map['unPlayedItemCount'] ?? 0) as int,
// playbackPositionTicks: (map['playbackPositionTicks'] ?? 0) as int,
// progress: (map['progress'] ?? 0.0) as double,
// played: (map['played'] ?? false) as bool,
// );
// }
// String toJson() => json.encode(toMap());
// factory UserData.fromJson(String source) => UserData.fromMap(json.decode(source) as Map<String, dynamic>);
// @override
// bool operator ==(covariant UserData other) {
// if (identical(this, other)) return true;
// return other.isFavourite == isFavourite &&
// other.playCount == playCount &&
// other.unPlayedItemCount == unPlayedItemCount &&
// other.playbackPositionTicks == playbackPositionTicks &&
// other.progress == progress &&
// other.played == played;
// }
// @override
// int get hashCode {
// return isFavourite.hashCode ^
// playCount.hashCode ^
// unPlayedItemCount.hashCode ^
// playbackPositionTicks.hashCode ^
// progress.hashCode ^
// played.hashCode;
// }
// }

View file

@ -1,8 +1,8 @@
import 'package:fladder/providers/auth_provider.dart';
import 'package:fladder/providers/user_provider.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart';
import 'package:fladder/providers/auth_provider.dart';
import 'package:fladder/providers/user_provider.dart';
const _defaultHeight = 576;
const _defaultWidth = 384;
@ -26,12 +26,14 @@ class ImageNotifier {
return Uri.decodeFull("$currentServerUrl/Users/$id/Images/${ImageType.primary.value}");
}
String getItemsImageUrl(String itemId,
String getItemsImageUrl(String? itemId,
{ImageType type = ImageType.primary,
int maxHeight = _defaultHeight,
int maxWidth = _defaultWidth,
int quality = _defaultQuality}) {
try {
if (itemId == null) return "";
return Uri.decodeFull(
"$currentServerUrl/Items/$itemId/Images/${type.value}?fillHeight=$maxHeight&fillWidth=$maxWidth&quality=$quality");
} catch (e) {
@ -39,8 +41,9 @@ class ImageNotifier {
}
}
String getItemsOrigImageUrl(String itemId, {ImageType type = ImageType.primary}) {
String getItemsOrigImageUrl(String? itemId, {ImageType type = ImageType.primary}) {
try {
if (itemId == null) return "";
return Uri.decodeFull("$currentServerUrl/Items/$itemId/Images/${type.value}");
} catch (e) {
return "";