freezer/lib/api/cache.dart

206 lines
5.4 KiB
Dart
Raw Normal View History

2023-07-29 02:17:26 +00:00
import 'package:freezer/api/definitions.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:json_annotation/json_annotation.dart';
import 'dart:async';
part 'cache.g.dart';
late Cache cache;
//Cache for miscellaneous things
@HiveType(typeId: 22)
@JsonSerializable()
class Cache {
static Future<LazyBox<Cache>> get _box =>
Hive.openLazyBox<Cache>('metacache');
//ID's of tracks that are in library
@HiveField(0, defaultValue: [])
@JsonKey(defaultValue: [])
List<String> libraryTracks = [];
2023-07-29 02:17:26 +00:00
//Track ID of logged track, to prevent duplicates
@HiveField(1)
@JsonKey(includeToJson: false, includeFromJson: false)
String? loggedTrackId;
@HiveField(2)
@JsonKey(defaultValue: [])
List<Track> history = [];
//All sorting cached
@HiveField(3)
@JsonKey(defaultValue: [])
List<Sorting?> sorts = [];
//Sleep timer
@JsonKey(includeToJson: false, includeFromJson: false)
DateTime? sleepTimerTime;
@JsonKey(includeToJson: false, includeFromJson: false)
// ignore: cancel_subscriptions
StreamSubscription? sleepTimer;
//Search history
@HiveField(4)
@JsonKey(name: 'searchHistory2', defaultValue: [])
List<SearchHistoryItem> searchHistory = [];
//If download threads warning was shown
@HiveField(5)
@JsonKey(defaultValue: false)
bool threadsWarning = false;
//Last time update check
@HiveField(6)
DateTime? lastUpdateCheck;
@HiveField(7)
String? favoritesPlaylistId;
@HiveField(8, defaultValue: false)
bool canStreamHQ = false;
@HiveField(9, defaultValue: false)
bool canStreamLossless = false;
2023-07-29 02:17:26 +00:00
@JsonKey(includeToJson: false, includeFromJson: false)
bool wakelock = false;
Cache();
2023-07-29 02:17:26 +00:00
//Wrapper to test if track is favorite against cache
bool checkTrackFavorite(Track t) {
if (t.favorite != null && t.favorite!) return true;
if (libraryTracks.isEmpty) return false;
return libraryTracks.contains(t.id);
2023-07-29 02:17:26 +00:00
}
//Add to history
void addToSearchHistory(DeezerMediaItem item) async {
// Remove duplicate
int i = searchHistory.indexWhere((e) => e.data.id == item.id);
if (i != -1) {
searchHistory.removeAt(i);
}
if (item is Track) {
searchHistory.add(SearchHistoryItem(item, SearchHistoryItemType.track));
}
if (item is Album) {
searchHistory.add(SearchHistoryItem(item, SearchHistoryItemType.album));
}
if (item is Artist) {
searchHistory.add(SearchHistoryItem(item, SearchHistoryItemType.artist));
}
if (item is Playlist) {
2023-07-29 02:17:26 +00:00
searchHistory
.add(SearchHistoryItem(item, SearchHistoryItemType.playlist));
}
2023-07-29 02:17:26 +00:00
await save();
}
//Save, load
static Future wipe() async {
await (await _box).clear();
}
// TODO: improve
static Future<Cache> load([int tryN = 0]) async {
2023-07-29 02:17:26 +00:00
final box = await _box;
if (tryN > 2) {
// recursion error, something's wrong
throw Exception("can't load cache");
}
//Doesn't exist, create new
2023-07-29 02:17:26 +00:00
if (box.isEmpty) {
final c = Cache();
await c.save();
return c;
}
try {
return (await box.get(0))!;
} catch (e) {
// invalidate cache on error
await box.clear();
return await load(tryN + 1);
}
2023-07-29 02:17:26 +00:00
}
Future<void> save() async {
final box = await _box;
await box.clear();
await box.put(0, this);
}
//JSON
factory Cache.fromJson(Map<String, dynamic> json) => _$CacheFromJson(json);
Map<String, dynamic> toJson() => _$CacheToJson(this);
//Search History JSON
// static List<SearchHistoryItem> _searchHistoryFromJson(List<dynamic>? json) {
// return (json ?? [])
// .map<SearchHistoryItem>((i) => _searchHistoryItemFromJson(i))
// .toList();
// }
// static SearchHistoryItem _searchHistoryItemFromJson(
// Map<String, dynamic> json) {
// SearchHistoryItemType type = SearchHistoryItemType.values[json['type']];
// dynamic data;
// switch (type) {
// case SearchHistoryItemType.TRACK:
// data = Track.fromJson(json['data']);
// break;
// case SearchHistoryItemType.ALBUM:
// data = Album.fromJson(json['data']);
// break;
// case SearchHistoryItemType.ARTIST:
// data = Artist.fromJson(json['data']);
// break;
// case SearchHistoryItemType.PLAYLIST:
// data = Playlist.fromJson(json['data']);
// break;
// }
// return SearchHistoryItem(data, type);
// }
}
@HiveType(typeId: 20)
@JsonSerializable()
class SearchHistoryItem {
@HiveField(0)
@JsonKey(
toJson: _searchHistoryItemTypeToJson,
fromJson: _searchHistoryItemTypeFromJson)
SearchHistoryItemType type;
@HiveField(1)
// TODO: make this type-safe
2023-07-29 02:17:26 +00:00
dynamic data;
SearchHistoryItem(this.data, this.type);
Map<String, dynamic> toJson() => _$SearchHistoryItemToJson(this);
factory SearchHistoryItem.fromJson(Map<String, dynamic> json) =>
_$SearchHistoryItemFromJson(json);
static int _searchHistoryItemTypeToJson(SearchHistoryItemType type) =>
type.index;
static SearchHistoryItemType _searchHistoryItemTypeFromJson(int index) =>
SearchHistoryItemType.values[index];
}
@HiveType(typeId: 21)
enum SearchHistoryItemType {
@HiveField(0)
track,
2023-07-29 02:17:26 +00:00
@HiveField(1)
album,
2023-07-29 02:17:26 +00:00
@HiveField(2)
artist,
2023-07-29 02:17:26 +00:00
@HiveField(3)
playlist
2023-07-29 02:17:26 +00:00
}