import '../../../core/contracts/library.dart'; import '../../../core/infra/emby_api/playback_resolver.dart'; class StreamSelection { final List subtitles; final List audios; final int preferredSubtitleStreamIndex; final int? preferredAudioStreamIndex; const StreamSelection({ required this.subtitles, required this.audios, required this.preferredSubtitleStreamIndex, required this.preferredAudioStreamIndex, }); } EmbyRawMediaSource? resolveActiveMediaSource( CrossServerSourceCard? selectedCrossServerCard, List localSources, int selectedSourceIdx, ) { return selectedCrossServerCard?.mediaSource ?? (selectedSourceIdx < localSources.length ? localSources[selectedSourceIdx] : null); } StreamSelection resolveStreamSelection( EmbyRawMediaSource? source, int? selectedSubtitleIdx, int selectedAudioIdx, ) { final subtitles = (source?.MediaStreams ?? []) .where((s) => s.Type == 'Subtitle') .where((s) { final isExternal = (s.IsExternal ?? false) || s.DeliveryMethod == 'External' || (s.DeliveryUrl != null && s.DeliveryUrl!.isNotEmpty); if (!isExternal) return true; return PlaybackResolver.isTextSubtitleCodec(s.Codec); }) .toList(); final audios = (source?.MediaStreams ?? []) .where((s) => s.Type == 'Audio') .toList(); final preferredSubtitleStreamIndex = selectedSubtitleIdx != null && selectedSubtitleIdx < subtitles.length ? subtitles[selectedSubtitleIdx].Index ?? -1 : -1; final preferredAudioStreamIndex = selectedAudioIdx < audios.length ? audios[selectedAudioIdx].Index : null; return StreamSelection( subtitles: subtitles, audios: audios, preferredSubtitleStreamIndex: preferredSubtitleStreamIndex, preferredAudioStreamIndex: preferredAudioStreamIndex, ); } int resolveDefaultSourceIndex( List sortedSources, String? rememberedMediaSourceId, { int fallback = 0, }) { if (rememberedMediaSourceId == null) return fallback; final idx = sortedSources.indexWhere((s) => s.Id == rememberedMediaSourceId); return idx >= 0 ? idx : fallback; }