refactor: update cover image handling to use item IDs and simplify library item actions

This commit is contained in:
Dr-Blank 2024-09-23 03:55:32 -04:00
parent d25d23a0b7
commit 405d625cdc
No known key found for this signature in database
GPG key ID: 7452CC63F210A266
15 changed files with 305 additions and 362 deletions

View file

@ -4,6 +4,7 @@ import 'package:logging/logging.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:shelfsdk/audiobookshelf_api.dart';
import 'package:vaani/api/api_provider.dart';
import 'package:vaani/api/library_item_provider.dart';
import 'package:vaani/db/cache_manager.dart';
/// provides cover images for the audiobooks
@ -19,52 +20,53 @@ final _logger = Logger('cover_image_provider');
@Riverpod(keepAlive: true)
class CoverImage extends _$CoverImage {
@override
Stream<Uint8List> build(LibraryItem libraryItem) async* {
Stream<Uint8List> build(String itemId) async* {
final api = ref.watch(authenticatedApiProvider);
// ! artifical delay for testing
// await Future.delayed(const Duration(seconds: 2));
// try to get the image from the cache
final file = await imageCacheManager.getFileFromMemory(libraryItem.id) ??
await imageCacheManager.getFileFromCache(libraryItem.id);
final file = await imageCacheManager.getFileFromMemory(itemId) ??
await imageCacheManager.getFileFromCache(itemId);
if (file != null) {
// if the image is in the cache, yield it
_logger.fine(
'cover image found in cache for ${libraryItem.id} at ${file.file.path}',
'cover image found in cache for $itemId at ${file.file.path}',
);
yield await file.file.readAsBytes();
final libraryItem = await ref.watch(libraryItemProvider(itemId).future);
// return if no need to fetch from the server
if (libraryItem.updatedAt.isBefore(await file.file.lastModified())) {
_logger.fine(
'cover image is up to date for ${libraryItem.id}, no need to fetch from the server',
'cover image is up to date for $itemId, no need to fetch from the server',
);
return;
} else {
_logger.fine(
'cover image stale for ${libraryItem.id}, fetching from the server',
'cover image stale for $itemId, fetching from the server',
);
}
} else {
_logger.fine('cover image not found in cache for ${libraryItem.id}');
_logger.fine('cover image not found in cache for $itemId');
}
// check if the image is in the cache
final coverImage = await api.items.getCover(
libraryItemId: libraryItem.id,
libraryItemId: itemId,
parameters: const GetImageReqParams(width: 1200),
);
// save the image to the cache
if (coverImage != null) {
final newFile = await imageCacheManager.putFile(
libraryItem.id,
itemId,
coverImage,
key: libraryItem.id,
key: itemId,
fileExtension: 'jpg',
);
_logger.fine(
'cover image fetched for for ${libraryItem.id}, file time: ${await newFile.lastModified()}',
'cover image fetched for for $itemId, file time: ${await newFile.lastModified()}',
);
}

View file

@ -6,7 +6,7 @@ part of 'image_provider.dart';
// RiverpodGenerator
// **************************************************************************
String _$coverImageHash() => r'702afafa217dfcbb290837caf21cc1ef54defd55';
String _$coverImageHash() => r'89cc4783cbc76bb41beae34384d92fb277135c75';
/// Copied from Dart SDK
class _SystemHash {
@ -30,10 +30,10 @@ class _SystemHash {
}
abstract class _$CoverImage extends BuildlessStreamNotifier<Uint8List> {
late final LibraryItem libraryItem;
late final String itemId;
Stream<Uint8List> build(
LibraryItem libraryItem,
String itemId,
);
}
@ -48,10 +48,10 @@ class CoverImageFamily extends Family<AsyncValue<Uint8List>> {
/// See also [CoverImage].
CoverImageProvider call(
LibraryItem libraryItem,
String itemId,
) {
return CoverImageProvider(
libraryItem,
itemId,
);
}
@ -60,7 +60,7 @@ class CoverImageFamily extends Family<AsyncValue<Uint8List>> {
covariant CoverImageProvider provider,
) {
return call(
provider.libraryItem,
provider.itemId,
);
}
@ -84,9 +84,9 @@ class CoverImageProvider
extends StreamNotifierProviderImpl<CoverImage, Uint8List> {
/// See also [CoverImage].
CoverImageProvider(
LibraryItem libraryItem,
String itemId,
) : this._internal(
() => CoverImage()..libraryItem = libraryItem,
() => CoverImage()..itemId = itemId,
from: coverImageProvider,
name: r'coverImageProvider',
debugGetCreateSourceHash:
@ -96,7 +96,7 @@ class CoverImageProvider
dependencies: CoverImageFamily._dependencies,
allTransitiveDependencies:
CoverImageFamily._allTransitiveDependencies,
libraryItem: libraryItem,
itemId: itemId,
);
CoverImageProvider._internal(
@ -106,17 +106,17 @@ class CoverImageProvider
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.libraryItem,
required this.itemId,
}) : super.internal();
final LibraryItem libraryItem;
final String itemId;
@override
Stream<Uint8List> runNotifierBuild(
covariant CoverImage notifier,
) {
return notifier.build(
libraryItem,
itemId,
);
}
@ -125,13 +125,13 @@ class CoverImageProvider
return ProviderOverride(
origin: this,
override: CoverImageProvider._internal(
() => create()..libraryItem = libraryItem,
() => create()..itemId = itemId,
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
libraryItem: libraryItem,
itemId: itemId,
),
);
}
@ -143,21 +143,21 @@ class CoverImageProvider
@override
bool operator ==(Object other) {
return other is CoverImageProvider && other.libraryItem == libraryItem;
return other is CoverImageProvider && other.itemId == itemId;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, libraryItem.hashCode);
hash = _SystemHash.combine(hash, itemId.hashCode);
return _SystemHash.finish(hash);
}
}
mixin CoverImageRef on StreamNotifierProviderRef<Uint8List> {
/// The parameter `libraryItem` of this provider.
LibraryItem get libraryItem;
/// The parameter `itemId` of this provider.
String get itemId;
}
class _CoverImageProviderElement
@ -166,7 +166,7 @@ class _CoverImageProviderElement
_CoverImageProviderElement(super.provider);
@override
LibraryItem get libraryItem => (origin as CoverImageProvider).libraryItem;
String get itemId => (origin as CoverImageProvider).itemId;
}
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View file

@ -13,7 +13,7 @@ part 'library_item_provider.g.dart';
final _logger = Logger('LibraryItemProvider');
/// provides the library item for the given id
@riverpod
@Riverpod(keepAlive: true)
class LibraryItem extends _$LibraryItem {
@override
Stream<shelfsdk.LibraryItemExpanded> build(String id) async* {
@ -22,7 +22,7 @@ class LibraryItem extends _$LibraryItem {
_logger.fine('LibraryItemProvider fetching library item: $id');
// ! this is a mock delay
// await Future.delayed(const Duration(seconds: 10));
// await Future.delayed(const Duration(seconds: 150));
// look for the item in the cache
final key = CacheKey.libraryItem(id);

View file

@ -6,7 +6,7 @@ part of 'library_item_provider.dart';
// RiverpodGenerator
// **************************************************************************
String _$libraryItemHash() => r'fa3f8309349c5b1b777f1bc919616e51c3f5b520';
String _$libraryItemHash() => r'a3cfa7f912e9498a70b5782899018b6964d6445c';
/// Copied from Dart SDK
class _SystemHash {
@ -30,7 +30,7 @@ class _SystemHash {
}
abstract class _$LibraryItem
extends BuildlessAutoDisposeStreamNotifier<shelfsdk.LibraryItemExpanded> {
extends BuildlessStreamNotifier<shelfsdk.LibraryItemExpanded> {
late final String id;
Stream<shelfsdk.LibraryItemExpanded> build(
@ -92,8 +92,8 @@ class LibraryItemFamily
/// provides the library item for the given id
///
/// Copied from [LibraryItem].
class LibraryItemProvider extends AutoDisposeStreamNotifierProviderImpl<
LibraryItem, shelfsdk.LibraryItemExpanded> {
class LibraryItemProvider extends StreamNotifierProviderImpl<LibraryItem,
shelfsdk.LibraryItemExpanded> {
/// provides the library item for the given id
///
/// Copied from [LibraryItem].
@ -151,8 +151,8 @@ class LibraryItemProvider extends AutoDisposeStreamNotifierProviderImpl<
}
@override
AutoDisposeStreamNotifierProviderElement<LibraryItem,
shelfsdk.LibraryItemExpanded> createElement() {
StreamNotifierProviderElement<LibraryItem, shelfsdk.LibraryItemExpanded>
createElement() {
return _LibraryItemProviderElement(this);
}
@ -171,14 +171,13 @@ class LibraryItemProvider extends AutoDisposeStreamNotifierProviderImpl<
}
mixin LibraryItemRef
on AutoDisposeStreamNotifierProviderRef<shelfsdk.LibraryItemExpanded> {
on StreamNotifierProviderRef<shelfsdk.LibraryItemExpanded> {
/// The parameter `id` of this provider.
String get id;
}
class _LibraryItemProviderElement
extends AutoDisposeStreamNotifierProviderElement<LibraryItem,
shelfsdk.LibraryItemExpanded> with LibraryItemRef {
class _LibraryItemProviderElement extends StreamNotifierProviderElement<
LibraryItem, shelfsdk.LibraryItemExpanded> with LibraryItemRef {
_LibraryItemProviderElement(super.provider);
@override