@@ -2,6 +2,7 @@ import '../../../models/trackers/tracker_context.dart';
|
||||
import '../../../utils/app_logger.dart';
|
||||
import '../../settings_service.dart';
|
||||
import '../tracker.dart';
|
||||
import '../tracker_constants.dart';
|
||||
import 'anilist_client.dart';
|
||||
import 'anilist_session.dart';
|
||||
|
||||
@@ -17,6 +18,9 @@ class AnilistTracker extends TrackerBase {
|
||||
@override
|
||||
String get name => 'anilist';
|
||||
|
||||
@override
|
||||
TrackerService get service => TrackerService.anilist;
|
||||
|
||||
@override
|
||||
bool get needsFribb => true;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import '../../../models/trackers/tracker_context.dart';
|
||||
import '../../../utils/app_logger.dart';
|
||||
import '../../settings_service.dart';
|
||||
import '../tracker.dart';
|
||||
import '../tracker_constants.dart';
|
||||
import 'mal_client.dart';
|
||||
import 'mal_session.dart';
|
||||
|
||||
@@ -22,6 +23,9 @@ class MalTracker extends TrackerBase {
|
||||
@override
|
||||
String get name => 'mal';
|
||||
|
||||
@override
|
||||
TrackerService get service => TrackerService.mal;
|
||||
|
||||
@override
|
||||
bool get needsFribb => true;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import '../../../models/trackers/tracker_context.dart';
|
||||
import '../../../utils/app_logger.dart';
|
||||
import '../../settings_service.dart';
|
||||
import '../tracker.dart';
|
||||
import '../tracker_constants.dart';
|
||||
import 'simkl_client.dart';
|
||||
import 'simkl_session.dart';
|
||||
|
||||
@@ -20,6 +21,9 @@ class SimklTracker extends TrackerBase {
|
||||
@override
|
||||
String get name => 'simkl';
|
||||
|
||||
@override
|
||||
TrackerService get service => TrackerService.simkl;
|
||||
|
||||
@override
|
||||
bool get needsFribb => false;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import '../../models/trackers/tracker_context.dart';
|
||||
import '../settings_service.dart';
|
||||
import 'tracker_constants.dart';
|
||||
|
||||
/// Abstract tracker contract: the coordinator calls [markWatched] once per
|
||||
/// playback when progress crosses the watched threshold. Enabled/auth gating
|
||||
@@ -7,6 +8,10 @@ import '../settings_service.dart';
|
||||
abstract class Tracker {
|
||||
String get name;
|
||||
|
||||
/// Stable identifier used to persist per-service settings (library filter,
|
||||
/// scrobble enabled, etc.).
|
||||
TrackerService get service;
|
||||
|
||||
bool get canScrobble;
|
||||
|
||||
/// True if this tracker's IDs only come from the Fribb anime mapping
|
||||
@@ -18,6 +23,12 @@ abstract class Tracker {
|
||||
Future<void> initialize();
|
||||
Future<void> setEnabled(bool enabled);
|
||||
|
||||
/// Whether an item in the given library should be scrobbled. Applies the
|
||||
/// per-tracker whitelist/blacklist — callers pass the Plex library
|
||||
/// `serverId:sectionId` globalKey (null when unknown, in which case the
|
||||
/// filter is bypassed so we err on the side of syncing).
|
||||
bool shouldScrobbleForLibrary(String? libraryGlobalKey);
|
||||
|
||||
Future<void> markWatched(TrackerContext ctx);
|
||||
}
|
||||
|
||||
@@ -45,4 +56,8 @@ abstract class TrackerBase implements Tracker {
|
||||
Future<void> setEnabled(bool enabled) async {
|
||||
_isEnabled = enabled;
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldScrobbleForLibrary(String? libraryGlobalKey) =>
|
||||
SettingsService.instanceOrNull?.isLibraryAllowedForTracker(service, libraryGlobalKey) ?? true;
|
||||
}
|
||||
|
||||
@@ -6,3 +6,11 @@ class TrackerConstants {
|
||||
/// pushed to each tracker.
|
||||
static const double watchedThresholdPercent = 80.0;
|
||||
}
|
||||
|
||||
/// Identifier used across the app to disambiguate per-service operations.
|
||||
/// The enum's `.name` forms part of the persistence key — do not rename
|
||||
/// without a migration.
|
||||
enum TrackerService { mal, anilist, simkl, trakt }
|
||||
|
||||
/// Blacklist+[] syncs every library (the default); whitelist+[] syncs nothing.
|
||||
enum TrackerLibraryFilterMode { blacklist, whitelist }
|
||||
|
||||
@@ -113,7 +113,9 @@ class TrackerCoordinator {
|
||||
}
|
||||
|
||||
Future<void> _dispatchMarkWatched(TrackerContext ctx) async {
|
||||
final active = _trackers.where((t) => t.canScrobble);
|
||||
final active = _trackers.where(
|
||||
(t) => t.canScrobble && t.shouldScrobbleForLibrary(ctx.libraryGlobalKey),
|
||||
);
|
||||
await Future.wait(active.map((t) async {
|
||||
try {
|
||||
await t.markWatched(ctx);
|
||||
@@ -127,6 +129,8 @@ class TrackerCoordinator {
|
||||
final resolver = _resolver;
|
||||
if (resolver == null) return null;
|
||||
|
||||
final libraryKey = metadata.librarySectionGlobalKey;
|
||||
|
||||
if (metadata.mediaType == PlexMediaType.movie) {
|
||||
final ids = await resolver.resolveForMovie(metadata.ratingKey);
|
||||
if (ids == null) return null;
|
||||
@@ -134,6 +138,7 @@ class TrackerCoordinator {
|
||||
external: ids.external,
|
||||
anime: ids.anime,
|
||||
ratingKey: metadata.ratingKey,
|
||||
libraryGlobalKey: libraryKey,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -147,6 +152,7 @@ class TrackerCoordinator {
|
||||
external: ids.external,
|
||||
anime: ids.anime,
|
||||
ratingKey: metadata.ratingKey,
|
||||
libraryGlobalKey: libraryKey,
|
||||
season: season,
|
||||
episodeNumber: number,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user