Files
ersatztv/ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs
T
Jason DoveandGitHub 5244d5076a use output duration flag (#49)
* re-enable output duration flag

* calculate appropriate duration for offline image
2021-03-08 11:16:56 +00:00

110 lines
4.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.FFmpeg;
using ErsatzTV.Core.Interfaces.Repositories;
using LanguageExt;
using Microsoft.Extensions.Logging;
namespace ErsatzTV.Application.Streaming.Queries
{
public class
GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<GetPlayoutItemProcessByChannelNumber>
{
private readonly FFmpegProcessService _ffmpegProcessService;
private readonly ILogger<GetPlayoutItemProcessByChannelNumberHandler> _logger;
private readonly IMediaSourceRepository _mediaSourceRepository;
private readonly IPlayoutRepository _playoutRepository;
public GetPlayoutItemProcessByChannelNumberHandler(
IChannelRepository channelRepository,
IConfigElementRepository configElementRepository,
IPlayoutRepository playoutRepository,
IMediaSourceRepository mediaSourceRepository,
FFmpegProcessService ffmpegProcessService,
ILogger<GetPlayoutItemProcessByChannelNumberHandler> logger)
: base(channelRepository, configElementRepository)
{
_playoutRepository = playoutRepository;
_mediaSourceRepository = mediaSourceRepository;
_ffmpegProcessService = ffmpegProcessService;
_logger = logger;
}
protected override async Task<Either<BaseError, Process>> GetProcess(
GetPlayoutItemProcessByChannelNumber _,
Channel channel,
string ffmpegPath)
{
DateTimeOffset now = DateTimeOffset.Now;
Option<PlayoutItem> maybePlayoutItem = await _playoutRepository.GetPlayoutItem(channel.Id, now);
return await maybePlayoutItem.Match<Task<Either<BaseError, Process>>>(
async playoutItem =>
{
MediaVersion version = playoutItem.MediaItem switch
{
Movie m => m.MediaVersions.Head(),
Episode e => e.MediaVersions.Head(),
_ => throw new ArgumentOutOfRangeException(nameof(playoutItem))
};
MediaFile file = version.MediaFiles.Head();
string path = file.Path;
if (playoutItem.MediaItem is PlexMovie plexMovie)
{
path = await GetReplacementPlexPath(plexMovie.LibraryPathId, path);
}
return _ffmpegProcessService.ForPlayoutItem(
ffmpegPath,
channel,
version,
path,
playoutItem.StartOffset,
now);
},
async () =>
{
if (channel.FFmpegProfile.Transcode)
{
Option<TimeSpan> maybeDuration = await _playoutRepository.GetNextItemStart(channel.Id, now)
.MapT(nextStart => nextStart - now);
return _ffmpegProcessService.ForOfflineImage(ffmpegPath, channel, maybeDuration);
}
var message =
$"Unable to locate playout item for channel {channel.Number}; offline image is unavailable because transcoding is disabled in ffmpeg profile '{channel.FFmpegProfile.Name}'";
return BaseError.New(message);
});
}
private async Task<string> GetReplacementPlexPath(int libraryPathId, string path)
{
List<PlexPathReplacement> replacements =
await _mediaSourceRepository.GetPlexPathReplacementsByLibraryId(libraryPathId);
// TODO: this might barf mixing platforms (i.e. plex on linux, etv on windows)
Option<PlexPathReplacement> maybeReplacement = replacements
.SingleOrDefault(r => path.StartsWith(r.PlexPath + Path.DirectorySeparatorChar));
return maybeReplacement.Match(
replacement =>
{
string finalPath = path.Replace(replacement.PlexPath, replacement.LocalPath);
_logger.LogInformation(
"Replacing plex path {PlexPath} with {LocalPath} resulting in {FinalPath}",
replacement.PlexPath,
replacement.LocalPath,
finalPath);
return finalPath;
},
() => path);
}
}
}