private async Task <bool> ApplyVersionUpdate(MediaItem mediaItem, MediaVersion version, string filePath) { MediaVersion mediaItemVersion = mediaItem.GetHeadVersion(); bool durationChange = mediaItemVersion.Duration != version.Duration; version.DateUpdated = _localFileSystem.GetLastWriteTime(filePath); return(await _metadataRepository.UpdateLocalStatistics(mediaItem, version) && durationChange); }
public async Task <Either <BaseError, bool> > RefreshStatistics( string ffmpegPath, string ffprobePath, MediaItem mediaItem) { try { string filePath = mediaItem.GetHeadVersion().MediaFiles.Head().Path; return(await RefreshStatistics(ffmpegPath, ffprobePath, mediaItem, filePath)); } catch (Exception ex) { _logger.LogWarning(ex, "Failed to refresh statistics for media item {Id}", mediaItem.Id); _client.Notify(ex); return(BaseError.New(ex.Message)); } }
private async Task <Either <BaseError, PlayoutItemWithPath> > CheckForFallbackFiller( TvContext dbContext, Channel channel, DateTimeOffset now) { // check for channel fallback Option <FillerPreset> maybeFallback = await dbContext.FillerPresets .SelectOneAsync(w => w.Id, w => w.Id == channel.FallbackFillerId); // then check for global fallback if (maybeFallback.IsNone) { maybeFallback = await dbContext.ConfigElements .GetValue <int>(ConfigElementKey.FFmpegGlobalFallbackFillerId) .BindT(fillerId => dbContext.FillerPresets.SelectOneAsync(w => w.Id, w => w.Id == fillerId)); } foreach (FillerPreset fallbackPreset in maybeFallback) { // turn this into a playout item var collectionKey = CollectionKey.ForFillerPreset(fallbackPreset); List <MediaItem> items = await MediaItemsForCollection.Collect( _mediaCollectionRepository, _televisionRepository, _artistRepository, collectionKey); // TODO: shuffle? does it really matter since we loop anyway MediaItem item = items[new Random().Next(items.Count)]; Option <TimeSpan> maybeDuration = await dbContext.PlayoutItems .Filter(pi => pi.Playout.ChannelId == channel.Id) .Filter(pi => pi.Start > now.UtcDateTime) .OrderBy(pi => pi.Start) .FirstOrDefaultAsync() .Map(Optional) .MapT(pi => pi.StartOffset - now); MediaVersion version = item.GetHeadVersion(); version.MediaFiles = await dbContext.MediaFiles .AsNoTracking() .Filter(mf => mf.MediaVersionId == version.Id) .ToListAsync(); version.Streams = await dbContext.MediaStreams .AsNoTracking() .Filter(ms => ms.MediaVersionId == version.Id) .ToListAsync(); DateTimeOffset finish = maybeDuration.Match( // next playout item exists // loop until it starts now.Add, // no next playout item exists // loop for 5 minutes if less than 30s, otherwise play full item () => version.Duration < TimeSpan.FromSeconds(30) ? now.AddMinutes(5) : now.Add(version.Duration)); var playoutItem = new PlayoutItem { MediaItem = item, MediaItemId = item.Id, Start = now.UtcDateTime, Finish = finish.UtcDateTime, FillerKind = FillerKind.Fallback, InPoint = TimeSpan.Zero, OutPoint = version.Duration }; return(await ValidatePlayoutItemPath(playoutItem)); } return(new UnableToLocatePlayoutItem()); }
public async Task <Either <BaseError, Dictionary <string, string> > > GetFormatTags( string ffprobePath, MediaItem mediaItem) { try { string mediaItemPath = mediaItem.GetHeadVersion().MediaFiles.Head().Path; Either <BaseError, FFprobe> maybeProbe = await GetProbeOutput(ffprobePath, mediaItemPath); return(maybeProbe.Match( ffprobe => { var result = new Dictionary <string, string>(); if (!string.IsNullOrWhiteSpace(ffprobe?.format?.tags?.album)) { result.Add(MetadataFormatTag.Album, ffprobe.format.tags.album); } if (!string.IsNullOrWhiteSpace(ffprobe?.format?.tags?.albumArtist)) { result.Add(MetadataFormatTag.AlbumArtist, ffprobe.format.tags.albumArtist); } if (!string.IsNullOrWhiteSpace(ffprobe?.format?.tags?.artist)) { result.Add(MetadataFormatTag.Artist, ffprobe.format.tags.artist); // if no album artist is present, use the track artist if (!result.ContainsKey(MetadataFormatTag.AlbumArtist)) { result.Add(MetadataFormatTag.AlbumArtist, ffprobe.format.tags.artist); } } if (!string.IsNullOrWhiteSpace(ffprobe?.format?.tags?.date)) { result.Add(MetadataFormatTag.Date, ffprobe.format.tags.date); } if (!string.IsNullOrWhiteSpace(ffprobe?.format?.tags?.genre)) { result.Add(MetadataFormatTag.Genre, ffprobe.format.tags.genre); } if (!string.IsNullOrWhiteSpace(ffprobe?.format?.tags?.title)) { result.Add(MetadataFormatTag.Title, ffprobe.format.tags.title); } if (!string.IsNullOrWhiteSpace(ffprobe?.format?.tags?.track)) { result.Add(MetadataFormatTag.Track, ffprobe.format.tags.track); } return Right <BaseError, Dictionary <string, string> >(result); }, Left <BaseError, Dictionary <string, string> >)); } catch (Exception ex) { _logger.LogWarning(ex, "Failed to get format tags for media item {Id}", mediaItem.Id); _client.Notify(ex); return(BaseError.New(ex.Message)); } }