public async Task <Either <BaseError, MediaItemScanResult <PlexMovie> > > GetOrAdd( PlexLibrary library, PlexMovie item) { await using TvContext context = _dbContextFactory.CreateDbContext(); Option <PlexMovie> maybeExisting = await context.PlexMovies .AsNoTracking() .Include(i => i.MovieMetadata) .ThenInclude(mm => mm.Genres) .Include(i => i.MovieMetadata) .ThenInclude(mm => mm.Tags) .Include(i => i.MovieMetadata) .ThenInclude(mm => mm.Studios) .Include(i => i.MovieMetadata) .ThenInclude(mm => mm.Artwork) .Include(i => i.MediaVersions) .ThenInclude(mv => mv.MediaFiles) .Include(i => i.LibraryPath) .ThenInclude(lp => lp.Library) .OrderBy(i => i.Key) .SingleOrDefaultAsync(i => i.Key == item.Key); return(await maybeExisting.Match( plexMovie => Right <BaseError, MediaItemScanResult <PlexMovie> >( new MediaItemScanResult <PlexMovie>(plexMovie) { IsAdded = true }).AsTask(), async() => await AddPlexMovie(context, library, item))); }
private async Task <string> GetPlayoutItemPath(PlayoutItem playoutItem) { MediaVersion version = playoutItem.MediaItem.GetHeadVersion(); MediaFile file = version.MediaFiles.Head(); string path = file.Path; return(playoutItem.MediaItem switch { PlexMovie plexMovie => await _plexPathReplacementService.GetReplacementPlexPath( plexMovie.LibraryPathId, path), PlexEpisode plexEpisode => await _plexPathReplacementService.GetReplacementPlexPath( plexEpisode.LibraryPathId, path), JellyfinMovie jellyfinMovie => await _jellyfinPathReplacementService.GetReplacementJellyfinPath( jellyfinMovie.LibraryPathId, path), JellyfinEpisode jellyfinEpisode => await _jellyfinPathReplacementService.GetReplacementJellyfinPath( jellyfinEpisode.LibraryPathId, path), EmbyMovie embyMovie => await _embyPathReplacementService.GetReplacementEmbyPath( embyMovie.LibraryPathId, path), EmbyEpisode embyEpisode => await _embyPathReplacementService.GetReplacementEmbyPath( embyEpisode.LibraryPathId, path), _ => path });
private async Task <Either <BaseError, MediaItemScanResult <PlexMovie> > > AddPlexMovie( TvContext context, PlexLibrary library, PlexMovie item) { try { item.LibraryPathId = library.Paths.Head().Id; await context.PlexMovies.AddAsync(item); await context.SaveChangesAsync(); await context.Entry(item).Reference(i => i.LibraryPath).LoadAsync(); await context.Entry(item.LibraryPath).Reference(lp => lp.Library).LoadAsync(); return(new MediaItemScanResult <PlexMovie>(item) { IsAdded = true }); } catch (Exception ex) { return(BaseError.New(ex.ToString())); } }
private async Task <Either <BaseError, MediaItemScanResult <PlexMovie> > > UpdateStatistics( MediaItemScanResult <PlexMovie> result, PlexMovie incoming, PlexConnection connection, PlexServerAuthToken token) { PlexMovie existing = result.Item; MediaVersion existingVersion = existing.MediaVersions.Head(); MediaVersion incomingVersion = incoming.MediaVersions.Head(); if (incomingVersion.DateUpdated > existingVersion.DateUpdated || string.IsNullOrWhiteSpace(existingVersion.SampleAspectRatio)) { Either <BaseError, MediaVersion> maybeStatistics = await _plexServerApiClient.GetStatistics(incoming.Key.Split("/").Last(), connection, token); await maybeStatistics.Match( async mediaVersion => { existingVersion.SampleAspectRatio = mediaVersion.SampleAspectRatio ?? "1:1"; existingVersion.VideoScanKind = mediaVersion.VideoScanKind; existingVersion.DateUpdated = incomingVersion.DateUpdated; await _metadataRepository.UpdatePlexStatistics(existingVersion); }, _ => Task.CompletedTask); } return(result); }
private PlexMovie GetObjectFromIndexWorker(int index) { PlexMovie obj = new PlexMovie(); DownloadInfo dlInfo = getContentDownloadInfo(index); obj.StreamInformation = dlInfo; obj.StreamIndex = index; return(obj); }
private static PlexMovie GetObjectFromIndexWorker(int index) { var obj = new PlexMovie(); var dlInfo = GetContentDownloadInfo(index); obj.StreamInformation = dlInfo; obj.StreamIndex = index; return(obj); }
public static DataTable MovieAttributesFromObject(PlexMovie content, bool silent = false) { var table = new DataTable("MovieAttributes"); var columnAttributeName = new DataColumn("Name", typeof(string)); var columnAttributeValue = new DataColumn("Value"); table.Columns.AddRange( new[] { columnAttributeName, columnAttributeValue }); try { var genre = new[] { "Genre", content.ContentGenre }; var runtime = new[] { "Runtime", Methods.CalculateTime(content.StreamInformation.ContentDuration) }; var resolution = new[] { "Resolution", content.StreamResolution.ResolutionString() }; var frameRate = new[] { "Frame-rate", FormatFramerate(content) }; var size = new[] { "File size", Methods.FormatBytes(content.StreamInformation.ByteLength) }; var container = new[] { "Container", content.StreamInformation.Container }; var newRows = new[] { genre, runtime, resolution, frameRate, size, container }; foreach (object[] row in newRows) { table.Rows.Add(row); } } catch (Exception ex) { LoggingHelpers.RecordException(ex.Message, "AttributeTableError"); if (!silent) { UIMessages.Error("Error occurred whilst building content attribute table:\n\n" + ex, @"Data Error"); } } return(table); }
private async Task <string> GetPlayoutItemPath(PlayoutItem 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; return(playoutItem.MediaItem switch { PlexMovie plexMovie => await GetReplacementPlexPath(plexMovie.LibraryPathId, path), PlexEpisode plexEpisode => await GetReplacementPlexPath(plexEpisode.LibraryPathId, path), _ => path });
private async Task <Either <BaseError, MediaItemScanResult <PlexMovie> > > UpdateArtwork( MediaItemScanResult <PlexMovie> result, PlexMovie incoming) { PlexMovie existing = result.Item; MovieMetadata existingMetadata = existing.MovieMetadata.Head(); MovieMetadata incomingMetadata = incoming.MovieMetadata.Head(); if (incomingMetadata.DateUpdated > existingMetadata.DateUpdated) { await UpdateArtworkIfNeeded(existingMetadata, incomingMetadata, ArtworkKind.Poster); await UpdateArtworkIfNeeded(existingMetadata, incomingMetadata, ArtworkKind.FanArt); await _metadataRepository.MarkAsUpdated(existingMetadata, incomingMetadata.DateUpdated); } return(result); }
private void PrevTitle() { if (StreamingContent.StreamIndex != 0) { PlexMovie next = GetObjectFromIndex(StreamingContent.StreamIndex - 1); StreamingContent = next; string FormTitle = StreamingContent.StreamInformation.ContentTitle; this.Text = FormTitle; this.Refresh(); //MessageBox.Show(StreamingContent.StreamIndex + "\n" + TitlesTable.Rows.Count); } else { PlexMovie next = GetObjectFromIndex(TitlesTable.Rows.Count - 1); StreamingContent = next; string FormTitle = StreamingContent.StreamInformation.ContentTitle; this.Text = FormTitle; this.Refresh(); //MessageBox.Show(StreamingContent.StreamIndex + "\n" + TitlesTable.Rows.Count); } }
private void NextTitle() { if (((StreamingContent.StreamIndex + 1) < TitlesTable.Rows.Count)) { PlexMovie next = GetObjectFromIndex(StreamingContent.StreamIndex + 1); StreamingContent = next; string FormTitle = StreamingContent.StreamInformation.ContentTitle; this.Text = FormTitle; this.Refresh(); //MessageBox.Show(StreamingContent.StreamIndex + "\n" + TitlesTable.Rows.Count); } else if ((StreamingContent.StreamIndex + 1) == TitlesTable.Rows.Count) { PlexMovie next = GetObjectFromIndex(0); StreamingContent = next; string FormTitle = StreamingContent.StreamInformation.ContentTitle; this.Text = FormTitle; this.Refresh(); //MessageBox.Show(StreamingContent.StreamIndex + "\n" + TitlesTable.Rows.Count); } }
private PlexMovie GetObjectFromIndex(int index) { PlexMovie result = (PlexMovie)PlexDL.WaitWindow.WaitWindow.Show(GetObjectFromIndexCallback, "Getting Metadata", new object[] { index }); return(result); }
//MOVIE OBJECT BUILDER public static PlexMovie GetMovieObjectFromIndex(int index, bool waitWindow = true) { try { if (waitWindow) { return((PlexMovie)WaitWindow.WaitWindow.Show(GetMovieObjectFromIndex_Callback, @"Getting metadata", index)); } var obj = new PlexMovie(); LoggingHelpers.RecordGeneralEntry(@"Content Parse Started"); LoggingHelpers.RecordGeneralEntry(@"Grabbing Titles"); var metadata = XmlMetadataContent.GetContentMetadata(index); LoggingHelpers.RecordGeneralEntry(@"Checking XML validity"); if (Methods.PlexXmlValid(metadata.Xml)) { LoggingHelpers.RecordGeneralEntry(@"XML Valid"); var dlInfo = DownloadInfoGatherers.GetContentDownloadInfo(metadata.Xml); if (dlInfo != null) { LoggingHelpers.RecordGeneralEntry(@"Assembling Object"); obj.ApiUri = metadata.ApiUri; obj.ContentGenre = XmlMetadataStrings.GetContentGenre(metadata.Xml); obj.StreamInformation = dlInfo; obj.StreamResolution = XmlMetadataObjects.GetContentResolution(metadata.Xml); obj.Actors = XmlMetadataObjects.GetActorsFromMetadata(metadata.Xml); obj.StreamIndex = index; obj.Synopsis = XmlMetadataStrings.GetContentSynopsis(metadata.Xml); //apply the raw metadata to the object (it won't get serialised) obj.RawMetadata = metadata.Xml; } else { UIMessages.Error( @"Failed to get contextual information; an unknown error occurred. Check the exception log for more information.", @"Data Error"); LoggingHelpers.RecordException( @"DownloadInfo invalid. This may be an internal error; please report this issue on GitHub.", @"ContextDownloadInfoNull"); LoggingHelpers.RecordGeneralEntry("DownloadInfo is invalid (no stream contextual information)"); } } else { LoggingHelpers.RecordGeneralEntry("XML Invalid"); } LoggingHelpers.RecordGeneralEntry("Returned assembled Movie object"); return(obj); } catch (ThreadAbortException) { //literally nothing; this gets raised when a cancellation happens. return(null); } catch (Exception ex) { UIMessages.Error("Content metadata error:\n\n" + ex, @"Data Error"); LoggingHelpers.RecordException(ex.Message, @"MovieObjectError"); return(null); } }
private async Task <Either <BaseError, MediaItemScanResult <PlexMovie> > > UpdateMetadata( MediaItemScanResult <PlexMovie> result, PlexMovie incoming) { PlexMovie existing = result.Item; MovieMetadata existingMetadata = existing.MovieMetadata.Head(); MovieMetadata incomingMetadata = incoming.MovieMetadata.Head(); if (incomingMetadata.DateUpdated > existingMetadata.DateUpdated) { foreach (Genre genre in existingMetadata.Genres .Filter(g => incomingMetadata.Genres.All(g2 => g2.Name != g.Name)) .ToList()) { existingMetadata.Genres.Remove(genre); if (await _metadataRepository.RemoveGenre(genre)) { result.IsUpdated = true; } } foreach (Genre genre in incomingMetadata.Genres .Filter(g => existingMetadata.Genres.All(g2 => g2.Name != g.Name)) .ToList()) { existingMetadata.Genres.Add(genre); if (await _movieRepository.AddGenre(existingMetadata, genre)) { result.IsUpdated = true; } } foreach (Studio studio in existingMetadata.Studios .Filter(s => incomingMetadata.Studios.All(s2 => s2.Name != s.Name)) .ToList()) { existingMetadata.Studios.Remove(studio); if (await _metadataRepository.RemoveStudio(studio)) { result.IsUpdated = true; } } foreach (Studio studio in incomingMetadata.Studios .Filter(s => existingMetadata.Studios.All(s2 => s2.Name != s.Name)) .ToList()) { existingMetadata.Studios.Add(studio); if (await _movieRepository.AddStudio(existingMetadata, studio)) { result.IsUpdated = true; } } if (incomingMetadata.SortTitle != existingMetadata.SortTitle) { existingMetadata.SortTitle = incomingMetadata.SortTitle; if (await _movieRepository.UpdateSortTitle(existingMetadata)) { result.IsUpdated = true; } } await _metadataRepository.MarkAsUpdated(existingMetadata, incomingMetadata.DateUpdated); // TODO: update other metadata? } return(result); }