private async Task <Either <BaseError, MediaItemScanResult <TMovie> > > UpdateStatistics( MediaItemScanResult <TMovie> result, TMovie incoming, string ffmpegPath, string ffprobePath) { TMovie existing = result.Item; if (result.IsAdded || MediaServerItemId(existing) != MediaServerItemId(incoming) || existing.MediaVersions.Head().Streams.Count == 0) { if (_localFileSystem.FileExists(result.LocalPath)) { _logger.LogDebug("Refreshing {Attribute} for {Path}", "Statistics", result.LocalPath); Either <BaseError, bool> refreshResult = await _localStatisticsProvider.RefreshStatistics( ffmpegPath, ffprobePath, existing, result.LocalPath); foreach (BaseError error in refreshResult.LeftToSeq()) { _logger.LogWarning( "Unable to refresh {Attribute} for media item {Path}. Error: {Error}", "Statistics", result.LocalPath, error.Value); } foreach (bool _ in refreshResult.RightToSeq()) { result.IsUpdated = true; } } } return(result); }
private async Task <Either <BaseError, Unit> > ProcessEpisodes( string showName, string seasonName, EmbyLibrary library, string ffmpegPath, string ffprobePath, List <EmbyPathReplacement> pathReplacements, EmbySeason season, List <EmbyItemEtag> existingEpisodes, List <EmbyEpisode> episodes, CancellationToken cancellationToken) { foreach (EmbyEpisode incoming in episodes) { if (cancellationToken.IsCancellationRequested) { return(new ScanCanceled()); } EmbyEpisode incomingEpisode = incoming; var updateStatistics = false; Option <EmbyItemEtag> maybeExisting = existingEpisodes.Find(ie => ie.ItemId == incoming.ItemId); if (maybeExisting.IsNone) { try { updateStatistics = true; incoming.LibraryPathId = library.Paths.Head().Id; _logger.LogDebug( "INSERT: Item id is new for show {Show} season {Season} episode {Episode}", showName, seasonName, incoming.EpisodeMetadata.HeadOrNone().Map(em => em.EpisodeNumber)); if (await _televisionRepository.AddEpisode(season, incoming)) { await _searchIndex.AddItems(_searchRepository, new List <MediaItem> { incoming }); } } catch (Exception ex) { updateStatistics = false; _logger.LogError( ex, "Error adding episode {Path}", incoming.MediaVersions.Head().MediaFiles.Head().Path); } } foreach (EmbyItemEtag existing in maybeExisting) { try { if (existing.Etag != incoming.Etag) { _logger.LogDebug( "UPDATE: Etag has changed for show {Show} season {Season} episode {Episode}", showName, seasonName, incoming.EpisodeMetadata.HeadOrNone().Map(em => em.EpisodeNumber)); updateStatistics = true; incoming.SeasonId = season.Id; incoming.LibraryPathId = library.Paths.Head().Id; Option <EmbyEpisode> maybeUpdated = await _televisionRepository.Update(incoming); foreach (EmbyEpisode updated in maybeUpdated) { await _searchIndex.UpdateItems(_searchRepository, new List <MediaItem> { updated }); incomingEpisode = updated; } } } catch (Exception ex) { updateStatistics = false; _logger.LogError( ex, "Error updating episode {Path}", incoming.MediaVersions.Head().MediaFiles.Head().Path); } } if (updateStatistics) { string localPath = _pathReplacementService.GetReplacementEmbyPath( pathReplacements, incoming.MediaVersions.Head().MediaFiles.Head().Path, false); _logger.LogDebug("Refreshing {Attribute} for {Path}", "Statistics", localPath); Either <BaseError, bool> refreshResult = await _localStatisticsProvider.RefreshStatistics( ffmpegPath, ffprobePath, incomingEpisode, localPath); if (refreshResult.Map(t => t).IfLeft(false)) { refreshResult = await UpdateSubtitles(incomingEpisode, localPath); } foreach (BaseError error in refreshResult.LeftToSeq()) { _logger.LogWarning( "Unable to refresh {Attribute} for media item {Path}. Error: {Error}", "Statistics", localPath, error.Value); } } } return(Unit.Default); }
private async Task <Either <BaseError, MediaItemScanResult <PlexEpisode> > > UpdateStatistics( List <PlexPathReplacement> pathReplacements, MediaItemScanResult <PlexEpisode> result, PlexEpisode incoming, PlexLibrary library, PlexConnection connection, PlexServerAuthToken token, string ffmpegPath, string ffprobePath, bool deepScan) { PlexEpisode existing = result.Item; MediaVersion existingVersion = existing.MediaVersions.Head(); MediaVersion incomingVersion = incoming.MediaVersions.Head(); if (result.IsAdded || existing.Etag != incoming.Etag || deepScan || existingVersion.Streams.Count == 0) { foreach (MediaFile incomingFile in incomingVersion.MediaFiles.HeadOrNone()) { foreach (MediaFile existingFile in existingVersion.MediaFiles.HeadOrNone()) { if (incomingFile.Path != existingFile.Path) { _logger.LogDebug( "Plex episode has moved from {OldPath} to {NewPath}", existingFile.Path, incomingFile.Path); existingFile.Path = incomingFile.Path; await _televisionRepository.UpdatePath(existingFile.Id, incomingFile.Path); } } } Either <BaseError, bool> refreshResult = true; string localPath = _plexPathReplacementService.GetReplacementPlexPath( pathReplacements, incoming.MediaVersions.Head().MediaFiles.Head().Path, false); if ((existing.Etag != incoming.Etag || existingVersion.Streams.Count == 0) && _localFileSystem.FileExists(localPath)) { _logger.LogDebug("Refreshing {Attribute} for {Path}", "Statistics", localPath); refreshResult = await _localStatisticsProvider.RefreshStatistics( ffmpegPath, ffprobePath, existing, localPath); } foreach (BaseError error in refreshResult.LeftToSeq()) { _logger.LogWarning( "Unable to refresh {Attribute} for media item {Path}. Error: {Error}", "Statistics", localPath, error.Value); } foreach (var _ in refreshResult.RightToSeq()) { foreach (MediaItem updated in await _searchRepository.GetItemToIndex(incoming.Id)) { await _searchIndex.UpdateItems( _searchRepository, new List <MediaItem> { updated }); } Either <BaseError, Tuple <EpisodeMetadata, MediaVersion> > maybeStatistics = await _plexServerApiClient.GetEpisodeMetadataAndStatistics( library, incoming.Key.Split("/").Last(), connection, token); foreach (Tuple <EpisodeMetadata, MediaVersion> tuple in maybeStatistics.RightToSeq()) { (EpisodeMetadata incomingMetadata, MediaVersion mediaVersion) = tuple; Option <EpisodeMetadata> maybeExisting = existing.EpisodeMetadata .Find(em => em.EpisodeNumber == incomingMetadata.EpisodeNumber); foreach (EpisodeMetadata existingMetadata in maybeExisting) { foreach (MetadataGuid guid in existingMetadata.Guids .Filter(g => incomingMetadata.Guids.All(g2 => g2.Guid != g.Guid)) .ToList()) { existingMetadata.Guids.Remove(guid); await _metadataRepository.RemoveGuid(guid); } foreach (MetadataGuid guid in incomingMetadata.Guids .Filter(g => existingMetadata.Guids.All(g2 => g2.Guid != g.Guid)) .ToList()) { existingMetadata.Guids.Add(guid); await _metadataRepository.AddGuid(existingMetadata, guid); } foreach (Tag tag in existingMetadata.Tags .Filter(g => incomingMetadata.Tags.All(g2 => g2.Name != g.Name)) .ToList()) { existingMetadata.Tags.Remove(tag); await _metadataRepository.RemoveTag(tag); } foreach (Tag tag in incomingMetadata.Tags .Filter(g => existingMetadata.Tags.All(g2 => g2.Name != g.Name)) .ToList()) { existingMetadata.Tags.Add(tag); await _televisionRepository.AddTag(existingMetadata, tag); } } existingVersion.SampleAspectRatio = mediaVersion.SampleAspectRatio; existingVersion.VideoScanKind = mediaVersion.VideoScanKind; existingVersion.DateUpdated = mediaVersion.DateUpdated; await _metadataRepository.UpdatePlexStatistics(existingVersion.Id, mediaVersion); } } } return(result); }