Files
2026-07-14 11:11:36 +08:00

132 lines
3.4 KiB
Dart

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 = <String>{
'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 = <String, String>{
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<PlayerExitResult?> 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<void> 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<String, String> 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,
);
}