diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs index 98897b9d1..d8ecc3685 100644 --- a/MediaBrowser.Api/ConfigurationService.cs +++ b/MediaBrowser.Api/ConfigurationService.cs @@ -143,7 +143,6 @@ namespace MediaBrowser.Api DisableSaversForType(typeof(Game), config); DisableSaversForType(typeof(GameSystem), config); DisableSaversForType(typeof(Movie), config); - DisableSaversForType(typeof(Trailer), config); DisableSaversForType(typeof(BoxSet), config); DisableSaversForType(typeof(Book), config); DisableSaversForType(typeof(Series), config); diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs index f791f1608..363b0a81b 100644 --- a/MediaBrowser.Controller/Entities/AggregateFolder.cs +++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs @@ -57,7 +57,7 @@ namespace MediaBrowser.Controller.Entities public List PhysicalLocationsList { get; set; } - protected override IEnumerable GetFileSystemChildren(DirectoryService directoryService) + protected override IEnumerable GetFileSystemChildren(IDirectoryService directoryService) { return CreateResolveArgs().FileSystemChildren; } @@ -119,7 +119,7 @@ namespace MediaBrowser.Controller.Entities /// Get the children of this folder from the actual file system /// /// IEnumerable{BaseItem}. - protected override IEnumerable GetNonCachedChildren(DirectoryService directoryService) + protected override IEnumerable GetNonCachedChildren(IDirectoryService directoryService) { return base.GetNonCachedChildren(directoryService).Concat(_virtualChildren); } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 87551ef7b..2b5570a80 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -52,7 +52,7 @@ namespace MediaBrowser.Controller.Entities.Audio } private readonly Task _cachedTask = Task.FromResult(true); - protected override Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, DirectoryService directoryService) + protected override Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) { if (IsAccessedByName) { diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 72e7f5bf1..38f40ea48 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -563,6 +563,8 @@ namespace MediaBrowser.Controller.Entities { var locationType = LocationType; + var requiresSave = false; + if (IsFolder || Parent != null) { options.DirectoryService = options.DirectoryService ?? new DirectoryService(Logger); @@ -571,13 +573,34 @@ namespace MediaBrowser.Controller.Entities GetFileSystemChildren(options.DirectoryService).ToList() : new List(); - await BeforeRefreshMetadata(options, files, cancellationToken).ConfigureAwait(false); + var ownedItemsChanged = await RefreshedOwnedItems(options, files, cancellationToken).ConfigureAwait(false); + + if (ownedItemsChanged) + { + requiresSave = true; + } } + var dateLastSaved = DateLastSaved; + await ProviderManager.RefreshMetadata(this, options, cancellationToken).ConfigureAwait(false); + + // If it wasn't saved by the provider process, save now + if (requiresSave && dateLastSaved == DateLastSaved) + { + await UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); + } } - protected virtual async Task BeforeRefreshMetadata(MetadataRefreshOptions options, List fileSystemChildren, CancellationToken cancellationToken) + /// + /// Refreshes owned items such as trailers, theme videos, special features, etc. + /// Returns true or false indicating if changes were found. + /// + /// + /// + /// + /// + protected virtual async Task RefreshedOwnedItems(MetadataRefreshOptions options, List fileSystemChildren, CancellationToken cancellationToken) { var themeSongsChanged = false; @@ -605,13 +628,10 @@ namespace MediaBrowser.Controller.Entities } } - if (themeSongsChanged || themeVideosChanged || localTrailersChanged) - { - options.ForceSave = true; - } + return themeSongsChanged || themeVideosChanged || localTrailersChanged; } - protected virtual IEnumerable GetFileSystemChildren(DirectoryService directoryService) + protected virtual IEnumerable GetFileSystemChildren(IDirectoryService directoryService) { var path = ContainingFolderPath; @@ -1205,7 +1225,7 @@ namespace MediaBrowser.Controller.Entities /// /// Validates that images within the item are still on the file system /// - public bool ValidateImages(DirectoryService directoryService) + public bool ValidateImages(IDirectoryService directoryService) { var allDirectories = ImageInfos.Select(i => System.IO.Path.GetDirectoryName(i.Path)).Distinct(StringComparer.OrdinalIgnoreCase).ToList(); var allFiles = allDirectories.SelectMany(directoryService.GetFiles).Select(i => i.FullName).ToList(); @@ -1390,5 +1410,22 @@ namespace MediaBrowser.Controller.Entities ParentIndexNumber = ParentIndexNumber }; } + + /// + /// This is called before any metadata refresh and returns ItemUpdateType indictating if changes were made, and what. + /// + /// ItemUpdateType. + public virtual ItemUpdateType BeforeMetadataRefresh() + { + var updateType = ItemUpdateType.None; + + if (string.IsNullOrEmpty(Name) && !string.IsNullOrEmpty(Path)) + { + Name = System.IO.Path.GetFileNameWithoutExtension(Path); + updateType = updateType | ItemUpdateType.MetadataEdit; + } + + return updateType; + } } } diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index eb442bf6f..25f42538c 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -61,7 +61,7 @@ namespace MediaBrowser.Controller.Entities public List PhysicalLocationsList { get; set; } - protected override IEnumerable GetFileSystemChildren(DirectoryService directoryService) + protected override IEnumerable GetFileSystemChildren(IDirectoryService directoryService) { return CreateResolveArgs().FileSystemChildren; } @@ -119,8 +119,9 @@ namespace MediaBrowser.Controller.Entities /// if set to true [recursive]. /// if set to true [refresh child metadata]. /// The refresh options. + /// The directory service. /// Task. - protected override Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, DirectoryService directoryService) + protected override Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) { CreateResolveArgs(); ResetDynamicChildren(); diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 933cf758c..f0b044d43 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -319,7 +319,7 @@ namespace MediaBrowser.Controller.Entities return ValidateChildrenWithCancellationSupport(progress, cancellationToken, recursive, true, metadataRefreshOptions, metadataRefreshOptions.DirectoryService); } - private async Task ValidateChildrenWithCancellationSupport(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, DirectoryService directoryService) + private async Task ValidateChildrenWithCancellationSupport(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) { cancellationToken.ThrowIfCancellationRequested(); @@ -373,7 +373,7 @@ namespace MediaBrowser.Controller.Entities /// The refresh options. /// The directory service. /// Task. - protected async virtual Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, DirectoryService directoryService) + protected async virtual Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) { var locationType = LocationType; @@ -593,7 +593,7 @@ namespace MediaBrowser.Controller.Entities /// The progress. /// The cancellation token. /// Task. - private async Task ValidateSubFolders(IList children, DirectoryService directoryService, IProgress progress, CancellationToken cancellationToken) + private async Task ValidateSubFolders(IList children, IDirectoryService directoryService, IProgress progress, CancellationToken cancellationToken) { var list = children; var childCount = list.Count; @@ -679,7 +679,7 @@ namespace MediaBrowser.Controller.Entities /// Get the children of this folder from the actual file system /// /// IEnumerable{BaseItem}. - protected virtual IEnumerable GetNonCachedChildren(DirectoryService directoryService) + protected virtual IEnumerable GetNonCachedChildren(IDirectoryService directoryService) { return LibraryManager.ResolvePaths(GetFileSystemChildren(directoryService), this); } @@ -927,17 +927,21 @@ namespace MediaBrowser.Controller.Entities return item; } - protected override Task BeforeRefreshMetadata(MetadataRefreshOptions options, List fileSystemChildren, CancellationToken cancellationToken) + protected override async Task RefreshedOwnedItems(MetadataRefreshOptions options, List fileSystemChildren, CancellationToken cancellationToken) { + var changesFound = false; + if (SupportsShortcutChildren && LocationType == LocationType.FileSystem) { if (RefreshLinkedChildren(fileSystemChildren)) { - options.ForceSave = true; + changesFound = true; } } - return base.BeforeRefreshMetadata(options, fileSystemChildren, cancellationToken); + var baseHasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); + + return baseHasChanges || changesFound; } /// diff --git a/MediaBrowser.Controller/Entities/IHasImages.cs b/MediaBrowser.Controller/Entities/IHasImages.cs index 053938f33..eee169363 100644 --- a/MediaBrowser.Controller/Entities/IHasImages.cs +++ b/MediaBrowser.Controller/Entities/IHasImages.cs @@ -1,8 +1,8 @@ -using System.IO; -using MediaBrowser.Controller.Providers; +using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using System; using System.Collections.Generic; +using System.IO; using System.Threading.Tasks; namespace MediaBrowser.Controller.Entities @@ -109,7 +109,7 @@ namespace MediaBrowser.Controller.Entities /// /// Validates the images and returns true or false indicating if any were removed. /// - bool ValidateImages(DirectoryService directoryService); + bool ValidateImages(IDirectoryService directoryService); /// /// Gets a value indicating whether this instance is owned item. @@ -166,5 +166,16 @@ namespace MediaBrowser.Controller.Entities { item.SetImagePath(imageType, 0, file); } + + /// + /// Sets the image path. + /// + /// The item. + /// Type of the image. + /// The file. + public static void SetImagePath(this IHasImages item, ImageType imageType, string file) + { + item.SetImagePath(imageType, new FileInfo(file)); + } } } diff --git a/MediaBrowser.Controller/Entities/IHasMetadata.cs b/MediaBrowser.Controller/Entities/IHasMetadata.cs index 1a1956c56..0285b6749 100644 --- a/MediaBrowser.Controller/Entities/IHasMetadata.cs +++ b/MediaBrowser.Controller/Entities/IHasMetadata.cs @@ -1,9 +1,9 @@ -using System; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Entities; +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 { @@ -49,5 +49,11 @@ namespace MediaBrowser.Controller.Entities /// The cancellation token. /// Task. Task UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken); + + /// + /// This is called before any metadata refresh and returns ItemUpdateType indictating if changes were made, and what. + /// + /// ItemUpdateType. + ItemUpdateType BeforeMetadataRefresh(); } } diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index 50cf31068..8eba21df0 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -96,9 +96,9 @@ namespace MediaBrowser.Controller.Entities.Movies return this.GetProviderId(MetadataProviders.Tmdb) ?? this.GetProviderId(MetadataProviders.Imdb) ?? base.GetUserDataKey(); } - protected override async Task BeforeRefreshMetadata(MetadataRefreshOptions options, List fileSystemChildren, CancellationToken cancellationToken) + protected override async Task RefreshedOwnedItems(MetadataRefreshOptions options, List fileSystemChildren, CancellationToken cancellationToken) { - await base.BeforeRefreshMetadata(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); + var hasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); // Must have a parent to have special features // In other words, it must be part of the Parent/Child tree @@ -108,9 +108,11 @@ namespace MediaBrowser.Controller.Entities.Movies if (specialFeaturesChanged) { - options.ForceSave = true; + hasChanges = true; } } + + return hasChanges; } private async Task RefreshSpecialFeatures(MetadataRefreshOptions options, IEnumerable fileSystemChildren, CancellationToken cancellationToken) diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index 5413aa885..39c11569a 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -1,5 +1,7 @@ -using MediaBrowser.Controller.Providers; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Entities; using System; using System.Collections.Generic; using System.Linq; @@ -260,5 +262,54 @@ namespace MediaBrowser.Controller.Entities.TV return id; } + + public override ItemUpdateType BeforeMetadataRefresh() + { + var updateType = base.BeforeMetadataRefresh(); + + var locationType = LocationType; + if (locationType == LocationType.FileSystem || locationType == LocationType.Offline) + { + if (!IndexNumber.HasValue && !string.IsNullOrEmpty(Path)) + { + IndexNumber = IndexNumber ?? TVUtils.GetEpisodeNumberFromFile(Path, Parent is Season); + + // If a change was made record it + if (IndexNumber.HasValue) + { + updateType = updateType | ItemUpdateType.MetadataImport; + } + } + + if (!IndexNumberEnd.HasValue && !string.IsNullOrEmpty(Path)) + { + IndexNumberEnd = IndexNumberEnd ?? TVUtils.GetEndingEpisodeNumberFromFile(Path); + + // If a change was made record it + if (IndexNumberEnd.HasValue) + { + updateType = updateType | ItemUpdateType.MetadataImport; + } + } + } + + if (!ParentIndexNumber.HasValue) + { + var season = Season; + + if (season != null) + { + ParentIndexNumber = season.IndexNumber; + } + + // If a change was made record it + if (ParentIndexNumber.HasValue) + { + updateType = updateType | ItemUpdateType.MetadataImport; + } + } + + return updateType; + } } } diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index ba79a95cc..830ccb8a2 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Localization; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; @@ -243,9 +244,40 @@ namespace MediaBrowser.Controller.Entities.TV } } + /// + /// Gets the lookup information. + /// + /// SeasonInfo. public SeasonInfo GetLookupInfo() { return GetItemLookupInfo(); } + + /// + /// This is called before any metadata refresh and returns ItemUpdateType indictating if changes were made, and what. + /// + /// ItemUpdateType. + public override ItemUpdateType BeforeMetadataRefresh() + { + var updateType = base.BeforeMetadataRefresh(); + + var locationType = LocationType; + + if (locationType == LocationType.FileSystem || locationType == LocationType.Offline) + { + if (!IndexNumber.HasValue && !string.IsNullOrEmpty(Path)) + { + IndexNumber = IndexNumber ?? TVUtils.GetSeasonNumberFromPath(Path); + + // If a change was made record it + if (IndexNumber.HasValue) + { + updateType = updateType | ItemUpdateType.MetadataImport; + } + } + } + + return updateType; + } } } diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index 4128c5d95..9afcdfe67 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Controller.Entities /// Get the children of this folder from the actual file system /// /// IEnumerable{BaseItem}. - protected override IEnumerable GetNonCachedChildren(DirectoryService directoryService) + protected override IEnumerable GetNonCachedChildren(IDirectoryService directoryService) { return base.GetNonCachedChildren(directoryService).Concat(LibraryManager.RootFolder.VirtualChildren); } diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index e2275fde7..e778b38bd 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -27,8 +27,15 @@ namespace MediaBrowser.Controller.Entities PlayableStreamFileNames = new List(); AdditionalPartIds = new List(); Tags = new List(); + SubtitleFiles = new List(); } + /// + /// Gets or sets the subtitle paths. + /// + /// The subtitle paths. + public List SubtitleFiles { get; set; } + /// /// Gets or sets a value indicating whether this instance has subtitles. /// @@ -156,9 +163,9 @@ namespace MediaBrowser.Controller.Entities } } - protected override async Task BeforeRefreshMetadata(MetadataRefreshOptions options, List fileSystemChildren, CancellationToken cancellationToken) + protected override async Task RefreshedOwnedItems(MetadataRefreshOptions options, List fileSystemChildren, CancellationToken cancellationToken) { - await base.BeforeRefreshMetadata(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); + var hasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); // Must have a parent to have additional parts // In other words, it must be part of the Parent/Child tree @@ -169,9 +176,11 @@ namespace MediaBrowser.Controller.Entities if (additionalPartsChanged) { - options.ForceSave = true; + hasChanges = true; } } + + return hasChanges; } /// diff --git a/MediaBrowser.Controller/Library/ItemUpdateType.cs b/MediaBrowser.Controller/Library/ItemUpdateType.cs index 31a00d7b4..cf6263356 100644 --- a/MediaBrowser.Controller/Library/ItemUpdateType.cs +++ b/MediaBrowser.Controller/Library/ItemUpdateType.cs @@ -5,7 +5,7 @@ namespace MediaBrowser.Controller.Library [Flags] public enum ItemUpdateType { - Unspecified = 1, + None = 1, MetadataImport = 2, ImageUpdate = 4, MetadataDownload = 8, diff --git a/MediaBrowser.Controller/Providers/DirectoryService.cs b/MediaBrowser.Controller/Providers/DirectoryService.cs index 961f3acc7..828d662f6 100644 --- a/MediaBrowser.Controller/Providers/DirectoryService.cs +++ b/MediaBrowser.Controller/Providers/DirectoryService.cs @@ -6,7 +6,16 @@ using MediaBrowser.Model.Logging; namespace MediaBrowser.Controller.Providers { - public class DirectoryService + public interface IDirectoryService + { + List GetFileSystemEntries(string path); + IEnumerable GetFiles(string path); + IEnumerable GetDirectories(string path); + FileInfo GetFile(string path); + DirectoryInfo GetDirectory(string path); + } + + public class DirectoryService : IDirectoryService { private readonly ILogger _logger; diff --git a/MediaBrowser.Controller/Providers/ICustomMetadataProvider.cs b/MediaBrowser.Controller/Providers/ICustomMetadataProvider.cs index 7cf9e961e..c98810cbc 100644 --- a/MediaBrowser.Controller/Providers/ICustomMetadataProvider.cs +++ b/MediaBrowser.Controller/Providers/ICustomMetadataProvider.cs @@ -12,6 +12,6 @@ namespace MediaBrowser.Controller.Providers public interface ICustomMetadataProvider : IMetadataProvider, ICustomMetadataProvider where TItemType : IHasMetadata { - Task FetchAsync(TItemType item, CancellationToken cancellationToken); + Task FetchAsync(TItemType item, IDirectoryService directoryService, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/Providers/IHasChangeMonitor.cs b/MediaBrowser.Controller/Providers/IHasChangeMonitor.cs index ada2cbc6c..aa0b0e3c9 100644 --- a/MediaBrowser.Controller/Providers/IHasChangeMonitor.cs +++ b/MediaBrowser.Controller/Providers/IHasChangeMonitor.cs @@ -9,8 +9,9 @@ namespace MediaBrowser.Controller.Providers /// Determines whether the specified item has changed. /// /// The item. + /// The directory service. /// The date. /// true if the specified item has changed; otherwise, false. - bool HasChanged(IHasMetadata item, DateTime date); + bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date); } } diff --git a/MediaBrowser.Controller/Providers/ILocalImageProvider.cs b/MediaBrowser.Controller/Providers/ILocalImageProvider.cs index cd139bb14..11b8897e7 100644 --- a/MediaBrowser.Controller/Providers/ILocalImageProvider.cs +++ b/MediaBrowser.Controller/Providers/ILocalImageProvider.cs @@ -17,7 +17,7 @@ namespace MediaBrowser.Controller.Providers public interface ILocalImageFileProvider : ILocalImageProvider { - List GetImages(IHasImages item, DirectoryService directoryService); + List GetImages(IHasImages item, IDirectoryService directoryService); } public class LocalImageInfo diff --git a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs index 3ab26ad66..780aa6a56 100644 --- a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs +++ b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Model.Logging; -using System; +using System; namespace MediaBrowser.Controller.Providers { @@ -17,13 +16,12 @@ namespace MediaBrowser.Controller.Providers /// [Obsolete] public bool ForceSave { get; set; } - - public DirectoryService DirectoryService { get; set; } } public class ImageRefreshOptions { public ImageRefreshMode ImageRefreshMode { get; set; } + public IDirectoryService DirectoryService { get; set; } public ImageRefreshOptions() { diff --git a/MediaBrowser.Model/Configuration/MetadataOptions.cs b/MediaBrowser.Model/Configuration/MetadataOptions.cs index f914a2d21..9fdcf045e 100644 --- a/MediaBrowser.Model/Configuration/MetadataOptions.cs +++ b/MediaBrowser.Model/Configuration/MetadataOptions.cs @@ -15,6 +15,7 @@ namespace MediaBrowser.Model.Configuration public ImageOption[] ImageOptions { get; set; } public string[] DisabledMetadataSavers { get; set; } + public string[] LocalMetadataReaders { get; set; } public MetadataOptions() : this(3, 1280) @@ -35,6 +36,7 @@ namespace MediaBrowser.Model.Configuration ImageOptions = imageOptions.ToArray(); DisabledMetadataSavers = new string[] { }; + LocalMetadataReaders = new string[] { }; } public int GetLimit(ImageType type) diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index df80b465f..0e93246c9 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -265,11 +265,6 @@ namespace MediaBrowser.Model.Configuration MetadataOptions = options.ToArray(); } - - public MetadataOptions GetMetadataOptions(string type) - { - return MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, type, StringComparison.OrdinalIgnoreCase)); - } } public enum ImageSavingConvention diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index af3c62396..c6bb6a7e1 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -32,6 +32,8 @@ namespace MediaBrowser.Model.Dto /// The date created. public DateTime? DateCreated { get; set; } + public DateTime? DateLastMediaAdded { get; set; } + public int? AirsBeforeSeasonNumber { get; set; } public int? AirsAfterSeasonNumber { get; set; } public int? AirsBeforeEpisodeNumber { get; set; } diff --git a/MediaBrowser.Model/Entities/MetadataProviders.cs b/MediaBrowser.Model/Entities/MetadataProviders.cs index ec7e14a6d..e86773789 100644 --- a/MediaBrowser.Model/Entities/MetadataProviders.cs +++ b/MediaBrowser.Model/Entities/MetadataProviders.cs @@ -6,40 +6,40 @@ namespace MediaBrowser.Model.Entities /// public enum MetadataProviders { - Gamesdb, + Gamesdb = 1, /// /// The imdb /// - Imdb, + Imdb = 2, /// /// The TMDB /// - Tmdb, + Tmdb = 3, /// /// The TVDB /// - Tvdb, + Tvdb = 4, /// /// The tvcom /// - Tvcom, + Tvcom = 5, /// /// The rotten tomatoes /// - RottenTomatoes, + RottenTomatoes = 6, /// /// Tmdb Collection Id /// - TmdbCollection, - MusicBrainzAlbum, - MusicBrainzAlbumArtist, - MusicBrainzArtist, - MusicBrainzReleaseGroup, - Zap2It, - NesBox, - NesBoxRom, - TvRage, - AudioDbArtist, - AudioDbAlbum + TmdbCollection = 7, + MusicBrainzAlbum = 8, + MusicBrainzAlbumArtist = 9, + MusicBrainzArtist = 10, + MusicBrainzReleaseGroup = 11, + Zap2It = 12, + NesBox = 13, + NesBoxRom = 14, + TvRage = 15, + AudioDbArtist = 16, + AudioDbAlbum = 17 } } diff --git a/MediaBrowser.Model/Providers/ImageProviderInfo.cs b/MediaBrowser.Model/Providers/ImageProviderInfo.cs index 1b8a2816a..4b5a07805 100644 --- a/MediaBrowser.Model/Providers/ImageProviderInfo.cs +++ b/MediaBrowser.Model/Providers/ImageProviderInfo.cs @@ -10,11 +10,5 @@ /// /// The name. public string Name { get; set; } - - /// - /// Gets or sets the order. - /// - /// The order. - public int Order { get; set; } } } diff --git a/MediaBrowser.Model/Querying/ItemFields.cs b/MediaBrowser.Model/Querying/ItemFields.cs index e16da857b..f5640227e 100644 --- a/MediaBrowser.Model/Querying/ItemFields.cs +++ b/MediaBrowser.Model/Querying/ItemFields.cs @@ -41,6 +41,11 @@ namespace MediaBrowser.Model.Querying /// DateCreated, + /// + /// The date last media added + /// + DateLastMediaAdded, + /// /// Item display preferences /// diff --git a/MediaBrowser.Providers/All/InternalMetadataFolderImageProvider.cs b/MediaBrowser.Providers/All/InternalMetadataFolderImageProvider.cs index a5a714dd8..c264b0c58 100644 --- a/MediaBrowser.Providers/All/InternalMetadataFolderImageProvider.cs +++ b/MediaBrowser.Providers/All/InternalMetadataFolderImageProvider.cs @@ -61,7 +61,7 @@ namespace MediaBrowser.Providers.All } } - public List GetImages(IHasImages item, DirectoryService directoryService) + public List GetImages(IHasImages item, IDirectoryService directoryService) { var path = _config.ApplicationPaths.GetInternalMetadataPath(item.Id); diff --git a/MediaBrowser.Providers/All/LocalImageProvider.cs b/MediaBrowser.Providers/All/LocalImageProvider.cs index f54975a69..983600397 100644 --- a/MediaBrowser.Providers/All/LocalImageProvider.cs +++ b/MediaBrowser.Providers/All/LocalImageProvider.cs @@ -57,7 +57,7 @@ namespace MediaBrowser.Providers.All return false; } - private IEnumerable GetFiles(IHasImages item, bool includeDirectories, DirectoryService directoryService) + private IEnumerable GetFiles(IHasImages item, bool includeDirectories, IDirectoryService directoryService) { if (item.LocationType != LocationType.FileSystem) { @@ -77,7 +77,7 @@ namespace MediaBrowser.Providers.All .Where(i => BaseItem.SupportedImageExtensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase)); } - public List GetImages(IHasImages item, DirectoryService directoryService) + public List GetImages(IHasImages item, IDirectoryService directoryService) { var files = GetFiles(item, true, directoryService).ToList(); @@ -88,12 +88,12 @@ namespace MediaBrowser.Providers.All return list; } - public List GetImages(IHasImages item, string path, DirectoryService directoryService) + public List GetImages(IHasImages item, string path, IDirectoryService directoryService) { return GetImages(item, new[] { path }, directoryService); } - public List GetImages(IHasImages item, IEnumerable paths, DirectoryService directoryService) + public List GetImages(IHasImages item, IEnumerable paths, IDirectoryService directoryService) { var files = paths.SelectMany(directoryService.GetFiles) .Where(i => @@ -113,7 +113,7 @@ namespace MediaBrowser.Providers.All return list; } - private void PopulateImages(IHasImages item, List images, List files, bool supportParentSeriesFiles, DirectoryService directoryService) + private void PopulateImages(IHasImages item, List images, List files, bool supportParentSeriesFiles, IDirectoryService directoryService) { var imagePrefix = string.Empty; @@ -185,7 +185,7 @@ namespace MediaBrowser.Providers.All } } - private void PopulateBackdrops(IHasImages item, List images, List files, string imagePrefix, DirectoryService directoryService) + private void PopulateBackdrops(IHasImages item, List images, List files, string imagePrefix, IDirectoryService directoryService) { PopulateBackdrops(images, files, imagePrefix, "backdrop", "backdrop", ImageType.Backdrop); @@ -212,7 +212,7 @@ namespace MediaBrowser.Providers.All } } - private void PopulateBackdropsFromExtraFanart(string path, List images, DirectoryService directoryService) + private void PopulateBackdropsFromExtraFanart(string path, List images, IDirectoryService directoryService) { var imageFiles = directoryService.GetFiles(path) .Where(i => @@ -262,7 +262,7 @@ namespace MediaBrowser.Providers.All } private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - private void PopulateSeasonImagesFromSeriesFolder(Season season, List images, DirectoryService directoryService) + private void PopulateSeasonImagesFromSeriesFolder(Season season, List images, IDirectoryService directoryService) { var seasonNumber = season.IndexNumber; diff --git a/MediaBrowser.Providers/BaseXmlProvider.cs b/MediaBrowser.Providers/BaseXmlProvider.cs index 60ae8333a..b80f27259 100644 --- a/MediaBrowser.Providers/BaseXmlProvider.cs +++ b/MediaBrowser.Providers/BaseXmlProvider.cs @@ -39,6 +39,10 @@ namespace MediaBrowser.Providers { result.HasMetadata = false; } + catch (DirectoryNotFoundException) + { + result.HasMetadata = false; + } finally { XmlProviderUtils.XmlParsingResourcePool.Release(); @@ -56,7 +60,7 @@ namespace MediaBrowser.Providers protected abstract FileInfo GetXmlFile(ItemInfo info); - public bool HasChanged(IHasMetadata item, DateTime date) + public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) { var file = GetXmlFile(new ItemInfo { IsInMixedFolder = item.IsInMixedFolder, Path = item.Path }); diff --git a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs index 8514c1932..e990ddd65 100644 --- a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs +++ b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs @@ -85,10 +85,12 @@ namespace MediaBrowser.Providers.BoxSets private BoxSet GetItem(RootObject obj) { - var item = new BoxSet(); + var item = new BoxSet + { + Name = obj.name, + Overview = obj.overview + }; - item.Name = obj.name; - item.Overview = obj.overview; item.SetProviderId(MetadataProviders.Tmdb, obj.id.ToString(_enUs)); return item; diff --git a/MediaBrowser.Providers/Folders/CollectionFolderImageProvider.cs b/MediaBrowser.Providers/Folders/CollectionFolderImageProvider.cs index a55c42e4b..04fe042c8 100644 --- a/MediaBrowser.Providers/Folders/CollectionFolderImageProvider.cs +++ b/MediaBrowser.Providers/Folders/CollectionFolderImageProvider.cs @@ -27,7 +27,7 @@ namespace MediaBrowser.Providers.Folders } } - public List GetImages(IHasImages item, DirectoryService directoryService) + public List GetImages(IHasImages item, IDirectoryService directoryService) { var collectionFolder = (CollectionFolder)item; diff --git a/MediaBrowser.Providers/Folders/ImagesByNameImageProvider.cs b/MediaBrowser.Providers/Folders/ImagesByNameImageProvider.cs index daefe25ac..7dc934573 100644 --- a/MediaBrowser.Providers/Folders/ImagesByNameImageProvider.cs +++ b/MediaBrowser.Providers/Folders/ImagesByNameImageProvider.cs @@ -38,7 +38,7 @@ namespace MediaBrowser.Providers.Folders } } - public List GetImages(IHasImages item, DirectoryService directoryService) + public List GetImages(IHasImages item, IDirectoryService directoryService) { var name = _fileSystem.GetValidFilename(item.Name); diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 95e6d5611..8f72e601b 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -34,7 +34,7 @@ namespace MediaBrowser.Providers.Manager _fileSystem = fileSystem; } - public bool ValidateImages(IHasImages item, IEnumerable providers, DirectoryService directoryService) + public bool ValidateImages(IHasImages item, IEnumerable providers, IDirectoryService directoryService) { var hasChanges = item.ValidateImages(directoryService); @@ -53,7 +53,7 @@ namespace MediaBrowser.Providers.Manager public async Task RefreshImages(IHasImages item, IEnumerable imageProviders, ImageRefreshOptions refreshOptions, MetadataOptions savedOptions, CancellationToken cancellationToken) { - var result = new RefreshResult { UpdateType = ItemUpdateType.Unspecified }; + var result = new RefreshResult { UpdateType = ItemUpdateType.None }; var providers = GetImageProviders(item, imageProviders).ToList(); diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 93879d826..d64c98d5b 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -4,11 +4,11 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -73,7 +73,7 @@ namespace MediaBrowser.Providers.Manager var itemOfType = (TItemType)item; var config = ProviderManager.GetMetadataOptions(item); - var updateType = ItemUpdateType.Unspecified; + var updateType = ItemUpdateType.None; var refreshResult = GetLastResult(item.Id); refreshResult.LastErrorMessage = string.Empty; refreshResult.LastStatus = ProviderRefreshStatus.Success; @@ -106,7 +106,7 @@ namespace MediaBrowser.Providers.Manager if (providers.Count > 0 || !refreshResult.DateLastMetadataRefresh.HasValue) { - updateType = updateType | BeforeMetadataRefresh(itemOfType); + updateType = updateType | item.BeforeMetadataRefresh(); } if (providers.Count > 0) @@ -138,15 +138,10 @@ namespace MediaBrowser.Providers.Manager updateType = updateType | BeforeSave(itemOfType); - var providersHadChanges = updateType > ItemUpdateType.Unspecified; + var providersHadChanges = updateType > ItemUpdateType.None; if (refreshOptions.ForceSave || providersHadChanges) { - if (string.IsNullOrEmpty(item.Name)) - { - throw new InvalidOperationException(item.GetType().Name + " has no name: " + item.Path); - } - // Save to database await SaveItem(itemOfType, updateType, cancellationToken); } @@ -157,16 +152,6 @@ namespace MediaBrowser.Providers.Manager } } - /// - /// Befores the metadata refresh. - /// - /// The item. - /// ItemUpdateType. - protected virtual ItemUpdateType BeforeMetadataRefresh(TItemType item) - { - return ItemUpdateType.Unspecified; - } - /// /// Befores the save. /// @@ -174,7 +159,7 @@ namespace MediaBrowser.Providers.Manager /// ItemUpdateType. protected virtual ItemUpdateType BeforeSave(TItemType item) { - return ItemUpdateType.Unspecified; + return ItemUpdateType.None; } /// @@ -198,15 +183,37 @@ namespace MediaBrowser.Providers.Manager var currentItem = item; var providersWithChanges = providers.OfType() - .Where(i => i.HasChanged(currentItem, currentItem.DateLastSaved)) + .Where(i => i.HasChanged(currentItem, options.DirectoryService, currentItem.DateLastSaved)) + .Cast>() .ToList(); - // If local providers are the only ones with changes, then just run those - if (providersWithChanges.All(i => i is ILocalMetadataProvider)) + if (providersWithChanges.Count == 0) { - providers = providersWithChanges.Count == 0 ? - new List>() : - providers.Where(i => i is ILocalMetadataProvider).ToList(); + providers = new List>(); + } + else + { + providers = providers.Where(i => + { + // If any provider reports a change, always run local ones as well + if (i is ILocalMetadataProvider) + { + return true; + } + + var anyRemoteProvidersChanged = providersWithChanges.OfType() + .Any(); + + // If any remote providers changed, run them all so that priorities can be honored + if (i is IRemoteMetadataProvider) + { + return anyRemoteProvidersChanged; + } + + // Run custom providers if they report a change or any remote providers change + return anyRemoteProvidersChanged || providersWithChanges.Contains(i); + + }).ToList(); } } @@ -227,7 +234,7 @@ namespace MediaBrowser.Providers.Manager var currentItem = item; providers = providers.OfType() - .Where(i => i.HasChanged(currentItem, dateLastImageRefresh.Value)) + .Where(i => i.HasChanged(currentItem, options.DirectoryService, dateLastImageRefresh.Value)) .Cast() .ToList(); } @@ -249,7 +256,7 @@ namespace MediaBrowser.Providers.Manager { var refreshResult = new RefreshResult { - UpdateType = ItemUpdateType.Unspecified, + UpdateType = ItemUpdateType.None, Providers = providers.Select(i => i.GetType().FullName.GetMD5()).ToList() }; @@ -316,26 +323,26 @@ namespace MediaBrowser.Providers.Manager await ExecuteRemoteProviders(item, temp, providers.OfType>(), refreshResult, cancellationToken).ConfigureAwait(false); } - if (refreshResult.UpdateType > ItemUpdateType.Unspecified) + if (refreshResult.UpdateType > ItemUpdateType.None) { MergeData(temp, item, item.LockedFields, true, true); } foreach (var provider in providers.OfType>()) { - await RunCustomProvider(provider, item, refreshResult, cancellationToken).ConfigureAwait(false); + await RunCustomProvider(provider, item, options.DirectoryService, refreshResult, cancellationToken).ConfigureAwait(false); } return refreshResult; } - private async Task RunCustomProvider(ICustomMetadataProvider provider, TItemType item, RefreshResult refreshResult, CancellationToken cancellationToken) + private async Task RunCustomProvider(ICustomMetadataProvider provider, TItemType item, IDirectoryService directoryService, RefreshResult refreshResult, CancellationToken cancellationToken) { Logger.Debug("Running {0} for {1}", provider.GetType().Name, item.Path ?? item.Name); try { - refreshResult.UpdateType = refreshResult.UpdateType | await provider.FetchAsync(item, cancellationToken).ConfigureAwait(false); + refreshResult.UpdateType = refreshResult.UpdateType | await provider.FetchAsync(item, directoryService, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index a6817cf32..604953909 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -279,8 +279,7 @@ namespace MediaBrowser.Providers.Manager { return GetRemoteImageProviders(item).Select(i => new ImageProviderInfo { - Name = i.Name, - Order = GetOrder(item, i) + Name = i.Name }); } @@ -298,21 +297,39 @@ namespace MediaBrowser.Providers.Manager return false; } - }).OrderBy(i => GetOrder(item, i)); + }).OrderBy(GetOrder); } public IEnumerable> GetMetadataProviders(IHasMetadata item) where T : IHasMetadata { - return GetMetadataProvidersInternal(item, false); + var options = GetMetadataOptions(item); + + return GetMetadataProvidersInternal(item, options, false); } - private IEnumerable> GetMetadataProvidersInternal(IHasMetadata item, bool includeDisabled) + private IEnumerable> GetMetadataProvidersInternal(IHasMetadata item, MetadataOptions options, bool includeDisabled) where T : IHasMetadata { return _metadataProviders.OfType>() .Where(i => CanRefresh(i, item, includeDisabled)) - .OrderBy(i => GetOrder(item, i)); + .OrderBy(i => + { + // See if there's a user-defined order + if (i is ILocalMetadataProvider) + { + var index = Array.IndexOf(options.LocalMetadataReaders, i.Name); + + if (index != -1) + { + return index; + } + } + + // Not configured. Just return some high number to put it at the end. + return 100; + }) + .ThenBy(GetOrder); } private IEnumerable GetRemoteImageProviders(IHasImages item) @@ -354,10 +371,9 @@ namespace MediaBrowser.Providers.Manager /// /// Gets the order. /// - /// The item. /// The provider. /// System.Int32. - private int GetOrder(IHasImages item, IImageProvider provider) + private int GetOrder(IImageProvider provider) { var hasOrder = provider as IHasOrder; @@ -372,19 +388,18 @@ namespace MediaBrowser.Providers.Manager /// /// Gets the order. /// - /// The item. /// The provider. /// System.Int32. - private int GetOrder(IHasMetadata item, IMetadataProvider provider) + private int GetOrder(IMetadataProvider provider) { var hasOrder = provider as IHasOrder; - if (hasOrder == null) + if (hasOrder != null) { - return 0; + return hasOrder.Order; } - return hasOrder.Order; + return 0; } public IEnumerable GetAllMetadataPlugins() @@ -432,6 +447,8 @@ namespace MediaBrowser.Providers.Manager Parent = new Folder() }; + var options = GetMetadataOptions(dummy); + var summary = new MetadataPluginSummary { ItemType = typeof(T).Name @@ -439,7 +456,7 @@ namespace MediaBrowser.Providers.Manager var imageProviders = GetImageProviders(dummy).ToList(); - AddMetadataPlugins(summary.Plugins, dummy); + AddMetadataPlugins(summary.Plugins, dummy, options); AddImagePlugins(summary.Plugins, dummy, imageProviders); summary.SupportedImageTypes = imageProviders.OfType() @@ -450,10 +467,10 @@ namespace MediaBrowser.Providers.Manager return summary; } - private void AddMetadataPlugins(List list, T item) + private void AddMetadataPlugins(List list, T item, MetadataOptions options) where T : IHasMetadata { - var providers = GetMetadataProvidersInternal(item, true).ToList(); + var providers = GetMetadataProvidersInternal(item, options, true).ToList(); // Locals list.AddRange(providers.Where(i => (i is ILocalMetadataProvider)).Select(i => new MetadataPlugin @@ -496,16 +513,21 @@ namespace MediaBrowser.Providers.Manager })); } - private readonly ConcurrentDictionary _fileLocks = new ConcurrentDictionary(); - public MetadataOptions GetMetadataOptions(IHasMetadata item) { var type = item.GetType().Name; + + if (item is Trailer) + { + type = typeof(Movie).Name; + } + return ConfigurationManager.Configuration.MetadataOptions .FirstOrDefault(i => string.Equals(i.ItemType, type, StringComparison.OrdinalIgnoreCase)) ?? new MetadataOptions(); } - + + private readonly ConcurrentDictionary _fileLocks = new ConcurrentDictionary(); /// /// Saves the metadata. /// @@ -517,7 +539,7 @@ namespace MediaBrowser.Providers.Manager foreach (var saver in _savers.Where(i => IsSaverEnabledForItem(i, item, updateType, true))) { _logger.Debug("Saving {0} to {1}.", item.Path ?? item.Name, saver.Name); - + var fileSaver = saver as IMetadataFileSaver; if (fileSaver != null) diff --git a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs index 5f1299e31..772f60163 100644 --- a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs @@ -159,7 +159,7 @@ namespace MediaBrowser.Providers.MediaInfo return item.LocationType == LocationType.FileSystem && item is Audio; } - public bool HasChanged(IHasMetadata item, DateTime date) + public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) { return item.DateModified > date; } diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs index 6eca3c0bc..951996a9f 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs @@ -13,10 +13,11 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; +using MediaBrowser.Model.Serialization; using System; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.Serialization; +using System.Linq; namespace MediaBrowser.Providers.MediaInfo { @@ -46,47 +47,47 @@ namespace MediaBrowser.Providers.MediaInfo get { return "ffprobe"; } } - public Task FetchAsync(Episode item, CancellationToken cancellationToken) + public Task FetchAsync(Episode item, IDirectoryService directoryService, CancellationToken cancellationToken) { - return FetchVideoInfo(item, cancellationToken); + return FetchVideoInfo(item, directoryService, cancellationToken); } - public Task FetchAsync(MusicVideo item, CancellationToken cancellationToken) + public Task FetchAsync(MusicVideo item, IDirectoryService directoryService, CancellationToken cancellationToken) { - return FetchVideoInfo(item, cancellationToken); + return FetchVideoInfo(item, directoryService, cancellationToken); } - public Task FetchAsync(Movie item, CancellationToken cancellationToken) + public Task FetchAsync(Movie item, IDirectoryService directoryService, CancellationToken cancellationToken) { - return FetchVideoInfo(item, cancellationToken); + return FetchVideoInfo(item, directoryService, cancellationToken); } - public Task FetchAsync(AdultVideo item, CancellationToken cancellationToken) + public Task FetchAsync(AdultVideo item, IDirectoryService directoryService, CancellationToken cancellationToken) { - return FetchVideoInfo(item, cancellationToken); + return FetchVideoInfo(item, directoryService, cancellationToken); } - public Task FetchAsync(LiveTvVideoRecording item, CancellationToken cancellationToken) + public Task FetchAsync(LiveTvVideoRecording item, IDirectoryService directoryService, CancellationToken cancellationToken) { - return FetchVideoInfo(item, cancellationToken); + return FetchVideoInfo(item, directoryService, cancellationToken); } - public Task FetchAsync(Trailer item, CancellationToken cancellationToken) + public Task FetchAsync(Trailer item, IDirectoryService directoryService, CancellationToken cancellationToken) { - return FetchVideoInfo(item, cancellationToken); + return FetchVideoInfo(item, directoryService, cancellationToken); } - public Task FetchAsync(Video item, CancellationToken cancellationToken) + public Task FetchAsync(Video item, IDirectoryService directoryService, CancellationToken cancellationToken) { - return FetchVideoInfo(item, cancellationToken); + return FetchVideoInfo(item, directoryService, cancellationToken); } - public Task FetchAsync(Audio item, CancellationToken cancellationToken) + public Task FetchAsync(Audio item, IDirectoryService directoryService, CancellationToken cancellationToken) { return FetchAudioInfo(item, cancellationToken); } - public Task FetchAsync(LiveTvAudioRecording item, CancellationToken cancellationToken) + public Task FetchAsync(LiveTvAudioRecording item, IDirectoryService directoryService, CancellationToken cancellationToken) { return FetchAudioInfo(item, cancellationToken); } @@ -103,8 +104,8 @@ namespace MediaBrowser.Providers.MediaInfo _json = json; } - private readonly Task _cachedTask = Task.FromResult(ItemUpdateType.Unspecified); - public Task FetchVideoInfo(T item, CancellationToken cancellationToken) + private readonly Task _cachedTask = Task.FromResult(ItemUpdateType.None); + public Task FetchVideoInfo(T item, IDirectoryService directoryService, CancellationToken cancellationToken) where T : Video { if (item.LocationType != LocationType.FileSystem) @@ -124,7 +125,7 @@ namespace MediaBrowser.Providers.MediaInfo var prober = new FFProbeVideoInfo(_logger, _isoManager, _mediaEncoder, _itemRepo, _blurayExaminer, _localization, _appPaths, _json); - return prober.ProbeVideo(item, cancellationToken); + return prober.ProbeVideo(item, directoryService, cancellationToken); } public Task FetchAudioInfo(T item, CancellationToken cancellationToken) @@ -140,9 +141,26 @@ namespace MediaBrowser.Providers.MediaInfo return prober.Probe(item, cancellationToken); } - public bool HasChanged(IHasMetadata item, DateTime date) + public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) { - return item.DateModified > date; + if (item.DateModified > date) + { + return true; + } + + if (item.LocationType == LocationType.FileSystem) + { + var video = item as Video; + + if (video != null) + { + var prober = new FFProbeVideoInfo(_logger, _isoManager, _mediaEncoder, _itemRepo, _blurayExaminer, _localization, _appPaths, _json); + + return !video.SubtitleFiles.SequenceEqual(prober.GetSubtitleFiles(video, directoryService).Select(i => i.FullName).OrderBy(i => i), StringComparer.OrdinalIgnoreCase); + } + } + + return false; } public int Order diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index f5b8496cb..074bcfdff 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -5,6 +5,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.MediaInfo; using MediaBrowser.Controller.Persistence; +using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; @@ -45,7 +46,7 @@ namespace MediaBrowser.Providers.MediaInfo _json = json; } - public async Task ProbeVideo(T item, CancellationToken cancellationToken) + public async Task ProbeVideo(T item, IDirectoryService directoryService, CancellationToken cancellationToken) where T : Video { var isoMount = await MountIsoIfNeeded(item, cancellationToken).ConfigureAwait(false); @@ -72,7 +73,7 @@ namespace MediaBrowser.Providers.MediaInfo cancellationToken.ThrowIfCancellationRequested(); - await Fetch(item, cancellationToken, result, isoMount).ConfigureAwait(false); + await Fetch(item, cancellationToken, result, isoMount, directoryService).ConfigureAwait(false); } finally @@ -125,7 +126,7 @@ namespace MediaBrowser.Providers.MediaInfo return result; } - protected async Task Fetch(Video video, CancellationToken cancellationToken, InternalMediaInfoResult data, IIsoMount isoMount) + protected async Task Fetch(Video video, CancellationToken cancellationToken, InternalMediaInfoResult data, IIsoMount isoMount, IDirectoryService directoryService) { if (data.format != null) { @@ -148,7 +149,7 @@ namespace MediaBrowser.Providers.MediaInfo FetchBdInfo(video, chapters, mediaStreams, inputPath, cancellationToken); } - AddExternalSubtitles(video, mediaStreams); + AddExternalSubtitles(video, mediaStreams, directoryService); FetchWtvInfo(video, data); @@ -342,76 +343,104 @@ namespace MediaBrowser.Providers.MediaInfo } } + public IEnumerable GetSubtitleFiles(Video video, IDirectoryService directoryService) + { + var containingPath = video.ContainingFolderPath; + + if (string.IsNullOrEmpty(containingPath)) + { + throw new ArgumentException(string.Format("Cannot search for items that don't have a path: {0} {1}", video.Name, video.Id)); + } + + var files = directoryService.GetFiles(containingPath); + + var videoFileNameWithoutExtension = Path.GetFileNameWithoutExtension(video.Path); + + return files.Where(i => + { + if (!i.Attributes.HasFlag(FileAttributes.Directory) && + SubtitleExtensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase)) + { + var fullName = i.FullName; + + var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fullName); + + if (string.Equals(videoFileNameWithoutExtension, fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + if (fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension + ".", StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + + return false; + }); + } + /// /// Adds the external subtitles. /// /// The video. /// The current streams. - private void AddExternalSubtitles(Video video, List currentStreams) + private void AddExternalSubtitles(Video video, List currentStreams, IDirectoryService directoryService) { - //var useParent = !video.ResolveArgs.IsDirectory; + var files = GetSubtitleFiles(video, directoryService); - //if (useParent && video.Parent == null) - //{ - // return; - //} + var startIndex = currentStreams.Count; + var streams = new List(); - //var fileSystemChildren = useParent - // ? video.Parent.ResolveArgs.FileSystemChildren - // : video.ResolveArgs.FileSystemChildren; + var videoFileNameWithoutExtension = Path.GetFileNameWithoutExtension(video.Path); - //var startIndex = currentStreams.Count; - //var streams = new List(); + foreach (var file in files) + { + var fullName = file.FullName; - //var videoFileNameWithoutExtension = Path.GetFileNameWithoutExtension(video.Path); + var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fullName); - //foreach (var file in fileSystemChildren - // .Where(f => !f.Attributes.HasFlag(FileAttributes.Directory) && SubtitleExtensions.Contains(Path.GetExtension(f.FullName), StringComparer.OrdinalIgnoreCase))) - //{ - // var fullName = file.FullName; + // If the subtitle file matches the video file name + if (string.Equals(videoFileNameWithoutExtension, fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase)) + { + streams.Add(new MediaStream + { + Index = startIndex++, + Type = MediaStreamType.Subtitle, + IsExternal = true, + Path = fullName, + Codec = Path.GetExtension(fullName).ToLower().TrimStart('.') + }); + } + else if (fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension + ".", StringComparison.OrdinalIgnoreCase)) + { + // Support xbmc naming conventions - 300.spanish.srt + var language = fileNameWithoutExtension.Split('.').LastOrDefault(); - // var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fullName); + // Try to translate to three character code + // Be flexible and check against both the full and three character versions + var culture = _localization.GetCultures() + .FirstOrDefault(i => string.Equals(i.DisplayName, language, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, language, StringComparison.OrdinalIgnoreCase) || string.Equals(i.ThreeLetterISOLanguageName, language, StringComparison.OrdinalIgnoreCase) || string.Equals(i.TwoLetterISOLanguageName, language, StringComparison.OrdinalIgnoreCase)); - // // If the subtitle file matches the video file name - // if (string.Equals(videoFileNameWithoutExtension, fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase)) - // { - // streams.Add(new MediaStream - // { - // Index = startIndex++, - // Type = MediaStreamType.Subtitle, - // IsExternal = true, - // Path = fullName, - // Codec = Path.GetExtension(fullName).ToLower().TrimStart('.') - // }); - // } - // else if (fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension + ".", StringComparison.OrdinalIgnoreCase)) - // { - // // Support xbmc naming conventions - 300.spanish.srt - // var language = fileNameWithoutExtension.Split('.').LastOrDefault(); + if (culture != null) + { + language = culture.ThreeLetterISOLanguageName; + } - // // Try to translate to three character code - // // Be flexible and check against both the full and three character versions - // var culture = _localization.GetCultures() - // .FirstOrDefault(i => string.Equals(i.DisplayName, language, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, language, StringComparison.OrdinalIgnoreCase) || string.Equals(i.ThreeLetterISOLanguageName, language, StringComparison.OrdinalIgnoreCase) || string.Equals(i.TwoLetterISOLanguageName, language, StringComparison.OrdinalIgnoreCase)); + streams.Add(new MediaStream + { + Index = startIndex++, + Type = MediaStreamType.Subtitle, + IsExternal = true, + Path = fullName, + Codec = Path.GetExtension(fullName).ToLower().TrimStart('.'), + Language = language + }); + } + } - // if (culture != null) - // { - // language = culture.ThreeLetterISOLanguageName; - // } + video.SubtitleFiles = streams.Select(i => i.Path).OrderBy(i => i).ToList(); - // streams.Add(new MediaStream - // { - // Index = startIndex++, - // Type = MediaStreamType.Subtitle, - // IsExternal = true, - // Path = fullName, - // Codec = Path.GetExtension(fullName).ToLower().TrimStart('.'), - // Language = language - // }); - // } - //} - - //currentStreams.AddRange(streams); + currentStreams.AddRange(streams); } /// diff --git a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs index 8c62f6be4..c230f65f9 100644 --- a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs @@ -126,7 +126,7 @@ namespace MediaBrowser.Providers.MediaInfo return item.LocationType == LocationType.FileSystem && item is Video; } - public bool HasChanged(IHasMetadata item, DateTime date) + public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) { return item.DateModified > date; } diff --git a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs index ba3b468d4..26395e9cc 100644 --- a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs +++ b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs @@ -345,7 +345,7 @@ namespace MediaBrowser.Providers.Movies }); } - public bool HasChanged(IHasMetadata item, DateTime date) + public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) { if (!_config.Configuration.EnableFanArtUpdates) { diff --git a/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs b/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs index 5699093e4..8a38e294c 100644 --- a/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs @@ -208,7 +208,7 @@ namespace MediaBrowser.Providers.Movies }); } - public bool HasChanged(IHasMetadata item, DateTime date) + public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) { return MovieDbProvider.Current.HasChanged(item, date); } diff --git a/MediaBrowser.Providers/Music/AlbumMetadataService.cs b/MediaBrowser.Providers/Music/AlbumMetadataService.cs index 410441fc8..0a3359156 100644 --- a/MediaBrowser.Providers/Music/AlbumMetadataService.cs +++ b/MediaBrowser.Providers/Music/AlbumMetadataService.cs @@ -99,7 +99,7 @@ namespace MediaBrowser.Providers.Music private ItemUpdateType SetAlbumArtistFromSongs(MusicAlbum item, IEnumerable public class GameXmlSaver : IMetadataFileSaver { - private readonly IServerConfigurationManager _config; - - public GameXmlSaver(IServerConfigurationManager config) - { - _config = config; - } - public string Name { get diff --git a/MediaBrowser.Providers/Savers/MovieXmlSaver.cs b/MediaBrowser.Providers/Savers/MovieXmlSaver.cs index 851c81f54..2b5fed41c 100644 --- a/MediaBrowser.Providers/Savers/MovieXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/MovieXmlSaver.cs @@ -1,18 +1,15 @@ -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; +using MediaBrowser.Model.Entities; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Security; using System.Text; using System.Threading; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Entities; namespace MediaBrowser.Providers.Savers { @@ -21,12 +18,10 @@ namespace MediaBrowser.Providers.Savers /// public class MovieXmlSaver : IMetadataFileSaver { - private readonly IServerConfigurationManager _config; private readonly IItemRepository _itemRepository; - public MovieXmlSaver(IServerConfigurationManager config, IItemRepository itemRepository) + public MovieXmlSaver(IItemRepository itemRepository) { - _config = config; _itemRepository = itemRepository; } diff --git a/MediaBrowser.Providers/Savers/SeasonXmlSaver.cs b/MediaBrowser.Providers/Savers/SeasonXmlSaver.cs index f8d4549cf..de3d1b68e 100644 --- a/MediaBrowser.Providers/Savers/SeasonXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/SeasonXmlSaver.cs @@ -1,25 +1,16 @@ -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; using System.Collections.Generic; using System.IO; using System.Text; using System.Threading; -using MediaBrowser.Model.Entities; namespace MediaBrowser.Providers.Savers { public class SeasonXmlSaver : IMetadataFileSaver { - private readonly IServerConfigurationManager _config; - - public SeasonXmlSaver(IServerConfigurationManager config) - { - _config = config; - } - public string Name { get diff --git a/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs b/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs index df0a87c35..5d947f8c5 100644 --- a/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Entities; @@ -13,13 +12,6 @@ namespace MediaBrowser.Providers.Savers { public class SeriesXmlSaver : IMetadataFileSaver { - private readonly IServerConfigurationManager _config; - - public SeriesXmlSaver(IServerConfigurationManager config) - { - _config = config; - } - public string Name { get diff --git a/MediaBrowser.Providers/TV/EpisodeLocalImageProvider.cs b/MediaBrowser.Providers/TV/EpisodeLocalImageProvider.cs index 8a3af13d8..4f806d834 100644 --- a/MediaBrowser.Providers/TV/EpisodeLocalImageProvider.cs +++ b/MediaBrowser.Providers/TV/EpisodeLocalImageProvider.cs @@ -21,7 +21,7 @@ namespace MediaBrowser.Providers.TV return item is Episode && item.LocationType == LocationType.FileSystem; } - public List GetImages(IHasImages item, DirectoryService directoryService) + public List GetImages(IHasImages item, IDirectoryService directoryService) { var parentPath = Path.GetDirectoryName(item.Path); diff --git a/MediaBrowser.Providers/TV/EpisodeMetadataService.cs b/MediaBrowser.Providers/TV/EpisodeMetadataService.cs index 94d166273..4b6ac04bc 100644 --- a/MediaBrowser.Providers/TV/EpisodeMetadataService.cs +++ b/MediaBrowser.Providers/TV/EpisodeMetadataService.cs @@ -1,26 +1,19 @@ using MediaBrowser.Common.IO; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.TV; -using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using System.IO; -using System.Threading; -using System.Threading.Tasks; namespace MediaBrowser.Providers.TV { public class EpisodeMetadataService : MetadataService { - private readonly ILibraryManager _libraryManager; - - public EpisodeMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, ILibraryManager libraryManager) + public EpisodeMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem) { - _libraryManager = libraryManager; } /// @@ -70,50 +63,5 @@ namespace MediaBrowser.Providers.TV target.IndexNumberEnd = source.IndexNumberEnd; } } - - protected override ItemUpdateType BeforeMetadataRefresh(Episode item) - { - var updateType = base.BeforeMetadataRefresh(item); - - var locationType = item.LocationType; - if (locationType == LocationType.FileSystem || locationType == LocationType.Offline) - { - var currentIndexNumber = item.IndexNumber; - var currentIndexNumberEnd = item.IndexNumberEnd; - var currentParentIndexNumber = item.ParentIndexNumber; - - var filename = Path.GetFileName(item.Path); - - item.IndexNumber = item.IndexNumber ?? TVUtils.GetEpisodeNumberFromFile(item.Path, item.Parent is Season); - item.IndexNumberEnd = item.IndexNumberEnd ?? TVUtils.GetEndingEpisodeNumberFromFile(item.Path); - - if (!item.ParentIndexNumber.HasValue) - { - var season = item.Season; - - if (season != null) - { - item.ParentIndexNumber = season.IndexNumber; - } - } - - if ((currentIndexNumber ?? -1) != (item.IndexNumber ?? -1)) - { - updateType = updateType | ItemUpdateType.MetadataImport; - } - - if ((currentIndexNumberEnd ?? -1) != (item.IndexNumberEnd ?? -1)) - { - updateType = updateType | ItemUpdateType.MetadataImport; - } - - if ((currentParentIndexNumber ?? -1) != (item.ParentIndexNumber ?? -1)) - { - updateType = updateType | ItemUpdateType.MetadataImport; - } - } - - return updateType; - } } } diff --git a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs index 62f7a985a..6f8da573d 100644 --- a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs +++ b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs @@ -275,7 +275,7 @@ namespace MediaBrowser.Providers.TV }); } - public bool HasChanged(IHasMetadata item, DateTime date) + public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) { if (!_config.Configuration.EnableFanArtUpdates) { diff --git a/MediaBrowser.Providers/TV/FanartSeriesProvider.cs b/MediaBrowser.Providers/TV/FanartSeriesProvider.cs index 85a2944f3..f18189a2a 100644 --- a/MediaBrowser.Providers/TV/FanartSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/FanartSeriesProvider.cs @@ -423,7 +423,7 @@ namespace MediaBrowser.Providers.TV } } - public bool HasChanged(IHasMetadata item, DateTime date) + public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) { if (!_config.Configuration.EnableFanArtUpdates) { diff --git a/MediaBrowser.Providers/TV/MovieDbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/MovieDbSeriesImageProvider.cs index 3a98d95e4..9795b7b11 100644 --- a/MediaBrowser.Providers/TV/MovieDbSeriesImageProvider.cs +++ b/MediaBrowser.Providers/TV/MovieDbSeriesImageProvider.cs @@ -203,7 +203,7 @@ namespace MediaBrowser.Providers.TV }); } - public bool HasChanged(IHasMetadata item, DateTime date) + public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) { return MovieDbSeriesProvider.Current.HasChanged(item, date); } diff --git a/MediaBrowser.Providers/TV/SeasonMetadataService.cs b/MediaBrowser.Providers/TV/SeasonMetadataService.cs index e76ad9075..4c0149d2e 100644 --- a/MediaBrowser.Providers/TV/SeasonMetadataService.cs +++ b/MediaBrowser.Providers/TV/SeasonMetadataService.cs @@ -1,25 +1,19 @@ using MediaBrowser.Common.IO; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.TV; -using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; 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.TV { public class SeasonMetadataService : MetadataService { - private readonly ILibraryManager _libraryManager; - - public SeasonMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, ILibraryManager libraryManager) + public SeasonMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem) { - _libraryManager = libraryManager; } /// @@ -34,20 +28,5 @@ namespace MediaBrowser.Providers.TV { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } - - protected override ItemUpdateType BeforeMetadataRefresh(Season item) - { - var updateType = base.BeforeMetadataRefresh(item); - - var currentIndexNumber = item.IndexNumber; - - item.IndexNumber = item.IndexNumber ?? TVUtils.GetSeasonNumberFromPath(item.Path); - - if ((currentIndexNumber ?? -1) != (item.IndexNumber ?? -1)) - { - updateType = updateType | ItemUpdateType.MetadataImport; - } - return updateType; - } } } diff --git a/MediaBrowser.Providers/TV/SeriesMetadataService.cs b/MediaBrowser.Providers/TV/SeriesMetadataService.cs index bc9f543cf..beb9ab595 100644 --- a/MediaBrowser.Providers/TV/SeriesMetadataService.cs +++ b/MediaBrowser.Providers/TV/SeriesMetadataService.cs @@ -8,8 +8,6 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; using System.Linq; -using System.Threading; -using System.Threading.Tasks; namespace MediaBrowser.Providers.TV { diff --git a/MediaBrowser.Providers/TV/TvdbEpisodeImageProvider.cs b/MediaBrowser.Providers/TV/TvdbEpisodeImageProvider.cs index 7d8f9e186..0830b6713 100644 --- a/MediaBrowser.Providers/TV/TvdbEpisodeImageProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbEpisodeImageProvider.cs @@ -192,7 +192,7 @@ namespace MediaBrowser.Providers.TV }); } - public bool HasChanged(IHasMetadata item, DateTime date) + public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) { if (item.LocationType != LocationType.Virtual) { diff --git a/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs index d0b405017..0c9712cae 100644 --- a/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs @@ -66,7 +66,7 @@ namespace MediaBrowser.Providers.TV return Task.FromResult(result); } - public bool HasChanged(IHasMetadata item, DateTime date) + public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) { // Only enable for virtual items if (item.LocationType != LocationType.Virtual) diff --git a/MediaBrowser.Providers/TV/TvdbPrescanTask.cs b/MediaBrowser.Providers/TV/TvdbPrescanTask.cs index a9edeee0e..4164a05ba 100644 --- a/MediaBrowser.Providers/TV/TvdbPrescanTask.cs +++ b/MediaBrowser.Providers/TV/TvdbPrescanTask.cs @@ -98,8 +98,19 @@ namespace MediaBrowser.Providers.TV string newUpdateTime; - var existingDirectories = Directory.EnumerateDirectories(path).Select(Path.GetFileName).ToList(); + var existingDirectories = Directory.EnumerateDirectories(path) + .Select(Path.GetFileName) + .ToList(); + var seriesIdsInLibrary = _libraryManager.RootFolder.RecursiveChildren + .OfType() + .Select(i => i.GetProviderId(MetadataProviders.Tvdb)) + .Where(i => !string.IsNullOrEmpty(i)) + .ToList(); + + var missingSeries = seriesIdsInLibrary.Except(existingDirectories, StringComparer.OrdinalIgnoreCase) + .ToList(); + // If this is our first time, update all series if (string.IsNullOrEmpty(lastUpdateTime)) { @@ -116,6 +127,8 @@ namespace MediaBrowser.Providers.TV newUpdateTime = GetUpdateTime(stream); } + existingDirectories.AddRange(missingSeries); + await UpdateSeries(existingDirectories, path, null, progress, cancellationToken).ConfigureAwait(false); } else @@ -130,7 +143,10 @@ namespace MediaBrowser.Providers.TV var nullableUpdateValue = lastUpdateValue == 0 ? (long?)null : lastUpdateValue; - await UpdateSeries(seriesToUpdate.Item1, path, nullableUpdateValue, progress, cancellationToken).ConfigureAwait(false); + var listToUpdate = seriesToUpdate.Item1.ToList(); + listToUpdate.AddRange(missingSeries); + + await UpdateSeries(listToUpdate, path, nullableUpdateValue, progress, cancellationToken).ConfigureAwait(false); } File.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8); diff --git a/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs b/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs index 5216d84c5..e4756ea71 100644 --- a/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs @@ -340,7 +340,7 @@ namespace MediaBrowser.Providers.TV }); } - public bool HasChanged(IHasMetadata item, DateTime date) + public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) { if (item.LocationType != LocationType.Virtual) { diff --git a/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs index 3e1664f85..765d17aa7 100644 --- a/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs @@ -337,7 +337,7 @@ namespace MediaBrowser.Providers.TV }); } - public bool HasChanged(IHasMetadata item, DateTime date) + public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) { if (!_config.Configuration.EnableTvDbUpdates) { diff --git a/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs index 9fdca568e..9a1373460 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs @@ -103,7 +103,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv get { return 0; } } - public bool HasChanged(IHasMetadata item, DateTime date) + public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) { return !item.HasImage(ImageType.Primary) && (DateTime.UtcNow - date).TotalDays >= 1; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs index 1dd6eb272..cb7635b45 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs @@ -103,7 +103,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv get { return 0; } } - public bool HasChanged(IHasMetadata item, DateTime date) + public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) { return !item.HasImage(ImageType.Primary) && (DateTime.UtcNow - date).TotalHours >= 6; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs index 0ba760768..be8955d16 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs @@ -103,7 +103,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv get { return 0; } } - public bool HasChanged(IHasMetadata item, DateTime date) + public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) { return !item.HasImage(ImageType.Primary) && (DateTime.UtcNow - date).TotalHours >= 3; } diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index d24b1425a..a0540f78d 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.324 + 3.0.325 MediaBrowser.Common.Internal Luke ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption. Copyright © Media Browser 2013 - + diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index 92939185f..4813ea39b 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.324 + 3.0.325 MediaBrowser.Common Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index c208cb725..3a08bb75a 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.324 + 3.0.325 Media Browser.Server.Core Media Browser Team ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains core components required to build plugins for Media Browser Server. Copyright © Media Browser 2013 - +