diff --git a/MediaBrowser.Api/Images/RemoteImageService.cs b/MediaBrowser.Api/Images/RemoteImageService.cs index dfa245c0ec..6058733222 100644 --- a/MediaBrowser.Api/Images/RemoteImageService.cs +++ b/MediaBrowser.Api/Images/RemoteImageService.cs @@ -378,7 +378,7 @@ namespace MediaBrowser.Api.Images /// System.String. private string GetFullCachePath(string filename) { - return Path.Combine(_appPaths.DownloadedImagesDataPath, filename.Substring(0, 1), filename); + return Path.Combine(_appPaths.CachePath, "remote-images", filename.Substring(0, 1), filename); } } } diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index 139d8c6fb5..836874db98 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -10,7 +10,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// /// Class Audio /// - public class Audio : BaseItem, IHasMediaStreams, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo + public class Audio : BaseItem, IHasMediaStreams, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo, IHasSeries { public Audio() { @@ -51,6 +51,15 @@ namespace MediaBrowser.Controller.Entities.Audio } } + [IgnoreDataMember] + public string SeriesName + { + get + { + return Album; + } + } + /// /// Gets or sets the artist. /// diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 8b8c1a6ff4..51c8a87273 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -11,7 +11,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// /// Class MusicAlbum /// - public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasTags, IHasLookupInfo + public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasTags, IHasLookupInfo, IHasSeries { public List SoundtrackIds { get; set; } @@ -50,6 +50,15 @@ namespace MediaBrowser.Controller.Entities.Audio } } + [IgnoreDataMember] + public string SeriesName + { + get + { + return AlbumArtist; + } + } + /// /// Override this to true if class should be grouped under a container in indicies /// The container class should be defined via IndexContainer diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 01e8741af2..b3b6361a71 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -256,7 +256,7 @@ namespace MediaBrowser.Controller.Entities private string _sortName; /// - /// Gets or sets the name of the sort. + /// Gets the name of the sort. /// /// The name of the sort. [IgnoreDataMember] diff --git a/MediaBrowser.Controller/Entities/Book.cs b/MediaBrowser.Controller/Entities/Book.cs index 211067f9d2..85cf60c522 100644 --- a/MediaBrowser.Controller/Entities/Book.cs +++ b/MediaBrowser.Controller/Entities/Book.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; namespace MediaBrowser.Controller.Entities { - public class Book : BaseItem, IHasTags, IHasPreferredMetadataLanguage, IHasLookupInfo + public class Book : BaseItem, IHasTags, IHasPreferredMetadataLanguage, IHasLookupInfo, IHasSeries { public override string MediaType { diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 101244d457..25197be675 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -518,7 +518,7 @@ namespace MediaBrowser.Controller.Entities foreach (var child in children) { - if (tasks.Count > 3) + if (tasks.Count > 5) { await Task.WhenAll(tasks).ConfigureAwait(false); tasks.Clear(); @@ -549,7 +549,7 @@ namespace MediaBrowser.Controller.Entities } else { - tasks.Add(RefreshChildMetadata(child, refreshOptions, recursive, innerProgress, cancellationToken)); + tasks.Add(RefreshChildMetadata(child, refreshOptions, false, innerProgress, cancellationToken)); } } diff --git a/MediaBrowser.Controller/Entities/IHasImages.cs b/MediaBrowser.Controller/Entities/IHasImages.cs index d260950bd2..62ef0a85a3 100644 --- a/MediaBrowser.Controller/Entities/IHasImages.cs +++ b/MediaBrowser.Controller/Entities/IHasImages.cs @@ -129,6 +129,12 @@ namespace MediaBrowser.Controller.Entities /// The images. /// true if XXXX, false otherwise. bool AddImages(ImageType imageType, IEnumerable images); + + /// + /// Determines whether [is save local metadata enabled]. + /// + /// true if [is save local metadata enabled]; otherwise, false. + bool IsSaveLocalMetadataEnabled(); } public static class HasImagesExtensions diff --git a/MediaBrowser.Controller/Entities/IHasMetadata.cs b/MediaBrowser.Controller/Entities/IHasMetadata.cs index 6466e18ce6..1a1956c56e 100644 --- a/MediaBrowser.Controller/Entities/IHasMetadata.cs +++ b/MediaBrowser.Controller/Entities/IHasMetadata.cs @@ -1,5 +1,8 @@ using System; using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.Library; using MediaBrowser.Model.Entities; namespace MediaBrowser.Controller.Entities @@ -33,16 +36,18 @@ namespace MediaBrowser.Controller.Entities /// The date last saved. DateTime DateLastSaved { get; set; } - /// - /// Determines whether [is save local metadata enabled]. - /// - /// true if [is save local metadata enabled]; otherwise, false. - bool IsSaveLocalMetadataEnabled(); - /// /// Gets a value indicating whether this instance is in mixed folder. /// /// true if this instance is in mixed folder; otherwise, false. bool IsInMixedFolder { get; } + + /// + /// Updates to repository. + /// + /// The update reason. + /// The cancellation token. + /// Task. + Task UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/Entities/IHasSeries.cs b/MediaBrowser.Controller/Entities/IHasSeries.cs new file mode 100644 index 0000000000..64c33a3766 --- /dev/null +++ b/MediaBrowser.Controller/Entities/IHasSeries.cs @@ -0,0 +1,12 @@ + +namespace MediaBrowser.Controller.Entities +{ + public interface IHasSeries + { + /// + /// Gets the name of the series. + /// + /// The name of the series. + string SeriesName { get; } + } +} diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index 4d01c6a961..7214f0f6f3 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -13,7 +13,7 @@ namespace MediaBrowser.Controller.Entities.Movies /// /// Class Movie /// - public class Movie : Video, IHasCriticRating, IHasSoundtracks, IHasBudget, IHasKeywords, IHasTrailers, IHasThemeMedia, IHasTaglines, IHasTags, IHasPreferredMetadataLanguage, IHasAwards, IHasMetascore, IHasLookupInfo + public class Movie : Video, IHasCriticRating, IHasSoundtracks, IHasBudget, IHasKeywords, IHasTrailers, IHasThemeMedia, IHasTaglines, IHasPreferredMetadataLanguage, IHasAwards, IHasMetascore, IHasLookupInfo { public List SpecialFeatureIds { get; set; } @@ -39,7 +39,6 @@ namespace MediaBrowser.Controller.Entities.Movies ThemeSongIds = new List(); ThemeVideoIds = new List(); Taglines = new List(); - Tags = new List(); Keywords = new List(); } @@ -52,12 +51,6 @@ namespace MediaBrowser.Controller.Entities.Movies public List RemoteTrailers { get; set; } - /// - /// Gets or sets the tags. - /// - /// The tags. - public List Tags { get; set; } - /// /// Gets or sets the taglines. /// diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index 515f802e99..5413aa8852 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -10,7 +10,7 @@ namespace MediaBrowser.Controller.Entities.TV /// /// Class Episode /// - public class Episode : Video, IHasLookupInfo + public class Episode : Video, IHasLookupInfo, IHasSeries { /// /// Gets the season in which it aired. @@ -138,6 +138,16 @@ namespace MediaBrowser.Controller.Entities.TV get { return FindParent(); } } + [IgnoreDataMember] + public string SeriesName + { + get + { + var series = Series; + return series == null ? null : series.Name; + } + } + /// /// Creates the name of the sort. /// diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index bc7e75b726..d266f1fded 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -1,11 +1,8 @@ -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Localization; +using MediaBrowser.Controller.Localization; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; -using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Runtime.Serialization; @@ -14,7 +11,7 @@ namespace MediaBrowser.Controller.Entities.TV /// /// Class Season /// - public class Season : Folder + public class Season : Folder, IHasSeries { /// @@ -218,7 +215,7 @@ namespace MediaBrowser.Controller.Entities.TV { episodes = episodes.Where(i => !i.IsVirtualUnaired); } - + return LibraryManager .Sort(episodes, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending) .Cast(); @@ -234,5 +231,15 @@ namespace MediaBrowser.Controller.Entities.TV // Don't block. Let either the entire series rating or episode rating determine it return false; } + + [IgnoreDataMember] + public string SeriesName + { + get + { + var series = Series; + return series == null ? null : series.Name; + } + } } } diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index 9b3104037c..d655c275d8 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -10,7 +10,7 @@ namespace MediaBrowser.Controller.Entities /// /// Class Trailer /// - public class Trailer : Video, IHasCriticRating, IHasSoundtracks, IHasBudget, IHasTrailers, IHasKeywords, IHasTaglines, IHasTags, IHasPreferredMetadataLanguage, IHasMetascore, IHasLookupInfo + public class Trailer : Video, IHasCriticRating, IHasSoundtracks, IHasBudget, IHasTrailers, IHasKeywords, IHasTaglines, IHasPreferredMetadataLanguage, IHasMetascore, IHasLookupInfo { public List SoundtrackIds { get; set; } @@ -28,7 +28,6 @@ namespace MediaBrowser.Controller.Entities Taglines = new List(); SoundtrackIds = new List(); LocalTrailerIds = new List(); - Tags = new List(); Keywords = new List(); } @@ -40,12 +39,6 @@ namespace MediaBrowser.Controller.Entities public List Keywords { get; set; } - /// - /// Gets or sets the tags. - /// - /// The tags. - public List Tags { get; set; } - /// /// Gets or sets the taglines. /// diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 6aa3ae819a..e7bee35f50 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -16,7 +16,7 @@ namespace MediaBrowser.Controller.Entities /// /// Class Video /// - public class Video : BaseItem, IHasMediaStreams, IHasAspectRatio + public class Video : BaseItem, IHasMediaStreams, IHasAspectRatio, IHasTags { public bool IsMultiPart { get; set; } @@ -26,6 +26,7 @@ namespace MediaBrowser.Controller.Entities { PlayableStreamFileNames = new List(); AdditionalPartIds = new List(); + Tags = new List(); } /// @@ -34,6 +35,12 @@ namespace MediaBrowser.Controller.Entities /// true if this instance has subtitles; otherwise, false. public bool HasSubtitles { get; set; } + /// + /// Gets or sets the tags. + /// + /// The tags. + public List Tags { get; set; } + /// /// Gets or sets the video bit rate. /// diff --git a/MediaBrowser.Controller/IServerApplicationPaths.cs b/MediaBrowser.Controller/IServerApplicationPaths.cs index e163ac31dd..05f6815979 100644 --- a/MediaBrowser.Controller/IServerApplicationPaths.cs +++ b/MediaBrowser.Controller/IServerApplicationPaths.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Configuration; +using System; +using MediaBrowser.Common.Configuration; namespace MediaBrowser.Controller { @@ -101,9 +102,16 @@ namespace MediaBrowser.Controller string TranscodingTempPath { get; } /// - /// Gets the downloaded images data path. + /// Gets the internal metadata path. /// - /// The downloaded images data path. - string DownloadedImagesDataPath { get; } + /// The internal metadata path. + string InternalMetadataPath { get; } + + /// + /// Gets the internal metadata path. + /// + /// The identifier. + /// System.String. + string GetInternalMetadataPath(Guid id); } } \ No newline at end of file diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 00e84177cb..41e737300d 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -94,6 +94,7 @@ + diff --git a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs index dbb8c1edf2..928e958338 100644 --- a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs +++ b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs @@ -247,7 +247,10 @@ namespace MediaBrowser.Controller.Providers { var val = reader.ReadElementContentAsString(); - + if (!string.IsNullOrWhiteSpace(val)) + { + item.ForcedSortName = val; + } break; } diff --git a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs index 6818fa52bc..f8580244a1 100644 --- a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs +++ b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs @@ -40,8 +40,6 @@ namespace MediaBrowser.Controller.Providers protected static readonly Task FalseTaskResult = Task.FromResult(false); - protected static readonly SemaphoreSlim XmlParsingResourcePool = new SemaphoreSlim(4, 4); - /// /// Supportses the specified item. /// diff --git a/MediaBrowser.Controller/Providers/BaseProviderInfo.cs b/MediaBrowser.Controller/Providers/BaseProviderInfo.cs index 829dd34c8e..3a33924f0d 100644 --- a/MediaBrowser.Controller/Providers/BaseProviderInfo.cs +++ b/MediaBrowser.Controller/Providers/BaseProviderInfo.cs @@ -38,14 +38,14 @@ namespace MediaBrowser.Controller.Providers /// /// The success /// - Success, - /// - /// The failure - /// - Failure, + Success = 0, /// /// The completed with errors /// - CompletedWithErrors - } + CompletedWithErrors = 1, + /// + /// The failure + /// + Failure = 2 + } } diff --git a/MediaBrowser.Controller/Providers/ILocalImageProvider.cs b/MediaBrowser.Controller/Providers/ILocalImageProvider.cs index d1ef68ce2a..6b97a552d1 100644 --- a/MediaBrowser.Controller/Providers/ILocalImageProvider.cs +++ b/MediaBrowser.Controller/Providers/ILocalImageProvider.cs @@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Providers { } - public interface IImageFileProvider : ILocalImageProvider + public interface ILocalImageFileProvider : ILocalImageProvider { List GetImages(IHasImages item); } diff --git a/MediaBrowser.Controller/Providers/IProviderRepository.cs b/MediaBrowser.Controller/Providers/IProviderRepository.cs index 1c0ad2cd73..3cd2c3f318 100644 --- a/MediaBrowser.Controller/Providers/IProviderRepository.cs +++ b/MediaBrowser.Controller/Providers/IProviderRepository.cs @@ -8,22 +8,6 @@ namespace MediaBrowser.Controller.Providers { public interface IProviderRepository : IRepository { - /// - /// Gets the provider history. - /// - /// The item identifier. - /// IEnumerable{BaseProviderInfo}. - IEnumerable GetProviderHistory(Guid itemId); - - /// - /// Saves the provider history. - /// - /// The identifier. - /// The history. - /// The cancellation token. - /// Task. - Task SaveProviderHistory(Guid id, IEnumerable history, CancellationToken cancellationToken); - /// /// Gets the metadata status. /// diff --git a/MediaBrowser.Controller/Providers/MetadataStatus.cs b/MediaBrowser.Controller/Providers/MetadataStatus.cs index 834d8ec35f..adfae54f50 100644 --- a/MediaBrowser.Controller/Providers/MetadataStatus.cs +++ b/MediaBrowser.Controller/Providers/MetadataStatus.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using MediaBrowser.Common.Extensions; namespace MediaBrowser.Controller.Providers { @@ -13,6 +12,18 @@ namespace MediaBrowser.Controller.Providers /// The item identifier. public Guid ItemId { get; set; } + /// + /// Gets or sets the name of the item. + /// + /// The name of the item. + public string ItemName { get; set; } + + /// + /// Gets or sets the name of the series. + /// + /// The name of the series. + public string SeriesName { get; set; } + /// /// Gets or sets the date last metadata refresh. /// diff --git a/MediaBrowser.Providers/AdultVideos/AdultVideoMetadataService.cs b/MediaBrowser.Providers/AdultVideos/AdultVideoMetadataService.cs index 4a713e735d..b0d6af8872 100644 --- a/MediaBrowser.Providers/AdultVideos/AdultVideoMetadataService.cs +++ b/MediaBrowser.Providers/AdultVideos/AdultVideoMetadataService.cs @@ -34,10 +34,5 @@ namespace MediaBrowser.Providers.AdultVideos { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } - - protected override Task SaveItem(AdultVideo item, ItemUpdateType reason, CancellationToken cancellationToken) - { - return _libraryManager.UpdateItem(item, reason, cancellationToken); - } } } diff --git a/MediaBrowser.Providers/All/InternalMetadataFolderImageProvider.cs b/MediaBrowser.Providers/All/InternalMetadataFolderImageProvider.cs new file mode 100644 index 0000000000..cecde64ca3 --- /dev/null +++ b/MediaBrowser.Providers/All/InternalMetadataFolderImageProvider.cs @@ -0,0 +1,71 @@ +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using System.Collections.Generic; +using System.IO; + +namespace MediaBrowser.Providers.All +{ + public class InternalMetadataFolderImageProvider : ILocalImageFileProvider, IHasOrder + { + private readonly IServerConfigurationManager _config; + + public InternalMetadataFolderImageProvider(IServerConfigurationManager config) + { + _config = config; + } + + public string Name + { + get { return "Internal Images"; } + } + + public bool Supports(IHasImages item) + { + if (!item.IsSaveLocalMetadataEnabled()) + { + return true; + } + + var locationType = item.LocationType; + + if (locationType == LocationType.FileSystem || + locationType == LocationType.Offline) + { + return false; + } + + // These always save locally + if (item is IItemByName || item is User) + { + return false; + } + + return true; + } + + public int Order + { + get + { + // Make sure this is last so that all other locations are scanned first + return 1000; + } + } + + public List GetImages(IHasImages item) + { + var path = _config.ApplicationPaths.GetInternalMetadataPath(item.Id); + + try + { + return new LocalImageProvider().GetImages(item, path); + } + catch (DirectoryNotFoundException) + { + return new List(); + } + } + } +} diff --git a/MediaBrowser.Providers/All/LocalImageProvider.cs b/MediaBrowser.Providers/All/LocalImageProvider.cs index 0d078499d5..7d70a35b6d 100644 --- a/MediaBrowser.Providers/All/LocalImageProvider.cs +++ b/MediaBrowser.Providers/All/LocalImageProvider.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; @@ -13,15 +12,8 @@ using System.Linq; namespace MediaBrowser.Providers.All { - public class LocalImageProvider : IImageFileProvider + public class LocalImageProvider : ILocalImageFileProvider { - private readonly IFileSystem _fileSystem; - - public LocalImageProvider(IFileSystem fileSystem) - { - _fileSystem = fileSystem; - } - public string Name { get { return "Local Images"; } @@ -91,12 +83,37 @@ namespace MediaBrowser.Providers.All var list = new List(); - PopulateImages(item, list, files); + PopulateImages(item, list, files, true); return list; } - private void PopulateImages(IHasImages item, List images, List files) + public List GetImages(IHasImages item, string path) + { + return GetImages(item, new[] { path }); + } + + public List GetImages(IHasImages item, IEnumerable paths) + { + var files = paths.SelectMany(i => new DirectoryInfo(i).EnumerateFiles("*", SearchOption.TopDirectoryOnly)) + .Where(i => + { + var ext = i.Extension; + + return !string.IsNullOrEmpty(ext) && + BaseItem.SupportedImageExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase); + }) + .Cast() + .ToList(); + + var list = new List(); + + PopulateImages(item, list, files, false); + + return list; + } + + private void PopulateImages(IHasImages item, List images, List files, bool supportParentSeriesFiles) { var imagePrefix = string.Empty; @@ -126,11 +143,14 @@ namespace MediaBrowser.Providers.All AddImage(files, images, imagePrefix + "thumb", ImageType.Thumb); AddImage(files, images, imagePrefix + "landscape", ImageType.Thumb); - var season = item as Season; - - if (season != null) + if (supportParentSeriesFiles) { - PopulateSeasonImagesFromSeriesFolder(season, images); + var season = item as Season; + + if (season != null) + { + PopulateSeasonImagesFromSeriesFolder(season, images); + } } } @@ -278,7 +298,7 @@ namespace MediaBrowser.Providers.All } } - private bool AddImage(List files, List images, string name, ImageType type) + private bool AddImage(IEnumerable files, List images, string name, ImageType type) { var image = GetImage(files, name) as FileInfo; diff --git a/MediaBrowser.Providers/Books/BookMetadataService.cs b/MediaBrowser.Providers/Books/BookMetadataService.cs index c314b0a084..0cf672e2d5 100644 --- a/MediaBrowser.Providers/Books/BookMetadataService.cs +++ b/MediaBrowser.Providers/Books/BookMetadataService.cs @@ -39,10 +39,5 @@ namespace MediaBrowser.Providers.Books target.SeriesName = source.SeriesName; } } - - protected override Task SaveItem(Book item, ItemUpdateType reason, CancellationToken cancellationToken) - { - return _libraryManager.UpdateItem(item, reason, cancellationToken); - } } } diff --git a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs index b1b5c7580c..f4716f6ddb 100644 --- a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs +++ b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs @@ -41,11 +41,6 @@ namespace MediaBrowser.Providers.BoxSets ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } - protected override Task SaveItem(BoxSet item, ItemUpdateType reason, CancellationToken cancellationToken) - { - return _libraryManager.UpdateItem(item, reason, cancellationToken); - } - protected override ItemUpdateType BeforeSave(BoxSet item) { var updateType = base.BeforeSave(item); diff --git a/MediaBrowser.Providers/Folders/CollectionFolderImageProvider.cs b/MediaBrowser.Providers/Folders/CollectionFolderImageProvider.cs new file mode 100644 index 0000000000..f1b9a8384e --- /dev/null +++ b/MediaBrowser.Providers/Folders/CollectionFolderImageProvider.cs @@ -0,0 +1,37 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Providers.All; +using System.Collections.Generic; + +namespace MediaBrowser.Providers.Folders +{ + public class CollectionFolderLocalImageProvider : ILocalImageFileProvider, IHasOrder + { + public string Name + { + get { return "Collection Folder Images"; } + } + + public bool Supports(IHasImages item) + { + return item is CollectionFolder && item.LocationType == LocationType.FileSystem; + } + + public int Order + { + get + { + // Run after LocalImageProvider + return 1; + } + } + + public List GetImages(IHasImages item) + { + var collectionFolder = (CollectionFolder)item; + + return new LocalImageProvider().GetImages(item, collectionFolder.PhysicalLocations); + } + } +} diff --git a/MediaBrowser.Providers/Folders/FolderMetadataService.cs b/MediaBrowser.Providers/Folders/FolderMetadataService.cs index 5ce23aa76e..c9e44177e2 100644 --- a/MediaBrowser.Providers/Folders/FolderMetadataService.cs +++ b/MediaBrowser.Providers/Folders/FolderMetadataService.cs @@ -7,8 +7,6 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; namespace MediaBrowser.Providers.Folders { @@ -35,11 +33,6 @@ namespace MediaBrowser.Providers.Folders ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } - protected override Task SaveItem(Folder item, ItemUpdateType reason, CancellationToken cancellationToken) - { - return _libraryManager.UpdateItem(item, reason, cancellationToken); - } - public override int Order { get diff --git a/MediaBrowser.Providers/Folders/ImagesByNameImageProvider.cs b/MediaBrowser.Providers/Folders/ImagesByNameImageProvider.cs new file mode 100644 index 0000000000..e87f0919fd --- /dev/null +++ b/MediaBrowser.Providers/Folders/ImagesByNameImageProvider.cs @@ -0,0 +1,57 @@ +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Providers.All; +using System.Collections.Generic; +using System.IO; + +namespace MediaBrowser.Providers.Folders +{ + public class ImagesByNameImageProvider : ILocalImageFileProvider, IHasOrder + { + private readonly IFileSystem _fileSystem; + private readonly IServerConfigurationManager _config; + + public ImagesByNameImageProvider(IFileSystem fileSystem, IServerConfigurationManager config) + { + _fileSystem = fileSystem; + _config = config; + } + + public string Name + { + get { return "Images By Name"; } + } + + public bool Supports(IHasImages item) + { + return item is ICollectionFolder; + } + + public int Order + { + get + { + // Run after LocalImageProvider, and after CollectionFolderImageProvider + return 2; + } + } + + public List GetImages(IHasImages item) + { + var name = _fileSystem.GetValidFilename(item.Name); + + var path = Path.Combine(_config.ApplicationPaths.GeneralPath, name); + + try + { + return new LocalImageProvider().GetImages(item, path); + } + catch (DirectoryNotFoundException) + { + return new List(); + } + } + } +} diff --git a/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs b/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs index 0f28628466..0eaed59c78 100644 --- a/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs +++ b/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs @@ -34,10 +34,5 @@ namespace MediaBrowser.Providers.GameGenres { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } - - protected override Task SaveItem(GameGenre item, ItemUpdateType reason, CancellationToken cancellationToken) - { - return _libraryManager.UpdateItem(item, reason, cancellationToken); - } } } diff --git a/MediaBrowser.Providers/Games/GameMetadataService.cs b/MediaBrowser.Providers/Games/GameMetadataService.cs index 3a786385b7..1586414ea2 100644 --- a/MediaBrowser.Providers/Games/GameMetadataService.cs +++ b/MediaBrowser.Providers/Games/GameMetadataService.cs @@ -39,10 +39,5 @@ namespace MediaBrowser.Providers.Games target.GameSystem = source.GameSystem; } } - - protected override Task SaveItem(Game item, ItemUpdateType reason, CancellationToken cancellationToken) - { - return _libraryManager.UpdateItem(item, reason, cancellationToken); - } } } diff --git a/MediaBrowser.Providers/Games/GameSystemMetadataService.cs b/MediaBrowser.Providers/Games/GameSystemMetadataService.cs index 9fb539d988..ae1ee1993b 100644 --- a/MediaBrowser.Providers/Games/GameSystemMetadataService.cs +++ b/MediaBrowser.Providers/Games/GameSystemMetadataService.cs @@ -39,10 +39,5 @@ namespace MediaBrowser.Providers.Games target.GameSystemName = source.GameSystemName; } } - - protected override Task SaveItem(GameSystem item, ItemUpdateType reason, CancellationToken cancellationToken) - { - return _libraryManager.UpdateItem(item, reason, cancellationToken); - } } } diff --git a/MediaBrowser.Providers/Genres/GenreMetadataService.cs b/MediaBrowser.Providers/Genres/GenreMetadataService.cs index 199f79baf7..b19241095f 100644 --- a/MediaBrowser.Providers/Genres/GenreMetadataService.cs +++ b/MediaBrowser.Providers/Genres/GenreMetadataService.cs @@ -34,10 +34,5 @@ namespace MediaBrowser.Providers.Genres { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } - - protected override Task SaveItem(Genre item, ItemUpdateType reason, CancellationToken cancellationToken) - { - return _libraryManager.UpdateItem(item, reason, cancellationToken); - } } } diff --git a/MediaBrowser.Providers/LiveTv/AudioRecordingService.cs b/MediaBrowser.Providers/LiveTv/AudioRecordingService.cs index d11fb77ee7..7ae27f4c9a 100644 --- a/MediaBrowser.Providers/LiveTv/AudioRecordingService.cs +++ b/MediaBrowser.Providers/LiveTv/AudioRecordingService.cs @@ -33,10 +33,5 @@ namespace MediaBrowser.Providers.LiveTv { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } - - protected override Task SaveItem(LiveTvAudioRecording item, ItemUpdateType reason, CancellationToken cancellationToken) - { - return _libraryManager.UpdateItem(item, reason, cancellationToken); - } } } diff --git a/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs b/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs index fecee3ae2c..57bc701565 100644 --- a/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs +++ b/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs @@ -29,10 +29,5 @@ namespace MediaBrowser.Providers.LiveTv { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } - - protected override Task SaveItem(LiveTvChannel item, ItemUpdateType reason, CancellationToken cancellationToken) - { - return _libraryManager.UpdateItem(item, reason, cancellationToken); - } } } diff --git a/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs b/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs index e6f0203238..3172e01349 100644 --- a/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs +++ b/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs @@ -33,10 +33,5 @@ namespace MediaBrowser.Providers.LiveTv { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } - - protected override Task SaveItem(LiveTvProgram item, ItemUpdateType reason, CancellationToken cancellationToken) - { - return _libraryManager.UpdateItem(item, reason, cancellationToken); - } } } diff --git a/MediaBrowser.Providers/LiveTv/VideoRecordingService.cs b/MediaBrowser.Providers/LiveTv/VideoRecordingService.cs index fb4156e8db..f526db7759 100644 --- a/MediaBrowser.Providers/LiveTv/VideoRecordingService.cs +++ b/MediaBrowser.Providers/LiveTv/VideoRecordingService.cs @@ -33,10 +33,5 @@ namespace MediaBrowser.Providers.LiveTv { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } - - protected override Task SaveItem(LiveTvVideoRecording item, ItemUpdateType reason, CancellationToken cancellationToken) - { - return _libraryManager.UpdateItem(item, reason, cancellationToken); - } } } diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 1bccc6bb81..1b0ae1b5e9 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -29,10 +29,6 @@ namespace MediaBrowser.Providers.Manager /// private readonly IServerConfigurationManager _config; - /// - /// The remote image cache - /// - private readonly FileSystemRepository _remoteImageCache; /// /// The _directory watchers /// @@ -41,17 +37,18 @@ namespace MediaBrowser.Providers.Manager private readonly ILogger _logger; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The config. /// The directory watchers. + /// The file system. + /// The logger. public ImageSaver(IServerConfigurationManager config, ILibraryMonitor libraryMonitor, IFileSystem fileSystem, ILogger logger) { _config = config; _libraryMonitor = libraryMonitor; _fileSystem = fileSystem; _logger = logger; - _remoteImageCache = new FileSystemRepository(config.ApplicationPaths.DownloadedImagesDataPath); } /// @@ -348,7 +345,7 @@ namespace MediaBrowser.Providers.Manager // None of the save local conditions passed, so store it in our internal folders if (string.IsNullOrEmpty(path)) { - path = _remoteImageCache.GetResourcePath(item.GetType().FullName + item.Id, filename + extension); + path = Path.Combine(_config.ApplicationPaths.GetInternalMetadataPath(item.Id), filename + extension); } return path; diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 4ba959d14b..b50e028bff 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -38,7 +38,7 @@ namespace MediaBrowser.Providers.Manager { var hasChanges = item.ValidateImages(); - foreach (var provider in providers.OfType()) + foreach (var provider in providers.OfType()) { var images = provider.GetImages(item); @@ -117,8 +117,7 @@ namespace MediaBrowser.Providers.Manager { var mimeType = "image/" + Path.GetExtension(response.Path).TrimStart('.').ToLower(); - var stream = _fileSystem.GetFileStream(response.Path, FileMode.Open, FileAccess.Read, - FileShare.Read, true); + var stream = _fileSystem.GetFileStream(response.Path, FileMode.Open, FileAccess.Read, FileShare.Read, true); await _providerManager.SaveImage((BaseItem)item, stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false); } @@ -335,7 +334,7 @@ namespace MediaBrowser.Providers.Manager } catch (HttpException ex) { - // Sometimes providers send back bad url's. Just move onto the next image + // Sometimes providers send back bad url's. Just move to the next image if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound) { continue; diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 21173aebc9..be42589b7c 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -37,10 +37,18 @@ namespace MediaBrowser.Providers.Manager /// /// Saves the provider result. /// + /// The item. /// The result. /// Task. - protected Task SaveProviderResult(MetadataStatus result) + protected Task SaveProviderResult(TItemType item, MetadataStatus result) { + result.ItemId = item.Id; + result.ItemName = item.Name; + + var series = item as IHasSeries; + + result.SeriesName = series == null ? null : series.SeriesName; + return ProviderRepo.SaveMetadataStatus(result, CancellationToken.None); } @@ -97,7 +105,6 @@ namespace MediaBrowser.Providers.Manager if (providers.Count > 0) { - var result = await RefreshWithProviders(itemOfType, refreshOptions, providers, cancellationToken).ConfigureAwait(false); updateType = updateType | result.UpdateType; @@ -140,7 +147,7 @@ namespace MediaBrowser.Providers.Manager if (providersHadChanges || refreshResult.IsDirty) { - await SaveProviderResult(refreshResult).ConfigureAwait(false); + await SaveProviderResult(itemOfType, refreshResult).ConfigureAwait(false); } } @@ -231,7 +238,10 @@ namespace MediaBrowser.Providers.Manager return providers; } - protected abstract Task SaveItem(TItemType item, ItemUpdateType reason, CancellationToken cancellationToken); + protected Task SaveItem(TItemType item, ItemUpdateType reason, CancellationToken cancellationToken) + { + return item.UpdateToRepository(reason, cancellationToken); + } public bool CanRefresh(IHasMetadata item) { @@ -298,6 +308,7 @@ namespace MediaBrowser.Providers.Manager } } + // Local metadata is king - if any is found don't run remote providers if (!options.ReplaceAllMetadata && !hasLocalMetadata) { await ExecuteRemoteProviders(item, temp, providers.OfType>(), refreshResult, cancellationToken).ConfigureAwait(false); @@ -349,7 +360,14 @@ namespace MediaBrowser.Providers.Manager { Logger.Debug("Running {0} for {1}", provider.GetType().Name, item.Path ?? item.Name); - id = id ?? item.GetLookupInfo(); + if (id == null) + { + id = item.GetLookupInfo(); + } + else + { + MergeNewData(temp, id); + } try { @@ -375,6 +393,15 @@ namespace MediaBrowser.Providers.Manager } } + private void MergeNewData(TItemType source, TIdType lookupInfo) + { + // Copy new provider id's that may have been obtained + foreach (var providerId in source.ProviderIds) + { + lookupInfo.ProviderIds[providerId.Key] = providerId.Value; + } + } + protected abstract void MergeData(TItemType source, TItemType target, List lockedFields, bool replaceData, bool mergeMetadataSettings); public virtual int Order diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index aec08a2927..e0b07ef3a1 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -470,7 +470,7 @@ namespace MediaBrowser.Providers.Manager })); // Savers - list.AddRange(_savers.Where(i => i.IsEnabledFor(item, ItemUpdateType.MetadataEdit)).OrderBy(i => i.Name).Select(i => new MetadataPlugin + list.AddRange(_savers.Where(i => IsSaverEnabledForItem(i, item, ItemUpdateType.MetadataEdit)).OrderBy(i => i.Name).Select(i => new MetadataPlugin { Name = i.Name, Type = MetadataPluginType.MetadataSaver @@ -506,7 +506,7 @@ namespace MediaBrowser.Providers.Manager /// Task. public async Task SaveMetadata(IHasMetadata item, ItemUpdateType updateType) { - foreach (var saver in _savers.Where(i => i.IsEnabledFor(item, updateType))) + foreach (var saver in _savers.Where(i => IsSaverEnabledForItem(i, item, updateType))) { _logger.Debug("Saving {0} to {1}.", item.Path ?? item.Name, saver.Name); @@ -514,13 +514,17 @@ namespace MediaBrowser.Providers.Manager if (fileSaver != null) { - var locationType = item.LocationType; - if (locationType == LocationType.Remote || locationType == LocationType.Virtual) - { - throw new ArgumentException("Only file-system based items can save metadata."); - } + string path = null; - var path = fileSaver.GetSavePath(item); + try + { + path = fileSaver.GetSavePath(item); + } + catch (Exception ex) + { + _logger.ErrorException("Error in {0} GetSavePath", ex, saver.Name); + continue; + } var semaphore = _fileLocks.GetOrAdd(path, key => new SemaphoreSlim(1, 1)); @@ -554,5 +558,18 @@ namespace MediaBrowser.Providers.Manager } } } + + private bool IsSaverEnabledForItem(IMetadataSaver saver, IHasMetadata item, ItemUpdateType updateType) + { + try + { + return saver.IsEnabledFor(item, updateType); + } + catch (Exception ex) + { + _logger.ErrorException("Error in {0}.IsEnabledFor", ex, saver.Name); + return false; + } + } } } diff --git a/MediaBrowser.Providers/ProviderUtils.cs b/MediaBrowser.Providers/Manager/ProviderUtils.cs similarity index 99% rename from MediaBrowser.Providers/ProviderUtils.cs rename to MediaBrowser.Providers/Manager/ProviderUtils.cs index ecefb72c40..6e994c9f28 100644 --- a/MediaBrowser.Providers/ProviderUtils.cs +++ b/MediaBrowser.Providers/Manager/ProviderUtils.cs @@ -3,7 +3,7 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Model.Entities; using System.Collections.Generic; -namespace MediaBrowser.Providers +namespace MediaBrowser.Providers.Manager { public static class ProviderUtils { diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index da9ea2947f..d494f17b6f 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -66,12 +66,15 @@ + + + @@ -145,8 +148,7 @@ - - + diff --git a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs index 94d8566e14..ba3b468d47 100644 --- a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs +++ b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs @@ -3,6 +3,7 @@ using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Dto; diff --git a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs index ebed0c2030..45d1eb5318 100644 --- a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs +++ b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; @@ -143,10 +144,6 @@ namespace MediaBrowser.Providers.Movies movieItem.TmdbCollectionName = movieData.belongs_to_collection.name; } } - else - { - movie.SetProviderId(MetadataProviders.TmdbCollection, null); // clear out any old entry - } float rating; string voteAvg = movieData.vote_average.ToString(CultureInfo.InvariantCulture); diff --git a/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs b/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs index be2f7ad614..db34688165 100644 --- a/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Dto; @@ -15,7 +16,7 @@ using System.Threading.Tasks; namespace MediaBrowser.Providers.Movies { - class MovieDbImageProvider : IRemoteImageProvider, IHasOrder + class MovieDbImageProvider : IRemoteImageProvider, IHasOrder, IHasChangeMonitor { private readonly IJsonSerializer _jsonSerializer; private readonly IHttpClient _httpClient; @@ -207,5 +208,10 @@ namespace MediaBrowser.Providers.Movies ResourcePool = MovieDbProvider.Current.MovieDbResourcePool }); } + + public bool HasChanged(IHasMetadata item, DateTime date) + { + return MovieDbProvider.Current.HasChanged(item, date); + } } } diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs index a9526787c4..36dfc64d2b 100644 --- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs @@ -19,7 +19,7 @@ namespace MediaBrowser.Providers.Movies /// /// Class MovieDbProvider /// - public class MovieDbProvider : IRemoteMetadataProvider, IDisposable, IHasChangeMonitor + public class MovieDbProvider : IRemoteMetadataProvider, IDisposable { internal readonly SemaphoreSlim MovieDbResourcePool = new SemaphoreSlim(1, 1); diff --git a/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs b/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs index df786cffc8..ed36cb7afc 100644 --- a/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; namespace MediaBrowser.Providers.Movies { - public class MovieDbTrailerProvider : IRemoteMetadataProvider, IHasChangeMonitor + public class MovieDbTrailerProvider : IRemoteMetadataProvider { public Task> GetMetadata(TrailerInfo info, CancellationToken cancellationToken) { diff --git a/MediaBrowser.Providers/Movies/MovieMetadataService.cs b/MediaBrowser.Providers/Movies/MovieMetadataService.cs index 674b364225..34536d97da 100644 --- a/MediaBrowser.Providers/Movies/MovieMetadataService.cs +++ b/MediaBrowser.Providers/Movies/MovieMetadataService.cs @@ -34,10 +34,5 @@ namespace MediaBrowser.Providers.Movies { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } - - protected override Task SaveItem(Movie item, ItemUpdateType reason, CancellationToken cancellationToken) - { - return _libraryManager.UpdateItem(item, reason, cancellationToken); - } } } diff --git a/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs b/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs index 3f200dc8c5..483175f371 100644 --- a/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs +++ b/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs @@ -1,6 +1,5 @@ using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; -using MediaBrowser.Common.Progress; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; diff --git a/MediaBrowser.Providers/Movies/TrailerMetadataService.cs b/MediaBrowser.Providers/Movies/TrailerMetadataService.cs index 620799a18d..d9ae6187cf 100644 --- a/MediaBrowser.Providers/Movies/TrailerMetadataService.cs +++ b/MediaBrowser.Providers/Movies/TrailerMetadataService.cs @@ -34,10 +34,5 @@ namespace MediaBrowser.Providers.Movies { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } - - protected override Task SaveItem(Trailer item, ItemUpdateType reason, CancellationToken cancellationToken) - { - return _libraryManager.UpdateItem(item, reason, cancellationToken); - } } } diff --git a/MediaBrowser.Providers/Music/AlbumMetadataService.cs b/MediaBrowser.Providers/Music/AlbumMetadataService.cs index d4bbe5a28c..410441fc82 100644 --- a/MediaBrowser.Providers/Music/AlbumMetadataService.cs +++ b/MediaBrowser.Providers/Music/AlbumMetadataService.cs @@ -42,11 +42,6 @@ namespace MediaBrowser.Providers.Music } } - protected override Task SaveItem(MusicAlbum item, ItemUpdateType reason, CancellationToken cancellationToken) - { - return _libraryManager.UpdateItem(item, reason, cancellationToken); - } - protected override ItemUpdateType BeforeSave(MusicAlbum item) { var updateType = base.BeforeSave(item); diff --git a/MediaBrowser.Providers/Music/ArtistMetadataService.cs b/MediaBrowser.Providers/Music/ArtistMetadataService.cs index 9cc4406ac0..1b7f229e47 100644 --- a/MediaBrowser.Providers/Music/ArtistMetadataService.cs +++ b/MediaBrowser.Providers/Music/ArtistMetadataService.cs @@ -9,12 +9,10 @@ using MediaBrowser.Providers.Manager; using System; using System.Collections.Generic; using System.Linq; -using System.Threading; -using System.Threading.Tasks; namespace MediaBrowser.Providers.Music { - public class ArtistMetadataService : MetadataService + public class ArtistMetadataService : MetadataService { private readonly ILibraryManager _libraryManager; @@ -37,11 +35,6 @@ namespace MediaBrowser.Providers.Music ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } - protected override Task SaveItem(MusicArtist item, ItemUpdateType reason, CancellationToken cancellationToken) - { - return _libraryManager.UpdateItem(item, reason, cancellationToken); - } - protected override ItemUpdateType BeforeSave(MusicArtist item) { var updateType = base.BeforeSave(item); diff --git a/MediaBrowser.Providers/Music/AudioMetadataService.cs b/MediaBrowser.Providers/Music/AudioMetadataService.cs index 408f499dcd..cda22b0f5e 100644 --- a/MediaBrowser.Providers/Music/AudioMetadataService.cs +++ b/MediaBrowser.Providers/Music/AudioMetadataService.cs @@ -44,10 +44,5 @@ namespace MediaBrowser.Providers.Music target.Album = source.Album; } } - - protected override Task SaveItem(Audio item, ItemUpdateType reason, CancellationToken cancellationToken) - { - return _libraryManager.UpdateItem(item, reason, cancellationToken); - } } } diff --git a/MediaBrowser.Providers/Music/Extensions.cs b/MediaBrowser.Providers/Music/Extensions.cs index 0ba02cbec2..671242eed1 100644 --- a/MediaBrowser.Providers/Music/Extensions.cs +++ b/MediaBrowser.Providers/Music/Extensions.cs @@ -63,5 +63,19 @@ namespace MediaBrowser.Providers.Music return id; } + + public static string GetArtistId(this ArtistInfo info) + { + string id; + info.ProviderIds.TryGetValue(MetadataProviders.MusicBrainzArtist.ToString(), out id); + + if (string.IsNullOrEmpty(id)) + { + return info.SongInfos.Select(i => i.GetProviderId(MetadataProviders.MusicBrainzAlbumArtist)) + .FirstOrDefault(i => !string.IsNullOrEmpty(i)); + } + + return id; + } } } diff --git a/MediaBrowser.Providers/Music/LastfmAlbumProvider.cs b/MediaBrowser.Providers/Music/LastfmAlbumProvider.cs index 0affbf9094..767c58cb99 100644 --- a/MediaBrowser.Providers/Music/LastfmAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/LastfmAlbumProvider.cs @@ -5,9 +5,11 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; +using MoreLinq; using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; @@ -39,6 +41,7 @@ namespace MediaBrowser.Providers.Music if (lastFmData != null && lastFmData.album != null) { result.HasMetadata = true; + result.Item = new MusicAlbum(); ProcessAlbumData(result.Item, lastFmData.album); } @@ -72,18 +75,18 @@ namespace MediaBrowser.Providers.Music } var albumArtist = item.GetAlbumArtist(); - //// Get each song, distinct by the combination of AlbumArtist and Album - //var songs = item.RecursiveChildren.OfType private void PrepareStatements() { - _deleteInfosCommand = _connection.CreateCommand(); - _deleteInfosCommand.CommandText = "delete from providerinfos where ItemId=@ItemId"; - _deleteInfosCommand.Parameters.Add(_deleteInfosCommand, "@ItemId"); - - _saveInfoCommand = _connection.CreateCommand(); - - _saveInfoCommand.CommandText = string.Format("replace into providerinfos ({0}) values ({1})", - string.Join(",", SaveHistoryColumns), - string.Join(",", SaveHistoryColumns.Select(i => "@" + i).ToArray())); - - foreach (var col in SaveHistoryColumns) - { - _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@" + col); - } - _saveStatusCommand = _connection.CreateCommand(); _saveStatusCommand.CommandText = string.Format("replace into MetadataStatus ({0}) values ({1})", @@ -133,132 +102,6 @@ namespace MediaBrowser.Server.Implementations.Persistence } } - public IEnumerable GetProviderHistory(Guid itemId) - { - if (itemId == Guid.Empty) - { - throw new ArgumentNullException("itemId"); - } - - using (var cmd = _connection.CreateCommand()) - { - var cmdText = "select " + string.Join(",", _historySelectColumns) + " from providerinfos where"; - - cmdText += " ItemId=@ItemId"; - cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = itemId; - - cmd.CommandText = cmdText; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) - { - while (reader.Read()) - { - yield return GetBaseProviderInfo(reader); - } - } - } - } - - /// - /// Gets the base provider information. - /// - /// The reader. - /// BaseProviderInfo. - private BaseProviderInfo GetBaseProviderInfo(IDataReader reader) - { - var item = new BaseProviderInfo - { - ProviderId = reader.GetGuid(0) - }; - - if (!reader.IsDBNull(1)) - { - item.ProviderVersion = reader.GetString(1); - } - - item.FileStamp = reader.GetGuid(2); - item.LastRefreshStatus = (ProviderRefreshStatus)Enum.Parse(typeof(ProviderRefreshStatus), reader.GetString(3), true); - item.LastRefreshed = reader.GetDateTime(4).ToUniversalTime(); - - return item; - } - - public async Task SaveProviderHistory(Guid id, IEnumerable infos, CancellationToken cancellationToken) - { - if (id == Guid.Empty) - { - throw new ArgumentNullException("id"); - } - - if (infos == null) - { - throw new ArgumentNullException("infos"); - } - - cancellationToken.ThrowIfCancellationRequested(); - - await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false); - - IDbTransaction transaction = null; - - try - { - transaction = _connection.BeginTransaction(); - - _deleteInfosCommand.GetParameter(0).Value = id; - - _deleteInfosCommand.Transaction = transaction; - - _deleteInfosCommand.ExecuteNonQuery(); - - foreach (var stream in infos) - { - cancellationToken.ThrowIfCancellationRequested(); - - _saveInfoCommand.GetParameter(0).Value = id; - _saveInfoCommand.GetParameter(1).Value = stream.ProviderId; - _saveInfoCommand.GetParameter(2).Value = stream.ProviderVersion; - _saveInfoCommand.GetParameter(3).Value = stream.FileStamp; - _saveInfoCommand.GetParameter(4).Value = stream.LastRefreshStatus.ToString(); - _saveInfoCommand.GetParameter(5).Value = stream.LastRefreshed; - - _saveInfoCommand.Transaction = transaction; - _saveInfoCommand.ExecuteNonQuery(); - } - - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) - { - transaction.Rollback(); - } - - throw; - } - catch (Exception e) - { - _logger.ErrorException("Failed to save provider info:", e); - - if (transaction != null) - { - transaction.Rollback(); - } - - throw; - } - finally - { - if (transaction != null) - { - transaction.Dispose(); - } - - _writeLock.Release(); - } - } - public MetadataStatus GetMetadataStatus(Guid itemId) { if (itemId == Guid.Empty) @@ -296,32 +139,42 @@ namespace MediaBrowser.Server.Implementations.Persistence if (!reader.IsDBNull(1)) { - result.DateLastMetadataRefresh = reader.GetDateTime(1).ToUniversalTime(); + result.ItemName = reader.GetString(1); } if (!reader.IsDBNull(2)) { - result.DateLastImagesRefresh = reader.GetDateTime(2).ToUniversalTime(); + result.SeriesName = reader.GetString(2); } if (!reader.IsDBNull(3)) { - result.LastStatus = (ProviderRefreshStatus)Enum.Parse(typeof(ProviderRefreshStatus), reader.GetString(3), true); + result.DateLastMetadataRefresh = reader.GetDateTime(3).ToUniversalTime(); } if (!reader.IsDBNull(4)) { - result.LastErrorMessage = reader.GetString(4); + result.DateLastImagesRefresh = reader.GetDateTime(4).ToUniversalTime(); } if (!reader.IsDBNull(5)) { - result.MetadataProvidersRefreshed = reader.GetString(5).Split('|').Where(i => !string.IsNullOrEmpty(i)).Select(i => new Guid(i)).ToList(); + result.LastStatus = (ProviderRefreshStatus)Enum.Parse(typeof(ProviderRefreshStatus), reader.GetString(5), true); } if (!reader.IsDBNull(6)) { - result.ImageProvidersRefreshed = reader.GetString(6).Split('|').Where(i => !string.IsNullOrEmpty(i)).Select(i => new Guid(i)).ToList(); + result.LastErrorMessage = reader.GetString(6); + } + + if (!reader.IsDBNull(7)) + { + result.MetadataProvidersRefreshed = reader.GetString(7).Split('|').Where(i => !string.IsNullOrEmpty(i)).Select(i => new Guid(i)).ToList(); + } + + if (!reader.IsDBNull(8)) + { + result.ImageProvidersRefreshed = reader.GetString(8).Split('|').Where(i => !string.IsNullOrEmpty(i)).Select(i => new Guid(i)).ToList(); } return result; @@ -345,12 +198,14 @@ namespace MediaBrowser.Server.Implementations.Persistence transaction = _connection.BeginTransaction(); _saveStatusCommand.GetParameter(0).Value = status.ItemId; - _saveStatusCommand.GetParameter(1).Value = status.DateLastMetadataRefresh; - _saveStatusCommand.GetParameter(2).Value = status.DateLastImagesRefresh; - _saveStatusCommand.GetParameter(3).Value = status.LastStatus.ToString(); - _saveStatusCommand.GetParameter(4).Value = status.LastErrorMessage; - _saveStatusCommand.GetParameter(5).Value = string.Join("|", status.MetadataProvidersRefreshed.ToArray()); - _saveStatusCommand.GetParameter(6).Value = string.Join("|", status.ImageProvidersRefreshed.ToArray()); + _saveStatusCommand.GetParameter(1).Value = status.ItemName; + _saveStatusCommand.GetParameter(2).Value = status.SeriesName; + _saveStatusCommand.GetParameter(3).Value = status.DateLastMetadataRefresh; + _saveStatusCommand.GetParameter(4).Value = status.DateLastImagesRefresh; + _saveStatusCommand.GetParameter(5).Value = status.LastStatus.ToString(); + _saveStatusCommand.GetParameter(6).Value = status.LastErrorMessage; + _saveStatusCommand.GetParameter(7).Value = string.Join("|", status.MetadataProvidersRefreshed.ToArray()); + _saveStatusCommand.GetParameter(8).Value = string.Join("|", status.ImageProvidersRefreshed.ToArray()); _saveStatusCommand.Transaction = transaction; diff --git a/MediaBrowser.Providers/RefreshIntrosTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/RefreshIntrosTask.cs similarity index 95% rename from MediaBrowser.Providers/RefreshIntrosTask.cs rename to MediaBrowser.Server.Implementations/ScheduledTasks/RefreshIntrosTask.cs index bfe7e7609f..a65b46f640 100644 --- a/MediaBrowser.Providers/RefreshIntrosTask.cs +++ b/MediaBrowser.Server.Implementations/ScheduledTasks/RefreshIntrosTask.cs @@ -1,5 +1,4 @@ using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Logging; using System; @@ -7,7 +6,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -namespace MediaBrowser.Providers +namespace MediaBrowser.Server.Implementations.ScheduledTasks { /// /// Class RefreshIntrosTask @@ -24,12 +23,13 @@ namespace MediaBrowser.Providers private readonly ILogger _logger; private readonly IFileSystem _fileSystem; - + /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The library manager. /// The logger. + /// The file system. public RefreshIntrosTask(ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem) { _libraryManager = libraryManager; diff --git a/MediaBrowser.Server.Implementations/ServerApplicationPaths.cs b/MediaBrowser.Server.Implementations/ServerApplicationPaths.cs index abb60a1d58..c36c49df0e 100644 --- a/MediaBrowser.Server.Implementations/ServerApplicationPaths.cs +++ b/MediaBrowser.Server.Implementations/ServerApplicationPaths.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Implementations; +using System; +using MediaBrowser.Common.Implementations; using MediaBrowser.Controller; using System.IO; @@ -213,18 +214,6 @@ namespace MediaBrowser.Server.Implementations } } - /// - /// Gets the images data path. - /// - /// The images data path. - public string DownloadedImagesDataPath - { - get - { - return Path.Combine(DataPath, "remote-images"); - } - } - /// /// Gets the artists path. /// @@ -249,5 +238,20 @@ namespace MediaBrowser.Server.Implementations return Path.Combine(ItemsByNamePath, "GameGenre"); } } + + public string InternalMetadataPath + { + get + { + return Path.Combine(DataPath, "metadata"); + } + } + + public string GetInternalMetadataPath(Guid id) + { + var idString = id.ToString("N"); + + return Path.Combine(InternalMetadataPath, idString.Substring(0, 2), idString); + } } }