浏览代码

Add nfo thumb tag support

David 4 年之前
父节点
当前提交
16694b0cfc
共有 25 个文件被更改,包括 266 次插入41 次删除
  1. 2 0
      Emby.Server.Implementations/ApplicationHost.cs
  2. 8 4
      MediaBrowser.Controller/Providers/MetadataResult.cs
  3. 6 0
      MediaBrowser.Providers/Manager/MetadataService.cs
  4. 77 1
      MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
  5. 4 2
      MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs
  6. 4 2
      MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs
  7. 4 2
      MediaBrowser.XbmcMetadata/Parsers/SeasonNfoParser.cs
  8. 4 2
      MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs
  9. 6 2
      MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs
  10. 6 2
      MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs
  11. 7 2
      MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs
  12. 6 2
      MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs
  13. 4 2
      MediaBrowser.XbmcMetadata/Providers/MovieNfoProvider.cs
  14. 4 2
      MediaBrowser.XbmcMetadata/Providers/MusicVideoNfoProvider.cs
  15. 6 2
      MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs
  16. 6 2
      MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs
  17. 4 2
      MediaBrowser.XbmcMetadata/Providers/VideoNfoProvider.cs
  18. 9 2
      tests/Jellyfin.XbmcMetadata.Tests/Parsers/EpisodeNfoProviderTests.cs
  19. 63 1
      tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs
  20. 8 3
      tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicAlbumNfoProviderTests.cs
  21. 8 1
      tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicArtistNfoParserTests.cs
  22. 8 1
      tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicVideoNfoParserTests.cs
  23. 8 1
      tests/Jellyfin.XbmcMetadata.Tests/Parsers/SeasonNfoProviderTests.cs
  24. 2 1
      tests/Jellyfin.XbmcMetadata.Tests/Parsers/SeriesNfoParserTests.cs
  25. 2 0
      tests/Jellyfin.XbmcMetadata.Tests/Test Data/Justice League.nfo

+ 2 - 0
Emby.Server.Implementations/ApplicationHost.cs

@@ -682,6 +682,8 @@ namespace Emby.Server.Implementations
             ServiceCollection.AddScoped<MediaInfoHelper>();
             ServiceCollection.AddScoped<AudioHelper>();
             ServiceCollection.AddScoped<DynamicHlsHelper>();
+
+            ServiceCollection.AddSingleton<IDirectoryService, DirectoryService>();
         }
 
         /// <summary>

+ 8 - 4
MediaBrowser.Controller/Providers/MetadataResult.cs

@@ -4,21 +4,25 @@ using System;
 using System.Collections.Generic;
 using System.Globalization;
 using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Entities;
 
 namespace MediaBrowser.Controller.Providers
 {
     public class MetadataResult<T>
     {
-        public List<LocalImageInfo> Images { get; set; }
-
-        public List<UserItemData> UserDataList { get; set; }
-
         public MetadataResult()
         {
             Images = new List<LocalImageInfo>();
+            RemoteImages = new List<(string url, ImageType type)>();
             ResultLanguage = "en";
         }
 
+        public List<LocalImageInfo> Images { get; set; }
+
+        public List<(string url, ImageType type)> RemoteImages { get; set; }
+
+        public List<UserItemData> UserDataList { get; set; }
+
         public List<PersonInfo> People { get; set; }
 
         public bool HasMetadata { get; set; }

+ 6 - 0
MediaBrowser.Providers/Manager/MetadataService.cs

@@ -706,6 +706,12 @@ namespace MediaBrowser.Providers.Manager
 
                     if (localItem.HasMetadata)
                     {
+                        foreach (var remoteImage in localItem.RemoteImages)
+                        {
+                            await ProviderManager.SaveImage(item, remoteImage.url, remoteImage.type, null, cancellationToken).ConfigureAwait(false);
+                            refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.ImageUpdate;
+                        }
+
                         if (imageService.MergeImages(item, localItem.Images))
                         {
                             refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.ImageUpdate;

+ 77 - 1
MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs

@@ -27,6 +27,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
         private readonly IConfigurationManager _config;
         private readonly IUserManager _userManager;
         private readonly IUserDataManager _userDataManager;
+        private readonly IDirectoryService _directoryService;
         private Dictionary<string, string> _validProviderIds;
 
         /// <summary>
@@ -37,12 +38,14 @@ namespace MediaBrowser.XbmcMetadata.Parsers
         /// <param name="providerManager">Instance of the <see cref="IProviderManager"/> interface.</param>
         /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
         /// <param name="userDataManager">Instance of the <see cref="IUserDataManager"/> interface.</param>
+        /// <param name="directoryService">Instance of the <see cref="IDirectoryService"/> interface.</param>
         public BaseNfoParser(
             ILogger logger,
             IConfigurationManager config,
             IProviderManager providerManager,
             IUserManager userManager,
-            IUserDataManager userDataManager)
+            IUserDataManager userDataManager,
+            IDirectoryService directoryService)
         {
             Logger = logger;
             _config = config;
@@ -50,6 +53,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
             _validProviderIds = new Dictionary<string, string>();
             _userManager = userManager;
             _userDataManager = userDataManager;
+            _directoryService = directoryService;
         }
 
         protected CultureInfo UsCulture { get; } = new CultureInfo("en-US");
@@ -785,6 +789,78 @@ namespace MediaBrowser.XbmcMetadata.Parsers
                         break;
                     }
 
+                case "thumb":
+                    {
+                        var artType = reader.GetAttribute("aspect");
+                        var val = reader.ReadElementContentAsString();
+
+                        // skip:
+                        // - empty aspect tag
+                        // - empty uri
+                        // - tag containing '.' because we can't set images for seasons, episodes or movie sets within series or movies
+                        if (string.IsNullOrEmpty(artType) || string.IsNullOrEmpty(val) || artType.Contains('.', StringComparison.Ordinal))
+                        {
+                            break;
+                        }
+
+                        ImageType imageType = artType switch
+                        {
+                            "banner" => ImageType.Banner,
+                            "clearlogo" => ImageType.Logo,
+                            "discart" => ImageType.Disc,
+                            "landscape" => ImageType.Thumb,
+                            "clearart" => ImageType.Art,
+                            // unknown type (including "poster") --> primary
+                            _ => ImageType.Primary,
+                        };
+
+                        Uri uri;
+                        try
+                        {
+                            uri = new Uri(val);
+                        }
+                        catch (UriFormatException ex)
+                        {
+                            Logger.LogError(ex, "Image location {Path} specified in nfo file for {ItemName} is not a valid URL or file path.", val, item.Name);
+                            break;
+                        }
+
+                        if (uri.IsFile)
+                        {
+                            // only allow one item of each type
+                            if (itemResult.Images.Any(x => x.Type == imageType))
+                            {
+                                break;
+                            }
+
+                            var fileSystemMetadata = _directoryService.GetFile(val);
+                            // non existing file returns null
+                            if (fileSystemMetadata == null || !fileSystemMetadata.Exists)
+                            {
+                                Logger.LogWarning("Artwork file {Path} specified in nfo file for {ItemName} does not exist.", uri, item.Name);
+                                break;
+                            }
+
+                            itemResult.Images.Add(new LocalImageInfo()
+                            {
+                                FileInfo = fileSystemMetadata,
+                                Type = imageType
+                            });
+                        }
+                        else
+                        {
+                            // only allow one item of each type
+                            if (itemResult.RemoteImages.Any(x => x.type == imageType))
+                            {
+                                break;
+                            }
+
+                            itemResult.RemoteImages.Add((uri.ToString(), imageType));
+                        }
+
+                        break;
+                    }
+
                 default:
                     string readerName = reader.Name;
                     if (_validProviderIds.TryGetValue(readerName, out string? providerIdValue))

+ 4 - 2
MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs

@@ -25,13 +25,15 @@ namespace MediaBrowser.XbmcMetadata.Parsers
         /// <param name="providerManager">Instance of the <see cref="IProviderManager"/> interface.</param>
         /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
         /// <param name="userDataManager">Instance of the <see cref="IUserDataManager"/> interface.</param>
+        /// <param name="directoryService">Instance of the <see cref="IDirectoryService"/> interface.</param>
         public EpisodeNfoParser(
             ILogger logger,
             IConfigurationManager config,
             IProviderManager providerManager,
             IUserManager userManager,
-            IUserDataManager userDataManager)
-            : base(logger, config, providerManager, userManager, userDataManager)
+            IUserDataManager userDataManager,
+            IDirectoryService directoryService)
+            : base(logger, config, providerManager, userManager, userDataManager, directoryService)
         {
         }
 

+ 4 - 2
MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs

@@ -25,13 +25,15 @@ namespace MediaBrowser.XbmcMetadata.Parsers
         /// <param name="providerManager">Instance of the <see cref="IProviderManager"/> interface.</param>
         /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
         /// <param name="userDataManager">Instance of the <see cref="IUserDataManager"/> interface.</param>
+        /// <param name="directoryService">Instance of the <see cref="DirectoryService"/> interface.</param>
         public MovieNfoParser(
             ILogger logger,
             IConfigurationManager config,
             IProviderManager providerManager,
             IUserManager userManager,
-            IUserDataManager userDataManager)
-            : base(logger, config, providerManager, userManager, userDataManager)
+            IUserDataManager userDataManager,
+            IDirectoryService directoryService)
+            : base(logger, config, providerManager, userManager, userDataManager, directoryService)
         {
         }
 

+ 4 - 2
MediaBrowser.XbmcMetadata/Parsers/SeasonNfoParser.cs

@@ -21,13 +21,15 @@ namespace MediaBrowser.XbmcMetadata.Parsers
         /// <param name="providerManager">Instance of the <see cref="IProviderManager"/> interface.</param>
         /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
         /// <param name="userDataManager">Instance of the <see cref="IUserDataManager"/> interface.</param>
+        /// <param name="directoryService">Instance of the <see cref="DirectoryService"/> interface.</param>
         public SeasonNfoParser(
             ILogger logger,
             IConfigurationManager config,
             IProviderManager providerManager,
             IUserManager userManager,
-            IUserDataManager userDataManager)
-            : base(logger, config, providerManager, userManager, userDataManager)
+            IUserDataManager userDataManager,
+            IDirectoryService directoryService)
+            : base(logger, config, providerManager, userManager, userDataManager, directoryService)
         {
         }
 

+ 4 - 2
MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs

@@ -22,13 +22,15 @@ namespace MediaBrowser.XbmcMetadata.Parsers
         /// <param name="providerManager">Instance of the <see cref="IProviderManager"/> interface.</param>
         /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
         /// <param name="userDataManager">Instance of the <see cref="IUserDataManager"/> interface.</param>
+        /// <param name="directoryService">Instance of the <see cref="IDirectoryService"/> interface.</param>
         public SeriesNfoParser(
             ILogger logger,
             IConfigurationManager config,
             IProviderManager providerManager,
             IUserManager userManager,
-            IUserDataManager userDataManager)
-            : base(logger, config, providerManager, userManager, userDataManager)
+            IUserDataManager userDataManager,
+            IDirectoryService directoryService)
+            : base(logger, config, providerManager, userManager, userDataManager, directoryService)
         {
         }
 

+ 6 - 2
MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs

@@ -20,6 +20,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
         private readonly IProviderManager _providerManager;
         private readonly IUserManager _userManager;
         private readonly IUserDataManager _userDataManager;
+        private readonly IDirectoryService _directoryService;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="AlbumNfoProvider"/> class.
@@ -30,13 +31,15 @@ namespace MediaBrowser.XbmcMetadata.Providers
         /// <param name="providerManager">Instance of the <see cref="IProviderManager"/> interface.</param>
         /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
         /// <param name="userDataManager">Instance of the <see cref="IUserDataManager"/> interface.</param>
+        /// <param name="directoryService">Instance of the <see cref="IDirectoryService"/> interface.</param>
         public AlbumNfoProvider(
             ILogger<AlbumNfoProvider> logger,
             IFileSystem fileSystem,
             IConfigurationManager config,
             IProviderManager providerManager,
             IUserManager userManager,
-            IUserDataManager userDataManager)
+            IUserDataManager userDataManager,
+            IDirectoryService directoryService)
             : base(fileSystem)
         {
             _logger = logger;
@@ -44,12 +47,13 @@ namespace MediaBrowser.XbmcMetadata.Providers
             _providerManager = providerManager;
             _userManager = userManager;
             _userDataManager = userDataManager;
+            _directoryService = directoryService;
         }
 
         /// <inheritdoc />
         protected override void Fetch(MetadataResult<MusicAlbum> result, string path, CancellationToken cancellationToken)
         {
-            new BaseNfoParser<MusicAlbum>(_logger, _config, _providerManager, _userManager, _userDataManager).Fetch(result, path, cancellationToken);
+            new BaseNfoParser<MusicAlbum>(_logger, _config, _providerManager, _userManager, _userDataManager, _directoryService).Fetch(result, path, cancellationToken);
         }
 
         /// <inheritdoc />

+ 6 - 2
MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs

@@ -20,6 +20,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
         private readonly IProviderManager _providerManager;
         private readonly IUserManager _userManager;
         private readonly IUserDataManager _userDataManager;
+        private readonly IDirectoryService _directoryService;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="ArtistNfoProvider"/> class.
@@ -30,13 +31,15 @@ namespace MediaBrowser.XbmcMetadata.Providers
         /// <param name="providerManager">Instance of the <see cref="IProviderManager"/> interface.</param>
         /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
         /// <param name="userDataManager">Instance of the <see cref="IUserDataManager"/> interface.</param>
+        /// <param name="directoryService">Instance of the <see cref="IDirectoryService"/> interface.</param>
         public ArtistNfoProvider(
             IFileSystem fileSystem,
             ILogger<ArtistNfoProvider> logger,
             IConfigurationManager config,
             IProviderManager providerManager,
             IUserManager userManager,
-            IUserDataManager userDataManager)
+            IUserDataManager userDataManager,
+            IDirectoryService directoryService)
             : base(fileSystem)
         {
             _logger = logger;
@@ -44,12 +47,13 @@ namespace MediaBrowser.XbmcMetadata.Providers
             _providerManager = providerManager;
             _userManager = userManager;
             _userDataManager = userDataManager;
+            _directoryService = directoryService;
         }
 
         /// <inheritdoc />
         protected override void Fetch(MetadataResult<MusicArtist> result, string path, CancellationToken cancellationToken)
         {
-            new BaseNfoParser<MusicArtist>(_logger, _config, _providerManager, _userManager, _userDataManager).Fetch(result, path, cancellationToken);
+            new BaseNfoParser<MusicArtist>(_logger, _config, _providerManager, _userManager, _userDataManager, _directoryService).Fetch(result, path, cancellationToken);
         }
 
         /// <inheritdoc />

+ 7 - 2
MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs

@@ -21,6 +21,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
         private readonly IProviderManager _providerManager;
         private readonly IUserManager _userManager;
         private readonly IUserDataManager _userDataManager;
+        private readonly IDirectoryService _directoryService;
 
         public BaseVideoNfoProvider(
             ILogger<BaseVideoNfoProvider<T>> logger,
@@ -28,7 +29,8 @@ namespace MediaBrowser.XbmcMetadata.Providers
             IConfigurationManager config,
             IProviderManager providerManager,
             IUserManager userManager,
-            IUserDataManager userDataManager)
+            IUserDataManager userDataManager,
+            IDirectoryService directoryService)
             : base(fileSystem)
         {
             _logger = logger;
@@ -36,6 +38,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
             _providerManager = providerManager;
             _userManager = userManager;
             _userDataManager = userDataManager;
+            _directoryService = directoryService;
         }
 
         /// <inheritdoc />
@@ -45,10 +48,12 @@ namespace MediaBrowser.XbmcMetadata.Providers
             {
                 Item = result.Item
             };
-            new MovieNfoParser(_logger, _config, _providerManager, _userManager, _userDataManager).Fetch(tmpItem, path, cancellationToken);
+            new MovieNfoParser(_logger, _config, _providerManager, _userManager, _userDataManager, _directoryService).Fetch(tmpItem, path, cancellationToken);
 
             result.Item = (T)tmpItem.Item;
             result.People = tmpItem.People;
+            result.Images = tmpItem.Images;
+            result.RemoteImages = tmpItem.RemoteImages;
 
             if (tmpItem.UserDataList != null)
             {

+ 6 - 2
MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs

@@ -20,6 +20,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
         private readonly IProviderManager _providerManager;
         private readonly IUserManager _userManager;
         private readonly IUserDataManager _userDataManager;
+        private readonly IDirectoryService _directoryService;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="EpisodeNfoProvider"/> class.
@@ -30,13 +31,15 @@ namespace MediaBrowser.XbmcMetadata.Providers
         /// <param name="providerManager">Instance of the <see cref="IProviderManager"/> interface.</param>
         /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
         /// <param name="userDataManager">Instance of the <see cref="IUserDataManager"/> interface.</param>
+        /// <param name="directoryService">Instance of the <see cref="IDirectoryService"/> interface.</param>
         public EpisodeNfoProvider(
             ILogger<EpisodeNfoProvider> logger,
             IFileSystem fileSystem,
             IConfigurationManager config,
             IProviderManager providerManager,
             IUserManager userManager,
-            IUserDataManager userDataManager)
+            IUserDataManager userDataManager,
+            IDirectoryService directoryService)
             : base(fileSystem)
         {
             _logger = logger;
@@ -44,12 +47,13 @@ namespace MediaBrowser.XbmcMetadata.Providers
             _providerManager = providerManager;
             _userManager = userManager;
             _userDataManager = userDataManager;
+            _directoryService = directoryService;
         }
 
         /// <inheritdoc />
         protected override void Fetch(MetadataResult<Episode> result, string path, CancellationToken cancellationToken)
         {
-            new EpisodeNfoParser(_logger, _config, _providerManager, _userManager, _userDataManager).Fetch(result, path, cancellationToken);
+            new EpisodeNfoParser(_logger, _config, _providerManager, _userManager, _userDataManager, _directoryService).Fetch(result, path, cancellationToken);
         }
 
         /// <inheritdoc />

+ 4 - 2
MediaBrowser.XbmcMetadata/Providers/MovieNfoProvider.cs

@@ -21,14 +21,16 @@ namespace MediaBrowser.XbmcMetadata.Providers
         /// <param name="providerManager">Instance of the <see cref="IProviderManager"/> interface.</param>
         /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
         /// <param name="userDataManager">Instance of the <see cref="IUserDataManager"/> interface.</param>
+        /// <param name="directoryService">Instance of the <see cref="IDirectoryService"/> interface.</param>
         public MovieNfoProvider(
             ILogger<MovieNfoProvider> logger,
             IFileSystem fileSystem,
             IConfigurationManager config,
             IProviderManager providerManager,
             IUserManager userManager,
-            IUserDataManager userDataManager)
-            : base(logger, fileSystem, config, providerManager, userManager, userDataManager)
+            IUserDataManager userDataManager,
+            IDirectoryService directoryService)
+            : base(logger, fileSystem, config, providerManager, userManager, userDataManager, directoryService)
         {
         }
     }

+ 4 - 2
MediaBrowser.XbmcMetadata/Providers/MusicVideoNfoProvider.cs

@@ -21,14 +21,16 @@ namespace MediaBrowser.XbmcMetadata.Providers
         /// <param name="providerManager">Instance of the <see cref="IProviderManager"/> interface.</param>
         /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
         /// <param name="userDataManager">Instance of the <see cref="IUserDataManager"/> interface.</param>
+        /// <param name="directoryService">Instance of the <see cref="IDirectoryService"/> interface.</param>
         public MusicVideoNfoProvider(
             ILogger<MusicVideoNfoProvider> logger,
             IFileSystem fileSystem,
             IConfigurationManager config,
             IProviderManager providerManager,
             IUserManager userManager,
-            IUserDataManager userDataManager)
-            : base(logger, fileSystem, config, providerManager, userManager, userDataManager)
+            IUserDataManager userDataManager,
+            IDirectoryService directoryService)
+            : base(logger, fileSystem, config, providerManager, userManager, userDataManager, directoryService)
         {
         }
     }

+ 6 - 2
MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs

@@ -20,6 +20,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
         private readonly IProviderManager _providerManager;
         private readonly IUserManager _userManager;
         private readonly IUserDataManager _userDataManager;
+        private readonly IDirectoryService _directoryService;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="SeasonNfoProvider"/> class.
@@ -30,13 +31,15 @@ namespace MediaBrowser.XbmcMetadata.Providers
         /// <param name="providerManager">Instance of the <see cref="IProviderManager"/> interface.</param>
         /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
         /// <param name="userDataManager">Instance of the <see cref="IUserDataManager"/> interface.</param>
+        /// <param name="directoryService">Instance of the <see cref="IDirectoryService"/> interface.</param>
         public SeasonNfoProvider(
             ILogger<SeasonNfoProvider> logger,
             IFileSystem fileSystem,
             IConfigurationManager config,
             IProviderManager providerManager,
             IUserManager userManager,
-            IUserDataManager userDataManager)
+            IUserDataManager userDataManager,
+            IDirectoryService directoryService)
             : base(fileSystem)
         {
             _logger = logger;
@@ -44,12 +47,13 @@ namespace MediaBrowser.XbmcMetadata.Providers
             _providerManager = providerManager;
             _userManager = userManager;
             _userDataManager = userDataManager;
+            _directoryService = directoryService;
         }
 
         /// <inheritdoc />
         protected override void Fetch(MetadataResult<Season> result, string path, CancellationToken cancellationToken)
         {
-            new SeasonNfoParser(_logger, _config, _providerManager, _userManager, _userDataManager).Fetch(result, path, cancellationToken);
+            new SeasonNfoParser(_logger, _config, _providerManager, _userManager, _userDataManager, _directoryService).Fetch(result, path, cancellationToken);
         }
 
         /// <inheritdoc />

+ 6 - 2
MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs

@@ -20,6 +20,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
         private readonly IProviderManager _providerManager;
         private readonly IUserManager _userManager;
         private readonly IUserDataManager _userDataManager;
+        private readonly IDirectoryService _directoryService;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="SeriesNfoProvider"/> class.
@@ -30,13 +31,15 @@ namespace MediaBrowser.XbmcMetadata.Providers
         /// <param name="providerManager">Instance of the <see cref="IProviderManager"/> interface.</param>
         /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
         /// <param name="userDataManager">Instance of the <see cref="IUserDataManager"/> interface.</param>
+        /// <param name="directoryService">Instance of the <see cref="IDirectoryService"/> interface.</param>
         public SeriesNfoProvider(
             ILogger<SeriesNfoProvider> logger,
             IFileSystem fileSystem,
             IConfigurationManager config,
             IProviderManager providerManager,
             IUserManager userManager,
-            IUserDataManager userDataManager)
+            IUserDataManager userDataManager,
+            IDirectoryService directoryService)
             : base(fileSystem)
         {
             _logger = logger;
@@ -44,12 +47,13 @@ namespace MediaBrowser.XbmcMetadata.Providers
             _providerManager = providerManager;
             _userManager = userManager;
             _userDataManager = userDataManager;
+            _directoryService = directoryService;
         }
 
         /// <inheritdoc />
         protected override void Fetch(MetadataResult<Series> result, string path, CancellationToken cancellationToken)
         {
-            new SeriesNfoParser(_logger, _config, _providerManager, _userManager, _userDataManager).Fetch(result, path, cancellationToken);
+            new SeriesNfoParser(_logger, _config, _providerManager, _userManager, _userDataManager, _directoryService).Fetch(result, path, cancellationToken);
         }
 
         /// <inheritdoc />

+ 4 - 2
MediaBrowser.XbmcMetadata/Providers/VideoNfoProvider.cs

@@ -21,14 +21,16 @@ namespace MediaBrowser.XbmcMetadata.Providers
         /// <param name="providerManager">Instance of the <see cref="IProviderManager"/> interface.</param>
         /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
         /// <param name="userDataManager">Instance of the <see cref="IUserDataManager"/> interface.</param>
+        /// <param name="directoryService">Instance of the <see cref="IDirectoryService"/> interface.</param>
         public VideoNfoProvider(
             ILogger<VideoNfoProvider> logger,
             IFileSystem fileSystem,
             IConfigurationManager config,
             IProviderManager providerManager,
             IUserManager userManager,
-            IUserDataManager userDataManager)
-            : base(logger, fileSystem, config, providerManager, userManager, userDataManager)
+            IUserDataManager userDataManager,
+            IDirectoryService directoryService)
+            : base(logger, fileSystem, config, providerManager, userManager, userDataManager, directoryService)
         {
         }
     }

+ 9 - 2
tests/Jellyfin.XbmcMetadata.Tests/Parsers/EpisodeNfoProviderTests.cs

@@ -37,8 +37,15 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
                 .Returns(new XbmcMetadataOptions());
             var user = new Mock<IUserManager>();
             var userData = new Mock<IUserDataManager>();
-
-            _parser = new EpisodeNfoParser(new NullLogger<EpisodeNfoParser>(), config.Object, providerManager.Object, user.Object, userData.Object);
+            var directoryService = new Mock<IDirectoryService>();
+
+            _parser = new EpisodeNfoParser(
+                new NullLogger<EpisodeNfoParser>(),
+                config.Object,
+                providerManager.Object,
+                user.Object,
+                userData.Object,
+                directoryService.Object);
         }
 
         [Fact]

+ 63 - 1
tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs

@@ -9,7 +9,9 @@ using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Providers;
+using MediaBrowser.Model.System;
 using MediaBrowser.Providers.Plugins.Tmdb.Movies;
 using MediaBrowser.XbmcMetadata.Parsers;
 using Microsoft.Extensions.Logging.Abstractions;
@@ -23,6 +25,7 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
         private readonly MovieNfoParser _parser;
         private readonly IUserDataManager _userDataManager;
         private readonly User _testUser;
+        private readonly FileSystemMetadata _localImageFileMetadata;
 
         public MovieNfoParserTests()
         {
@@ -52,8 +55,36 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
             userData.Setup(x => x.GetUserData(_testUser, It.IsAny<BaseItem>()))
                 .Returns(new UserItemData());
 
+            var directoryService = new Mock<IDirectoryService>();
+            if (MediaBrowser.Common.System.OperatingSystem.Id != OperatingSystemId.Windows)
+            {
+                _localImageFileMetadata = new FileSystemMetadata()
+                {
+                    Exists = true,
+                    FullName = "/media/movies/Justice League (2017).jpg"
+                };
+                directoryService.Setup(x => x.GetFile(_localImageFileMetadata.FullName))
+                    .Returns(_localImageFileMetadata);
+            }
+            else
+            {
+                _localImageFileMetadata = new FileSystemMetadata()
+                {
+                    Exists = true,
+                    FullName = "C:\\media\\movies\\Justice League (2017).jpg"
+                };
+                directoryService.Setup(x => x.GetFile(_localImageFileMetadata.FullName))
+                    .Returns(_localImageFileMetadata);
+            }
+
             _userDataManager = userData.Object;
-            _parser = new MovieNfoParser(new NullLogger<MovieNfoParser>(), configManager.Object, providerManager.Object, user.Object, userData.Object);
+            _parser = new MovieNfoParser(
+                new NullLogger<MovieNfoParser>(),
+                configManager.Object,
+                providerManager.Object,
+                user.Object,
+                userData.Object,
+                directoryService.Object);
         }
 
         [Fact]
@@ -134,6 +165,37 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
             // Movie set
             Assert.Equal("702342", item.ProviderIds[MetadataProvider.TmdbCollection.ToString()]);
             Assert.Equal("Justice League Collection", item.CollectionName);
+
+            // Images
+            Assert.Equal(6, result.RemoteImages.Count);
+
+            var posters = result.RemoteImages.Where(x => x.type == ImageType.Primary).ToList();
+            Assert.Single(posters);
+            Assert.Equal("http://image.tmdb.org/t/p/original/9rtrRGeRnL0JKtu9IMBWsmlmmZz.jpg", posters[0].url);
+
+            var logos = result.RemoteImages.Where(x => x.type == ImageType.Logo).ToList();
+            Assert.Single(logos);
+            Assert.Equal("https://assets.fanart.tv/fanart/movies/141052/hdmovielogo/justice-league-5865bf95cbadb.png", logos[0].url);
+
+            var banners = result.RemoteImages.Where(x => x.type == ImageType.Banner).ToList();
+            Assert.Single(banners);
+            Assert.Equal("https://assets.fanart.tv/fanart/movies/141052/moviebanner/justice-league-586017e95adbd.jpg", banners[0].url);
+
+            var thumbs = result.RemoteImages.Where(x => x.type == ImageType.Thumb).ToList();
+            Assert.Single(thumbs);
+            Assert.Equal("https://assets.fanart.tv/fanart/movies/141052/moviethumb/justice-league-585fb155c3743.jpg", thumbs[0].url);
+
+            var art = result.RemoteImages.Where(x => x.type == ImageType.Art).ToList();
+            Assert.Single(art);
+            Assert.Equal("https://assets.fanart.tv/fanart/movies/141052/hdmovieclearart/justice-league-5865c23193041.png", art[0].url);
+
+            var discArt = result.RemoteImages.Where(x => x.type == ImageType.Disc).ToList();
+            Assert.Single(discArt);
+            Assert.Equal("https://assets.fanart.tv/fanart/movies/141052/moviedisc/justice-league-5a3af26360617.png", discArt[0].url);
+
+            // Local Image - contains only one item depending on operating system
+            Assert.Single(result.Images);
+            Assert.Equal(_localImageFileMetadata.Name, result.Images[0].FileInfo.Name);
         }
 
         [Theory]

+ 8 - 3
tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicAlbumNfoProviderTests.cs

@@ -1,7 +1,6 @@
 #pragma warning disable CA5369
 
 using System;
-using System.Linq;
 using System.Threading;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Controller.Entities.Audio;
@@ -11,7 +10,6 @@ using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Providers;
 using MediaBrowser.Providers.Music;
-using MediaBrowser.Providers.Plugins.MusicBrainz;
 using MediaBrowser.XbmcMetadata.Parsers;
 using Microsoft.Extensions.Logging.Abstractions;
 using Moq;
@@ -38,8 +36,15 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
                 .Returns(new XbmcMetadataOptions());
             var user = new Mock<IUserManager>();
             var userData = new Mock<IUserDataManager>();
+            var directoryService = new Mock<IDirectoryService>();
 
-            _parser = new BaseNfoParser<MusicAlbum>(new NullLogger<BaseNfoParser<MusicAlbum>>(), config.Object, providerManager.Object, user.Object, userData.Object);
+            _parser = new BaseNfoParser<MusicAlbum>(
+                new NullLogger<BaseNfoParser<MusicAlbum>>(),
+                config.Object,
+                providerManager.Object,
+                user.Object,
+                userData.Object,
+                directoryService.Object);
         }
 
         [Fact]

+ 8 - 1
tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicArtistNfoParserTests.cs

@@ -35,8 +35,15 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
                 .Returns(new XbmcMetadataOptions());
             var user = new Mock<IUserManager>();
             var userData = new Mock<IUserDataManager>();
+            var directoryService = new Mock<IDirectoryService>();
 
-            _parser = new BaseNfoParser<MusicArtist>(new NullLogger<BaseNfoParser<MusicArtist>>(), config.Object, providerManager.Object, user.Object, userData.Object);
+            _parser = new BaseNfoParser<MusicArtist>(
+                new NullLogger<BaseNfoParser<MusicArtist>>(),
+                config.Object,
+                providerManager.Object,
+                user.Object,
+                userData.Object,
+                directoryService.Object);
         }
 
         [Fact]

+ 8 - 1
tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicVideoNfoParserTests.cs

@@ -30,8 +30,15 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
 
             var user = new Mock<IUserManager>();
             var userData = new Mock<IUserDataManager>();
+            var directoryService = new Mock<IDirectoryService>();
 
-            _parser = new MovieNfoParser(new NullLogger<BaseNfoParser<MusicVideo>>(), config.Object, providerManager.Object, user.Object, userData.Object);
+            _parser = new MovieNfoParser(
+                new NullLogger<BaseNfoParser<MusicVideo>>(),
+                config.Object,
+                providerManager.Object,
+                user.Object,
+                userData.Object,
+                directoryService.Object);
         }
 
         [Fact]

+ 8 - 1
tests/Jellyfin.XbmcMetadata.Tests/Parsers/SeasonNfoProviderTests.cs

@@ -31,8 +31,15 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
                 .Returns(new XbmcMetadataOptions());
             var user = new Mock<IUserManager>();
             var userData = new Mock<IUserDataManager>();
+            var directoryService = new Mock<IDirectoryService>();
 
-            _parser = new SeasonNfoParser(new NullLogger<SeasonNfoParser>(), config.Object, providerManager.Object, user.Object, userData.Object);
+            _parser = new SeasonNfoParser(
+                new NullLogger<SeasonNfoParser>(),
+                config.Object,
+                providerManager.Object,
+                user.Object,
+                userData.Object,
+                directoryService.Object);
         }
 
         [Fact]

+ 2 - 1
tests/Jellyfin.XbmcMetadata.Tests/Parsers/SeriesNfoParserTests.cs

@@ -29,8 +29,9 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
                 .Returns(new XbmcMetadataOptions());
             var user = new Mock<IUserManager>();
             var userData = new Mock<IUserDataManager>();
+            var directoryService = new Mock<IDirectoryService>();
 
-            _parser = new SeriesNfoParser(new NullLogger<SeriesNfoParser>(), config.Object, providerManager.Object, user.Object, userData.Object);
+            _parser = new SeriesNfoParser(new NullLogger<SeriesNfoParser>(), config.Object, providerManager.Object, user.Object, userData.Object, directoryService.Object);
         }
 
         [Fact]

+ 2 - 0
tests/Jellyfin.XbmcMetadata.Tests/Test Data/Justice League.nfo

@@ -59,6 +59,8 @@
     <thumb aspect="poster" preview="http://image.tmdb.org/t/p/w500/exLtrlI7JjKcfQVTccI7XdQRFMz.jpg">http://image.tmdb.org/t/p/original/exLtrlI7JjKcfQVTccI7XdQRFMz.jpg</thumb>
     <thumb aspect="poster" preview="http://image.tmdb.org/t/p/w500/paLcue01KpfQftorfjKqqD4qvlL.jpg">http://image.tmdb.org/t/p/original/paLcue01KpfQftorfjKqqD4qvlL.jpg</thumb>
     <thumb aspect="poster" preview="http://image.tmdb.org/t/p/w500/yVDIfiKIsCbdFcgLXW34bAsnQvy.jpg">http://image.tmdb.org/t/p/original/yVDIfiKIsCbdFcgLXW34bAsnQvy.jpg</thumb>
+    <thumb aspect="poster">C:\media\movies\Justice League (2017).jpg</thumb>
+    <thumb aspect="poster">/media/movies/Justice League (2017).jpg</thumb>
     <thumb aspect="clearlogo" preview="https://assets.fanart.tv/preview/movies/141052/hdmovielogo/justice-league-5865bf95cbadb.png">https://assets.fanart.tv/fanart/movies/141052/hdmovielogo/justice-league-5865bf95cbadb.png</thumb>
     <thumb aspect="clearlogo" preview="https://assets.fanart.tv/preview/movies/141052/hdmovielogo/justice-league-585e9ca3bcf6a.png">https://assets.fanart.tv/fanart/movies/141052/hdmovielogo/justice-league-585e9ca3bcf6a.png</thumb>
     <thumb aspect="clearlogo" preview="https://assets.fanart.tv/preview/movies/141052/hdmovielogo/justice-league-57b476a831d74.png">https://assets.fanart.tv/fanart/movies/141052/hdmovielogo/justice-league-57b476a831d74.png</thumb>