Files
sm-emby-share/lib/providers/di/di_trakt.dart
T

122 lines
3.6 KiB
Dart
Raw Normal View History

2026-07-14 11:11:36 +08:00
part of '../di_providers.dart';
final traktGatewayProvider = Provider<TraktGateway>((ref) => TraktApiClient());
final traktTokenStoreProvider = Provider<TraktTokenStore>(
(ref) => TraktTokenStore(),
);
final traktAuthProvider = Provider<TraktAuth>((ref) {
return TraktAuth(
store: ref.read(traktTokenStoreProvider),
gateway: ref.read(traktGatewayProvider),
);
});
final authedTraktGatewayProvider = Provider<AuthedTraktGateway>((ref) {
return AuthedTraktClient(auth: ref.read(traktAuthProvider));
});
final traktSyncQueueProvider = FutureProvider<TraktPendingSyncQueue>((
ref,
) async {
final dir = await ref.watch(appDataDirProvider.future);
return TraktPendingSyncQueue(
store: JsonTraktSyncJobStore(
file: File('${dir.path}/trakt_pending_sync_queue.json'),
),
sender: ref.read(authedTraktGatewayProvider),
policy: TraktRetryPolicy(),
);
});
final traktSyncServiceProvider = FutureProvider<TraktSyncService>((ref) async {
final queue = await ref.read(traktSyncQueueProvider.future);
return TraktSyncService(
traktGateway: ref.read(authedTraktGatewayProvider),
queue: queue,
);
});
final traktContinueWatchingProvider =
FutureProvider<List<TraktContinueWatchingItem>>((ref) async {
final authed = ref.read(authedTraktGatewayProvider);
if (!await authed.isConnected()) return const [];
final ready = await ref.watch(_tmdbReadyProvider.future);
if (ready == null) return const [];
final List<Map<String, dynamic>> raw;
try {
raw = await authed.fetchPlayback();
} catch (e) {
AppLogger.warn('Trakt', 'fetchPlayback failed', e);
return const [];
}
final entries = raw
.map(TraktPlaybackEntry.fromJson)
.whereType<TraktPlaybackEntry>()
.toList();
entries.sort((a, b) {
final pa = a.pausedAt;
final pb = b.pausedAt;
if (pa == null && pb == null) return 0;
if (pa == null) return 1;
if (pb == null) return -1;
return pb.compareTo(pa);
});
final base = <TraktContinueWatchingItem>[];
final seenKeys = <String>{};
for (final e in entries) {
final item = TraktContinueWatchingItem.fromEntry(e);
if (item == null) continue;
if (!seenKeys.add('${item.mediaType}:${item.tmdbId}')) continue;
base.add(item);
if (base.length >= 20) break;
}
if (base.isEmpty) return const [];
const enrichConcurrency = 5;
final gateway = ref.read(tmdbGatewayProvider);
final enriched = <TraktContinueWatchingItem>[];
for (var i = 0; i < base.length; i += enrichConcurrency) {
final chunk = base.skip(i).take(enrichConcurrency);
final results = await Future.wait(
chunk.map((it) async {
try {
final detail = await gateway.getMediaDetail(
ready.config,
it.tmdbId.toString(),
it.mediaType,
language: ready.language,
);
final localized = detail?.title;
final titled = (localized != null && localized.isNotEmpty)
? it.withTitle(localized)
: it;
final url = TmdbImageUrl.backdrop(
ready.config.imageBaseUrl,
detail?.backdropPath,
size: 'w780',
);
return titled.withBackdrop(url);
} catch (_) {
return it;
}
}),
);
enriched.addAll(results);
}
return enriched;
});