122 lines
3.6 KiB
Dart
122 lines
3.6 KiB
Dart
|
|
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;
|
||
|
|
});
|