From 7c5646d416372983ac8996b1a6539e671db18c86 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Thu, 16 Sep 2021 14:59:35 +0100 Subject: [PATCH 1/2] feat(plex): :zap: Use the new Plex Pass includeGuids feature for syncing plex movies --- src/Ombi.Api.Plex/Models/Metadata.cs | 4 ++- src/Ombi.Api.Plex/PlexApi.cs | 1 + .../Jobs/Plex/PlexContentSync.cs | 27 ++++++++++++------- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/Ombi.Api.Plex/Models/Metadata.cs b/src/Ombi.Api.Plex/Models/Metadata.cs index 92e66b35c..d0bb227ad 100644 --- a/src/Ombi.Api.Plex/Models/Metadata.cs +++ b/src/Ombi.Api.Plex/Models/Metadata.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; + namespace Ombi.Api.Plex.Models { public class Metadata @@ -44,7 +46,7 @@ namespace Ombi.Api.Plex.Models public string grandparentTheme { get; set; } public string chapterSource { get; set; } public Medium[] Media { get; set; } - public PlexGuids[] Guid { get; set; } + public List Guid { get; set; } = new List(); // public Director[] Director { get; set; } // public Writer[] Writer { get; set; } } diff --git a/src/Ombi.Api.Plex/PlexApi.cs b/src/Ombi.Api.Plex/PlexApi.cs index b80534bb9..77c129cd7 100644 --- a/src/Ombi.Api.Plex/PlexApi.cs +++ b/src/Ombi.Api.Plex/PlexApi.cs @@ -123,6 +123,7 @@ namespace Ombi.Api.Plex public async Task GetLibrary(string authToken, string plexFullHost, string libraryId) { var request = new Request($"library/sections/{libraryId}/all", plexFullHost, HttpMethod.Get); + request.AddQueryString("includeGuids","1"); await AddHeaders(request, authToken); return await Api.Request(request); } diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs index dbad7ac84..0c210668c 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs @@ -287,17 +287,26 @@ namespace Ombi.Schedule.Jobs.Plex } Logger.LogDebug("Adding movie {0}", movie.title); - var metaData = await PlexApi.GetMetadata(servers.PlexAuthToken, servers.FullUri, - movie.ratingKey); - - var meta = metaData.MediaContainer.Metadata.FirstOrDefault(); - var guids = new List + var guids = new List(); + if (!movie.Guid.Any()) { - meta.guid - }; - if (meta.Guid != null) + var metaData = await PlexApi.GetMetadata(servers.PlexAuthToken, servers.FullUri, + movie.ratingKey); + + var meta = metaData.MediaContainer.Metadata.FirstOrDefault(); + guids.Add(meta.guid); + if (meta.Guid != null) + { + foreach (var g in meta.Guid) + { + guids.Add(g.Id); + } + } + } + else { - foreach (var g in meta.Guid) + // Currently a Plex Pass feature only + foreach (var g in movie.Guid) { guids.Add(g.Id); } From 98f655e92e260107d0b3e396635137f63935f13c Mon Sep 17 00:00:00 2001 From: tidusjar Date: Thu, 16 Sep 2021 20:31:49 +0100 Subject: [PATCH 2/2] test: :white_check_mark: Added some unit tests around the new code in the Plex Sync --- .../Ombi.Schedule.Tests.csproj | 5 +- .../PlexContentSyncTests.cs | 144 +++++++++++++ .../Jobs/Plex/PlexContentSync.cs | 194 +++++++++--------- 3 files changed, 249 insertions(+), 94 deletions(-) create mode 100644 src/Ombi.Schedule.Tests/PlexContentSyncTests.cs diff --git a/src/Ombi.Schedule.Tests/Ombi.Schedule.Tests.csproj b/src/Ombi.Schedule.Tests/Ombi.Schedule.Tests.csproj index 003c240f1..5ee3c0fed 100644 --- a/src/Ombi.Schedule.Tests/Ombi.Schedule.Tests.csproj +++ b/src/Ombi.Schedule.Tests/Ombi.Schedule.Tests.csproj @@ -7,12 +7,13 @@ - + + - + diff --git a/src/Ombi.Schedule.Tests/PlexContentSyncTests.cs b/src/Ombi.Schedule.Tests/PlexContentSyncTests.cs new file mode 100644 index 000000000..3b9fa33b0 --- /dev/null +++ b/src/Ombi.Schedule.Tests/PlexContentSyncTests.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Moq; +using Moq.AutoMock; +using NUnit.Framework; +using Ombi.Api.Plex; +using Ombi.Api.Plex.Models; +using Ombi.Core.Settings.Models.External; +using Ombi.Schedule.Jobs.Plex; +using Ombi.Store.Entities; +using Ombi.Store.Repository; + +namespace Ombi.Schedule.Tests +{ + [TestFixture] + public class PlexContentSyncTests + { + + private AutoMocker _mocker; + private PlexContentSync _subject; + + [SetUp] + public void Setup() + { + _mocker = new AutoMocker(); + _subject = _mocker.CreateInstance(); + } + + [Test] + public async Task DoesNotSyncExistingMovie() + { + var content = new Mediacontainer + { + Metadata = new[] + { + new Metadata + { + title = "test1", + year = 2021, + type = "movie" + }, + } + }; + var contentToAdd = new HashSet(); + var contentProcessed = new Dictionary(); + _mocker.Setup(x => + x.GetFirstContentByCustom(It.IsAny>>())) + .Returns(Task.FromResult(new PlexServerContent())); + + await _subject.MovieLoop(new PlexServers(), content, contentToAdd, contentProcessed); + + Assert.That(contentToAdd, Is.Empty); + } + + [Test] + public async Task SyncsMovieWithGuidFromInitalMetadata() + { + var content = new Mediacontainer + { + Metadata = new[] + { + new Metadata + { + title = "test1", + year = 2021, + type = "movie", + Guid = new List + { + new PlexGuids + { + Id = "imdb://tt0322259" + } + }, + ratingKey = 1 + }, + } + }; + var contentToAdd = new HashSet(); + var contentProcessed = new Dictionary(); + + await _subject.MovieLoop(new PlexServers(), content, contentToAdd, contentProcessed); + + var first = contentToAdd.First(); + Assert.That(first.ImdbId, Is.EqualTo("tt0322259")); + _mocker.Verify(x => x.GetMetadata(It.IsAny(), It.IsAny(),It.IsAny()), Times.Never); + } + + [Test] + public async Task SyncsMovieWithGuidFromCallToApi() + { + var content = new Mediacontainer + { + Metadata = new[] + { + new Metadata + { + ratingKey = 11, + title = "test1", + year = 2021, + type = "movie", + }, + } + }; + var contentToAdd = new HashSet(); + var contentProcessed = new Dictionary(); + _mocker.Setup(x => x.GetMetadata(It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(Task.FromResult(new PlexMetadata + { + MediaContainer = new Mediacontainer + { + Metadata = new[] + { + new Metadata + { + ratingKey = 11, + title = "test1", + year = 2021, + type = "movie", + Guid = new List + { + new PlexGuids + { + Id = "imdb://tt0322259" + } + }, + } + } + } + })); + + await _subject.MovieLoop(new PlexServers { Ip = "http://test.com/", Port = 80}, content, contentToAdd, contentProcessed); + + var first = contentToAdd.First(); + Assert.That(first.ImdbId, Is.EqualTo("tt0322259")); + + _mocker.Verify(x => x.GetMetadata(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + } + } +} diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs index 0c210668c..3289c5a24 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs @@ -262,100 +262,122 @@ namespace Ombi.Schedule.Jobs.Plex } if (content.viewGroup.Equals(PlexMediaType.Movie.ToString(), StringComparison.InvariantCultureIgnoreCase)) { - Logger.LogDebug("Processing Movies"); - foreach (var movie in content?.Metadata ?? new Metadata[] { }) + await MovieLoop(servers, content, contentToAdd, contentProcessed); + } + if (contentToAdd.Count > 500) + { + await Repo.AddRange(contentToAdd); + foreach (var c in contentToAdd) { - // Let's check if we have this movie + contentProcessed.Add(c.Id, c.Key); + } + contentToAdd.Clear(); + } + } - try - { - var existing = await Repo.GetFirstContentByCustom(x => x.Title == movie.title - && x.ReleaseYear == movie.year.ToString() - && x.Type == PlexMediaTypeEntity.Movie); - // The rating key keeps changing - //var existing = await Repo.GetByKey(movie.ratingKey); - if (existing != null) - { - Logger.LogDebug("We already have movie {0}", movie.title); - continue; - } + if (contentToAdd.Any()) + { + await Repo.AddRange(contentToAdd); + foreach (var c in contentToAdd) + { + contentProcessed.Add(c.Id, c.Key); + } + } - var hasSameKey = await Repo.GetByKey(movie.ratingKey); - if (hasSameKey != null) - { - await Repo.Delete(hasSameKey); - } + retVal.Content = contentProcessed.Values; + retVal.Episodes = episodesProcessed; + return retVal; + } - Logger.LogDebug("Adding movie {0}", movie.title); - var guids = new List(); - if (!movie.Guid.Any()) - { - var metaData = await PlexApi.GetMetadata(servers.PlexAuthToken, servers.FullUri, - movie.ratingKey); + public async Task MovieLoop(PlexServers servers, Mediacontainer content, HashSet contentToAdd, + Dictionary contentProcessed) + { + Logger.LogDebug("Processing Movies"); + foreach (var movie in content?.Metadata ?? new Metadata[] { }) + { + // Let's check if we have this movie - var meta = metaData.MediaContainer.Metadata.FirstOrDefault(); - guids.Add(meta.guid); - if (meta.Guid != null) - { - foreach (var g in meta.Guid) - { - guids.Add(g.Id); - } - } - } - else - { - // Currently a Plex Pass feature only - foreach (var g in movie.Guid) - { - guids.Add(g.Id); - } - } + try + { + var existing = await Repo.GetFirstContentByCustom(x => x.Title == movie.title + && x.ReleaseYear == movie.year.ToString() + && x.Type == PlexMediaTypeEntity.Movie); + // The rating key keeps changing + //var existing = await Repo.GetByKey(movie.ratingKey); + if (existing != null) + { + Logger.LogDebug("We already have movie {0}", movie.title); + continue; + } - var providerIds = PlexHelper.GetProviderIdsFromMetadata(guids.ToArray()); + var hasSameKey = await Repo.GetByKey(movie.ratingKey); + if (hasSameKey != null) + { + await Repo.Delete(hasSameKey); + } - var item = new PlexServerContent - { - AddedAt = DateTime.Now, - Key = movie.ratingKey, - ReleaseYear = movie.year.ToString(), - Type = PlexMediaTypeEntity.Movie, - Title = movie.title, - Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, movie.ratingKey), - Seasons = new List(), - Quality = movie.Media?.FirstOrDefault()?.videoResolution ?? string.Empty - }; - if (providerIds.ImdbId.HasValue()) - { - item.ImdbId = providerIds.ImdbId; - } - if (providerIds.TheMovieDb.HasValue()) - { - item.TheMovieDbId = providerIds.TheMovieDb; - } - if (providerIds.TheTvDb.HasValue()) + Logger.LogDebug("Adding movie {0}", movie.title); + var guids = new List(); + if (!movie.Guid.Any()) + { + var metaData = await PlexApi.GetMetadata(servers.PlexAuthToken, servers.FullUri, + movie.ratingKey); + + var meta = metaData.MediaContainer.Metadata.FirstOrDefault(); + guids.Add(meta.guid); + if (meta.Guid != null) + { + foreach (var g in meta.Guid) { - item.TvDbId = providerIds.TheTvDb; + guids.Add(g.Id); } - contentToAdd.Add(item); } - catch (Exception e) + } + else + { + // Currently a Plex Pass feature only + foreach (var g in movie.Guid) { - Logger.LogError(LoggingEvents.PlexContentCacher, e, "Exception when adding new Movie {0}", - movie.title); + guids.Add(g.Id); } + } - if (contentToAdd.Count > 500) - { - await Repo.AddRange(contentToAdd); - foreach (var c in contentToAdd) - { - contentProcessed.Add(c.Id, c.Key); - } - contentToAdd.Clear(); - } + var providerIds = PlexHelper.GetProviderIdsFromMetadata(guids.ToArray()); + + var item = new PlexServerContent + { + AddedAt = DateTime.Now, + Key = movie.ratingKey, + ReleaseYear = movie.year.ToString(), + Type = PlexMediaTypeEntity.Movie, + Title = movie.title, + Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, movie.ratingKey), + Seasons = new List(), + Quality = movie.Media?.FirstOrDefault()?.videoResolution ?? string.Empty + }; + if (providerIds.ImdbId.HasValue()) + { + item.ImdbId = providerIds.ImdbId; + } + + if (providerIds.TheMovieDb.HasValue()) + { + item.TheMovieDbId = providerIds.TheMovieDb; } + + if (providerIds.TheTvDb.HasValue()) + { + item.TvDbId = providerIds.TheTvDb; + } + + contentToAdd.Add(item); + } + catch (Exception e) + { + Logger.LogError(LoggingEvents.PlexContentCacher, e, "Exception when adding new Movie {0}", + movie.title); } + if (contentToAdd.Count > 500) { await Repo.AddRange(contentToAdd); @@ -363,22 +385,10 @@ namespace Ombi.Schedule.Jobs.Plex { contentProcessed.Add(c.Id, c.Key); } - contentToAdd.Clear(); - } - } - if (contentToAdd.Any()) - { - await Repo.AddRange(contentToAdd); - foreach (var c in contentToAdd) - { - contentProcessed.Add(c.Id, c.Key); + contentToAdd.Clear(); } } - - retVal.Content = contentProcessed.Values; - retVal.Episodes = episodesProcessed; - return retVal; } private async Task ProcessTvShow(PlexServers servers, Metadata show, HashSet contentToAdd, Dictionary contentProcessed)