diff options
Diffstat (limited to 'MediaBrowser.Server.Implementations/Library')
15 files changed, 630 insertions, 287 deletions
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 28671fb7c..712ea4ef3 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -33,6 +33,9 @@ using System.Net; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Controller.Channels; +using MediaBrowser.Model.Channels; +using MediaBrowser.Model.Dto; using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Library; using MediaBrowser.Model.Net; @@ -143,6 +146,7 @@ namespace MediaBrowser.Server.Implementations.Library private readonly Func<ILibraryMonitor> _libraryMonitorFactory; private readonly Func<IProviderManager> _providerManagerFactory; private readonly Func<IUserViewManager> _userviewManager; + public bool IsScanRunning { get; private set; } /// <summary> /// The _library items cache @@ -305,9 +309,14 @@ namespace MediaBrowser.Server.Implementations.Library /// <returns>Task.</returns> private async Task UpdateSeasonZeroNames(string newName, CancellationToken cancellationToken) { - var seasons = RootFolder.GetRecursiveChildren(i => i is Season) - .Cast<Season>() - .Where(i => i.IndexNumber.HasValue && i.IndexNumber.Value == 0 && !string.Equals(i.Name, newName, StringComparison.Ordinal)) + var seasons = GetItemList(new InternalItemsQuery + { + IncludeItemTypes = new[] { typeof(Season).Name }, + Recursive = true, + IndexNumber = 0 + + }).Cast<Season>() + .Where(i => !string.Equals(i.Name, newName, StringComparison.Ordinal)) .ToList(); foreach (var season in seasons) @@ -345,10 +354,6 @@ namespace MediaBrowser.Server.Implementations.Library private void RegisterItem(Guid id, BaseItem item) { - if (item.SourceType != SourceType.Library) - { - return; - } if (item is IItemByName) { if (!(item is MusicArtist)) @@ -356,10 +361,25 @@ namespace MediaBrowser.Server.Implementations.Library return; } } - //if (!(item is Folder)) - //{ - // return; - //} + + if (item.IsFolder) + { + if (!(item is ICollectionFolder) && !(item is UserView) && !(item is Channel)) + { + if (item.SourceType != SourceType.Library) + { + return; + } + } + } + else + { + if (item is Photo) + { + return; + } + } + LibraryItemsCache.AddOrUpdate(id, item, delegate { return item; }); } @@ -514,38 +534,6 @@ namespace MediaBrowser.Server.Implementations.Library return key.GetMD5(); } - public IEnumerable<BaseItem> ReplaceVideosWithPrimaryVersions(IEnumerable<BaseItem> items) - { - if (items == null) - { - throw new ArgumentNullException("items"); - } - - var dict = new Dictionary<Guid, BaseItem>(); - - foreach (var item in items) - { - var video = item as Video; - - if (video != null) - { - if (video.PrimaryVersionId.HasValue) - { - var primary = GetItemById(video.PrimaryVersionId.Value) as Video; - - if (primary != null) - { - dict[primary.Id] = primary; - continue; - } - } - } - dict[item.Id] = item; - } - - return dict.Values; - } - /// <summary> /// Ensure supplied item has only one instance throughout /// </summary> @@ -800,27 +788,22 @@ namespace MediaBrowser.Server.Implementations.Library return _userRootFolder; } - public BaseItem FindByPath(string path) + public BaseItem FindByPath(string path, bool? isFolder) { + // If this returns multiple items it could be tricky figuring out which one is correct. + // In most cases, the newest one will be and the others obsolete but not yet cleaned up + var query = new InternalItemsQuery { - Path = path + Path = path, + IsFolder = isFolder, + SortBy = new[] { ItemSortBy.DateCreated }, + SortOrder = SortOrder.Descending, + Limit = 1 }; - // Only use the database result if there's exactly one item, otherwise we run the risk of returning old data that hasn't been cleaned yet. - var items = GetItemIds(query).Select(GetItemById).Where(i => i != null).ToArray(); - - if (items.Length == 1) - { - return items[0]; - } - - if (items.Length == 0) - { - return null; - } - - return RootFolder.FindByPath(path); + return GetItemList(query) + .FirstOrDefault(); } /// <summary> @@ -929,7 +912,10 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentNullException("name"); } - var validFilename = _fileSystem.GetValidFilename(name).Trim(); + // Trim the period at the end because windows will have a hard time with that + var validFilename = _fileSystem.GetValidFilename(name) + .Trim() + .TrimEnd('.'); string subFolderPrefix = null; @@ -951,31 +937,23 @@ namespace MediaBrowser.Server.Implementations.Library Path.Combine(path, validFilename) : Path.Combine(path, subFolderPrefix, validFilename); - var id = GetNewItemId(fullPath, type); - - BaseItem obj; - - if (!_libraryItemsCache.TryGetValue(id, out obj)) - { - obj = CreateItemByName<T>(fullPath, name, id); - - RegisterItem(id, obj); - } - - return obj as T; + return CreateItemByName<T>(fullPath, name); } - private T CreateItemByName<T>(string path, string name, Guid id) + private T CreateItemByName<T>(string path, string name) where T : BaseItem, new() { - var isArtist = typeof(T) == typeof(MusicArtist); - - if (isArtist) + if (typeof(T) == typeof(MusicArtist)) { - var existing = RootFolder - .GetRecursiveChildren(i => i is T && NameExtensions.AreEqual(i.Name, name)) - .Cast<T>() - .FirstOrDefault(); + var existing = GetItemList(new InternalItemsQuery + { + IncludeItemTypes = new[] { typeof(T).Name }, + Name = name + + }).Cast<MusicArtist>() + .OrderBy(i => i.IsAccessedByName ? 1 : 0) + .Cast<T>() + .FirstOrDefault(); if (existing != null) { @@ -983,6 +961,8 @@ namespace MediaBrowser.Server.Implementations.Library } } + var id = GetNewItemId(path, typeof(T)); + var item = GetItemById(id) as T; if (item == null) @@ -996,11 +976,6 @@ namespace MediaBrowser.Server.Implementations.Library Path = path }; - if (isArtist) - { - (item as MusicArtist).IsAccessedByName = true; - } - var task = CreateItem(item, CancellationToken.None); Task.WaitAll(task); } @@ -1102,6 +1077,7 @@ namespace MediaBrowser.Server.Implementations.Library /// <returns>Task.</returns> public async Task ValidateMediaLibraryInternal(IProgress<double> progress, CancellationToken cancellationToken) { + IsScanRunning = true; _libraryMonitorFactory().Stop(); try @@ -1111,6 +1087,7 @@ namespace MediaBrowser.Server.Implementations.Library finally { _libraryMonitorFactory().Start(); + IsScanRunning = false; } } @@ -1289,6 +1266,8 @@ namespace MediaBrowser.Server.Implementations.Library item = RetrieveItem(id); + //_logger.Debug("GetitemById {0}", id); + if (item != null) { RegisterItem(item); @@ -1297,59 +1276,162 @@ namespace MediaBrowser.Server.Implementations.Library return item; } - public BaseItem GetMemoryItemById(Guid id) + public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query) { - if (id == Guid.Empty) + if (query.Recursive && query.ParentId.HasValue) { - throw new ArgumentNullException("id"); + var parent = GetItemById(query.ParentId.Value); + if (parent != null) + { + SetTopParentIdsOrAncestors(query, new List<BaseItem> { parent }); + query.ParentId = null; + } } - BaseItem item; + if (query.User != null) + { + AddUserToQuery(query, query.User); + } - LibraryItemsCache.TryGetValue(id, out item); + return ItemRepository.GetItemList(query); + } - return item; + public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query, IEnumerable<string> parentIds) + { + var parents = parentIds.Select(i => GetItemById(new Guid(i))).Where(i => i != null).ToList(); + + SetTopParentIdsOrAncestors(query, parents); + + if (query.AncestorIds.Length == 0 && query.TopParentIds.Length == 0) + { + if (query.User != null) + { + AddUserToQuery(query, query.User); + } + } + + return ItemRepository.GetItemList(query); } - public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query) + public QueryResult<BaseItem> QueryItems(InternalItemsQuery query) { if (query.User != null) { AddUserToQuery(query, query.User); } - var result = ItemRepository.GetItemIdsList(query); + if (query.EnableTotalRecordCount) + { + return ItemRepository.GetItems(query); + } - return result.Select(GetItemById).Where(i => i != null); + return new QueryResult<BaseItem> + { + Items = ItemRepository.GetItemList(query).ToArray() + }; } - public QueryResult<BaseItem> QueryItems(InternalItemsQuery query) + public List<Guid> GetItemIds(InternalItemsQuery query) { if (query.User != null) { AddUserToQuery(query, query.User); } - return ItemRepository.GetItems(query); + return ItemRepository.GetItemIdsList(query); } - public List<Guid> GetItemIds(InternalItemsQuery query) + public QueryResult<Tuple<BaseItem, ItemCounts>> GetStudios(InternalItemsQuery query) { if (query.User != null) { AddUserToQuery(query, query.User); } - return ItemRepository.GetItemIdsList(query); + SetTopParentOrAncestorIds(query); + return ItemRepository.GetStudios(query); } - public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query, IEnumerable<string> parentIds) + public QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query) { - var parents = parentIds.Select(i => GetItemById(new Guid(i))).Where(i => i != null).ToList(); + if (query.User != null) + { + AddUserToQuery(query, query.User); + } - SetTopParentIdsOrAncestors(query, parents); + SetTopParentOrAncestorIds(query); + return ItemRepository.GetGenres(query); + } - return GetItemIds(query).Select(GetItemById).Where(i => i != null); + public QueryResult<Tuple<BaseItem, ItemCounts>> GetGameGenres(InternalItemsQuery query) + { + if (query.User != null) + { + AddUserToQuery(query, query.User); + } + + SetTopParentOrAncestorIds(query); + return ItemRepository.GetGameGenres(query); + } + + public QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query) + { + if (query.User != null) + { + AddUserToQuery(query, query.User); + } + + SetTopParentOrAncestorIds(query); + return ItemRepository.GetMusicGenres(query); + } + + public QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query) + { + if (query.User != null) + { + AddUserToQuery(query, query.User); + } + + SetTopParentOrAncestorIds(query); + return ItemRepository.GetArtists(query); + } + + private void SetTopParentOrAncestorIds(InternalItemsQuery query) + { + if (query.AncestorIds.Length == 0) + { + return; + } + + var parents = query.AncestorIds.Select(i => GetItemById(new Guid(i))).ToList(); + + if (parents.All(i => + { + if (i is ICollectionFolder || i is UserView) + { + return true; + } + + //_logger.Debug("Query requires ancestor query due to type: " + i.GetType().Name); + return false; + + })) + { + // Optimize by querying against top level views + query.TopParentIds = parents.SelectMany(i => GetTopParentsForQuery(i, query.User)).Select(i => i.Id.ToString("N")).ToArray(); + query.AncestorIds = new string[] { }; + } + } + + public QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query) + { + if (query.User != null) + { + AddUserToQuery(query, query.User); + } + + SetTopParentOrAncestorIds(query); + return ItemRepository.GetAlbumArtists(query); } public QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query) @@ -1369,24 +1451,17 @@ namespace MediaBrowser.Server.Implementations.Library AddUserToQuery(query, query.User); } - var initialResult = ItemRepository.GetItemIds(query); + if (query.EnableTotalRecordCount) + { + return ItemRepository.GetItems(query); + } return new QueryResult<BaseItem> { - TotalRecordCount = initialResult.TotalRecordCount, - Items = initialResult.Items.Select(GetItemById).Where(i => i != null).ToArray() + Items = ItemRepository.GetItemList(query).ToArray() }; } - public QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query, IEnumerable<string> parentIds) - { - var parents = parentIds.Select(i => GetItemById(new Guid(i))).Where(i => i != null).ToList(); - - SetTopParentIdsOrAncestors(query, parents); - - return GetItemsResult(query); - } - private void SetTopParentIdsOrAncestors(InternalItemsQuery query, List<BaseItem> parents) { if (parents.All(i => @@ -1396,7 +1471,7 @@ namespace MediaBrowser.Server.Implementations.Library return true; } - _logger.Debug("Query requires ancestor query due to type: " + i.GetType().Name); + //_logger.Debug("Query requires ancestor query due to type: " + i.GetType().Name); return false; })) @@ -1413,7 +1488,7 @@ namespace MediaBrowser.Server.Implementations.Library private void AddUserToQuery(InternalItemsQuery query, User user) { - if (query.AncestorIds.Length == 0 && !query.ParentId.HasValue && query.ChannelIds.Length == 0 && query.TopParentIds.Length == 0) + if (query.AncestorIds.Length == 0 && !query.ParentId.HasValue && query.ChannelIds.Length == 0 && query.TopParentIds.Length == 0 && string.IsNullOrWhiteSpace(query.AncestorWithPresentationUniqueKey)) { var userViews = _userviewManager().GetUserViews(new UserViewQuery { @@ -1438,8 +1513,13 @@ namespace MediaBrowser.Server.Implementations.Library } if (string.Equals(view.ViewType, CollectionType.Channels)) { - // TODO: Return channels - return new[] { view }; + var channelResult = BaseItem.ChannelManager.GetChannelsInternal(new ChannelQuery + { + UserId = user.Id.ToString("N") + + }, CancellationToken.None).Result; + + return channelResult.Items; } // Translate view into folders @@ -1465,8 +1545,12 @@ namespace MediaBrowser.Server.Implementations.Library // Handle grouping if (user != null && !string.IsNullOrWhiteSpace(view.ViewType) && UserView.IsEligibleForGrouping(view.ViewType)) { - var collectionFolders = user.RootFolder.GetChildren(user, true).OfType<CollectionFolder>().Where(i => string.IsNullOrWhiteSpace(i.CollectionType) || string.Equals(i.CollectionType, view.ViewType, StringComparison.OrdinalIgnoreCase)); - return collectionFolders.SelectMany(i => GetTopParentsForQuery(i, user)); + return user.RootFolder + .GetChildren(user, true) + .OfType<CollectionFolder>() + .Where(i => string.IsNullOrWhiteSpace(i.CollectionType) || string.Equals(i.CollectionType, view.ViewType, StringComparison.OrdinalIgnoreCase)) + .Where(i => user.IsFolderGrouped(i.Id)) + .SelectMany(i => GetTopParentsForQuery(i, user)); } return new BaseItem[] { }; } @@ -1847,7 +1931,7 @@ namespace MediaBrowser.Server.Implementations.Library private string GetContentTypeOverride(string path, bool inherit) { - var nameValuePair = ConfigurationManager.Configuration.ContentTypes.FirstOrDefault(i => string.Equals(i.Name, path, StringComparison.OrdinalIgnoreCase) || (inherit && _fileSystem.ContainsSubPath(i.Name, path))); + var nameValuePair = ConfigurationManager.Configuration.ContentTypes.FirstOrDefault(i => string.Equals(i.Name, path, StringComparison.OrdinalIgnoreCase) || (inherit && !string.IsNullOrWhiteSpace(i.Name) && _fileSystem.ContainsSubPath(i.Name, path))); if (nameValuePair != null) { return nameValuePair.Value; @@ -2322,7 +2406,7 @@ namespace MediaBrowser.Server.Implementations.Library public IEnumerable<Video> FindTrailers(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService) { - var files = fileSystemChildren.Where(i => i.IsDirectory) + var files = owner.IsInMixedFolder ? new List<FileSystemMetadata>() : fileSystemChildren.Where(i => i.IsDirectory) .Where(i => string.Equals(i.Name, BaseItem.TrailerFolderName, StringComparison.OrdinalIgnoreCase)) .SelectMany(i => _fileSystem.GetFiles(i.FullName, false)) .ToList(); @@ -2361,6 +2445,7 @@ namespace MediaBrowser.Server.Implementations.Library } video.ExtraType = ExtraType.Trailer; + video.TrailerTypes = new List<TrailerType> { TrailerType.LocalTrailer }; return video; @@ -2575,5 +2660,205 @@ namespace MediaBrowser.Server.Implementations.Library throw new InvalidOperationException(); } + + public void AddVirtualFolder(string name, string collectionType, string[] mediaPaths, bool refreshLibrary) + { + if (string.IsNullOrWhiteSpace(name)) + { + throw new ArgumentNullException("name"); + } + + name = _fileSystem.GetValidFilename(name); + + var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath; + + var virtualFolderPath = Path.Combine(rootFolderPath, name); + while (_fileSystem.DirectoryExists(virtualFolderPath)) + { + name += "1"; + virtualFolderPath = Path.Combine(rootFolderPath, name); + } + + if (mediaPaths != null) + { + var invalidpath = mediaPaths.FirstOrDefault(i => !_fileSystem.DirectoryExists(i)); + if (invalidpath != null) + { + throw new ArgumentException("The specified path does not exist: " + invalidpath + "."); + } + } + + _libraryMonitorFactory().Stop(); + + try + { + _fileSystem.CreateDirectory(virtualFolderPath); + + if (!string.IsNullOrEmpty(collectionType)) + { + var path = Path.Combine(virtualFolderPath, collectionType + ".collection"); + + using (File.Create(path)) + { + + } + } + + if (mediaPaths != null) + { + foreach (var path in mediaPaths) + { + AddMediaPath(name, path); + } + } + } + finally + { + Task.Run(() => + { + // No need to start if scanning the library because it will handle it + if (refreshLibrary) + { + ValidateMediaLibrary(new Progress<double>(), CancellationToken.None); + } + else + { + // Need to add a delay here or directory watchers may still pick up the changes + var task = Task.Delay(1000); + // Have to block here to allow exceptions to bubble + Task.WaitAll(task); + + _libraryMonitorFactory().Start(); + } + }); + } + } + + public void RemoveVirtualFolder(string name, bool refreshLibrary) + { + if (string.IsNullOrWhiteSpace(name)) + { + throw new ArgumentNullException("name"); + } + + var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath; + + var path = Path.Combine(rootFolderPath, name); + + if (!_fileSystem.DirectoryExists(path)) + { + throw new DirectoryNotFoundException("The media folder does not exist"); + } + + _libraryMonitorFactory().Stop(); + + try + { + _fileSystem.DeleteDirectory(path, true); + } + finally + { + Task.Run(() => + { + // No need to start if scanning the library because it will handle it + if (refreshLibrary) + { + ValidateMediaLibrary(new Progress<double>(), CancellationToken.None); + } + else + { + // Need to add a delay here or directory watchers may still pick up the changes + var task = Task.Delay(1000); + // Have to block here to allow exceptions to bubble + Task.WaitAll(task); + + _libraryMonitorFactory().Start(); + } + }); + } + } + + private const string ShortcutFileExtension = ".mblink"; + private const string ShortcutFileSearch = "*" + ShortcutFileExtension; + public void AddMediaPath(string virtualFolderName, string path) + { + if (string.IsNullOrWhiteSpace(path)) + { + throw new ArgumentNullException("path"); + } + + if (!_fileSystem.DirectoryExists(path)) + { + throw new DirectoryNotFoundException("The path does not exist."); + } + + var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath; + var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName); + + var shortcutFilename = _fileSystem.GetFileNameWithoutExtension(path); + + var lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension); + + while (_fileSystem.FileExists(lnk)) + { + shortcutFilename += "1"; + lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension); + } + + _fileSystem.CreateShortcut(lnk, path); + + RemoveContentTypeOverrides(path); + } + + private void RemoveContentTypeOverrides(string path) + { + if (string.IsNullOrWhiteSpace(path)) + { + throw new ArgumentNullException("path"); + } + + var removeList = new List<NameValuePair>(); + + foreach (var contentType in ConfigurationManager.Configuration.ContentTypes) + { + if (string.Equals(path, contentType.Name, StringComparison.OrdinalIgnoreCase) + || _fileSystem.ContainsSubPath(path, contentType.Name)) + { + removeList.Add(contentType); + } + } + + if (removeList.Count > 0) + { + ConfigurationManager.Configuration.ContentTypes = ConfigurationManager.Configuration.ContentTypes + .Except(removeList) + .ToArray(); + + ConfigurationManager.SaveConfiguration(); + } + } + + public void RemoveMediaPath(string virtualFolderName, string mediaPath) + { + if (string.IsNullOrWhiteSpace(mediaPath)) + { + throw new ArgumentNullException("mediaPath"); + } + + var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath; + var path = Path.Combine(rootFolderPath, virtualFolderName); + + if (!_fileSystem.DirectoryExists(path)) + { + throw new DirectoryNotFoundException(string.Format("The media collection {0} does not exist", virtualFolderName)); + } + + var shortcut = Directory.EnumerateFiles(path, ShortcutFileSearch, SearchOption.AllDirectories).FirstOrDefault(f => _fileSystem.ResolveShortcut(f).Equals(mediaPath, StringComparison.OrdinalIgnoreCase)); + + if (!string.IsNullOrEmpty(shortcut)) + { + _fileSystem.DeleteFile(shortcut); + } + } } }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs index 96d570ef9..78107b82d 100644 --- a/MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs +++ b/MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs @@ -6,6 +6,8 @@ using System; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Entities.TV; namespace MediaBrowser.Server.Implementations.Library { @@ -22,18 +24,24 @@ namespace MediaBrowser.Server.Implementations.Library public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) { - var items = _libraryManager.RootFolder - .GetRecursiveChildren(i => i is IHasTrailers) - .Cast<IHasTrailers>() - .ToList(); + var items = _libraryManager.GetItemList(new InternalItemsQuery + { + IncludeItemTypes = new[] { typeof(BoxSet).Name, typeof(Game).Name, typeof(Movie).Name, typeof(Series).Name }, + Recursive = true + + }).OfType<IHasTrailers>().ToList(); + + var trailerTypes = Enum.GetNames(typeof(TrailerType)) + .Select(i => (TrailerType)Enum.Parse(typeof(TrailerType), i, true)) + .Except(new[] { TrailerType.LocalTrailer }) + .ToArray(); var trailers = _libraryManager.GetItemList(new InternalItemsQuery { IncludeItemTypes = new[] { typeof(Trailer).Name }, - ExcludeTrailerTypes = new[] - { - TrailerType.LocalTrailer - } + TrailerTypes = trailerTypes, + Recursive = true + }).ToArray(); var numComplete = 0; diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs index 95f5cb0e1..4f3fe1bf3 100644 --- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -69,10 +69,6 @@ namespace MediaBrowser.Server.Implementations.Library if (stream.IsTextSubtitleStream) { - if (string.Equals(stream.Codec, "ass", StringComparison.OrdinalIgnoreCase)) - { - return false; - } return true; } @@ -175,13 +171,6 @@ namespace MediaBrowser.Server.Implementations.Library source.SupportsTranscoding = false; } } - else if (string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase)) - { - if (!user.Policy.EnableVideoPlaybackTranscoding) - { - source.SupportsTranscoding = false; - } - } } } @@ -267,15 +256,17 @@ namespace MediaBrowser.Server.Implementations.Library private void SetUserProperties(IHasUserData item, MediaSourceInfo source, User user) { - var userData = item == null ? new UserItemData() : _userDataManager.GetUserData(user.Id, item.GetUserDataKey()); + var userData = item == null ? new UserItemData() : _userDataManager.GetUserData(user, item); + + var allowRememberingSelection = item == null || item.EnableRememberingTrackSelections; - SetDefaultAudioStreamIndex(source, userData, user); - SetDefaultSubtitleStreamIndex(source, userData, user); + SetDefaultAudioStreamIndex(source, userData, user, allowRememberingSelection); + SetDefaultSubtitleStreamIndex(source, userData, user, allowRememberingSelection); } - private void SetDefaultSubtitleStreamIndex(MediaSourceInfo source, UserItemData userData, User user) + private void SetDefaultSubtitleStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection) { - if (userData.SubtitleStreamIndex.HasValue && user.Configuration.RememberSubtitleSelections && user.Configuration.SubtitleMode != SubtitlePlaybackMode.None) + if (userData.SubtitleStreamIndex.HasValue && user.Configuration.RememberSubtitleSelections && user.Configuration.SubtitleMode != SubtitlePlaybackMode.None && allowRememberingSelection) { var index = userData.SubtitleStreamIndex.Value; // Make sure the saved index is still valid @@ -304,9 +295,9 @@ namespace MediaBrowser.Server.Implementations.Library user.Configuration.SubtitleMode, audioLangage); } - private void SetDefaultAudioStreamIndex(MediaSourceInfo source, UserItemData userData, User user) + private void SetDefaultAudioStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection) { - if (userData.AudioStreamIndex.HasValue && user.Configuration.RememberAudioSelections) + if (userData.AudioStreamIndex.HasValue && user.Configuration.RememberAudioSelections && allowRememberingSelection) { var index = userData.AudioStreamIndex.Value; // Make sure the saved index is still valid diff --git a/MediaBrowser.Server.Implementations/Library/MusicManager.cs b/MediaBrowser.Server.Implementations/Library/MusicManager.cs index aad7c112b..3ff434898 100644 --- a/MediaBrowser.Server.Implementations/Library/MusicManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MusicManager.cs @@ -30,7 +30,10 @@ namespace MediaBrowser.Server.Implementations.Library public IEnumerable<Audio> GetInstantMixFromArtist(MusicArtist artist, User user) { var genres = user.RootFolder - .GetRecursiveChildren(user, i => i is Audio) + .GetRecursiveChildren(user, new InternalItemsQuery(user) + { + IncludeItemTypes = new[] { typeof(Audio).Name } + }) .Cast<Audio>() .Where(i => i.HasAnyArtist(artist.Name)) .SelectMany(i => i.Genres) @@ -43,7 +46,10 @@ namespace MediaBrowser.Server.Implementations.Library public IEnumerable<Audio> GetInstantMixFromAlbum(MusicAlbum item, User user) { var genres = item - .GetRecursiveChildren(user, i => i is Audio) + .GetRecursiveChildren(user, new InternalItemsQuery(user) + { + IncludeItemTypes = new[] { typeof(Audio).Name } + }) .Cast<Audio>() .SelectMany(i => i.Genres) .Concat(item.Genres) @@ -55,7 +61,10 @@ namespace MediaBrowser.Server.Implementations.Library public IEnumerable<Audio> GetInstantMixFromFolder(Folder item, User user) { var genres = item - .GetRecursiveChildren(user, i => i is Audio) + .GetRecursiveChildren(user, new InternalItemsQuery(user) + { + IncludeItemTypes = new[] {typeof(Audio).Name} + }) .Cast<Audio>() .SelectMany(i => i.Genres) .Concat(item.Genres) @@ -67,7 +76,10 @@ namespace MediaBrowser.Server.Implementations.Library public IEnumerable<Audio> GetInstantMixFromPlaylist(Playlist item, User user) { var genres = item - .GetRecursiveChildren(user, i => i is Audio) + .GetRecursiveChildren(user, new InternalItemsQuery(user) + { + IncludeItemTypes = new[] { typeof(Audio).Name } + }) .Cast<Audio>() .SelectMany(i => i.Genres) .Concat(item.Genres) @@ -86,7 +98,7 @@ namespace MediaBrowser.Server.Implementations.Library Genres = genreList.ToArray() - }, new string[] { }); + }); var genresDictionary = genreList.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); diff --git a/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs b/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs index 60e7e2df3..9f949db92 100644 --- a/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs +++ b/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs @@ -44,7 +44,6 @@ namespace MediaBrowser.Server.Implementations.Library // Make sure DateCreated and DateModified have values var fileInfo = directoryService.GetFile(item.Path); - item.DateModified = fileSystem.GetLastWriteTimeUtc(fileInfo); SetDateCreated(item, fileSystem, fileInfo); EnsureName(item, fileInfo); @@ -80,7 +79,7 @@ namespace MediaBrowser.Server.Implementations.Library item.GetParents().Any(i => i.IsLocked); // Make sure DateCreated and DateModified have values - EnsureDates(fileSystem, item, args, true); + EnsureDates(fileSystem, item, args); } /// <summary> @@ -125,8 +124,7 @@ namespace MediaBrowser.Server.Implementations.Library /// <param name="fileSystem">The file system.</param> /// <param name="item">The item.</param> /// <param name="args">The args.</param> - /// <param name="includeCreationTime">if set to <c>true</c> [include creation time].</param> - private static void EnsureDates(IFileSystem fileSystem, BaseItem item, ItemResolveArgs args, bool includeCreationTime) + private static void EnsureDates(IFileSystem fileSystem, BaseItem item, ItemResolveArgs args) { if (fileSystem == null) { @@ -148,12 +146,7 @@ namespace MediaBrowser.Server.Implementations.Library if (childData != null) { - if (includeCreationTime) - { - SetDateCreated(item, fileSystem, childData); - } - - item.DateModified = fileSystem.GetLastWriteTimeUtc(childData); + SetDateCreated(item, fileSystem, childData); } else { @@ -161,21 +154,13 @@ namespace MediaBrowser.Server.Implementations.Library if (fileData.Exists) { - if (includeCreationTime) - { - SetDateCreated(item, fileSystem, fileData); - } - item.DateModified = fileSystem.GetLastWriteTimeUtc(fileData); + SetDateCreated(item, fileSystem, fileData); } } } else { - if (includeCreationTime) - { - SetDateCreated(item, fileSystem, args.FileInfo); - } - item.DateModified = fileSystem.GetLastWriteTimeUtc(args.FileInfo); + SetDateCreated(item, fileSystem, args.FileInfo); } } diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs index 9edd3f83f..703a33856 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs @@ -126,7 +126,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers } else { - var videoInfo = parser.ResolveFile(args.Path); + var videoInfo = parser.Resolve(args.Path, false, false); if (videoInfo == null) { diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs index 8beb03b71..9dd30edde 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs @@ -5,15 +5,19 @@ using MediaBrowser.Model.Entities; using System; using System.IO; using System.Linq; +using CommonIO; namespace MediaBrowser.Server.Implementations.Library.Resolvers { public class PhotoResolver : ItemResolver<Photo> { private readonly IImageProcessor _imageProcessor; - public PhotoResolver(IImageProcessor imageProcessor) + private readonly ILibraryManager _libraryManager; + + public PhotoResolver(IImageProcessor imageProcessor, ILibraryManager libraryManager) { _imageProcessor = imageProcessor; + _libraryManager = libraryManager; } /// <summary> @@ -23,20 +27,45 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers /// <returns>Trailer.</returns> protected override Photo Resolve(ItemResolveArgs args) { - // Must be an image file within a photo collection - if (string.Equals(args.GetCollectionType(), CollectionType.Photos, StringComparison.OrdinalIgnoreCase) && - !args.IsDirectory && - IsImageFile(args.Path, _imageProcessor)) + if (!args.IsDirectory) { - return new Photo + // Must be an image file within a photo collection + var collectionType = args.GetCollectionType(); + + if (string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase) || + string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase)) { - Path = args.Path - }; + if (IsImageFile(args.Path, _imageProcessor)) + { + var filename = Path.GetFileNameWithoutExtension(args.Path); + + // Make sure the image doesn't belong to a video file + if (args.DirectoryService.GetFiles(Path.GetDirectoryName(args.Path)).Any(i => IsOwnedByMedia(i, filename))) + { + return null; + } + + return new Photo + { + Path = args.Path + }; + } + } } return null; } + private bool IsOwnedByMedia(FileSystemMetadata file, string imageFilename) + { + if (_libraryManager.IsVideoFile(file.FullName) && imageFilename.StartsWith(Path.GetFileNameWithoutExtension(file.Name), StringComparison.OrdinalIgnoreCase)) + { + return true; + } + + return false; + } + private static readonly string[] IgnoreFiles = { "folder", @@ -44,7 +73,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers "landscape", "fanart", "backdrop", - "poster" + "poster", + "cover" }; internal static bool IsImageFile(string path, IImageProcessor imageProcessor) diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs index e62049821..7b8832c59 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs @@ -1,6 +1,9 @@ -using MediaBrowser.Controller.Entities.TV; +using System; +using System.IO; +using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using System.Linq; +using MediaBrowser.Model.Entities; namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV { @@ -28,7 +31,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV } var season = parent as Season; - // Just in case the user decided to nest episodes. // Not officially supported but in some cases we can handle it. if (season == null) @@ -37,10 +39,31 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV } // If the parent is a Season or Series, then this is an Episode if the VideoResolver returns something - if (season != null || args.HasParent<Series>()) + // Also handle flat tv folders + if (season != null || + string.Equals(args.GetCollectionType(), CollectionType.TvShows, StringComparison.OrdinalIgnoreCase) || + args.HasParent<Series>()) { var episode = ResolveVideo<Episode>(args, false); + if (episode != null) + { + var series = parent as Series; + if (series == null) + { + series = parent.GetParents().OfType<Series>().FirstOrDefault(); + } + + if (series != null) + { + episode.SeriesId = series.Id; + } + if (season != null) + { + episode.SeasonId = season.Id; + } + } + return episode; } diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs index 7d13b11ad..eeac1345e 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs @@ -38,10 +38,12 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV if (args.Parent is Series && args.IsDirectory) { var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions(); - + var series = ((Series)args.Parent); + var season = new Season { - IndexNumber = new SeasonPathParser(namingOptions, new RegexProvider()).Parse(args.Path, true, true).SeasonNumber + IndexNumber = new SeasonPathParser(namingOptions, new RegexProvider()).Parse(args.Path, true, true).SeasonNumber, + SeriesId = series.Id }; if (season.IndexNumber.HasValue && season.IndexNumber.Value == 0) diff --git a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs index 276fc329f..cf6f070d0 100644 --- a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs +++ b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs @@ -87,13 +87,16 @@ namespace MediaBrowser.Server.Implementations.Library { var searchTerm = query.SearchTerm; + if (searchTerm != null) + { + searchTerm = searchTerm.Trim().RemoveDiacritics(); + } + if (string.IsNullOrWhiteSpace(searchTerm)) { throw new ArgumentNullException("searchTerm"); } - searchTerm = searchTerm.RemoveDiacritics(); - var terms = GetWords(searchTerm); var hints = new List<Tuple<BaseItem, string, int>>(); @@ -119,7 +122,7 @@ namespace MediaBrowser.Server.Implementations.Library AddIfMissing(excludeItemTypes, typeof(MusicGenre).Name); } - if (query.IncludePeople && (includeItemTypes.Count == 0 || includeItemTypes.Contains("People", StringComparer.OrdinalIgnoreCase))) + if (query.IncludePeople && (includeItemTypes.Count == 0 || includeItemTypes.Contains("People", StringComparer.OrdinalIgnoreCase) || includeItemTypes.Contains("Person", StringComparer.OrdinalIgnoreCase))) { if (!query.IncludeMedia) { @@ -165,7 +168,7 @@ namespace MediaBrowser.Server.Implementations.Library Limit = query.Limit, IncludeItemsByName = true - }, new string[] { }); + }); // Add search hints based on item name hints.AddRange(mediaItems.Where(IncludeInSearch).Select(item => diff --git a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs index ae737d244..715f3c522 100644 --- a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs @@ -10,6 +10,7 @@ using MediaBrowser.Model.Logging; using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -22,7 +23,8 @@ namespace MediaBrowser.Server.Implementations.Library { public event EventHandler<UserDataSaveEventArgs> UserDataSaved; - private readonly ConcurrentDictionary<string, UserItemData> _userData = new ConcurrentDictionary<string, UserItemData>(); + private readonly ConcurrentDictionary<string, UserItemData> _userData = + new ConcurrentDictionary<string, UserItemData>(StringComparer.OrdinalIgnoreCase); private readonly ILogger _logger; private readonly IServerConfigurationManager _config; @@ -56,27 +58,28 @@ namespace MediaBrowser.Server.Implementations.Library cancellationToken.ThrowIfCancellationRequested(); - var key = item.GetUserDataKey(); + var keys = item.GetUserDataKeys(); - try + foreach (var key in keys) { - await Repository.SaveUserData(userId, key, userData, cancellationToken).ConfigureAwait(false); - - var newValue = userData; + try + { + await Repository.SaveUserData(userId, key, userData, cancellationToken).ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.ErrorException("Error saving user data", ex); - // Once it succeeds, put it into the dictionary to make it available to everyone else - _userData.AddOrUpdate(GetCacheKey(userId, key), newValue, delegate { return newValue; }); + throw; + } } - catch (Exception ex) - { - _logger.ErrorException("Error saving user data", ex); - throw; - } + var cacheKey = GetCacheKey(userId, item.Id); + _userData.AddOrUpdate(cacheKey, userData, (k, v) => userData); EventHelper.FireEventIfNotNull(UserDataSaved, this, new UserDataSaveEventArgs { - Key = key, + Keys = keys, UserData = userData, SaveReason = reason, UserId = userId, @@ -116,7 +119,7 @@ namespace MediaBrowser.Server.Implementations.Library throw; } - + } /// <summary> @@ -134,51 +137,86 @@ namespace MediaBrowser.Server.Implementations.Library return Repository.GetAllUserData(userId); } - /// <summary> - /// Gets the user data. - /// </summary> - /// <param name="userId">The user id.</param> - /// <param name="key">The key.</param> - /// <returns>Task{UserItemData}.</returns> - public UserItemData GetUserData(Guid userId, string key) + public UserItemData GetUserData(Guid userId, Guid itemId, List<string> keys) { if (userId == Guid.Empty) { throw new ArgumentNullException("userId"); } - if (string.IsNullOrEmpty(key)) + if (keys == null) + { + throw new ArgumentNullException("keys"); + } + if (keys.Count == 0) { - throw new ArgumentNullException("key"); + throw new ArgumentException("UserData keys cannot be empty."); } - return _userData.GetOrAdd(GetCacheKey(userId, key), keyName => GetUserDataFromRepository(userId, key)); + var cacheKey = GetCacheKey(userId, itemId); + + return _userData.GetOrAdd(cacheKey, k => GetUserDataInternal(userId, keys)); } - public UserItemData GetUserDataFromRepository(Guid userId, string key) + private UserItemData GetUserDataInternal(Guid userId, List<string> keys) { - var data = Repository.GetUserData(userId, key); + var userData = Repository.GetUserData(userId, keys); - return data; + if (userData != null) + { + return userData; + } + + if (keys.Count > 0) + { + return new UserItemData + { + UserId = userId, + Key = keys[0] + }; + } + + return null; } /// <summary> /// Gets the internal key. /// </summary> - /// <param name="userId">The user id.</param> - /// <param name="key">The key.</param> /// <returns>System.String.</returns> - private string GetCacheKey(Guid userId, string key) + private string GetCacheKey(Guid userId, Guid itemId) + { + return userId.ToString("N") + itemId.ToString("N"); + } + + public UserItemData GetUserData(IHasUserData user, IHasUserData item) + { + return GetUserData(user.Id, item); + } + + public UserItemData GetUserData(string userId, IHasUserData item) + { + return GetUserData(new Guid(userId), item); + } + + public UserItemData GetUserData(Guid userId, IHasUserData item) { - return userId + key; + return GetUserData(userId, item.Id, item.GetUserDataKeys()); } - public UserItemDataDto GetUserDataDto(IHasUserData item, User user) + public async Task<UserItemDataDto> GetUserDataDto(IHasUserData item, User user) { - var userData = GetUserData(user.Id, item.GetUserDataKey()); + var userData = GetUserData(user.Id, item); var dto = GetUserItemDataDto(userData); - item.FillUserDataDtoValues(dto, userData, user); + await item.FillUserDataDtoValues(dto, userData, null, user).ConfigureAwait(false); + return dto; + } + + public async Task<UserItemDataDto> GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user) + { + var userData = GetUserData(user.Id, item); + var dto = GetUserItemDataDto(userData); + await item.FillUserDataDtoValues(dto, userData, itemDto, user).ConfigureAwait(false); return dto; } @@ -261,10 +299,5 @@ namespace MediaBrowser.Server.Implementations.Library return playedToCompletion; } - - public UserItemData GetUserData(string userId, string key) - { - return GetUserData(new Guid(userId), key); - } } } diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs index c1807efe9..6456d7f81 100644 --- a/MediaBrowser.Server.Implementations/Library/UserManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs @@ -352,6 +352,7 @@ namespace MediaBrowser.Server.Implementations.Library users.Add(user); user.Policy.IsAdministrator = true; + user.Policy.EnableContentDeletion = true; user.Policy.EnableRemoteControlOfOtherUsers = true; await UpdateUserPolicy(user, user.Policy, false).ConfigureAwait(false); } @@ -728,7 +729,7 @@ namespace MediaBrowser.Server.Implementations.Library var text = new StringBuilder(); - var localAddress = _appHost.LocalApiUrl ?? string.Empty; + var localAddress = _appHost.GetLocalApiUrl().Result ?? string.Empty; text.AppendLine("Use your web browser to visit:"); text.AppendLine(string.Empty); diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs index 9f6e39b46..319e715c3 100644 --- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs @@ -105,7 +105,7 @@ namespace MediaBrowser.Server.Implementations.Library } } - if (user.Configuration.DisplayFoldersView) + if (_config.Configuration.EnableFolderView) { var name = _localizationManager.GetLocalizedString("ViewType" + CollectionType.Folders); list.Add(await _libraryManager.GetNamedView(name, CollectionType.Folders, string.Empty, cancellationToken).ConfigureAwait(false)); @@ -121,7 +121,7 @@ namespace MediaBrowser.Server.Implementations.Library var channels = channelResult.Items; - if (!user.Configuration.DisplayChannelsInline && channels.Length > 0) + if (user.Configuration.EnableChannelView && channels.Length > 0) { list.Add(await _channelManager.GetInternalChannelFolder(cancellationToken).ConfigureAwait(false)); } @@ -202,23 +202,7 @@ namespace MediaBrowser.Server.Implementations.Library { var user = _userManager.GetUserById(request.UserId); - var includeTypes = request.IncludeItemTypes; - - var currentUser = user; - - var libraryItems = GetItemsForLatestItems(user, request.ParentId, includeTypes, request.Limit ?? 10).Where(i => - { - if (request.IsPlayed.HasValue) - { - var val = request.IsPlayed.Value; - if (i is Video && i.IsPlayed(currentUser) != val) - { - return false; - } - } - - return true; - }); + var libraryItems = GetItemsForLatestItems(user, request); var list = new List<Tuple<BaseItem, List<BaseItem>>>(); @@ -254,8 +238,13 @@ namespace MediaBrowser.Server.Implementations.Library return list; } - private IEnumerable<BaseItem> GetItemsForLatestItems(User user, string parentId, string[] includeItemTypes, int limit) + private IEnumerable<BaseItem> GetItemsForLatestItems(User user, LatestItemsQuery request) { + var parentId = request.ParentId; + + var includeItemTypes = request.IncludeItemTypes; + var limit = request.Limit ?? 10; + var parentIds = string.IsNullOrEmpty(parentId) ? new string[] { } : new[] { parentId }; @@ -276,7 +265,12 @@ namespace MediaBrowser.Server.Implementations.Library var excludeItemTypes = includeItemTypes.Length == 0 ? new[] { - typeof(Person).Name, typeof(Studio).Name, typeof(Year).Name, typeof(GameGenre).Name, typeof(MusicGenre).Name, typeof(Genre).Name + typeof(Person).Name, + typeof(Studio).Name, + typeof(Year).Name, + typeof(GameGenre).Name, + typeof(MusicGenre).Name, + typeof(Genre).Name } : new string[] { }; @@ -288,8 +282,9 @@ namespace MediaBrowser.Server.Implementations.Library IsFolder = includeItemTypes.Length == 0 ? false : (bool?)null, ExcludeItemTypes = excludeItemTypes, ExcludeLocationTypes = new[] { LocationType.Virtual }, - Limit = limit * 20, - ExcludeSourceTypes = parentIds.Length == 0 ? new[] { SourceType.Channel, SourceType.LiveTV } : new SourceType[] { } + Limit = limit * 5, + ExcludeSourceTypes = parentIds.Length == 0 ? new[] { SourceType.Channel, SourceType.LiveTV } : new SourceType[] { }, + IsPlayed = request.IsPlayed }, parentIds); } diff --git a/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs index c122d64d3..c1803b5e4 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs @@ -35,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// <returns>Task.</returns> public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) { - var items = _libraryManager.RootFolder.GetRecursiveChildren() + var items = _libraryManager.RootFolder.GetRecursiveChildren(i => true) .SelectMany(i => i.Studios) .DistinctNames() .ToList(); @@ -73,28 +73,6 @@ namespace MediaBrowser.Server.Implementations.Library.Validators progress.Report(percent); } - var allIds = _libraryManager.GetItemIds(new InternalItemsQuery - { - IncludeItemTypes = new[] { typeof(Studio).Name } - }); - - var invalidIds = allIds - .Except(validIds) - .ToList(); - - foreach (var id in invalidIds) - { - cancellationToken.ThrowIfCancellationRequested(); - - var item = _libraryManager.GetItemById(id); - - await _libraryManager.DeleteItem(item, new DeleteOptions - { - DeleteFileLocation = false - - }).ConfigureAwait(false); - } - progress.Report(100); } } diff --git a/MediaBrowser.Server.Implementations/Library/Validators/YearsPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/YearsPostScanTask.cs index 5ea5fb254..7f52a4506 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/YearsPostScanTask.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/YearsPostScanTask.cs @@ -20,16 +20,12 @@ namespace MediaBrowser.Server.Implementations.Library.Validators public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) { - var allYears = _libraryManager.RootFolder.GetRecursiveChildren(i => i.ProductionYear.HasValue) - .Select(i => i.ProductionYear ?? -1) - .Where(i => i > 0) - .Distinct() - .ToList(); - - var count = allYears.Count; + var yearNumber = 1900; + var maxYear = DateTime.UtcNow.Year + 3; + var count = maxYear - yearNumber + 1; var numComplete = 0; - foreach (var yearNumber in allYears) + while (yearNumber < maxYear) { try { @@ -53,6 +49,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators percent *= 100; progress.Report(percent); + yearNumber++; } } } |
