From 0b2518cbfe3a14f7d41e9535a15ea9686ca0f823 Mon Sep 17 00:00:00 2001 From: Maxr1998 Date: Wed, 6 Dec 2023 01:35:37 +0100 Subject: [PATCH] :sparkles: Also write offline listens to Hive box --- lib/main.dart | 2 + lib/models/finamp_models.dart | 40 ++++++++++++++++++- lib/models/finamp_models.g.dart | 52 +++++++++++++++++++++++++ lib/services/offline_listen_helper.dart | 38 +++++++++--------- 4 files changed, 112 insertions(+), 20 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 2057db61c..04ff52c00 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -175,6 +175,7 @@ Future setupHive() async { Hive.registerAdapter(DownloadedImageAdapter()); Hive.registerAdapter(ThemeModeAdapter()); Hive.registerAdapter(LocaleAdapter()); + Hive.registerAdapter(OfflineListenAdapter()); await Future.wait([ Hive.openBox("DownloadedParents"), Hive.openBox("DownloadedItems"), @@ -186,6 +187,7 @@ Future setupHive() async { Hive.openBox("DownloadedImageIds"), Hive.openBox("ThemeMode"), Hive.openBox(LocaleHelper.boxName), + Hive.openBox("OfflineListens") ]); // If the settings box is empty, we add an initial settings value here. diff --git a/lib/models/finamp_models.dart b/lib/models/finamp_models.dart index e4d037a28..618947427 100644 --- a/lib/models/finamp_models.dart +++ b/lib/models/finamp_models.dart @@ -5,12 +5,12 @@ import 'package:flutter_downloader/flutter_downloader.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:hive/hive.dart'; import 'package:json_annotation/json_annotation.dart'; -import 'package:uuid/uuid.dart'; import 'package:path/path.dart' as path_helper; +import 'package:uuid/uuid.dart'; import '../services/finamp_settings_helper.dart'; -import 'jellyfin_models.dart'; import '../services/get_internal_song_dir.dart'; +import 'jellyfin_models.dart'; part 'finamp_models.g.dart'; @@ -571,3 +571,39 @@ class DownloadedImage { downloadLocationId: downloadLocationId, ); } + +@HiveType(typeId: 43) +class OfflineListen { + OfflineListen({ + required this.timestamp, + required this.userId, + required this.itemId, + required this.name, + this.artist, + this.album, + this.trackMbid, + }); + + /// The stop timestamp of the listen, measured in seconds since the epoch. + @HiveField(0) + int timestamp; + + @HiveField(1) + String userId; + + @HiveField(2) + String itemId; + + @HiveField(3) + String name; + + @HiveField(4) + String? artist; + + @HiveField(5) + String? album; + + // The MusicBrainz ID of the track, if available. + @HiveField(6) + String? trackMbid; +} \ No newline at end of file diff --git a/lib/models/finamp_models.g.dart b/lib/models/finamp_models.g.dart index e8e2fe943..36d1d1b57 100644 --- a/lib/models/finamp_models.g.dart +++ b/lib/models/finamp_models.g.dart @@ -372,6 +372,58 @@ class DownloadedImageAdapter extends TypeAdapter { typeId == other.typeId; } +class OfflineListenAdapter extends TypeAdapter { + @override + final int typeId = 43; + + @override + OfflineListen read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return OfflineListen( + timestamp: fields[0] as int, + userId: fields[1] as String, + itemId: fields[2] as String, + name: fields[3] as String, + artist: fields[4] as String?, + album: fields[5] as String?, + trackMbid: fields[6] as String?, + ); + } + + @override + void write(BinaryWriter writer, OfflineListen obj) { + writer + ..writeByte(7) + ..writeByte(0) + ..write(obj.timestamp) + ..writeByte(1) + ..write(obj.userId) + ..writeByte(2) + ..write(obj.itemId) + ..writeByte(3) + ..write(obj.name) + ..writeByte(4) + ..write(obj.artist) + ..writeByte(5) + ..write(obj.album) + ..writeByte(6) + ..write(obj.trackMbid); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is OfflineListenAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + class TabContentTypeAdapter extends TypeAdapter { @override final int typeId = 36; diff --git a/lib/services/offline_listen_helper.dart b/lib/services/offline_listen_helper.dart index 3e5937e0c..0affc86d5 100644 --- a/lib/services/offline_listen_helper.dart +++ b/lib/services/offline_listen_helper.dart @@ -2,8 +2,10 @@ import 'dart:convert'; import 'dart:io'; import 'package:audio_service/audio_service.dart'; +import 'package:finamp/models/finamp_models.dart'; import 'package:finamp/services/finamp_user_helper.dart'; import 'package:get_it/get_it.dart'; +import 'package:hive/hive.dart'; import 'package:logging/logging.dart'; import 'package:path_provider/path_provider.dart'; @@ -33,15 +35,17 @@ class OfflineListenLogHelper { Future logOfflineListen(MediaItem item) async { final itemJson = item.extras!["itemJson"]; - await _logOfflineListen( + final offlineListen = OfflineListen( timestamp: DateTime.now().millisecondsSinceEpoch ~/ 1000, + userId: _finampUserHelper.currentUserId!, itemId: itemJson["Id"], name: itemJson["Name"], artist: itemJson["AlbumArtist"], album: itemJson["Album"], trackMbid: itemJson["ProviderIds"]?["MusicBrainzTrack"], - userId: _finampUserHelper.currentUserId, ); + + await _logOfflineListen(offlineListen); } /// Logs a listen to a file. @@ -49,23 +53,21 @@ class OfflineListenLogHelper { /// This is used when the user is offline or submitting live playback events fails. /// The [timestamp] provided to this function should be in seconds /// and marks the time the track was stopped. - Future _logOfflineListen({ - required int timestamp, - required String itemId, - required String name, - String? artist, - String? album, - String? trackMbid, - String? userId, - }) async { + Future _logOfflineListen(OfflineListen listen) async { + Hive.box("OfflineListens").add(listen); + + _exportOfflineListenToFile(listen); + } + + Future _exportOfflineListenToFile(OfflineListen listen) async { final data = { - 'timestamp': timestamp, - 'item_id': itemId, - 'title': name, - 'artist': artist, - 'album': album, - 'track_mbid': trackMbid, - 'user_id': userId, + 'timestamp': listen.timestamp, + 'item_id': listen.itemId, + 'title': listen.name, + 'artist': listen.artist, + 'album': listen.album, + 'track_mbid': listen.trackMbid, + 'user_id': listen.userId, }; final content = json.encode(data) + Platform.lineTerminator;