import 'package:flutter/widgets.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../core/contracts/library.dart'; import '../../core/contracts/tmdb.dart'; import '../../core/infra/emby_api/emby_headers.dart'; import '../../features/player/player_launcher.dart'; import '../../providers/di_providers.dart'; import '../../providers/session_provider.dart'; import '../../providers/tmdb_prefetch_provider.dart'; import 'platform_device_name.dart'; const _kContainerTypes = { 'BoxSet', 'CollectionFolder', 'Folder', 'Playlist', 'UserView', }; void goMediaDetail(BuildContext context, EmbyRawItem item, {WidgetRef? ref}) { if (_kContainerTypes.contains(item.Type)) { context.push( Uri( path: '/library/${item.Id}', queryParameters: { 'collection': '1', if (item.Name.isNotEmpty) 'title': item.Name, }, ).toString(), ); return; } if (ref != null) { ref.read(tmdbPrefetchProvider.notifier).prefetchItem(item, priority: true); } final isEpisode = item.Type == 'Episode'; final seriesId = isEpisode && (item.SeriesId?.isNotEmpty ?? false) ? item.SeriesId : null; final seasonId = isEpisode && (item.SeasonId?.isNotEmpty ?? false) ? item.SeasonId : null; final query = { if (seriesId != null) 'seriesId': seriesId, if (seasonId != null) 'seasonId': seasonId, }; context.push( Uri( path: '/media/${item.Id}', queryParameters: query.isNotEmpty ? query : null, ).toString(), extra: item, ); } Future playFromTmdbOnServer( BuildContext context, WidgetRef ref, { required String serverId, required String itemId, String? mediaSourceId, int preferredSubtitleStreamIndex = -1, int? preferredAudioStreamIndex, bool fromStart = false, int? startPositionTicks, String? backdropUrl, }) async { final active = ref.read(activeSessionProvider); if (active?.serverId != serverId) { await ref.read(sessionProvider.notifier).switchSession(serverId); } if (!context.mounted) return null; return PlayerLauncher.launch( context: context, itemId: itemId, serverId: serverId, mediaSourceId: mediaSourceId, preferredSubtitleStreamIndex: preferredSubtitleStreamIndex, preferredAudioStreamIndex: preferredAudioStreamIndex, startPositionTicks: startPositionTicks, fromStart: fromStart, backdropUrl: backdropUrl, ref: ref, ); } void goTmdbDetail( BuildContext context, { required int tmdbId, required String mediaType, TmdbRecommendation? seed, }) { if (mediaType != 'movie' && mediaType != 'tv') return; context.push('/tmdb/$mediaType/$tmdbId', extra: seed); } Future goMediaDetailOnServer( BuildContext context, WidgetRef ref, { required String serverId, required EmbyRawItem item, }) async { final activeId = ref.read(sessionProvider).value?.activeServerId; if (serverId != activeId) { await ref.read(sessionProvider.notifier).switchSession(serverId); } if (context.mounted) { goMediaDetail(context, item); } } Map buildEmbyImageHeaders( WidgetRef ref, { required String token, required String userId, }) { final deviceId = ref.read(deviceIdProvider).value ?? ''; return EmbyRequestHeaders.image( deviceId: deviceId, deviceName: kEmbyDeviceName, token: token, userId: userId, ); }