Pato05
f126ffef46
use get_url api by default, and fall back to old generation if get_url failed start to write a better cachemanager to implement in all systems write in more appropriate directories on windows and linux improve check for Connectivity by adding a fallback (needed for example on linux systems without NetworkManager) allow to dynamically change track quality without rebuilding the object
206 lines
5.4 KiB
Dart
206 lines
5.4 KiB
Dart
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 = [];
|
|
|
|
//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;
|
|
|
|
@JsonKey(includeToJson: false, includeFromJson: false)
|
|
bool wakelock = false;
|
|
|
|
Cache();
|
|
|
|
//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);
|
|
}
|
|
|
|
//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) {
|
|
searchHistory
|
|
.add(SearchHistoryItem(item, SearchHistoryItemType.playlist));
|
|
}
|
|
|
|
await save();
|
|
}
|
|
|
|
//Save, load
|
|
|
|
static Future wipe() async {
|
|
await (await _box).clear();
|
|
}
|
|
|
|
// TODO: improve
|
|
static Future<Cache> load([int tryN = 0]) async {
|
|
final box = await _box;
|
|
|
|
if (tryN > 2) {
|
|
// recursion error, something's wrong
|
|
throw Exception("can't load cache");
|
|
}
|
|
|
|
//Doesn't exist, create new
|
|
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);
|
|
}
|
|
}
|
|
|
|
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
|
|
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,
|
|
@HiveField(1)
|
|
album,
|
|
@HiveField(2)
|
|
artist,
|
|
@HiveField(3)
|
|
playlist
|
|
}
|