diff --git a/src/NzbDrone.Core.Test/Extras/Metadata/Consumers/Kometa/FindMetadataFileFixture.cs b/src/NzbDrone.Core.Test/Extras/Metadata/Consumers/Kometa/FindMetadataFileFixture.cs new file mode 100644 index 0000000000..7a9a8608c0 --- /dev/null +++ b/src/NzbDrone.Core.Test/Extras/Metadata/Consumers/Kometa/FindMetadataFileFixture.cs @@ -0,0 +1,59 @@ +using System.IO; +using FizzWare.NBuilder; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.Extras.Metadata; +using NzbDrone.Core.Extras.Metadata.Consumers.Kometa; +using NzbDrone.Core.Movies; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Test.Common; + +namespace NzbDrone.Core.Test.Extras.Metadata.Consumers.Kometa +{ + [TestFixture] + public class FindMetadataFileFixture : CoreTest + { + private Movie _movie; + + [SetUp] + public void Setup() + { + _movie = Builder.CreateNew() + .With(s => s.Path = @"C:\Test\Movies\Movie.Title.2024".AsOsAgnostic()) + .Build(); + } + + [Test] + public void should_return_null_if_filename_is_not_handled() + { + var path = Path.Combine(_movie.Path, "file.jpg"); + + Subject.FindMetadataFile(_movie, path).Should().BeNull(); + } + + [TestCase(".jpg")] + public void should_return_null_if_not_valid_file_for_movie(string extension) + { + var path = Path.Combine(_movie.Path, "movie.title.2024" + extension); + + Subject.FindMetadataFile(_movie, path).Should().BeNull(); + } + + [Test] + public void should_not_return_metadata_if_image_file_is_a_thumb() + { + var path = Path.Combine(_movie.Path, "movie.title.2024-thumb.jpg"); + + Subject.FindMetadataFile(_movie, path).Should().BeNull(); + } + + [TestCase("poster.jpg")] + [TestCase("background.jpg")] + public void should_return_movie_image_for_images_in_movie_folder(string filename) + { + var path = Path.Combine(_movie.Path, filename); + + Subject.FindMetadataFile(_movie, path).Type.Should().Be(MetadataType.MovieImage); + } + } +} diff --git a/src/NzbDrone.Core/Extras/Metadata/Consumers/Kometa/KometaMetadata.cs b/src/NzbDrone.Core/Extras/Metadata/Consumers/Kometa/KometaMetadata.cs new file mode 100644 index 0000000000..5749d45292 --- /dev/null +++ b/src/NzbDrone.Core/Extras/Metadata/Consumers/Kometa/KometaMetadata.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.Extras.Metadata.Files; +using NzbDrone.Core.MediaCover; +using NzbDrone.Core.MediaFiles; +using NzbDrone.Core.Movies; + +namespace NzbDrone.Core.Extras.Metadata.Consumers.Kometa +{ + public class KometaMetadata : MetadataBase + { + private static readonly Regex MovieImagesRegex = new (@"^(?:poster|background)\.(?:png|jpe?g)$", RegexOptions.Compiled | RegexOptions.IgnoreCase); + + private readonly IMapCoversToLocal _mediaCoverService; + + public override string Name => "Kometa"; + + public KometaMetadata(IMapCoversToLocal mediaCoverService) + { + _mediaCoverService = mediaCoverService; + } + + public override MetadataFile FindMetadataFile(Movie movie, string path) + { + var filename = Path.GetFileName(path); + + if (filename == null) + { + return null; + } + + var metadata = new MetadataFile + { + MovieId = movie.Id, + Consumer = GetType().Name, + RelativePath = movie.Path.GetRelativePath(path) + }; + + if (MovieImagesRegex.IsMatch(filename)) + { + metadata.Type = MetadataType.MovieImage; + return metadata; + } + + return null; + } + + public override MetadataFileResult MovieMetadata(Movie movie, MovieFile movieFile) + { + return null; + } + + public override List MovieImages(Movie movie) + { + if (!Settings.MovieImages) + { + return new List(); + } + + return ProcessMovieImages(movie).ToList(); + } + + private IEnumerable ProcessMovieImages(Movie movie) + { + foreach (var image in movie.MovieMetadata.Value.Images.Where(i => i.CoverType is MediaCoverTypes.Poster or MediaCoverTypes.Fanart)) + { + var source = _mediaCoverService.GetCoverPath(movie.Id, image.CoverType); + + var filename = image.CoverType switch + { + MediaCoverTypes.Poster => "poster", + MediaCoverTypes.Fanart => "background", + _ => throw new ArgumentOutOfRangeException($"{image.CoverType} is not supported") + }; + + var destination = filename + Path.GetExtension(source); + + yield return new ImageFileResult(destination, source); + } + } + } +} diff --git a/src/NzbDrone.Core/Extras/Metadata/Consumers/Kometa/KometaMetadataSettings.cs b/src/NzbDrone.Core/Extras/Metadata/Consumers/Kometa/KometaMetadataSettings.cs new file mode 100644 index 0000000000..6eae8c23a7 --- /dev/null +++ b/src/NzbDrone.Core/Extras/Metadata/Consumers/Kometa/KometaMetadataSettings.cs @@ -0,0 +1,29 @@ +using FluentValidation; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.ThingiProvider; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Extras.Metadata.Consumers.Kometa +{ + public class KometaSettingsValidator : AbstractValidator + { + } + + public class KometaMetadataSettings : IProviderConfig + { + private static readonly KometaSettingsValidator Validator = new (); + + public KometaMetadataSettings() + { + MovieImages = true; + } + + [FieldDefinition(0, Label = "MetadataSettingsMovieImages", Type = FieldType.Checkbox, Section = MetadataSectionType.Image, HelpText = "poster.jpg, background.jpg")] + public bool MovieImages { get; set; } + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +}