2
0
Эх сурвалжийг харах

Merge branch 'dev' into Video-Playlist-Controls

T. Adams 10 жил өмнө
parent
commit
eff23da373
100 өөрчлөгдсөн 1149 нэмэгдсэн , 805 устгасан
  1. 1 1
      MediaBrowser.Api/ItemRefreshService.cs
  2. 18 5
      MediaBrowser.Api/ItemUpdateService.cs
  3. 4 6
      MediaBrowser.Api/Music/AlbumsService.cs
  4. 3 8
      MediaBrowser.Api/Playback/TranscodingThrottler.cs
  5. 1 1
      MediaBrowser.Api/SearchService.cs
  6. 1 0
      MediaBrowser.Api/StartupWizardService.cs
  7. 4 2
      MediaBrowser.Api/Subtitles/SubtitleService.cs
  8. 47 30
      MediaBrowser.Api/UserLibrary/ItemsService.cs
  9. 0 10
      MediaBrowser.Controller/Entities/Audio/Audio.cs
  10. 16 4
      MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs
  11. 0 10
      MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
  12. 1 1
      MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
  13. 2 1
      MediaBrowser.Controller/Entities/BaseItem.cs
  14. 2 2
      MediaBrowser.Controller/Entities/InternalItemsQuery.cs
  15. 0 10
      MediaBrowser.Controller/Entities/MusicVideo.cs
  16. 4 2
      MediaBrowser.Controller/Entities/UserView.cs
  17. 30 15
      MediaBrowser.Controller/Entities/UserViewBuilder.cs
  18. 5 3
      MediaBrowser.Controller/Library/ILibraryManager.cs
  19. 2 4
      MediaBrowser.Controller/Library/IUserViewManager.cs
  20. 46 0
      MediaBrowser.Controller/MediaBrowser.Controller.csproj
  21. 1 1
      MediaBrowser.Controller/Playlists/Playlist.cs
  22. 28 0
      MediaBrowser.Controller/Providers/AlbumInfo.cs
  23. 14 0
      MediaBrowser.Controller/Providers/ArtistInfo.cs
  24. 7 0
      MediaBrowser.Controller/Providers/BookInfo.cs
  25. 7 0
      MediaBrowser.Controller/Providers/BoxSetInfo.cs
  26. 11 0
      MediaBrowser.Controller/Providers/ChannelItemLookupInfo.cs
  27. 0 10
      MediaBrowser.Controller/Providers/DirectoryService.cs
  28. 10 0
      MediaBrowser.Controller/Providers/DynamicImageInfo.cs
  29. 35 0
      MediaBrowser.Controller/Providers/DynamicImageResponse.cs
  30. 12 0
      MediaBrowser.Controller/Providers/EpisodeIdentity.cs
  31. 34 0
      MediaBrowser.Controller/Providers/EpisodeInfo.cs
  32. 15 0
      MediaBrowser.Controller/Providers/ExtraInfo.cs
  33. 9 0
      MediaBrowser.Controller/Providers/ExtraSource.cs
  34. 11 0
      MediaBrowser.Controller/Providers/GameInfo.cs
  35. 11 0
      MediaBrowser.Controller/Providers/GameSystemInfo.cs
  36. 0 5
      MediaBrowser.Controller/Providers/ICustomMetadataProvider.cs
  37. 15 0
      MediaBrowser.Controller/Providers/IDirectoryService.cs
  38. 27 0
      MediaBrowser.Controller/Providers/IDynamicImageProvider.cs
  39. 0 19
      MediaBrowser.Controller/Providers/IExtrasProvider.cs
  40. 0 12
      MediaBrowser.Controller/Providers/IHasChangeMonitor.cs
  41. 14 0
      MediaBrowser.Controller/Providers/IHasIdentities.cs
  42. 16 0
      MediaBrowser.Controller/Providers/IHasItemChangeMonitor.cs
  43. 8 0
      MediaBrowser.Controller/Providers/IHasLookupInfo.cs
  44. 7 0
      MediaBrowser.Controller/Providers/IHasOrder.cs
  45. 20 0
      MediaBrowser.Controller/Providers/IImageFileSaver.cs
  46. 1 19
      MediaBrowser.Controller/Providers/IImageSaver.cs
  47. 7 0
      MediaBrowser.Controller/Providers/IItemIdentity.cs
  48. 4 0
      MediaBrowser.Controller/Providers/IItemIdentityConverter.cs
  49. 4 0
      MediaBrowser.Controller/Providers/IItemIdentityProvider.cs
  50. 10 0
      MediaBrowser.Controller/Providers/ILocalImageFileProvider.cs
  51. 1 74
      MediaBrowser.Controller/Providers/ILocalImageProvider.cs
  52. 0 27
      MediaBrowser.Controller/Providers/ILocalMetadataProvider.cs
  53. 0 11
      MediaBrowser.Controller/Providers/IMetadataProvider.cs
  54. 7 0
      MediaBrowser.Controller/Providers/IPreRefreshProvider.cs
  55. 8 0
      MediaBrowser.Controller/Providers/IProviderManager.cs
  56. 1 30
      MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs
  57. 17 0
      MediaBrowser.Controller/Providers/IRemoteSearchProvider.cs
  58. 0 11
      MediaBrowser.Controller/Providers/ISeriesOrderManager.cs
  59. 10 0
      MediaBrowser.Controller/Providers/ISeriesOrderProvider.cs
  60. 25 0
      MediaBrowser.Controller/Providers/ImageRefreshMode.cs
  61. 29 0
      MediaBrowser.Controller/Providers/ImageRefreshOptions.cs
  62. 1 20
      MediaBrowser.Controller/Providers/ItemIdentities.cs
  63. 9 0
      MediaBrowser.Controller/Providers/ItemInfo.cs
  64. 1 205
      MediaBrowser.Controller/Providers/ItemLookupInfo.cs
  65. 11 0
      MediaBrowser.Controller/Providers/LocalImageInfo.cs
  66. 24 0
      MediaBrowser.Controller/Providers/LocalMetadataResult.cs
  67. 25 0
      MediaBrowser.Controller/Providers/MetadataRefreshMode.cs
  68. 1 73
      MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs
  69. 8 0
      MediaBrowser.Controller/Providers/MetadataResult.cs
  70. 7 0
      MediaBrowser.Controller/Providers/MovieInfo.cs
  71. 7 0
      MediaBrowser.Controller/Providers/MusicVideoInfo.cs
  72. 7 0
      MediaBrowser.Controller/Providers/PersonLookupInfo.cs
  73. 19 0
      MediaBrowser.Controller/Providers/RemoteSearchQuery.cs
  74. 11 0
      MediaBrowser.Controller/Providers/SeasonIdentity.cs
  75. 32 0
      MediaBrowser.Controller/Providers/SeasonInfo.cs
  76. 9 0
      MediaBrowser.Controller/Providers/SeriesIdentity.cs
  77. 25 0
      MediaBrowser.Controller/Providers/SeriesInfo.cs
  78. 7 0
      MediaBrowser.Controller/Providers/SeriesOrderTypes.cs
  79. 17 0
      MediaBrowser.Controller/Providers/SongInfo.cs
  80. 7 0
      MediaBrowser.Controller/Providers/TrailerInfo.cs
  81. 1 1
      MediaBrowser.Controller/Sync/IServerSyncProvider.cs
  82. 18 0
      MediaBrowser.Controller/Sync/SendFileResult.cs
  83. 3 3
      MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
  84. 3 3
      MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
  85. 4 48
      MediaBrowser.Model/ApiClient/IApiClient.cs
  86. 6 0
      MediaBrowser.Model/Configuration/ServerConfiguration.cs
  87. 12 0
      MediaBrowser.Model/Dto/BaseItemDto.cs
  88. 17 0
      MediaBrowser.Model/Dto/NameIdPair.cs
  89. 4 0
      MediaBrowser.Model/LiveTv/RecordingInfoDto.cs
  90. 1 1
      MediaBrowser.Model/MediaBrowser.Model.csproj
  91. 9 15
      MediaBrowser.Model/Querying/ItemQuery.cs
  92. 0 29
      MediaBrowser.Model/Querying/SimilarItemsByNameQuery.cs
  93. 42 29
      MediaBrowser.Providers/FolderImages/DefaultImageProvider.cs
  94. 3 3
      MediaBrowser.Providers/Manager/ItemImageProvider.cs
  95. 80 2
      MediaBrowser.Providers/Manager/ProviderManager.cs
  96. 1 1
      MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
  97. 3 1
      MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
  98. 1 1
      MediaBrowser.Server.Implementations/Collections/CollectionImageProvider.cs
  99. 50 11
      MediaBrowser.Server.Implementations/Dto/DtoService.cs
  100. 40 25
      MediaBrowser.Server.Implementations/Library/LibraryManager.cs

+ 1 - 1
MediaBrowser.Api/ItemRefreshService.cs

@@ -53,7 +53,7 @@ namespace MediaBrowser.Api
             var albums = _libraryManager.RootFolder
                                         .GetRecursiveChildren()
                                         .OfType<MusicAlbum>()
-                                        .Where(i => i.HasArtist(item.Name))
+                                        .Where(i => i.HasAnyArtist(item.Name))
                                         .ToList();
 
             var musicArtists = albums

+ 18 - 5
MediaBrowser.Api/ItemUpdateService.cs

@@ -389,20 +389,33 @@ namespace MediaBrowser.Api
                 game.PlayersSupported = request.Players;
             }
 
-            var song = item as Audio;
+            var hasAlbumArtists = item as IHasAlbumArtist;
+            if (hasAlbumArtists != null)
+            {
+                hasAlbumArtists.AlbumArtists = request
+                    .AlbumArtists
+                    .Select(i => i.Name)
+                    .ToList();
+            }
 
+            var hasArtists = item as IHasArtist;
+            if (hasArtists != null)
+            {
+                hasArtists.Artists = request
+                    .ArtistItems
+                    .Select(i => i.Name)
+                    .ToList();
+            }
+            
+            var song = item as Audio;
             if (song != null)
             {
                 song.Album = request.Album;
-                song.AlbumArtists = string.IsNullOrWhiteSpace(request.AlbumArtist) ? new List<string>() : new List<string> { request.AlbumArtist };
-                song.Artists = request.Artists.ToList();
             }
 
             var musicVideo = item as MusicVideo;
-
             if (musicVideo != null)
             {
-                musicVideo.Artists = request.Artists.ToList();
                 musicVideo.Album = request.Album;
             }
 

+ 4 - 6
MediaBrowser.Api/Music/AlbumsService.cs

@@ -77,15 +77,13 @@ namespace MediaBrowser.Api.Music
             var album1 = (MusicAlbum)item1;
             var album2 = (MusicAlbum)item2;
 
-            var artists1 = album1.GetRecursiveChildren(i => i is IHasArtist)
-                .Cast<IHasArtist>()
-                .SelectMany(i => i.AllArtists)
+            var artists1 = album1
+                .AllArtists
                 .Distinct(StringComparer.OrdinalIgnoreCase)
                 .ToList();
 
-            var artists2 = album2.GetRecursiveChildren(i => i is IHasArtist)
-                .Cast<IHasArtist>()
-                .SelectMany(i => i.AllArtists)
+            var artists2 = album2
+                .AllArtists
                 .Distinct(StringComparer.OrdinalIgnoreCase)
                 .ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
 

+ 3 - 8
MediaBrowser.Api/Playback/TranscodingThrottler.cs

@@ -25,10 +25,7 @@ namespace MediaBrowser.Api.Playback
 
         public void Start()
         {
-            if (_processManager.SupportsSuspension)
-            {
-                //_timer = new Timer(TimerCallback, null, 5000, 5000);
-            }
+            _timer = new Timer(TimerCallback, null, 5000, 5000);
         }
 
         private void TimerCallback(object state)
@@ -58,8 +55,7 @@ namespace MediaBrowser.Api.Playback
 
             try
             {
-                //_job.Process.StandardInput.WriteLine("p");
-                _processManager.SuspendProcess(_job.Process);
+                _job.Process.StandardInput.WriteLine("p");
                 _isPaused = true;
             }
             catch (Exception ex)
@@ -77,8 +73,7 @@ namespace MediaBrowser.Api.Playback
 
             try
             {
-                //_job.Process.StandardInput.WriteLine("u");
-                _processManager.ResumeProcess(_job.Process);
+                _job.Process.StandardInput.WriteLine("u");
                 _isPaused = false;
             }
             catch (Exception ex)

+ 1 - 1
MediaBrowser.Api/SearchService.cs

@@ -211,7 +211,7 @@ namespace MediaBrowser.Api
                 result.SongCount = album.Tracks.Count();
 
                 result.Artists = album.Artists.ToArray();
-                result.AlbumArtist = album.AlbumArtists.FirstOrDefault();
+                result.AlbumArtist = album.AlbumArtist;
             }
 
             var song = item as Audio;

+ 1 - 0
MediaBrowser.Api/StartupWizardService.cs

@@ -65,6 +65,7 @@ namespace MediaBrowser.Api
             _config.Configuration.MergeMetadataAndImagesByName = true;
             _config.Configuration.EnableStandaloneMetadata = true;
             _config.Configuration.EnableLibraryMetadataSubFolder = true;
+            _config.Configuration.EnableUserSpecificUserViews = true;
             _config.SaveConfiguration();
         }
 

+ 4 - 2
MediaBrowser.Api/Subtitles/SubtitleService.cs

@@ -125,13 +125,15 @@ namespace MediaBrowser.Api.Subtitles
         private readonly ISubtitleManager _subtitleManager;
         private readonly ISubtitleEncoder _subtitleEncoder;
         private readonly IMediaSourceManager _mediaSourceManager;
+        private readonly IProviderManager _providerManager;
 
-        public SubtitleService(ILibraryManager libraryManager, ISubtitleManager subtitleManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager)
+        public SubtitleService(ILibraryManager libraryManager, ISubtitleManager subtitleManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager, IProviderManager providerManager)
         {
             _libraryManager = libraryManager;
             _subtitleManager = subtitleManager;
             _subtitleEncoder = subtitleEncoder;
             _mediaSourceManager = mediaSourceManager;
+            _providerManager = providerManager;
         }
 
         public object Get(GetSubtitlePlaylist request)
@@ -256,7 +258,7 @@ namespace MediaBrowser.Api.Subtitles
                     await _subtitleManager.DownloadSubtitles(video, request.SubtitleId, CancellationToken.None)
                         .ConfigureAwait(false);
 
-                    await video.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService()), CancellationToken.None).ConfigureAwait(false);
+                    _providerManager.QueueRefresh(video.Id, new MetadataRefreshOptions());
                 }
                 catch (Exception ex)
                 {

+ 47 - 30
MediaBrowser.Api/UserLibrary/ItemsService.cs

@@ -46,9 +46,6 @@ namespace MediaBrowser.Api.UserLibrary
         [ApiMember(Name = "PersonTypes", Description = "Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         public string PersonTypes { get; set; }
 
-        [ApiMember(Name = "AllGenres", Description = "Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
-        public string AllGenres { get; set; }
-
         /// <summary>
         /// Limit results to items containing specific studios
         /// </summary>
@@ -56,6 +53,9 @@ namespace MediaBrowser.Api.UserLibrary
         [ApiMember(Name = "Studios", Description = "Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
         public string Studios { get; set; }
 
+        [ApiMember(Name = "StudioIds", Description = "Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+        public string StudioIds { get; set; }
+        
         /// <summary>
         /// Gets or sets the studios.
         /// </summary>
@@ -63,6 +63,9 @@ namespace MediaBrowser.Api.UserLibrary
         [ApiMember(Name = "Artists", Description = "Optional. If specified, results will be filtered based on artist. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
         public string Artists { get; set; }
 
+        [ApiMember(Name = "ArtistIds", Description = "Optional. If specified, results will be filtered based on artist. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+        public string ArtistIds { get; set; }
+        
         [ApiMember(Name = "Albums", Description = "Optional. If specified, results will be filtered based on album. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
         public string Albums { get; set; }
 
@@ -226,14 +229,14 @@ namespace MediaBrowser.Api.UserLibrary
         [ApiMember(Name = "CollapseBoxSetItems", Description = "Whether or not to hide items behind their boxsets.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
         public bool? CollapseBoxSetItems { get; set; }
 
-        public string[] GetAllGenres()
+        public string[] GetStudios()
         {
-            return (AllGenres ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
+            return (Studios ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
         }
 
-        public string[] GetStudios()
+        public string[] GetStudioIds()
         {
-            return (Studios ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
+            return (StudioIds ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
         }
 
         public string[] GetPersonTypes()
@@ -241,7 +244,7 @@ namespace MediaBrowser.Api.UserLibrary
             return (PersonTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
         }
 
-        public IEnumerable<VideoType> GetVideoTypes()
+        public VideoType[] GetVideoTypes()
         {
             var val = VideoTypes;
 
@@ -250,7 +253,7 @@ namespace MediaBrowser.Api.UserLibrary
                 return new VideoType[] { };
             }
 
-            return val.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(v => (VideoType)Enum.Parse(typeof(VideoType), v, true));
+            return val.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(v => (VideoType)Enum.Parse(typeof(VideoType), v, true)).ToArray();
         }
     }
 
@@ -471,8 +474,8 @@ namespace MediaBrowser.Api.UserLibrary
                 Tags = request.GetTags(),
                 OfficialRatings = request.GetOfficialRatings(),
                 Genres = request.GetGenres(),
-                AllGenres = request.GetAllGenres(),
                 Studios = request.GetStudios(),
+                StudioIds = request.GetStudioIds(),
                 Person = request.Person,
                 PersonTypes = request.GetPersonTypes(),
                 Years = request.GetYears(),
@@ -609,6 +612,8 @@ namespace MediaBrowser.Api.UserLibrary
 
         private bool ApplyAdditionalFilters(GetItems request, BaseItem i, User user, bool isPreFiltered, ILibraryManager libraryManager)
         {
+            var video = i as Video;
+            
             if (!isPreFiltered)
             {
                 var mediaTypes = request.GetMediaTypes();
@@ -656,7 +661,6 @@ namespace MediaBrowser.Api.UserLibrary
                 if (request.Is3D.HasValue)
                 {
                     var val = request.Is3D.Value;
-                    var video = i as Video;
 
                     if (video == null || val != video.Video3DFormat.HasValue)
                     {
@@ -667,7 +671,6 @@ namespace MediaBrowser.Api.UserLibrary
                 if (request.IsHD.HasValue)
                 {
                     var val = request.IsHD.Value;
-                    var video = i as Video;
 
                     if (video == null || val != video.IsHD)
                     {
@@ -809,8 +812,6 @@ namespace MediaBrowser.Api.UserLibrary
                 {
                     var val = request.HasSubtitles.Value;
 
-                    var video = i as Video;
-
                     if (video == null || val != video.HasSubtitles)
                     {
                         return false;
@@ -930,23 +931,11 @@ namespace MediaBrowser.Api.UserLibrary
                     return false;
                 }
 
-                // Apply genre filter
-                var allGenres = request.GetAllGenres();
-                if (allGenres.Length > 0 && !allGenres.All(v => i.Genres.Contains(v, StringComparer.OrdinalIgnoreCase)))
-                {
-                    return false;
-                }
-
                 // Filter by VideoType
-                if (!string.IsNullOrEmpty(request.VideoTypes))
+                var videoTypes = request.GetVideoTypes();
+                if (videoTypes.Length > 0 && (video == null || !videoTypes.Contains(video.VideoType)))
                 {
-                    var types = request.VideoTypes.Split(',');
-
-                    var video = i as Video;
-                    if (video == null || !types.Contains(video.VideoType.ToString(), StringComparer.OrdinalIgnoreCase))
-                    {
-                        return false;
-                    }
+                    return false;
                 }
 
                 var imageTypes = request.GetImageTypes().ToList();
@@ -965,6 +954,17 @@ namespace MediaBrowser.Api.UserLibrary
                     return false;
                 }
 
+                // Apply studio filter
+                var studioIds = request.GetStudioIds();
+                if (studioIds.Length > 0 && !studioIds.Any(id =>
+                {
+                    var studioItem = libraryManager.GetItemById(id);
+                    return studioItem != null && i.Studios.Contains(studioItem.Name, StringComparer.OrdinalIgnoreCase);
+                }))
+                {
+                    return false;
+                }
+
                 // Apply year filter
                 var years = request.GetYears();
                 if (years.Length > 0 && !(i.ProductionYear.HasValue && years.Contains(i.ProductionYear.Value)))
@@ -1030,6 +1030,23 @@ namespace MediaBrowser.Api.UserLibrary
                 }
             }
 
+            // Artists
+            if (!string.IsNullOrEmpty(request.ArtistIds))
+            {
+                var artistIds = request.ArtistIds.Split('|');
+
+                var audio = i as IHasArtist;
+
+                if (!(audio != null && artistIds.Any(id =>
+                {
+                    var artistItem = libraryManager.GetItemById(id);
+                    return artistItem != null && audio.HasAnyArtist(artistItem.Name);
+                })))
+                {
+                    return false;
+                }
+            }
+
             // Artists
             if (!string.IsNullOrEmpty(request.Artists))
             {
@@ -1037,7 +1054,7 @@ namespace MediaBrowser.Api.UserLibrary
 
                 var audio = i as IHasArtist;
 
-                if (!(audio != null && artists.Any(audio.HasArtist)))
+                if (!(audio != null && artists.Any(audio.HasAnyArtist)))
                 {
                     return false;
                 }

+ 0 - 10
MediaBrowser.Controller/Entities/Audio/Audio.cs

@@ -171,16 +171,6 @@ namespace MediaBrowser.Controller.Entities.Audio
                     + (IndexNumber != null ? IndexNumber.Value.ToString("0000 - ") : "") + Name;
         }
 
-        /// <summary>
-        /// Determines whether the specified name has artist.
-        /// </summary>
-        /// <param name="name">The name.</param>
-        /// <returns><c>true</c> if the specified name has artist; otherwise, <c>false</c>.</returns>
-        public bool HasArtist(string name)
-        {
-            return AllArtists.Contains(name, StringComparer.OrdinalIgnoreCase);
-        }
-
         /// <summary>
         /// Gets the user data key.
         /// </summary>

+ 16 - 4
MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs

@@ -1,4 +1,6 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
+using System.Linq;
 
 namespace MediaBrowser.Controller.Entities.Audio
 {
@@ -9,10 +11,20 @@ namespace MediaBrowser.Controller.Entities.Audio
 
     public interface IHasArtist
     {
-        bool HasArtist(string name);
-
         List<string> AllArtists { get; }
 
-        List<string> Artists { get; }
+        List<string> Artists { get; set; }
+    }
+
+    public static class HasArtistExtensions
+    {
+        public static bool HasArtist(this IHasArtist hasArtist, string artist)
+        {
+            return hasArtist.Artists.Contains(artist, StringComparer.OrdinalIgnoreCase);
+        }
+        public static bool HasAnyArtist(this IHasArtist hasArtist, string artist)
+        {
+            return hasArtist.AllArtists.Contains(artist, StringComparer.OrdinalIgnoreCase);
+        }
     }
 }

+ 0 - 10
MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs

@@ -120,16 +120,6 @@ namespace MediaBrowser.Controller.Entities.Audio
             get { return Parent as MusicArtist ?? UnknwonArtist; }
         }
 
-        /// <summary>
-        /// Determines whether the specified artist has artist.
-        /// </summary>
-        /// <param name="artist">The artist.</param>
-        /// <returns><c>true</c> if the specified artist has artist; otherwise, <c>false</c>.</returns>
-        public bool HasArtist(string artist)
-        {
-            return AllArtists.Contains(artist, StringComparer.OrdinalIgnoreCase);
-        }
-
         public List<string> Artists { get; set; }
 
         /// <summary>

+ 1 - 1
MediaBrowser.Controller/Entities/Audio/MusicArtist.cs

@@ -213,7 +213,7 @@ namespace MediaBrowser.Controller.Entities.Audio
             return i =>
             {
                 var hasArtist = i as IHasArtist;
-                return hasArtist != null && hasArtist.HasArtist(Name);
+                return hasArtist != null && hasArtist.HasAnyArtist(Name);
             };
         }
     }

+ 2 - 1
MediaBrowser.Controller/Entities/BaseItem.cs

@@ -1455,7 +1455,8 @@ namespace MediaBrowser.Controller.Entities
         /// <returns>Task.</returns>
         public virtual Task ChangedExternally()
         {
-            return RefreshMetadata(CancellationToken.None);
+            ProviderManager.QueueRefresh(Id, new MetadataRefreshOptions());
+            return Task.FromResult(true);
         }
 
         /// <summary>

+ 2 - 2
MediaBrowser.Controller/Entities/InternalItemsQuery.cs

@@ -30,7 +30,6 @@ namespace MediaBrowser.Controller.Entities
         public string[] IncludeItemTypes { get; set; }
         public string[] ExcludeItemTypes { get; set; }
         public string[] Genres { get; set; }
-        public string[] AllGenres { get; set; }
 
         public bool? IsMissing { get; set; }
         public bool? IsUnaired { get; set; }
@@ -66,6 +65,7 @@ namespace MediaBrowser.Controller.Entities
         public bool? HasParentalRating { get; set; }
 
         public string[] Studios { get; set; }
+        public string[] StudioIds { get; set; }
         public ImageType[] ImageTypes { get; set; }
         public VideoType[] VideoTypes { get; set; }
         public int[] Years { get; set; }
@@ -80,9 +80,9 @@ namespace MediaBrowser.Controller.Entities
             MediaTypes = new string[] { };
             IncludeItemTypes = new string[] { };
             ExcludeItemTypes = new string[] { };
-            AllGenres = new string[] { };
             Genres = new string[] { };
             Studios = new string[] { };
+            StudioIds = new string[] { };
             ImageTypes = new ImageType[] { };
             VideoTypes = new VideoType[] { };
             Years = new int[] { };

+ 0 - 10
MediaBrowser.Controller/Entities/MusicVideo.cs

@@ -47,16 +47,6 @@ namespace MediaBrowser.Controller.Entities
             }
         }
 
-        /// <summary>
-        /// Determines whether the specified name has artist.
-        /// </summary>
-        /// <param name="name">The name.</param>
-        /// <returns><c>true</c> if the specified name has artist; otherwise, <c>false</c>.</returns>
-        public bool HasArtist(string name)
-        {
-            return AllArtists.Contains(name, StringComparer.OrdinalIgnoreCase);
-        }
-        
         /// <summary>
         /// Gets the user data key.
         /// </summary>

+ 4 - 2
MediaBrowser.Controller/Entities/UserView.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.TV;
+using MediaBrowser.Controller.Playlists;
+using MediaBrowser.Controller.TV;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Querying;
 using System;
@@ -15,6 +16,7 @@ namespace MediaBrowser.Controller.Entities
         public Guid? UserId { get; set; }
 
         public static ITVSeriesManager TVSeriesManager;
+        public static IPlaylistManager PlaylistManager;
 
         public bool ContainsDynamicCategories(User user)
         {
@@ -30,7 +32,7 @@ namespace MediaBrowser.Controller.Entities
                 parent = LibraryManager.GetItemById(ParentId) as Folder ?? parent;
             }
 
-            return new UserViewBuilder(UserViewManager, LiveTvManager, ChannelManager, LibraryManager, Logger, UserDataManager, TVSeriesManager, CollectionManager)
+            return new UserViewBuilder(UserViewManager, LiveTvManager, ChannelManager, LibraryManager, Logger, UserDataManager, TVSeriesManager, CollectionManager, PlaylistManager)
                 .GetUserItems(parent, this, ViewType, query);
         }
 

+ 30 - 15
MediaBrowser.Controller/Entities/UserViewBuilder.cs

@@ -5,6 +5,7 @@ using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Controller.Playlists;
 using MediaBrowser.Controller.TV;
 using MediaBrowser.Model.Channels;
 using MediaBrowser.Model.Entities;
@@ -30,8 +31,9 @@ namespace MediaBrowser.Controller.Entities
         private readonly IUserDataManager _userDataManager;
         private readonly ITVSeriesManager _tvSeriesManager;
         private readonly ICollectionManager _collectionManager;
+        private readonly IPlaylistManager _playlistManager;
 
-        public UserViewBuilder(IUserViewManager userViewManager, ILiveTvManager liveTvManager, IChannelManager channelManager, ILibraryManager libraryManager, ILogger logger, IUserDataManager userDataManager, ITVSeriesManager tvSeriesManager, ICollectionManager collectionManager)
+        public UserViewBuilder(IUserViewManager userViewManager, ILiveTvManager liveTvManager, IChannelManager channelManager, ILibraryManager libraryManager, ILogger logger, IUserDataManager userDataManager, ITVSeriesManager tvSeriesManager, ICollectionManager collectionManager, IPlaylistManager playlistManager)
         {
             _userViewManager = userViewManager;
             _liveTvManager = liveTvManager;
@@ -41,6 +43,7 @@ namespace MediaBrowser.Controller.Entities
             _userDataManager = userDataManager;
             _tvSeriesManager = tvSeriesManager;
             _collectionManager = collectionManager;
+            _playlistManager = playlistManager;
         }
 
         public async Task<QueryResult<BaseItem>> GetUserItems(Folder queryParent, Folder displayParent, string viewType, InternalItemsQuery query)
@@ -115,6 +118,9 @@ namespace MediaBrowser.Controller.Entities
                 case CollectionType.Games:
                     return await GetGameView(user, queryParent, query).ConfigureAwait(false);
 
+                case CollectionType.Playlists:
+                    return await GetPlaylistsView(queryParent, user, query).ConfigureAwait(false);
+
                 case CollectionType.BoxSets:
                     return await GetBoxsetView(queryParent, user, query).ConfigureAwait(false);
 
@@ -572,6 +578,11 @@ namespace MediaBrowser.Controller.Entities
             return GetResult(items, queryParent, query);
         }
 
+        private async Task<QueryResult<BaseItem>> GetPlaylistsView(Folder parent, User user, InternalItemsQuery query)
+        {
+            return GetResult(_playlistManager.GetPlaylists(user.Id.ToString("N")), parent, query);
+        }
+
         private async Task<QueryResult<BaseItem>> GetBoxsetView(Folder parent, User user, InternalItemsQuery query)
         {
             return GetResult(GetMediaFolders(user).SelectMany(i =>
@@ -935,11 +946,6 @@ namespace MediaBrowser.Controller.Entities
                 return false;
             }
 
-            if (request.AllGenres.Length > 0)
-            {
-                return false;
-            }
-
             if (request.Genres.Length > 0)
             {
                 return false;
@@ -1050,6 +1056,11 @@ namespace MediaBrowser.Controller.Entities
                 return false;
             }
 
+            if (request.StudioIds.Length > 0)
+            {
+                return false;
+            }
+
             if (request.VideoTypes.Length > 0)
             {
                 return false;
@@ -1569,12 +1580,6 @@ namespace MediaBrowser.Controller.Entities
                 return false;
             }
 
-            // Apply genre filter
-            if (query.AllGenres.Length > 0 && !query.AllGenres.All(v => item.Genres.Contains(v, StringComparer.OrdinalIgnoreCase)))
-            {
-                return false;
-            }
-
             // Filter by VideoType
             if (query.VideoTypes.Length > 0)
             {
@@ -1596,6 +1601,16 @@ namespace MediaBrowser.Controller.Entities
                 return false;
             }
 
+            // Apply studio filter
+            if (query.StudioIds.Length > 0 && !query.StudioIds.Any(id =>
+            {
+                var studioItem = libraryManager.GetItemById(id);
+                return studioItem != null && item.Studios.Contains(studioItem.Name, StringComparer.OrdinalIgnoreCase);
+            }))
+            {
+                return false;
+            }
+
             // Apply year filter
             if (query.Years.Length > 0)
             {
@@ -1714,7 +1729,7 @@ namespace MediaBrowser.Controller.Entities
 
             var parent = user.RootFolder;
 
-            //list.Add(await GetUserView(SpecialFolder.LiveTvNowPlaying, user, "0", parent).ConfigureAwait(false));
+            //list.Add(await GetUserSubView(SpecialFolder.LiveTvNowPlaying, user, "0", parent).ConfigureAwait(false));
             list.Add(await GetUserView(SpecialFolder.LiveTvChannels, user, string.Empty, parent).ConfigureAwait(false));
             list.Add(await GetUserView(SpecialFolder.LiveTvRecordingGroups, user, string.Empty, parent).ConfigureAwait(false));
 
@@ -1723,7 +1738,7 @@ namespace MediaBrowser.Controller.Entities
 
         private async Task<UserView> GetUserView(string name, string type, User user, string sortName, BaseItem parent)
         {
-            var view = await _userViewManager.GetUserView(name, parent.Id.ToString("N"), type, user, sortName, CancellationToken.None)
+            var view = await _userViewManager.GetUserSubView(name, parent.Id.ToString("N"), type, user, sortName, CancellationToken.None)
                         .ConfigureAwait(false);
 
             return view;
@@ -1731,7 +1746,7 @@ namespace MediaBrowser.Controller.Entities
 
         private async Task<UserView> GetUserView(string type, User user, string sortName, BaseItem parent)
         {
-            var view = await _userViewManager.GetUserView(parent.Id.ToString("N"), type, user, sortName, CancellationToken.None)
+            var view = await _userViewManager.GetUserSubView(parent.Id.ToString("N"), type, user, sortName, CancellationToken.None)
                         .ConfigureAwait(false);
 
             return view;

+ 5 - 3
MediaBrowser.Controller/Library/ILibraryManager.cs

@@ -302,7 +302,7 @@ namespace MediaBrowser.Controller.Library
         IEnumerable<BaseItem> ReplaceVideosWithPrimaryVersions(IEnumerable<BaseItem> items);
 
         /// <summary>
-        /// Gets the special folder.
+        /// Gets the named view.
         /// </summary>
         /// <param name="user">The user.</param>
         /// <param name="name">The name.</param>
@@ -311,7 +311,7 @@ namespace MediaBrowser.Controller.Library
         /// <param name="sortName">Name of the sort.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task&lt;UserView&gt;.</returns>
-        Task<UserView> GetSpecialFolder(User user,
+        Task<UserView> GetNamedView(User user,
             string name,
             string parentId,
             string viewType, 
@@ -321,12 +321,14 @@ namespace MediaBrowser.Controller.Library
         /// <summary>
         /// Gets the named view.
         /// </summary>
+        /// <param name="user">The user.</param>
         /// <param name="name">The name.</param>
         /// <param name="viewType">Type of the view.</param>
         /// <param name="sortName">Name of the sort.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task&lt;UserView&gt;.</returns>
-        Task<UserView> GetNamedView(string name, 
+        Task<UserView> GetNamedView(User user,
+            string name, 
             string viewType, 
             string sortName, 
             CancellationToken cancellationToken);

+ 2 - 4
MediaBrowser.Controller/Library/IUserViewManager.cs

@@ -12,12 +12,10 @@ namespace MediaBrowser.Controller.Library
     {
         Task<IEnumerable<Folder>> GetUserViews(UserViewQuery query, CancellationToken cancellationToken);
 
-        Task<UserView> GetUserView(string name, string parentId, string type, User user, string sortName,
+        Task<UserView> GetUserSubView(string name, string parentId, string type, User user, string sortName,
             CancellationToken cancellationToken);
 
-        Task<UserView> GetUserView(string type, string sortName, CancellationToken cancellationToken);
-
-        Task<UserView> GetUserView(string category, string type, User user, string sortName, CancellationToken cancellationToken);
+        Task<UserView> GetUserSubView(string category, string type, User user, string sortName, CancellationToken cancellationToken);
 
         List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request);
     }

+ 46 - 0
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -247,22 +247,67 @@
     <Compile Include="Persistence\MediaStreamQuery.cs" />
     <Compile Include="Playlists\IPlaylistManager.cs" />
     <Compile Include="Playlists\Playlist.cs" />
+    <Compile Include="Providers\AlbumInfo.cs" />
+    <Compile Include="Providers\ArtistInfo.cs" />
+    <Compile Include="Providers\BookInfo.cs" />
+    <Compile Include="Providers\BoxSetInfo.cs" />
+    <Compile Include="Providers\ChannelItemLookupInfo.cs" />
     <Compile Include="Providers\DirectoryService.cs" />
+    <Compile Include="Providers\DynamicImageInfo.cs" />
+    <Compile Include="Providers\DynamicImageResponse.cs" />
+    <Compile Include="Providers\EpisodeIdentity.cs" />
+    <Compile Include="Providers\EpisodeInfo.cs" />
+    <Compile Include="Providers\ExtraInfo.cs" />
+    <Compile Include="Providers\ExtraSource.cs" />
+    <Compile Include="Providers\GameInfo.cs" />
+    <Compile Include="Providers\GameSystemInfo.cs" />
     <Compile Include="Providers\ICustomMetadataProvider.cs" />
+    <Compile Include="Providers\IDirectoryService.cs" />
+    <Compile Include="Providers\IDynamicImageProvider.cs" />
     <Compile Include="Providers\IExternalId.cs" />
     <Compile Include="Providers\IExtrasProvider.cs" />
     <Compile Include="Providers\IForcedProvider.cs" />
     <Compile Include="Providers\IHasChangeMonitor.cs" />
     <Compile Include="Entities\IHasMetadata.cs" />
+    <Compile Include="Providers\IHasIdentities.cs" />
+    <Compile Include="Providers\IHasItemChangeMonitor.cs" />
+    <Compile Include="Providers\IHasLookupInfo.cs" />
+    <Compile Include="Providers\IHasOrder.cs" />
+    <Compile Include="Providers\IImageFileSaver.cs" />
     <Compile Include="Providers\IImageProvider.cs" />
     <Compile Include="Providers\IImageSaver.cs" />
+    <Compile Include="Providers\IItemIdentity.cs" />
+    <Compile Include="Providers\IItemIdentityConverter.cs" />
+    <Compile Include="Providers\IItemIdentityProvider.cs" />
+    <Compile Include="Providers\ILocalImageFileProvider.cs" />
     <Compile Include="Providers\ILocalMetadataProvider.cs" />
+    <Compile Include="Providers\ImageRefreshMode.cs" />
+    <Compile Include="Providers\ImageRefreshOptions.cs" />
+    <Compile Include="Providers\IPreRefreshProvider.cs" />
     <Compile Include="Providers\IProviderRepository.cs" />
     <Compile Include="Providers\IRemoteImageProvider.cs" />
     <Compile Include="Providers\ILocalImageProvider.cs" />
     <Compile Include="Providers\IMetadataProvider.cs" />
     <Compile Include="Providers\IMetadataService.cs" />
     <Compile Include="Providers\IRemoteMetadataProvider.cs" />
+    <Compile Include="Providers\IRemoteSearchProvider.cs" />
+    <Compile Include="Providers\ISeriesOrderProvider.cs" />
+    <Compile Include="Providers\ItemInfo.cs" />
+    <Compile Include="Providers\LocalImageInfo.cs" />
+    <Compile Include="Providers\LocalMetadataResult.cs" />
+    <Compile Include="Providers\MetadataRefreshMode.cs" />
+    <Compile Include="Providers\MetadataResult.cs" />
+    <Compile Include="Providers\MovieInfo.cs" />
+    <Compile Include="Providers\MusicVideoInfo.cs" />
+    <Compile Include="Providers\PersonLookupInfo.cs" />
+    <Compile Include="Providers\RemoteSearchQuery.cs" />
+    <Compile Include="Providers\SeasonIdentity.cs" />
+    <Compile Include="Providers\SeasonInfo.cs" />
+    <Compile Include="Providers\SeriesIdentity.cs" />
+    <Compile Include="Providers\SeriesInfo.cs" />
+    <Compile Include="Providers\SeriesOrderTypes.cs" />
+    <Compile Include="Providers\SongInfo.cs" />
+    <Compile Include="Providers\TrailerInfo.cs" />
     <Compile Include="Providers\VideoContentType.cs" />
     <Compile Include="RelatedMedia\IRelatedMediaProvider.cs" />
     <Compile Include="Security\AuthenticationInfo.cs" />
@@ -350,6 +395,7 @@
     <Compile Include="Sync\ISyncManager.cs" />
     <Compile Include="Sync\ISyncProvider.cs" />
     <Compile Include="Sync\ISyncRepository.cs" />
+    <Compile Include="Sync\SendFileResult.cs" />
     <Compile Include="Themes\IAppThemeManager.cs" />
     <Compile Include="Themes\InternalThemeImage.cs" />
     <Compile Include="TV\ITVSeriesManager.cs" />

+ 1 - 1
MediaBrowser.Controller/Playlists/Playlist.cs

@@ -106,7 +106,7 @@ namespace MediaBrowser.Controller.Playlists
                 Func<BaseItem, bool> filter = i =>
                 {
                     var audio = i as Audio;
-                    return audio != null && audio.HasArtist(musicArtist.Name);
+                    return audio != null && audio.HasAnyArtist(musicArtist.Name);
                 };
 
                 var items = user == null

+ 28 - 0
MediaBrowser.Controller/Providers/AlbumInfo.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class AlbumInfo : ItemLookupInfo
+    {
+        /// <summary>
+        /// Gets or sets the album artist.
+        /// </summary>
+        /// <value>The album artist.</value>
+        public List<string> AlbumArtists { get; set; }
+
+        /// <summary>
+        /// Gets or sets the artist provider ids.
+        /// </summary>
+        /// <value>The artist provider ids.</value>
+        public Dictionary<string, string> ArtistProviderIds { get; set; }
+        public List<SongInfo> SongInfos { get; set; }
+
+        public AlbumInfo()
+        {
+            ArtistProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+            SongInfos = new List<SongInfo>();
+            AlbumArtists = new List<string>();
+        }
+    }
+}

+ 14 - 0
MediaBrowser.Controller/Providers/ArtistInfo.cs

@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class ArtistInfo : ItemLookupInfo
+    {
+        public List<SongInfo> SongInfos { get; set; }
+
+        public ArtistInfo()
+        {
+            SongInfos = new List<SongInfo>();
+        }
+    }
+}

+ 7 - 0
MediaBrowser.Controller/Providers/BookInfo.cs

@@ -0,0 +1,7 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class BookInfo : ItemLookupInfo
+    {
+        public string SeriesName { get; set; }
+    }
+}

+ 7 - 0
MediaBrowser.Controller/Providers/BoxSetInfo.cs

@@ -0,0 +1,7 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class BoxSetInfo : ItemLookupInfo
+    {
+
+    }
+}

+ 11 - 0
MediaBrowser.Controller/Providers/ChannelItemLookupInfo.cs

@@ -0,0 +1,11 @@
+using MediaBrowser.Model.Channels;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class ChannelItemLookupInfo : ItemLookupInfo
+    {
+        public ChannelMediaContentType ContentType { get; set; }
+        public ExtraType ExtraType { get; set; }
+    }
+}

+ 0 - 10
MediaBrowser.Controller/Providers/DirectoryService.cs

@@ -7,16 +7,6 @@ using System.Linq;
 
 namespace MediaBrowser.Controller.Providers
 {
-    public interface IDirectoryService
-    {
-        IEnumerable<FileSystemInfo> GetFileSystemEntries(string path);
-        IEnumerable<FileSystemInfo> GetFiles(string path);
-        IEnumerable<FileSystemInfo> GetDirectories(string path);
-        IEnumerable<FileSystemInfo> GetFiles(string path, bool clearCache);
-        FileSystemInfo GetFile(string path);
-        Dictionary<string, FileSystemInfo> GetFileSystemDictionary(string path);
-    }
-
     public class DirectoryService : IDirectoryService
     {
         private readonly ILogger _logger;

+ 10 - 0
MediaBrowser.Controller/Providers/DynamicImageInfo.cs

@@ -0,0 +1,10 @@
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class DynamicImageInfo
+    {
+        public string ImageId { get; set; }
+        public ImageType Type { get; set; }
+    }
+}

+ 35 - 0
MediaBrowser.Controller/Providers/DynamicImageResponse.cs

@@ -0,0 +1,35 @@
+using System;
+using System.IO;
+using MediaBrowser.Model.Drawing;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class DynamicImageResponse
+    {
+        public string Path { get; set; }
+        public Stream Stream { get; set; }
+        public ImageFormat Format { get; set; }
+        public bool HasImage { get; set; }
+        public string InternalCacheKey { get; set; }
+
+        public void SetFormatFromMimeType(string mimeType)
+        {
+            if (mimeType.EndsWith("gif", StringComparison.OrdinalIgnoreCase))
+            {
+                Format = ImageFormat.Gif;
+            }
+            else if (mimeType.EndsWith("bmp", StringComparison.OrdinalIgnoreCase))
+            {
+                Format = ImageFormat.Bmp;
+            }
+            else if (mimeType.EndsWith("png", StringComparison.OrdinalIgnoreCase))
+            {
+                Format = ImageFormat.Png;
+            }
+            else
+            {
+                Format = ImageFormat.Jpg;
+            }
+        }
+    }
+}

+ 12 - 0
MediaBrowser.Controller/Providers/EpisodeIdentity.cs

@@ -0,0 +1,12 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class EpisodeIdentity : IItemIdentity
+    {
+        public string Type { get; set; }
+
+        public string SeriesId { get; set; }
+        public int? SeasonIndex { get; set; }
+        public int IndexNumber { get; set; }
+        public int? IndexNumberEnd { get; set; }
+    }
+}

+ 34 - 0
MediaBrowser.Controller/Providers/EpisodeInfo.cs

@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class EpisodeInfo : ItemLookupInfo, IHasIdentities<EpisodeIdentity>
+    {
+        private List<EpisodeIdentity> _identities = new List<EpisodeIdentity>();
+
+        public Dictionary<string, string> SeriesProviderIds { get; set; }
+
+        public int? IndexNumberEnd { get; set; }
+        public int? AnimeSeriesIndex { get; set; }
+
+        public EpisodeInfo()
+        {
+            SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+        }
+
+        public IEnumerable<EpisodeIdentity> Identities
+        {
+            get { return _identities; }
+        }
+
+        public async Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken)
+        {
+            var identifier = new ItemIdentifier<EpisodeInfo, EpisodeIdentity>();
+            _identities = (await identifier.FindIdentities(this, providerManager, cancellationToken)).ToList();
+        }
+    }
+}

+ 15 - 0
MediaBrowser.Controller/Providers/ExtraInfo.cs

@@ -0,0 +1,15 @@
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class ExtraInfo
+    {
+        public string Path { get; set; }
+
+        public LocationType LocationType { get; set; }
+
+        public bool IsDownloadable { get; set; }
+
+        public ExtraType ExtraType { get; set; }
+    }
+}

+ 9 - 0
MediaBrowser.Controller/Providers/ExtraSource.cs

@@ -0,0 +1,9 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public enum ExtraSource
+    {
+        Local = 1,
+        Metadata = 2,
+        Remote = 3
+    }
+}

+ 11 - 0
MediaBrowser.Controller/Providers/GameInfo.cs

@@ -0,0 +1,11 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class GameInfo : ItemLookupInfo
+    {
+        /// <summary>
+        /// Gets or sets the game system.
+        /// </summary>
+        /// <value>The game system.</value>
+        public string GameSystem { get; set; }
+    }
+}

+ 11 - 0
MediaBrowser.Controller/Providers/GameSystemInfo.cs

@@ -0,0 +1,11 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class GameSystemInfo : ItemLookupInfo
+    {
+        /// <summary>
+        /// Gets or sets the path.
+        /// </summary>
+        /// <value>The path.</value>
+        public string Path { get; set; }
+    }
+}

+ 0 - 5
MediaBrowser.Controller/Providers/ICustomMetadataProvider.cs

@@ -21,9 +21,4 @@ namespace MediaBrowser.Controller.Providers
         /// <returns>Task{ItemUpdateType}.</returns>
         Task<ItemUpdateType> FetchAsync(TItemType item, MetadataRefreshOptions options, CancellationToken cancellationToken);
     }
-
-    public interface IPreRefreshProvider : ICustomMetadataProvider
-    {
-        
-    }
 }

+ 15 - 0
MediaBrowser.Controller/Providers/IDirectoryService.cs

@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+using System.IO;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IDirectoryService
+    {
+        IEnumerable<FileSystemInfo> GetFileSystemEntries(string path);
+        IEnumerable<FileSystemInfo> GetFiles(string path);
+        IEnumerable<FileSystemInfo> GetDirectories(string path);
+        IEnumerable<FileSystemInfo> GetFiles(string path, bool clearCache);
+        FileSystemInfo GetFile(string path);
+        Dictionary<string, FileSystemInfo> GetFileSystemDictionary(string path);
+    }
+}

+ 27 - 0
MediaBrowser.Controller/Providers/IDynamicImageProvider.cs

@@ -0,0 +1,27 @@
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IDynamicImageProvider : IImageProvider
+    {
+        /// <summary>
+        /// Gets the supported images.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <returns>IEnumerable{ImageType}.</returns>
+        IEnumerable<ImageType> GetSupportedImages(IHasImages item);
+
+        /// <summary>
+        /// Gets the image.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="type">The type.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task{DynamicImageResponse}.</returns>
+        Task<DynamicImageResponse> GetImage(IHasImages item, ImageType type, CancellationToken cancellationToken);
+    }
+}

+ 0 - 19
MediaBrowser.Controller/Providers/IExtrasProvider.cs

@@ -1,5 +1,4 @@
 using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Entities;
 
 namespace MediaBrowser.Controller.Providers
 {
@@ -18,22 +17,4 @@ namespace MediaBrowser.Controller.Providers
         /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
         bool Supports(IHasMetadata item);
     }
-
-    public enum ExtraSource
-    {
-        Local = 1,
-        Metadata = 2,
-        Remote = 3
-    }
-
-    public class ExtraInfo
-    {
-        public string Path { get; set; }
-
-        public LocationType LocationType { get; set; }
-
-        public bool IsDownloadable { get; set; }
-
-        public ExtraType ExtraType { get; set; }
-    }
 }

+ 0 - 12
MediaBrowser.Controller/Providers/IHasChangeMonitor.cs

@@ -14,16 +14,4 @@ namespace MediaBrowser.Controller.Providers
         /// <returns><c>true</c> if the specified item has changed; otherwise, <c>false</c>.</returns>
         bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date);
     }
-
-    public interface IHasItemChangeMonitor
-    {
-        /// <summary>
-        /// Determines whether the specified item has changed.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <param name="status">The status.</param>
-        /// <param name="directoryService">The directory service.</param>
-        /// <returns><c>true</c> if the specified item has changed; otherwise, <c>false</c>.</returns>
-        bool HasChanged(IHasMetadata item, MetadataStatus status, IDirectoryService directoryService);
-    }
 }

+ 14 - 0
MediaBrowser.Controller/Providers/IHasIdentities.cs

@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IHasIdentities<out TIdentity>
+        where TIdentity : IItemIdentity
+    {
+        IEnumerable<TIdentity> Identities { get; }
+
+        Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken);
+    }
+}

+ 16 - 0
MediaBrowser.Controller/Providers/IHasItemChangeMonitor.cs

@@ -0,0 +1,16 @@
+using MediaBrowser.Controller.Entities;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IHasItemChangeMonitor
+    {
+        /// <summary>
+        /// Determines whether the specified item has changed.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="status">The status.</param>
+        /// <param name="directoryService">The directory service.</param>
+        /// <returns><c>true</c> if the specified item has changed; otherwise, <c>false</c>.</returns>
+        bool HasChanged(IHasMetadata item, MetadataStatus status, IDirectoryService directoryService);
+    }
+}

+ 8 - 0
MediaBrowser.Controller/Providers/IHasLookupInfo.cs

@@ -0,0 +1,8 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IHasLookupInfo<out TLookupInfoType>
+        where TLookupInfoType : ItemLookupInfo, new()
+    {
+        TLookupInfoType GetLookupInfo();
+    }
+}

+ 7 - 0
MediaBrowser.Controller/Providers/IHasOrder.cs

@@ -0,0 +1,7 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IHasOrder
+    {
+        int Order { get; }
+    }
+}

+ 20 - 0
MediaBrowser.Controller/Providers/IImageFileSaver.cs

@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Drawing;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IImageFileSaver : IImageSaver
+    {
+        /// <summary>
+        /// Gets the save paths.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="type">The type.</param>
+        /// <param name="format">The format.</param>
+        /// <param name="index">The index.</param>
+        /// <returns>IEnumerable{System.String}.</returns>
+        IEnumerable<string> GetSavePaths(IHasImages item, ImageType type, ImageFormat format, int index);
+    }
+}

+ 1 - 19
MediaBrowser.Controller/Providers/IImageSaver.cs

@@ -1,9 +1,4 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Drawing;
-using MediaBrowser.Model.Entities;
-using System.Collections.Generic;
-
-namespace MediaBrowser.Controller.Providers
+namespace MediaBrowser.Controller.Providers
 {
     public interface IImageSaver
     {
@@ -13,17 +8,4 @@ namespace MediaBrowser.Controller.Providers
         /// <value>The name.</value>
         string Name { get; }
     }
-
-    public interface IImageFileSaver : IImageSaver
-    {
-        /// <summary>
-        /// Gets the save paths.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <param name="type">The type.</param>
-        /// <param name="format">The format.</param>
-        /// <param name="index">The index.</param>
-        /// <returns>IEnumerable{System.String}.</returns>
-        IEnumerable<string> GetSavePaths(IHasImages item, ImageType type, ImageFormat format, int index);
-    }
 }

+ 7 - 0
MediaBrowser.Controller/Providers/IItemIdentity.cs

@@ -0,0 +1,7 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IItemIdentity
+    {
+        string Type { get; }
+    }
+}

+ 4 - 0
MediaBrowser.Controller/Providers/IItemIdentityConverter.cs

@@ -0,0 +1,4 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IItemIdentityConverter : IHasOrder { }
+}

+ 4 - 0
MediaBrowser.Controller/Providers/IItemIdentityProvider.cs

@@ -0,0 +1,4 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IItemIdentityProvider : IHasOrder { }
+}

+ 10 - 0
MediaBrowser.Controller/Providers/ILocalImageFileProvider.cs

@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public interface ILocalImageFileProvider : ILocalImageProvider
+    {
+        List<LocalImageInfo> GetImages(IHasImages item, IDirectoryService directoryService);
+    }
+}

+ 1 - 74
MediaBrowser.Controller/Providers/ILocalImageProvider.cs

@@ -1,13 +1,4 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Drawing;
-using MediaBrowser.Model.Entities;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers
+namespace MediaBrowser.Controller.Providers
 {
     /// <summary>
     /// This is just a marker interface
@@ -15,68 +6,4 @@ namespace MediaBrowser.Controller.Providers
     public interface ILocalImageProvider : IImageProvider
     {
     }
-
-    public interface ILocalImageFileProvider : ILocalImageProvider
-    {
-        List<LocalImageInfo> GetImages(IHasImages item, IDirectoryService directoryService);
-    }
-
-    public class LocalImageInfo
-    {
-        public FileSystemInfo FileInfo { get; set; }
-        public ImageType Type { get; set; }
-    }
-
-    public interface IDynamicImageProvider : IImageProvider
-    {
-        /// <summary>
-        /// Gets the supported images.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <returns>IEnumerable{ImageType}.</returns>
-        IEnumerable<ImageType> GetSupportedImages(IHasImages item);
-
-        /// <summary>
-        /// Gets the image.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <param name="type">The type.</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task{DynamicImageResponse}.</returns>
-        Task<DynamicImageResponse> GetImage(IHasImages item, ImageType type, CancellationToken cancellationToken);
-    }
-
-    public class DynamicImageInfo
-    {
-        public string ImageId { get; set; }
-        public ImageType Type { get; set; }
-    }
-
-    public class DynamicImageResponse
-    {
-        public string Path { get; set; }
-        public Stream Stream { get; set; }
-        public ImageFormat Format { get; set; }
-        public bool HasImage { get; set; }
-
-        public void SetFormatFromMimeType(string mimeType)
-        {
-            if (mimeType.EndsWith("gif", StringComparison.OrdinalIgnoreCase))
-            {
-                Format = ImageFormat.Gif;
-            }
-            else if (mimeType.EndsWith("bmp", StringComparison.OrdinalIgnoreCase))
-            {
-                Format = ImageFormat.Bmp;
-            }
-            else if (mimeType.EndsWith("png", StringComparison.OrdinalIgnoreCase))
-            {
-                Format = ImageFormat.Png;
-            }
-            else
-            {
-                Format = ImageFormat.Jpg;
-            }
-        }
-    }
 }

+ 0 - 27
MediaBrowser.Controller/Providers/ILocalMetadataProvider.cs

@@ -1,6 +1,4 @@
 using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Entities;
-using System.Collections.Generic;
 using System.Threading;
 using System.Threading.Tasks;
 
@@ -24,29 +22,4 @@ namespace MediaBrowser.Controller.Providers
             IDirectoryService directoryService,
             CancellationToken cancellationToken);
     }
-
-    public class ItemInfo
-    {
-        public string Path { get; set; }
-
-        public bool IsInMixedFolder { get; set; }
-    }
-
-    public class LocalMetadataResult<T>
-        where T : IHasMetadata
-    {
-        public bool HasMetadata { get; set; }
-        public T Item { get; set; }
-        
-        public List<LocalImageInfo> Images { get; set; }
-        public List<ChapterInfo> Chapters { get; set; }
-        public List<UserItemData> UserDataLIst { get; set; }
-
-        public LocalMetadataResult()
-        {
-            Images = new List<LocalImageInfo>();
-            Chapters = new List<ChapterInfo>();
-            UserDataLIst = new List<UserItemData>();
-        }
-    }
 }

+ 0 - 11
MediaBrowser.Controller/Providers/IMetadataProvider.cs

@@ -19,15 +19,4 @@ namespace MediaBrowser.Controller.Providers
            where TItemType : IHasMetadata
     {
     }
-
-    public interface IHasOrder
-    {
-        int Order { get; }
-    }
-
-    public class MetadataResult<T>
-    {
-        public bool HasMetadata { get; set; }
-        public T Item { get; set; }
-    }
 }

+ 7 - 0
MediaBrowser.Controller/Providers/IPreRefreshProvider.cs

@@ -0,0 +1,7 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IPreRefreshProvider : ICustomMetadataProvider
+    {
+        
+    }
+}

+ 8 - 0
MediaBrowser.Controller/Providers/IProviderManager.cs

@@ -4,6 +4,7 @@ using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Providers;
+using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Threading;
@@ -16,6 +17,13 @@ namespace MediaBrowser.Controller.Providers
     /// </summary>
     public interface IProviderManager
     {
+        /// <summary>
+        /// Queues the refresh.
+        /// </summary>
+        /// <param name="itemId">The item identifier.</param>
+        /// <param name="options">The options.</param>
+        void QueueRefresh(Guid itemId, MetadataRefreshOptions options);
+
         /// <summary>
         /// Refreshes the metadata.
         /// </summary>

+ 1 - 30
MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs

@@ -1,5 +1,4 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities;
 using MediaBrowser.Model.Providers;
 using System.Collections.Generic;
 using System.Threading;
@@ -18,37 +17,9 @@ namespace MediaBrowser.Controller.Providers
         Task<MetadataResult<TItemType>> GetMetadata(TLookupInfoType info, CancellationToken cancellationToken);
     }
 
-    public interface IRemoteSearchProvider : IMetadataProvider
-    {
-        /// <summary>
-        /// Gets the image response.
-        /// </summary>
-        /// <param name="url">The URL.</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task{HttpResponseInfo}.</returns>
-        Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken);
-    }
-
     public interface IRemoteSearchProvider<in TLookupInfoType> : IRemoteSearchProvider
         where TLookupInfoType : ItemLookupInfo
     {
         Task<IEnumerable<RemoteSearchResult>> GetSearchResults(TLookupInfoType searchInfo, CancellationToken cancellationToken);
     }
-    
-    public class RemoteSearchQuery<T>
-        where T : ItemLookupInfo
-    {
-        public T SearchInfo { get; set; }
-
-        /// <summary>
-        /// If set will only search within the given provider
-        /// </summary>
-        public string SearchProviderName { get; set; }
-
-        /// <summary>
-        /// Gets or sets a value indicating whether [include disabled providers].
-        /// </summary>
-        /// <value><c>true</c> if [include disabled providers]; otherwise, <c>false</c>.</value>
-        public bool IncludeDisabledProviders { get; set; }
-    }
 }

+ 17 - 0
MediaBrowser.Controller/Providers/IRemoteSearchProvider.cs

@@ -0,0 +1,17 @@
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IRemoteSearchProvider : IMetadataProvider
+    {
+        /// <summary>
+        /// Gets the image response.
+        /// </summary>
+        /// <param name="url">The URL.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task{HttpResponseInfo}.</returns>
+        Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken);
+    }
+}

+ 0 - 11
MediaBrowser.Controller/Providers/ISeriesOrderManager.cs

@@ -7,17 +7,6 @@ using MediaBrowser.Common;
 
 namespace MediaBrowser.Controller.Providers
 {
-    public interface ISeriesOrderProvider
-    {
-        string OrderType { get; }
-        Task<int?> FindSeriesIndex(string seriesName);
-    }
-
-    public static class SeriesOrderTypes
-    {
-        public const string Anime = "Anime";
-    }
-
     public interface ISeriesOrderManager
     {
         Task<int?> FindSeriesIndex(string orderType, string seriesName);

+ 10 - 0
MediaBrowser.Controller/Providers/ISeriesOrderProvider.cs

@@ -0,0 +1,10 @@
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public interface ISeriesOrderProvider
+    {
+        string OrderType { get; }
+        Task<int?> FindSeriesIndex(string seriesName);
+    }
+}

+ 25 - 0
MediaBrowser.Controller/Providers/ImageRefreshMode.cs

@@ -0,0 +1,25 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public enum ImageRefreshMode
+    {
+        /// <summary>
+        /// The none
+        /// </summary>
+        None = 0,
+
+        /// <summary>
+        /// The default
+        /// </summary>
+        Default = 1,
+
+        /// <summary>
+        /// Existing images will be validated
+        /// </summary>
+        ValidationOnly = 2,
+
+        /// <summary>
+        /// All providers will be executed to search for new metadata
+        /// </summary>
+        FullRefresh = 3
+    }
+}

+ 29 - 0
MediaBrowser.Controller/Providers/ImageRefreshOptions.cs

@@ -0,0 +1,29 @@
+using System.Collections.Generic;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class ImageRefreshOptions
+    {
+        public ImageRefreshMode ImageRefreshMode { get; set; }
+        public IDirectoryService DirectoryService { get; private set; }
+
+        public bool ReplaceAllImages { get; set; }
+
+        public List<ImageType> ReplaceImages { get; set; }
+
+        public ImageRefreshOptions(IDirectoryService directoryService)
+        {
+            ImageRefreshMode = ImageRefreshMode.Default;
+            DirectoryService = directoryService;
+
+            ReplaceImages = new List<ImageType>();
+        }
+
+        public bool IsReplacingImage(ImageType type)
+        {
+            return ImageRefreshMode == ImageRefreshMode.FullRefresh &&
+                   (ReplaceAllImages || ReplaceImages.Contains(type));
+        }
+    }
+}

+ 1 - 20
MediaBrowser.Controller/Providers/ItemIdentities.cs

@@ -1,24 +1,7 @@
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
+using System.Threading.Tasks;
 
 namespace MediaBrowser.Controller.Providers
 {
-    public interface IItemIdentity
-    {
-        string Type { get; }
-    }
-
-    public interface IHasIdentities<out TIdentity>
-        where TIdentity : IItemIdentity
-    {
-        IEnumerable<TIdentity> Identities { get; }
-
-        Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken);
-    }
-
-    public interface IItemIdentityProvider : IHasOrder { }
-
     public interface IItemIdentityProvider<in TLookupInfo, TIdentity> : IItemIdentityProvider
         where TLookupInfo : ItemLookupInfo
         where TIdentity : IItemIdentity
@@ -26,8 +9,6 @@ namespace MediaBrowser.Controller.Providers
         Task<TIdentity> FindIdentity(TLookupInfo info);
     }
 
-    public interface IItemIdentityConverter : IHasOrder { }
-
     public interface IItemIdentityConverter<TIdentity> : IItemIdentityConverter
         where TIdentity : IItemIdentity
     {

+ 9 - 0
MediaBrowser.Controller/Providers/ItemInfo.cs

@@ -0,0 +1,9 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class ItemInfo
+    {
+        public string Path { get; set; }
+
+        public bool IsInMixedFolder { get; set; }
+    }
+}

+ 1 - 205
MediaBrowser.Controller/Providers/ItemLookupInfo.cs

@@ -1,8 +1,4 @@
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Channels;
-using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Entities;
 using System;
 using System.Collections.Generic;
 
@@ -43,204 +39,4 @@ namespace MediaBrowser.Controller.Providers
             ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
         }
     }
-
-    public interface IHasLookupInfo<out TLookupInfoType>
-        where TLookupInfoType : ItemLookupInfo, new()
-    {
-        TLookupInfoType GetLookupInfo();
-    }
-
-    public class ArtistInfo : ItemLookupInfo
-    {
-        public List<SongInfo> SongInfos { get; set; }
-
-        public ArtistInfo()
-        {
-            SongInfos = new List<SongInfo>();
-        }
-    }
-
-    public class AlbumInfo : ItemLookupInfo
-    {
-        /// <summary>
-        /// Gets or sets the album artist.
-        /// </summary>
-        /// <value>The album artist.</value>
-        public List<string> AlbumArtists { get; set; }
-
-        /// <summary>
-        /// Gets or sets the artist provider ids.
-        /// </summary>
-        /// <value>The artist provider ids.</value>
-        public Dictionary<string, string> ArtistProviderIds { get; set; }
-        public List<SongInfo> SongInfos { get; set; }
-
-        public AlbumInfo()
-        {
-            ArtistProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
-            SongInfos = new List<SongInfo>();
-            AlbumArtists = new List<string>();
-        }
-    }
-
-    public class GameInfo : ItemLookupInfo
-    {
-        /// <summary>
-        /// Gets or sets the game system.
-        /// </summary>
-        /// <value>The game system.</value>
-        public string GameSystem { get; set; }
-    }
-
-    public class GameSystemInfo : ItemLookupInfo
-    {
-        /// <summary>
-        /// Gets or sets the path.
-        /// </summary>
-        /// <value>The path.</value>
-        public string Path { get; set; }
-    }
-
-    public class EpisodeInfo : ItemLookupInfo, IHasIdentities<EpisodeIdentity>
-    {
-        private List<EpisodeIdentity> _identities = new List<EpisodeIdentity>();
-
-        public Dictionary<string, string> SeriesProviderIds { get; set; }
-
-        public int? IndexNumberEnd { get; set; }
-        public int? AnimeSeriesIndex { get; set; }
-
-        public EpisodeInfo()
-        {
-            SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
-        }
-
-        public IEnumerable<EpisodeIdentity> Identities
-        {
-            get { return _identities; }
-        }
-
-        public async Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken)
-        {
-            var identifier = new ItemIdentifier<EpisodeInfo, EpisodeIdentity>();
-            _identities = (await identifier.FindIdentities(this, providerManager, cancellationToken)).ToList();
-        }
-    }
-
-    public class EpisodeIdentity : IItemIdentity
-    {
-        public string Type { get; set; }
-
-        public string SeriesId { get; set; }
-        public int? SeasonIndex { get; set; }
-        public int IndexNumber { get; set; }
-        public int? IndexNumberEnd { get; set; }
-    }
-
-    public class SongInfo : ItemLookupInfo
-    {
-        public List<string> AlbumArtists { get; set; }
-        public string Album { get; set; }
-        public List<string> Artists { get; set; }
-
-        public SongInfo()
-        {
-            Artists = new List<string>();
-            AlbumArtists = new List<string>();
-        }
-    }
-
-    public class SeriesInfo : ItemLookupInfo, IHasIdentities<SeriesIdentity>
-    {
-        private List<SeriesIdentity> _identities = new List<SeriesIdentity>();
-
-        public int? AnimeSeriesIndex { get; set; }
-
-        public IEnumerable<SeriesIdentity> Identities
-        {
-            get { return _identities; }
-        }
-
-        public async Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken)
-        {
-            var identifier = new ItemIdentifier<SeriesInfo, SeriesIdentity>();
-            _identities = (await identifier.FindIdentities(this, providerManager, cancellationToken)).ToList();
-        }
-    }
-
-    public class SeriesIdentity : IItemIdentity
-    {
-        public string Type { get; set; }
-
-        public string Id { get; set; }
-    }
-
-    public class PersonLookupInfo : ItemLookupInfo
-    {
-
-    }
-
-    public class MovieInfo : ItemLookupInfo
-    {
-
-    }
-
-    public class BoxSetInfo : ItemLookupInfo
-    {
-
-    }
-
-    public class MusicVideoInfo : ItemLookupInfo
-    {
-
-    }
-
-    public class TrailerInfo : ItemLookupInfo
-    {
-        public bool IsLocalTrailer { get; set; }
-    }
-
-    public class BookInfo : ItemLookupInfo
-    {
-        public string SeriesName { get; set; }
-    }
-
-    public class SeasonInfo : ItemLookupInfo, IHasIdentities<SeasonIdentity>
-    {
-        private List<SeasonIdentity> _identities = new List<SeasonIdentity>();
-
-        public Dictionary<string, string> SeriesProviderIds { get; set; }
-        public int? AnimeSeriesIndex { get; set; }
-
-        public SeasonInfo()
-        {
-            SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
-        }
-
-        public IEnumerable<SeasonIdentity> Identities
-        {
-            get { return _identities; }
-        }
-
-        public async Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken)
-        {
-            var identifier = new ItemIdentifier<SeasonInfo, SeasonIdentity>();
-            _identities = (await identifier.FindIdentities(this, providerManager, cancellationToken)).ToList();
-        }
-    }
-
-    public class SeasonIdentity : IItemIdentity
-    {
-        public string Type { get; set; }
-
-        public string SeriesId { get; set; }
-
-        public int SeasonIndex { get; set; }
-    }
-
-    public class ChannelItemLookupInfo : ItemLookupInfo
-    {
-        public ChannelMediaContentType ContentType { get; set; }
-        public ExtraType ExtraType { get; set; }
-    }
 }

+ 11 - 0
MediaBrowser.Controller/Providers/LocalImageInfo.cs

@@ -0,0 +1,11 @@
+using System.IO;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class LocalImageInfo
+    {
+        public FileSystemInfo FileInfo { get; set; }
+        public ImageType Type { get; set; }
+    }
+}

+ 24 - 0
MediaBrowser.Controller/Providers/LocalMetadataResult.cs

@@ -0,0 +1,24 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class LocalMetadataResult<T>
+        where T : IHasMetadata
+    {
+        public bool HasMetadata { get; set; }
+        public T Item { get; set; }
+        
+        public List<LocalImageInfo> Images { get; set; }
+        public List<ChapterInfo> Chapters { get; set; }
+        public List<UserItemData> UserDataLIst { get; set; }
+
+        public LocalMetadataResult()
+        {
+            Images = new List<LocalImageInfo>();
+            Chapters = new List<ChapterInfo>();
+            UserDataLIst = new List<UserItemData>();
+        }
+    }
+}

+ 25 - 0
MediaBrowser.Controller/Providers/MetadataRefreshMode.cs

@@ -0,0 +1,25 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public enum MetadataRefreshMode
+    {
+        /// <summary>
+        /// The none
+        /// </summary>
+        None = 0,
+
+        /// <summary>
+        /// The validation only
+        /// </summary>
+        ValidationOnly = 1,
+
+        /// <summary>
+        /// Providers will be executed based on default rules
+        /// </summary>
+        Default = 2,
+
+        /// <summary>
+        /// All providers will be executed to search for new metadata
+        /// </summary>
+        FullRefresh = 3
+    }
+}

+ 1 - 73
MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs

@@ -1,6 +1,4 @@
-using MediaBrowser.Model.Entities;
-using System.Collections.Generic;
-using System.Linq;
+using System.Linq;
 
 namespace MediaBrowser.Controller.Providers
 {
@@ -40,74 +38,4 @@ namespace MediaBrowser.Controller.Providers
             ReplaceImages = copy.ReplaceImages.ToList();
         }
     }
-
-    public class ImageRefreshOptions
-    {
-        public ImageRefreshMode ImageRefreshMode { get; set; }
-        public IDirectoryService DirectoryService { get; private set; }
-
-        public bool ReplaceAllImages { get; set; }
-
-        public List<ImageType> ReplaceImages { get; set; }
-
-        public ImageRefreshOptions(IDirectoryService directoryService)
-        {
-            ImageRefreshMode = ImageRefreshMode.Default;
-            DirectoryService = directoryService;
-
-            ReplaceImages = new List<ImageType>();
-        }
-
-        public bool IsReplacingImage(ImageType type)
-        {
-            return ImageRefreshMode == ImageRefreshMode.FullRefresh &&
-                (ReplaceAllImages || ReplaceImages.Contains(type));
-        }
-    }
-
-    public enum MetadataRefreshMode
-    {
-        /// <summary>
-        /// The none
-        /// </summary>
-        None = 0,
-
-        /// <summary>
-        /// The validation only
-        /// </summary>
-        ValidationOnly = 1,
-
-        /// <summary>
-        /// Providers will be executed based on default rules
-        /// </summary>
-        Default = 2,
-
-        /// <summary>
-        /// All providers will be executed to search for new metadata
-        /// </summary>
-        FullRefresh = 3
-    }
-
-    public enum ImageRefreshMode
-    {
-        /// <summary>
-        /// The none
-        /// </summary>
-        None = 0,
-
-        /// <summary>
-        /// The default
-        /// </summary>
-        Default = 1,
-
-        /// <summary>
-        /// Existing images will be validated
-        /// </summary>
-        ValidationOnly = 2,
-
-        /// <summary>
-        /// All providers will be executed to search for new metadata
-        /// </summary>
-        FullRefresh = 3
-    }
 }

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

@@ -0,0 +1,8 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class MetadataResult<T>
+    {
+        public bool HasMetadata { get; set; }
+        public T Item { get; set; }
+    }
+}

+ 7 - 0
MediaBrowser.Controller/Providers/MovieInfo.cs

@@ -0,0 +1,7 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class MovieInfo : ItemLookupInfo
+    {
+
+    }
+}

+ 7 - 0
MediaBrowser.Controller/Providers/MusicVideoInfo.cs

@@ -0,0 +1,7 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class MusicVideoInfo : ItemLookupInfo
+    {
+
+    }
+}

+ 7 - 0
MediaBrowser.Controller/Providers/PersonLookupInfo.cs

@@ -0,0 +1,7 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class PersonLookupInfo : ItemLookupInfo
+    {
+
+    }
+}

+ 19 - 0
MediaBrowser.Controller/Providers/RemoteSearchQuery.cs

@@ -0,0 +1,19 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class RemoteSearchQuery<T>
+        where T : ItemLookupInfo
+    {
+        public T SearchInfo { get; set; }
+
+        /// <summary>
+        /// If set will only search within the given provider
+        /// </summary>
+        public string SearchProviderName { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether [include disabled providers].
+        /// </summary>
+        /// <value><c>true</c> if [include disabled providers]; otherwise, <c>false</c>.</value>
+        public bool IncludeDisabledProviders { get; set; }
+    }
+}

+ 11 - 0
MediaBrowser.Controller/Providers/SeasonIdentity.cs

@@ -0,0 +1,11 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class SeasonIdentity : IItemIdentity
+    {
+        public string Type { get; set; }
+
+        public string SeriesId { get; set; }
+
+        public int SeasonIndex { get; set; }
+    }
+}

+ 32 - 0
MediaBrowser.Controller/Providers/SeasonInfo.cs

@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class SeasonInfo : ItemLookupInfo, IHasIdentities<SeasonIdentity>
+    {
+        private List<SeasonIdentity> _identities = new List<SeasonIdentity>();
+
+        public Dictionary<string, string> SeriesProviderIds { get; set; }
+        public int? AnimeSeriesIndex { get; set; }
+
+        public SeasonInfo()
+        {
+            SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+        }
+
+        public IEnumerable<SeasonIdentity> Identities
+        {
+            get { return _identities; }
+        }
+
+        public async Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken)
+        {
+            var identifier = new ItemIdentifier<SeasonInfo, SeasonIdentity>();
+            _identities = (await identifier.FindIdentities(this, providerManager, cancellationToken)).ToList();
+        }
+    }
+}

+ 9 - 0
MediaBrowser.Controller/Providers/SeriesIdentity.cs

@@ -0,0 +1,9 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class SeriesIdentity : IItemIdentity
+    {
+        public string Type { get; set; }
+
+        public string Id { get; set; }
+    }
+}

+ 25 - 0
MediaBrowser.Controller/Providers/SeriesInfo.cs

@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class SeriesInfo : ItemLookupInfo, IHasIdentities<SeriesIdentity>
+    {
+        private List<SeriesIdentity> _identities = new List<SeriesIdentity>();
+
+        public int? AnimeSeriesIndex { get; set; }
+
+        public IEnumerable<SeriesIdentity> Identities
+        {
+            get { return _identities; }
+        }
+
+        public async Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken)
+        {
+            var identifier = new ItemIdentifier<SeriesInfo, SeriesIdentity>();
+            _identities = (await identifier.FindIdentities(this, providerManager, cancellationToken)).ToList();
+        }
+    }
+}

+ 7 - 0
MediaBrowser.Controller/Providers/SeriesOrderTypes.cs

@@ -0,0 +1,7 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public static class SeriesOrderTypes
+    {
+        public const string Anime = "Anime";
+    }
+}

+ 17 - 0
MediaBrowser.Controller/Providers/SongInfo.cs

@@ -0,0 +1,17 @@
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class SongInfo : ItemLookupInfo
+    {
+        public List<string> AlbumArtists { get; set; }
+        public string Album { get; set; }
+        public List<string> Artists { get; set; }
+
+        public SongInfo()
+        {
+            Artists = new List<string>();
+            AlbumArtists = new List<string>();
+        }
+    }
+}

+ 7 - 0
MediaBrowser.Controller/Providers/TrailerInfo.cs

@@ -0,0 +1,7 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class TrailerInfo : ItemLookupInfo
+    {
+        public bool IsLocalTrailer { get; set; }
+    }
+}

+ 1 - 1
MediaBrowser.Controller/Sync/IServerSyncProvider.cs

@@ -18,7 +18,7 @@ namespace MediaBrowser.Controller.Sync
         /// <param name="progress">The progress.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
-        Task SendFile(Stream stream, string remotePath, SyncTarget target, IProgress<double> progress, CancellationToken cancellationToken);
+        Task<SendFileResult> SendFile(Stream stream, string remotePath, SyncTarget target, IProgress<double> progress, CancellationToken cancellationToken);
 
         /// <summary>
         /// Deletes the file.

+ 18 - 0
MediaBrowser.Controller/Sync/SendFileResult.cs

@@ -0,0 +1,18 @@
+using MediaBrowser.Model.MediaInfo;
+
+namespace MediaBrowser.Controller.Sync
+{
+    public class SendFileResult
+    {
+        /// <summary>
+        /// Gets or sets the path.
+        /// </summary>
+        /// <value>The path.</value>
+        public string Path { get; set; }
+        /// <summary>
+        /// Gets or sets the protocol.
+        /// </summary>
+        /// <value>The protocol.</value>
+        public MediaProtocol Protocol { get; set; }
+    }
+}

+ 3 - 3
MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj

@@ -491,6 +491,9 @@
     <Compile Include="..\MediaBrowser.Model\Dto\MetadataEditorInfo.cs">
       <Link>Dto\MetadataEditorInfo.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Dto\NameIdPair.cs">
+      <Link>Dto\NameIdPair.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Dto\NameValuePair.cs">
       <Link>Dto\NameValuePair.cs</Link>
     </Compile>
@@ -977,9 +980,6 @@
     <Compile Include="..\MediaBrowser.Model\Querying\SessionQuery.cs">
       <Link>Querying\SessionQuery.cs</Link>
     </Compile>
-    <Compile Include="..\MediaBrowser.Model\Querying\SimilarItemsByNameQuery.cs">
-      <Link>Querying\SimilarItemsByNameQuery.cs</Link>
-    </Compile>
     <Compile Include="..\MediaBrowser.Model\Querying\SimilarItemsQuery.cs">
       <Link>Querying\SimilarItemsQuery.cs</Link>
     </Compile>

+ 3 - 3
MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj

@@ -459,6 +459,9 @@
     <Compile Include="..\MediaBrowser.Model\Dto\MetadataEditorInfo.cs">
       <Link>Dto\MetadataEditorInfo.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Dto\NameIdPair.cs">
+      <Link>Dto\NameIdPair.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Dto\NameValuePair.cs">
       <Link>Dto\NameValuePair.cs</Link>
     </Compile>
@@ -939,9 +942,6 @@
     <Compile Include="..\MediaBrowser.Model\Querying\SessionQuery.cs">
       <Link>Querying\SessionQuery.cs</Link>
     </Compile>
-    <Compile Include="..\MediaBrowser.Model\Querying\SimilarItemsByNameQuery.cs">
-      <Link>Querying\SimilarItemsByNameQuery.cs</Link>
-    </Compile>
     <Compile Include="..\MediaBrowser.Model\Querying\SimilarItemsQuery.cs">
       <Link>Querying\SimilarItemsQuery.cs</Link>
     </Compile>

+ 4 - 48
MediaBrowser.Model/ApiClient/IApiClient.cs

@@ -251,12 +251,12 @@ namespace MediaBrowser.Model.ApiClient
         Task<ItemsResult> GetAdditionalParts(string itemId, string userId);
 
         /// <summary>
-        /// Gets the live media information.
+        /// Gets the playback information.
         /// </summary>
         /// <param name="itemId">The item identifier.</param>
         /// <param name="userId">The user identifier.</param>
         /// <returns>Task&lt;LiveMediaInfoResult&gt;.</returns>
-        Task<LiveMediaInfoResult> GetLiveMediaInfo(string itemId, string userId);
+        Task<LiveMediaInfoResult> GetPlaybackInfo(string itemId, string userId);
 
         /// <summary>
         /// Gets the users async.
@@ -344,14 +344,14 @@ namespace MediaBrowser.Model.ApiClient
         /// </summary>
         /// <param name="query">The query.</param>
         /// <returns>Task{ItemsResult}.</returns>
-        Task<ItemsResult> GetInstantMixFromArtistAsync(SimilarItemsByNameQuery query);
+        Task<ItemsResult> GetInstantMixFromArtistAsync(SimilarItemsQuery query);
 
         /// <summary>
         /// Gets the instant mix from music genre async.
         /// </summary>
         /// <param name="query">The query.</param>
         /// <returns>Task{ItemsResult}.</returns>
-        Task<ItemsResult> GetInstantMixFromMusicGenreAsync(SimilarItemsByNameQuery query);
+        Task<ItemsResult> GetInstantMixFromMusicGenreAsync(SimilarItemsQuery query);
 
         /// <summary>
         /// Gets the similar movies async.
@@ -417,15 +417,6 @@ namespace MediaBrowser.Model.ApiClient
         /// <returns>Task{ItemsResult}.</returns>
         Task<ItemsResult> GetAlbumArtistsAsync(ArtistsQuery query);
 
-        /// <summary>
-        /// Gets a studio
-        /// </summary>
-        /// <param name="name">The name.</param>
-        /// <param name="userId">The user id.</param>
-        /// <returns>Task{BaseItemDto}.</returns>
-        /// <exception cref="ArgumentNullException">userId</exception>
-        Task<BaseItemDto> GetStudioAsync(string name, string userId);
-
         /// <summary>
         /// Gets the next up async.
         /// </summary>
@@ -494,15 +485,6 @@ namespace MediaBrowser.Model.ApiClient
         /// <returns>Task{BaseItemDto}.</returns>
         Task<BaseItemDto> GetGameGenreAsync(string name, string userId);
 
-        /// <summary>
-        /// Gets the artist async.
-        /// </summary>
-        /// <param name="name">The name.</param>
-        /// <param name="userId">The user id.</param>
-        /// <returns>Task{BaseItemDto}.</returns>
-        /// <exception cref="ArgumentNullException">name</exception>
-        Task<BaseItemDto> GetArtistAsync(string name, string userId);
-
         /// <summary>
         /// Restarts the server.
         /// </summary>
@@ -1011,14 +993,6 @@ namespace MediaBrowser.Model.ApiClient
         /// <exception cref="ArgumentNullException">item</exception>
         string GetPersonImageUrl(BaseItemPerson item, ImageOptions options);
 
-        /// <summary>
-        /// Gets an image url that can be used to download an image from the api
-        /// </summary>
-        /// <param name="year">The year.</param>
-        /// <param name="options">The options.</param>
-        /// <returns>System.String.</returns>
-        string GetYearImageUrl(int year, ImageOptions options);
-
         /// <summary>
         /// Gets an image url that can be used to download an image from the api
         /// </summary>
@@ -1044,24 +1018,6 @@ namespace MediaBrowser.Model.ApiClient
         /// <returns>System.String.</returns>
         string GetGameGenreImageUrl(string name, ImageOptions options);
 
-        /// <summary>
-        /// Gets an image url that can be used to download an image from the api
-        /// </summary>
-        /// <param name="name">The name.</param>
-        /// <param name="options">The options.</param>
-        /// <returns>System.String.</returns>
-        /// <exception cref="ArgumentNullException">name</exception>
-        string GetStudioImageUrl(string name, ImageOptions options);
-
-        /// <summary>
-        /// Gets the artist image URL.
-        /// </summary>
-        /// <param name="name">The name.</param>
-        /// <param name="options">The options.</param>
-        /// <returns>System.String.</returns>
-        /// <exception cref="ArgumentNullException">name</exception>
-        string GetArtistImageUrl(string name, ImageOptions options);
-
         /// <summary>
         /// This is a helper to get a list of backdrop url's from a given ApiBaseItemWrapper. If the actual item does not have any backdrops it will return backdrops from the first parent that does.
         /// </summary>

+ 6 - 0
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -44,6 +44,12 @@ namespace MediaBrowser.Model.Configuration
         /// <value><c>true</c> if [use HTTPS]; otherwise, <c>false</c>.</value>
         public bool EnableHttps { get; set; }
 
+        /// <summary>
+        /// Gets or sets a value indicating whether [enable user specific user views].
+        /// </summary>
+        /// <value><c>true</c> if [enable user specific user views]; otherwise, <c>false</c>.</value>
+        public bool EnableUserSpecificUserViews { get; set; }
+        
         /// <summary>
         /// Gets or sets the value pointing to the file system where the ssl certiifcate is located..
         /// </summary>

+ 12 - 0
MediaBrowser.Model/Dto/BaseItemDto.cs

@@ -466,6 +466,12 @@ namespace MediaBrowser.Model.Dto
         /// <value>The artists.</value>
         public List<string> Artists { get; set; }
 
+        /// <summary>
+        /// Gets or sets the artist items.
+        /// </summary>
+        /// <value>The artist items.</value>
+        public List<NameIdPair> ArtistItems { get; set; }
+
         /// <summary>
         /// Gets or sets the album.
         /// </summary>
@@ -507,6 +513,12 @@ namespace MediaBrowser.Model.Dto
         /// <value>The album artist.</value>
         public string AlbumArtist { get; set; }
 
+        /// <summary>
+        /// Gets or sets the album artists.
+        /// </summary>
+        /// <value>The album artists.</value>
+        public List<NameIdPair> AlbumArtists { get; set; }
+        
         /// <summary>
         /// Gets or sets the name of the season.
         /// </summary>

+ 17 - 0
MediaBrowser.Model/Dto/NameIdPair.cs

@@ -0,0 +1,17 @@
+
+namespace MediaBrowser.Model.Dto
+{
+    public class NameIdPair
+    {
+        /// <summary>
+        /// Gets or sets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name { get; set; }
+        /// <summary>
+        /// Gets or sets the identifier.
+        /// </summary>
+        /// <value>The identifier.</value>
+        public string Id { get; set; }
+    }
+}

+ 4 - 0
MediaBrowser.Model/LiveTv/RecordingInfoDto.cs

@@ -273,6 +273,10 @@ namespace MediaBrowser.Model.LiveTv
         /// <value>The type.</value>
         public string Type { get; set; }
 
+        /// <summary>
+        /// Gets or sets the media sources.
+        /// </summary>
+        /// <value>The media sources.</value>
         public List<MediaSourceInfo> MediaSources { get; set; }
         
         public RecordingInfoDto()

+ 1 - 1
MediaBrowser.Model/MediaBrowser.Model.csproj

@@ -139,6 +139,7 @@
     <Compile Include="Drawing\ImageOrientation.cs" />
     <Compile Include="Dto\IHasServerId.cs" />
     <Compile Include="Dto\MetadataEditorInfo.cs" />
+    <Compile Include="Dto\NameIdPair.cs" />
     <Compile Include="Dto\NameValuePair.cs" />
     <Compile Include="MediaInfo\LiveMediaInfoResult.cs" />
     <Compile Include="Dto\MediaSourceType.cs" />
@@ -321,7 +322,6 @@
     <Compile Include="Querying\QueryResult.cs" />
     <Compile Include="Querying\SeasonQuery.cs" />
     <Compile Include="Querying\SessionQuery.cs" />
-    <Compile Include="Querying\SimilarItemsByNameQuery.cs" />
     <Compile Include="Querying\SimilarItemsQuery.cs" />
     <Compile Include="Querying\UpcomingEpisodesQuery.cs" />
     <Compile Include="Querying\UserQuery.cs" />

+ 9 - 15
MediaBrowser.Model/Querying/ItemQuery.cs

@@ -39,11 +39,11 @@ namespace MediaBrowser.Model.Querying
         public string[] SortBy { get; set; }
 
         /// <summary>
-        /// Filter by artists
+        /// Gets or sets the artist ids.
         /// </summary>
-        /// <value>The artists.</value>
-        public string[] Artists { get; set; }
-
+        /// <value>The artist ids.</value>
+        public string[] ArtistIds { get; set; }
+        
         /// <summary>
         /// The sort order to return results with
         /// </summary>
@@ -93,16 +93,10 @@ namespace MediaBrowser.Model.Querying
         public string[] Genres { get; set; }
 
         /// <summary>
-        /// Limit results to items containing specific genres
-        /// </summary>
-        /// <value>The genres.</value>
-        public string[] AllGenres { get; set; }
-
-        /// <summary>
-        /// Limit results to items containing specific studios
+        /// Gets or sets the studio ids.
         /// </summary>
-        /// <value>The studios.</value>
-        public string[] Studios { get; set; }
+        /// <value>The studio ids.</value>
+        public string[] StudioIds { get; set; }
 
         /// <summary>
         /// Gets or sets the exclude item types.
@@ -306,13 +300,13 @@ namespace MediaBrowser.Model.Querying
             VideoTypes = new VideoType[] { };
 
             Genres = new string[] { };
-            Studios = new string[] { };
+            StudioIds = new string[] { };
             IncludeItemTypes = new string[] { };
             ExcludeItemTypes = new string[] { };
             Years = new int[] { };
             PersonTypes = new string[] { };
             Ids = new string[] { };
-            Artists = new string[] { };
+            ArtistIds = new string[] { };
 
             ImageTypes = new ImageType[] { };
             AirDays = new DayOfWeek[] { };

+ 0 - 29
MediaBrowser.Model/Querying/SimilarItemsByNameQuery.cs

@@ -1,29 +0,0 @@
-namespace MediaBrowser.Model.Querying
-{
-    public class SimilarItemsByNameQuery
-    {
-        /// <summary>
-        /// The user to localize search results for
-        /// </summary>
-        /// <value>The user id.</value>
-        public string UserId { get; set; }
-
-        /// <summary>
-        /// Gets or sets the name.
-        /// </summary>
-        /// <value>The name.</value>
-        public string Name { get; set; }
-
-        /// <summary>
-        /// The maximum number of items to return
-        /// </summary>
-        /// <value>The limit.</value>
-        public int? Limit { get; set; }
-
-        /// <summary>
-        /// Fields to return within the items, in addition to basic information
-        /// </summary>
-        /// <value>The fields.</value>
-        public ItemFields[] Fields { get; set; }
-    }
-}

+ 42 - 29
MediaBrowser.Providers/FolderImages/DefaultImageProvider.cs

@@ -12,7 +12,7 @@ using System.Threading.Tasks;
 
 namespace MediaBrowser.Providers.FolderImages
 {
-    public class DefaultImageProvider : IRemoteImageProvider, IHasItemChangeMonitor
+    public class DefaultImageProvider : IRemoteImageProvider, IHasItemChangeMonitor, IHasOrder
     {
         private readonly IHttpClient _httpClient;
 
@@ -36,36 +36,42 @@ namespace MediaBrowser.Providers.FolderImages
 
             if (view != null)
             {
-                return GetImages(view.ViewType, cancellationToken);
+                return GetImages(view.ViewType, view.ParentId != Guid.Empty, cancellationToken);
             }
 
             var folder = (ICollectionFolder)item;
-            return GetImages(folder.CollectionType, cancellationToken);
+            return GetImages(folder.CollectionType, false, cancellationToken);
         }
 
-        private Task<IEnumerable<RemoteImageInfo>> GetImages(string viewType, CancellationToken cancellationToken)
+        private Task<IEnumerable<RemoteImageInfo>> GetImages(string viewType, bool isSubView, CancellationToken cancellationToken)
         {
-            var url = GetImageUrl(viewType);
+            var url = GetImageUrl(viewType, isSubView);
+            var list = new List<RemoteImageInfo>();
 
-            return Task.FromResult<IEnumerable<RemoteImageInfo>>(new List<RemoteImageInfo>
+            if (!string.IsNullOrWhiteSpace(url))
             {
-                 new RemoteImageInfo
-                 {
-                      ProviderName = Name,
-                      Url = url,
-                      Type = ImageType.Primary
-                 },
-
-                 new RemoteImageInfo
-                 {
-                      ProviderName = Name,
-                      Url = url,
-                      Type = ImageType.Thumb
-                 }
-            });
+                list.AddRange(new List<RemoteImageInfo>
+                {
+                    new RemoteImageInfo
+                    {
+                        ProviderName = Name,
+                        Url = url,
+                        Type = ImageType.Primary
+                    },
+
+                    new RemoteImageInfo
+                    {
+                        ProviderName = Name,
+                        Url = url,
+                        Type = ImageType.Thumb
+                    }
+                });
+            }
+
+            return Task.FromResult<IEnumerable<RemoteImageInfo>>(list);
         }
 
-        private string GetImageUrl(string viewType)
+        private string GetImageUrl(string viewType, bool isSubView)
         {
             const string urlPrefix = "https://raw.githubusercontent.com/MediaBrowser/MediaBrowser.Resources/master/images/folders/";
 
@@ -102,6 +108,11 @@ namespace MediaBrowser.Providers.FolderImages
                 return urlPrefix + "movies.png";
             }
 
+            if (isSubView)
+            {
+                return null;
+            }
+
             return urlPrefix + "generic.png";
         }
 
@@ -112,14 +123,7 @@ namespace MediaBrowser.Providers.FolderImages
 
         public bool Supports(IHasImages item)
         {
-            var view = item as UserView;
-
-            if (view != null)
-            {
-                return !view.UserId.HasValue;
-            }
-            
-            return item is ICollectionFolder;
+            return item is ICollectionFolder || item is UserView;
         }
 
         public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
@@ -136,5 +140,14 @@ namespace MediaBrowser.Providers.FolderImages
         {
             return GetSupportedImages(item).Any(i => !item.HasImage(i));
         }
+
+        public int Order
+        {
+            get
+            {
+                // Run after the dynamic image provider
+                return 1;
+            }
+        }
     }
 }

+ 3 - 3
MediaBrowser.Providers/Manager/ItemImageProvider.cs

@@ -135,17 +135,17 @@ namespace MediaBrowser.Providers.Manager
                         {
                             if (!string.IsNullOrEmpty(response.Path))
                             {
-                                var mimeType = "image/" + Path.GetExtension(response.Path).TrimStart('.').ToLower();
+                                var mimeType = MimeTypes.GetMimeType(response.Path);
 
                                 var stream = _fileSystem.GetFileStream(response.Path, FileMode.Open, FileAccess.Read, FileShare.Read, true);
 
-                                await _providerManager.SaveImage(item, stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false);
+                                await _providerManager.SaveImage(item, stream, mimeType, imageType, null, response.InternalCacheKey, cancellationToken).ConfigureAwait(false);
                             }
                             else
                             {
                                 var mimeType = "image/" + response.Format.ToString().ToLower();
 
-                                await _providerManager.SaveImage(item, response.Stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false);
+                                await _providerManager.SaveImage(item, response.Stream, mimeType, imageType, null, response.InternalCacheKey, cancellationToken).ConfigureAwait(false);
                             }
 
                             downloadedImages.Add(imageType);

+ 80 - 2
MediaBrowser.Providers/Manager/ProviderManager.cs

@@ -26,7 +26,7 @@ namespace MediaBrowser.Providers.Manager
     /// <summary>
     /// Class ProviderManager
     /// </summary>
-    public class ProviderManager : IProviderManager
+    public class ProviderManager : IProviderManager, IDisposable
     {
         /// <summary>
         /// The _logger
@@ -63,6 +63,8 @@ namespace MediaBrowser.Providers.Manager
 
         private IExternalId[] _externalIds;
 
+        private readonly Func<ILibraryManager> _libraryManagerFactory;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="ProviderManager" /> class.
         /// </summary>
@@ -71,7 +73,7 @@ namespace MediaBrowser.Providers.Manager
         /// <param name="libraryMonitor">The directory watchers.</param>
         /// <param name="logManager">The log manager.</param>
         /// <param name="fileSystem">The file system.</param>
-        public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, ILibraryMonitor libraryMonitor, ILogManager logManager, IFileSystem fileSystem, IServerApplicationPaths appPaths)
+        public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, ILibraryMonitor libraryMonitor, ILogManager logManager, IFileSystem fileSystem, IServerApplicationPaths appPaths, Func<ILibraryManager> libraryManagerFactory)
         {
             _logger = logManager.GetLogger("ProviderManager");
             _httpClient = httpClient;
@@ -79,6 +81,7 @@ namespace MediaBrowser.Providers.Manager
             _libraryMonitor = libraryMonitor;
             _fileSystem = fileSystem;
             _appPaths = appPaths;
+            _libraryManagerFactory = libraryManagerFactory;
         }
 
         /// <summary>
@@ -841,5 +844,80 @@ namespace MediaBrowser.Providers.Manager
 
                 });
         }
+
+        private readonly ConcurrentQueue<Tuple<Guid, MetadataRefreshOptions>> _refreshQueue =
+            new ConcurrentQueue<Tuple<Guid, MetadataRefreshOptions>>();
+
+        private readonly object _refreshTimerLock = new object();
+        private Timer _refreshTimer;
+
+        public void QueueRefresh(Guid id, MetadataRefreshOptions options)
+        {
+            if (_disposed)
+            {
+                return;
+            }
+
+            _refreshQueue.Enqueue(new Tuple<Guid, MetadataRefreshOptions>(id, options));
+            StartRefreshTimer();
+        }
+
+        private void StartRefreshTimer()
+        {
+            lock (_refreshTimerLock)
+            {
+                if (_refreshTimer == null)
+                {
+                    _refreshTimer = new Timer(RefreshTimerCallback, null, 100, Timeout.Infinite);
+                }
+            }
+        }
+
+        private void StopRefreshTimer()
+        {
+            lock (_refreshTimerLock)
+            {
+                if (_refreshTimer != null)
+                {
+                    _refreshTimer.Dispose();
+                    _refreshTimer = null;
+                }
+            }
+        }
+
+        private async void RefreshTimerCallback(object state)
+        {
+            Tuple<Guid, MetadataRefreshOptions> refreshItem;
+            var libraryManager = _libraryManagerFactory();
+
+            while (_refreshQueue.TryDequeue(out refreshItem))
+            {
+                if (_disposed)
+                {
+                    return;
+                }
+
+                try
+                {
+                    var item = libraryManager.GetItemById(refreshItem.Item1);
+                    if (item != null)
+                    {
+                        await item.RefreshMetadata(refreshItem.Item2, CancellationToken.None).ConfigureAwait(false);
+                    }
+                }
+                catch (Exception ex)
+                {
+                    _logger.ErrorException("Error refreshing item", ex);
+                }
+            }
+
+            StopRefreshTimer();
+        }
+
+        private bool _disposed;
+        public void Dispose()
+        {
+            _disposed = true;
+        }
     }
 }

+ 1 - 1
MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs

@@ -387,7 +387,7 @@ namespace MediaBrowser.Providers.MediaInfo
             if (!string.IsNullOrEmpty(val))
             {
                 // Sometimes the artist name is listed here, account for that
-                var studios = Split(val, true).Where(i => !audio.HasArtist(i));
+                var studios = Split(val, true).Where(i => !audio.HasAnyArtist(i));
 
                 foreach (var studio in studios)
                 {

+ 3 - 1
MediaBrowser.Server.Implementations/Channels/ChannelManager.cs

@@ -1400,7 +1400,9 @@ namespace MediaBrowser.Server.Implementations.Channels
         public async Task<Folder> GetInternalChannelFolder(string userId, CancellationToken cancellationToken)
         {
             var name = _localization.GetLocalizedString("ViewTypeChannels");
-            return await _libraryManager.GetNamedView(name, "channels", "zz_" + name, cancellationToken).ConfigureAwait(false);
+            var user = _userManager.GetUserById(userId);
+
+            return await _libraryManager.GetNamedView(user, name, "channels", "zz_" + name, cancellationToken).ConfigureAwait(false);
         }
 
         public async Task DownloadChannelItem(IChannelMediaItem item, string destination,

+ 1 - 1
MediaBrowser.Server.Implementations/Collections/CollectionImageProvider.cs

@@ -14,7 +14,7 @@ using System.Threading.Tasks;
 
 namespace MediaBrowser.Server.Implementations.Collections
 {
-    public class CollectionImageProvider : BaseDynamicImageProvider<BoxSet>, ICustomMetadataProvider<BoxSet>
+    public class CollectionImageProvider : BaseDynamicImageProvider<BoxSet>
     {
         public CollectionImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths) : base(fileSystem, providerManager, applicationPaths)
         {

+ 50 - 11
MediaBrowser.Server.Implementations/Dto/DtoService.cs

@@ -504,7 +504,6 @@ namespace MediaBrowser.Server.Implementations.Dto
             }
 
             dto.Album = item.Album;
-            dto.Artists = item.Artists;
         }
 
         private void SetGameProperties(BaseItemDto dto, Game item)
@@ -1142,7 +1141,6 @@ namespace MediaBrowser.Server.Implementations.Dto
             if (audio != null)
             {
                 dto.Album = audio.Album;
-                dto.Artists = audio.Artists;
 
                 var albumParent = audio.FindParent<MusicAlbum>();
 
@@ -1163,18 +1161,65 @@ namespace MediaBrowser.Server.Implementations.Dto
 
             if (album != null)
             {
-                dto.Artists = album.Artists;
-
                 dto.SoundtrackIds = album.SoundtrackIds
                     .Select(i => i.ToString("N"))
                     .ToArray();
             }
 
-            var hasAlbumArtist = item as IHasAlbumArtist;
+            var hasArtist = item as IHasArtist;
+            if (hasArtist != null)
+            {
+                dto.Artists = hasArtist.Artists;
+
+                dto.ArtistItems = hasArtist
+                    .Artists
+                    .Select(i =>
+                    {
+                        try
+                        {
+                            var artist = _libraryManager.GetArtist(i);
+                            return new NameIdPair
+                            {
+                                Name = artist.Name,
+                                Id = artist.Id.ToString("N")
+                            };
+                        }
+                        catch (Exception ex)
+                        {
+                            _logger.ErrorException("Error getting artist", ex);
+                            return null;
+                        }
+                    })
+                    .Where(i => i != null)
+                    .ToList();
+            }
 
+            var hasAlbumArtist = item as IHasAlbumArtist;
             if (hasAlbumArtist != null)
             {
                 dto.AlbumArtist = hasAlbumArtist.AlbumArtists.FirstOrDefault();
+
+                dto.AlbumArtists = hasAlbumArtist
+                    .AlbumArtists
+                    .Select(i =>
+                    {
+                        try
+                        {
+                            var artist = _libraryManager.GetArtist(i);
+                            return new NameIdPair
+                            {
+                                Name = artist.Name,
+                                Id = artist.Id.ToString("N")
+                            };
+                        }
+                        catch (Exception ex)
+                        {
+                            _logger.ErrorException("Error getting album artist", ex);
+                            return null;
+                        }
+                    })
+                    .Where(i => i != null)
+                    .ToList();
             }
 
             // Add video info
@@ -1231,7 +1276,6 @@ namespace MediaBrowser.Server.Implementations.Dto
 
             // Add MovieInfo
             var movie = item as Movie;
-
             if (movie != null)
             {
                 if (fields.Contains(ItemFields.TmdbCollectionName))
@@ -1241,7 +1285,6 @@ namespace MediaBrowser.Server.Implementations.Dto
             }
 
             var hasSpecialFeatures = item as IHasSpecialFeatures;
-
             if (hasSpecialFeatures != null)
             {
                 var specialFeatureCount = hasSpecialFeatures.SpecialFeatureIds.Count;
@@ -1254,7 +1297,6 @@ namespace MediaBrowser.Server.Implementations.Dto
 
             // Add EpisodeInfo
             var episode = item as Episode;
-
             if (episode != null)
             {
                 dto.IndexNumberEnd = episode.IndexNumberEnd;
@@ -1296,7 +1338,6 @@ namespace MediaBrowser.Server.Implementations.Dto
 
             // Add SeriesInfo
             var series = item as Series;
-
             if (series != null)
             {
                 dto.AirDays = series.AirDays;
@@ -1346,7 +1387,6 @@ namespace MediaBrowser.Server.Implementations.Dto
 
             // Add SeasonInfo
             var season = item as Season;
-
             if (season != null)
             {
                 series = season.Series;
@@ -1380,7 +1420,6 @@ namespace MediaBrowser.Server.Implementations.Dto
             }
 
             var musicVideo = item as MusicVideo;
-
             if (musicVideo != null)
             {
                 SetMusicVideoProperties(dto, musicVideo);

+ 40 - 25
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -1584,15 +1584,22 @@ namespace MediaBrowser.Server.Implementations.Library
                 .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i));
         }
 
-        public async Task<UserView> GetNamedView(string name,
-            string type,
+        public async Task<UserView> GetNamedView(User user,
+            string name,
+            string viewType,
             string sortName,
             CancellationToken cancellationToken)
         {
+            if (ConfigurationManager.Configuration.EnableUserSpecificUserViews)
+            {
+                return await GetNamedViewInternal(user, name, null, viewType, sortName, cancellationToken)
+                            .ConfigureAwait(false);
+            }
+
             var path = Path.Combine(ConfigurationManager.ApplicationPaths.ItemsByNamePath,
                             "views");
 
-            path = Path.Combine(path, _fileSystem.GetValidFilename(type));
+            path = Path.Combine(path, _fileSystem.GetValidFilename(viewType));
 
             var id = GetNewItemId(path + "_namedview_" + name, typeof(UserView));
 
@@ -1611,7 +1618,7 @@ namespace MediaBrowser.Server.Implementations.Library
                     Id = id,
                     DateCreated = DateTime.UtcNow,
                     Name = name,
-                    ViewType = type,
+                    ViewType = viewType,
                     ForcedSortName = sortName
                 };
 
@@ -1627,31 +1634,38 @@ namespace MediaBrowser.Server.Implementations.Library
 
             if (refresh)
             {
-                await item.RefreshMetadata(new MetadataRefreshOptions
-                {
-                    ForceSave = true
-
-                }, cancellationToken).ConfigureAwait(false);
+                await item.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None).ConfigureAwait(false);
+                _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions());
             }
 
             return item;
         }
 
-        public async Task<UserView> GetSpecialFolder(User user,
+        public Task<UserView> GetNamedView(User user,
             string name,
             string parentId,
             string viewType,
             string sortName,
             CancellationToken cancellationToken)
         {
-            if (string.IsNullOrWhiteSpace(name))
+            if (string.IsNullOrWhiteSpace(parentId))
             {
-                throw new ArgumentNullException("name");
+                throw new ArgumentNullException("parentId");
             }
 
-            if (string.IsNullOrWhiteSpace(parentId))
+            return GetNamedViewInternal(user, name, parentId, viewType, sortName, cancellationToken);
+        }
+
+        private async Task<UserView> GetNamedViewInternal(User user,
+            string name,
+            string parentId,
+            string viewType,
+            string sortName,
+            CancellationToken cancellationToken)
+        {
+            if (string.IsNullOrWhiteSpace(name))
             {
-                throw new ArgumentNullException("parentId");
+                throw new ArgumentNullException("name");
             }
 
             if (string.IsNullOrWhiteSpace(viewType))
@@ -1659,9 +1673,9 @@ namespace MediaBrowser.Server.Implementations.Library
                 throw new ArgumentNullException("viewType");
             }
 
-            var id = GetNewItemId("7_namedview_" + name + user.Id.ToString("N") + parentId, typeof(UserView));
+            var id = GetNewItemId("23_namedview_" + name + user.Id.ToString("N") + (parentId ?? string.Empty), typeof(UserView));
 
-            var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", "specialviews", id.ToString("N"));
+            var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N"));
 
             var item = GetItemById(id) as UserView;
 
@@ -1679,27 +1693,28 @@ namespace MediaBrowser.Server.Implementations.Library
                     Name = name,
                     ViewType = viewType,
                     ForcedSortName = sortName,
-                    UserId = user.Id,
-                    ParentId = new Guid(parentId)
+                    UserId = user.Id
                 };
 
+                if (!string.IsNullOrWhiteSpace(parentId))
+                {
+                    item.ParentId = new Guid(parentId);
+                }
+
                 await CreateItem(item, cancellationToken).ConfigureAwait(false);
 
                 refresh = true;
             }
 
-            if (!refresh && item != null)
+            if (!refresh)
             {
                 refresh = (DateTime.UtcNow - item.DateLastSaved).TotalHours >= 24;
             }
 
             if (refresh)
             {
-                await item.RefreshMetadata(new MetadataRefreshOptions
-                {
-                    ForceSave = true
-
-                }, cancellationToken).ConfigureAwait(false);
+                await item.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None).ConfigureAwait(false);
+                _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions());
             }
 
             return item;
@@ -1849,7 +1864,7 @@ namespace MediaBrowser.Server.Implementations.Library
             // These cause apps to have problems
             options.AudioFileExtensions.Remove(".m3u");
             options.AudioFileExtensions.Remove(".wpl");
-        
+
             if (!ConfigurationManager.Configuration.EnableAudioArchiveFiles)
             {
                 options.AudioFileExtensions.Remove(".rar");

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно