|
|
|
@ -1,3 +1,4 @@ |
|
|
|
|
|
|
|
using System.Collections.Immutable; |
|
|
|
using System.Globalization; |
|
|
|
using System.Globalization; |
|
|
|
using System.IO.Abstractions; |
|
|
|
using System.IO.Abstractions; |
|
|
|
using System.Runtime.InteropServices; |
|
|
|
using System.Runtime.InteropServices; |
|
|
|
@ -134,18 +135,27 @@ public partial class SyncNextPlayoutHandler( |
|
|
|
.ThenInclude(i => (i as Episode).MediaVersions) |
|
|
|
.ThenInclude(i => (i as Episode).MediaVersions) |
|
|
|
.ThenInclude(mv => mv.Streams) |
|
|
|
.ThenInclude(mv => mv.Streams) |
|
|
|
.Include(i => i.MediaItem) |
|
|
|
.Include(i => i.MediaItem) |
|
|
|
|
|
|
|
.ThenInclude(i => (i as Episode).EpisodeMetadata) |
|
|
|
|
|
|
|
.ThenInclude(em => em.Subtitles) |
|
|
|
|
|
|
|
.Include(i => i.MediaItem) |
|
|
|
.ThenInclude(i => (i as Movie).MediaVersions) |
|
|
|
.ThenInclude(i => (i as Movie).MediaVersions) |
|
|
|
.ThenInclude(mv => mv.MediaFiles) |
|
|
|
.ThenInclude(mv => mv.MediaFiles) |
|
|
|
.Include(i => i.MediaItem) |
|
|
|
.Include(i => i.MediaItem) |
|
|
|
.ThenInclude(i => (i as Movie).MediaVersions) |
|
|
|
.ThenInclude(i => (i as Movie).MediaVersions) |
|
|
|
.ThenInclude(mv => mv.Streams) |
|
|
|
.ThenInclude(mv => mv.Streams) |
|
|
|
.Include(i => i.MediaItem) |
|
|
|
.Include(i => i.MediaItem) |
|
|
|
|
|
|
|
.ThenInclude(i => (i as Movie).MovieMetadata) |
|
|
|
|
|
|
|
.ThenInclude(mm => mm.Subtitles) |
|
|
|
|
|
|
|
.Include(i => i.MediaItem) |
|
|
|
.ThenInclude(i => (i as OtherVideo).MediaVersions) |
|
|
|
.ThenInclude(i => (i as OtherVideo).MediaVersions) |
|
|
|
.ThenInclude(mv => mv.MediaFiles) |
|
|
|
.ThenInclude(mv => mv.MediaFiles) |
|
|
|
.Include(i => i.MediaItem) |
|
|
|
.Include(i => i.MediaItem) |
|
|
|
.ThenInclude(i => (i as OtherVideo).MediaVersions) |
|
|
|
.ThenInclude(i => (i as OtherVideo).MediaVersions) |
|
|
|
.ThenInclude(mv => mv.Streams) |
|
|
|
.ThenInclude(mv => mv.Streams) |
|
|
|
.Include(i => i.MediaItem) |
|
|
|
.Include(i => i.MediaItem) |
|
|
|
|
|
|
|
.ThenInclude(i => (i as OtherVideo).OtherVideoMetadata) |
|
|
|
|
|
|
|
.ThenInclude(ovm => ovm.Subtitles) |
|
|
|
|
|
|
|
.Include(i => i.MediaItem) |
|
|
|
.ThenInclude(i => (i as MusicVideo).MediaVersions) |
|
|
|
.ThenInclude(i => (i as MusicVideo).MediaVersions) |
|
|
|
.ThenInclude(mv => mv.MediaFiles) |
|
|
|
.ThenInclude(mv => mv.MediaFiles) |
|
|
|
.Include(i => i.MediaItem) |
|
|
|
.Include(i => i.MediaItem) |
|
|
|
@ -238,6 +248,8 @@ public partial class SyncNextPlayoutHandler( |
|
|
|
nextPlayoutItem, |
|
|
|
nextPlayoutItem, |
|
|
|
playoutItem.PreferredAudioLanguageCode ?? channel.PreferredAudioLanguageCode, |
|
|
|
playoutItem.PreferredAudioLanguageCode ?? channel.PreferredAudioLanguageCode, |
|
|
|
playoutItem.PreferredAudioTitle ?? channel.PreferredAudioTitle, |
|
|
|
playoutItem.PreferredAudioTitle ?? channel.PreferredAudioTitle, |
|
|
|
|
|
|
|
playoutItem.PreferredSubtitleLanguageCode ?? channel.PreferredSubtitleLanguageCode, |
|
|
|
|
|
|
|
playoutItem.SubtitleMode ?? channel.SubtitleMode, |
|
|
|
cancellationToken); |
|
|
|
cancellationToken); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -254,13 +266,14 @@ public partial class SyncNextPlayoutHandler( |
|
|
|
Core.Next.PlayoutItem nextPlayoutItem, |
|
|
|
Core.Next.PlayoutItem nextPlayoutItem, |
|
|
|
string preferredAudioLanguage, |
|
|
|
string preferredAudioLanguage, |
|
|
|
string preferredAudioTitle, |
|
|
|
string preferredAudioTitle, |
|
|
|
|
|
|
|
string preferredSubtitleLanguage, |
|
|
|
|
|
|
|
ChannelSubtitleMode subtitleMode, |
|
|
|
CancellationToken cancellationToken) |
|
|
|
CancellationToken cancellationToken) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// TODO: NEXT: support subtitles
|
|
|
|
List<Subtitle> allSubtitles = await GetSubtitles(audioVersion.MediaItem); |
|
|
|
List<Subtitle> allSubtitles = []; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Option<MediaStream> maybeAudioStream = Option<MediaStream>.None; |
|
|
|
Option<MediaStream> maybeAudioStream = Option<MediaStream>.None; |
|
|
|
//Option<Subtitle> maybeSubtitle = Option<Subtitle>.None;
|
|
|
|
Option<Subtitle> maybeSubtitle = Option<Subtitle>.None; |
|
|
|
|
|
|
|
|
|
|
|
if (channel.StreamSelectorMode is ChannelStreamSelectorMode.Custom) |
|
|
|
if (channel.StreamSelectorMode is ChannelStreamSelectorMode.Custom) |
|
|
|
{ |
|
|
|
{ |
|
|
|
@ -270,7 +283,7 @@ public partial class SyncNextPlayoutHandler( |
|
|
|
audioVersion, |
|
|
|
audioVersion, |
|
|
|
allSubtitles); |
|
|
|
allSubtitles); |
|
|
|
maybeAudioStream = result.AudioStream; |
|
|
|
maybeAudioStream = result.AudioStream; |
|
|
|
//maybeSubtitle = result.Subtitle;
|
|
|
|
maybeSubtitle = result.Subtitle; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (channel.StreamSelectorMode is ChannelStreamSelectorMode.Default || maybeAudioStream.IsNone) |
|
|
|
if (channel.StreamSelectorMode is ChannelStreamSelectorMode.Default || maybeAudioStream.IsNone) |
|
|
|
@ -285,13 +298,14 @@ public partial class SyncNextPlayoutHandler( |
|
|
|
shouldLogMessages: false, |
|
|
|
shouldLogMessages: false, |
|
|
|
cancellationToken); |
|
|
|
cancellationToken); |
|
|
|
|
|
|
|
|
|
|
|
// maybeSubtitle =
|
|
|
|
maybeSubtitle = |
|
|
|
// await ffmpegStreamSelector.SelectSubtitleStream(
|
|
|
|
await ffmpegStreamSelector.SelectSubtitleStream( |
|
|
|
// allSubtitles.ToImmutableList(),
|
|
|
|
allSubtitles.ToImmutableList(), |
|
|
|
// channel,
|
|
|
|
channel, |
|
|
|
// preferredSubtitleLanguage,
|
|
|
|
preferredSubtitleLanguage, |
|
|
|
// subtitleMode,
|
|
|
|
subtitleMode, |
|
|
|
// cancellationToken);
|
|
|
|
shouldLogMessages: false, |
|
|
|
|
|
|
|
cancellationToken); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
foreach (MediaStream audioStream in maybeAudioStream) |
|
|
|
foreach (MediaStream audioStream in maybeAudioStream) |
|
|
|
@ -303,6 +317,16 @@ public partial class SyncNextPlayoutHandler( |
|
|
|
nextPlayoutItem.Tracks.Audio.StreamIndex = audioStream.Index; |
|
|
|
nextPlayoutItem.Tracks.Audio.StreamIndex = audioStream.Index; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
foreach (Subtitle subtitle in maybeSubtitle) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (nextPlayoutItem.Tracks?.Subtitle?.StreamIndex is null) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
nextPlayoutItem.Tracks ??= new Core.Next.PlayoutItemTracks(); |
|
|
|
|
|
|
|
nextPlayoutItem.Tracks.Subtitle ??= new Core.Next.TrackSelection(); |
|
|
|
|
|
|
|
nextPlayoutItem.Tracks.Subtitle.StreamIndex = subtitle.StreamIndex; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private async Task<Option<Core.Next.Source>> SourceForItem( |
|
|
|
private async Task<Option<Core.Next.Source>> SourceForItem( |
|
|
|
@ -431,4 +455,38 @@ public partial class SyncNextPlayoutHandler( |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static async Task<List<Subtitle>> GetSubtitles(MediaItem mediaItem) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
List<Subtitle> allSubtitles = mediaItem switch |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
Episode episode => await Optional(episode.EpisodeMetadata).Flatten().HeadOrNone() |
|
|
|
|
|
|
|
.Map(mm => mm.Subtitles ?? []) |
|
|
|
|
|
|
|
.IfNoneAsync([]), |
|
|
|
|
|
|
|
Movie movie => await Optional(movie.MovieMetadata).Flatten().HeadOrNone() |
|
|
|
|
|
|
|
.Map(mm => mm.Subtitles ?? []) |
|
|
|
|
|
|
|
.IfNoneAsync([]), |
|
|
|
|
|
|
|
//MusicVideo musicVideo => await GetMusicVideoSubtitles(musicVideo, channel, settings),
|
|
|
|
|
|
|
|
OtherVideo otherVideo => await Optional(otherVideo.OtherVideoMetadata).Flatten().HeadOrNone() |
|
|
|
|
|
|
|
.Map(mm => mm.Subtitles ?? []) |
|
|
|
|
|
|
|
.IfNoneAsync([]), |
|
|
|
|
|
|
|
_ => [] |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool isMediaServer = mediaItem is PlexMovie or PlexEpisode or |
|
|
|
|
|
|
|
JellyfinMovie or JellyfinEpisode or EmbyMovie or EmbyEpisode; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (isMediaServer) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return []; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// closed captions are currently unsupported
|
|
|
|
|
|
|
|
//allSubtitles.RemoveAll(s => s.Codec == "eia_608");
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: support text subtitles; external image subtitles
|
|
|
|
|
|
|
|
allSubtitles.RemoveAll(s => !s.IsImage || s.SubtitleKind is not SubtitleKind.Embedded); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return allSubtitles; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|