diff options
Diffstat (limited to 'MediaBrowser.Server.Implementations/Library')
27 files changed, 458 insertions, 414 deletions
diff --git a/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs index 1771bbdb2..db4910c52 100644 --- a/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs +++ b/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs @@ -1,4 +1,4 @@ -using MediaBrowser.Common.Extensions; +using MediaBrowser.Model.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index ab72d89fd..aac4c87f5 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -13,7 +13,6 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Resolvers; using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Naming.Audio; @@ -22,6 +21,7 @@ using MediaBrowser.Naming.IO; using MediaBrowser.Naming.TV; using MediaBrowser.Naming.Video; using MediaBrowser.Server.Implementations.Library.Validators; +using MediaBrowser.Server.Implementations.Logging; using MediaBrowser.Server.Implementations.ScheduledTasks; using System; using System.Collections.Concurrent; @@ -218,11 +218,7 @@ namespace MediaBrowser.Server.Implementations.Library /// <summary> /// The _root folder sync lock /// </summary> - private object _rootFolderSyncLock = new object(); - /// <summary> - /// The _root folder initialized - /// </summary> - private bool _rootFolderInitialized; + private readonly object _rootFolderSyncLock = new object(); /// <summary> /// Gets the root folder. /// </summary> @@ -231,17 +227,17 @@ namespace MediaBrowser.Server.Implementations.Library { get { - LazyInitializer.EnsureInitialized(ref _rootFolder, ref _rootFolderInitialized, ref _rootFolderSyncLock, CreateRootFolder); - return _rootFolder; - } - private set - { - _rootFolder = value; - - if (value == null) + if (_rootFolder == null) { - _rootFolderInitialized = false; + lock (_rootFolderSyncLock) + { + if (_rootFolder == null) + { + _rootFolder = CreateRootFolder(); + } + } } + return _rootFolder; } } @@ -336,8 +332,8 @@ namespace MediaBrowser.Server.Implementations.Library /// <returns>Task.</returns> private async Task UpdateSeasonZeroNames(string newName, CancellationToken cancellationToken) { - var seasons = RootFolder.RecursiveChildren - .OfType<Season>() + 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)) .ToList(); @@ -392,7 +388,7 @@ namespace MediaBrowser.Server.Implementations.Library var locationType = item.LocationType; var children = item.IsFolder - ? ((Folder)item).RecursiveChildren.ToList() + ? ((Folder)item).GetRecursiveChildren().ToList() : new List<BaseItem>(); foreach (var metadataPath in GetMetadataPaths(item, children)) @@ -401,11 +397,11 @@ namespace MediaBrowser.Server.Implementations.Library try { - Directory.Delete(metadataPath, true); + _fileSystem.DeleteDirectory(metadataPath, true); } catch (DirectoryNotFoundException) { - + } catch (Exception ex) { @@ -420,12 +416,12 @@ namespace MediaBrowser.Server.Implementations.Library if (Directory.Exists(path)) { _logger.Debug("Deleting path {0}", path); - Directory.Delete(path, true); + _fileSystem.DeleteDirectory(path, true); } else if (File.Exists(path)) { _logger.Debug("Deleting path {0}", path); - File.Delete(path); + _fileSystem.DeleteFile(path); } } @@ -521,6 +517,11 @@ namespace MediaBrowser.Server.Implementations.Library 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) @@ -577,12 +578,12 @@ namespace MediaBrowser.Server.Implementations.Library var fullPath = fileInfo.FullName; - if (string.IsNullOrWhiteSpace(collectionType)) + if (string.IsNullOrWhiteSpace(collectionType) && parent != null) { collectionType = GetContentTypeOverride(fullPath, true); } - var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, this, directoryService) + var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, directoryService) { Parent = parent, Path = fullPath, @@ -756,12 +757,14 @@ namespace MediaBrowser.Server.Implementations.Library Directory.CreateDirectory(userRootPath); - _userRootFolder = GetItemById(GetNewItemId(userRootPath, typeof(UserRootFolder))) as UserRootFolder; + var tmpItem = GetItemById(GetNewItemId(userRootPath, typeof(UserRootFolder))) as UserRootFolder; - if (_userRootFolder == null) + if (tmpItem == null) { - _userRootFolder = (UserRootFolder)ResolvePath(new DirectoryInfo(userRootPath)); + tmpItem = (UserRootFolder)ResolvePath(new DirectoryInfo(userRootPath)); } + + _userRootFolder = tmpItem; } } } @@ -841,13 +844,25 @@ namespace MediaBrowser.Server.Implementations.Library } /// <summary> + /// Gets the artists path. + /// </summary> + /// <value>The artists path.</value> + public string ArtistsPath + { + get + { + return Path.Combine(ConfigurationManager.ApplicationPaths.ItemsByNamePath, "artists"); + } + } + + /// <summary> /// Gets a Genre /// </summary> /// <param name="name">The name.</param> /// <returns>Task{Genre}.</returns> public MusicArtist GetArtist(string name) { - return GetItemByName<MusicArtist>(ConfigurationManager.ApplicationPaths.ArtistsPath, name); + return GetItemByName<MusicArtist>(ArtistsPath, name); } private T GetItemByName<T>(string path, string name) @@ -892,14 +907,6 @@ namespace MediaBrowser.Server.Implementations.Library return obj as T; } - /// <summary> - /// Creates an IBN item based on a given path - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="path">The path.</param> - /// <param name="name">The name.</param> - /// <returns>Task{``0}.</returns> - /// <exception cref="System.IO.IOException">Path not created: + path</exception> private T CreateItemByName<T>(string path, string name, Guid id) where T : BaseItem, new() { @@ -909,9 +916,10 @@ namespace MediaBrowser.Server.Implementations.Library { var validFilename = _fileSystem.GetValidFilename(name).Trim(); - var existing = RootFolder.RecursiveChildren - .OfType<T>() - .FirstOrDefault(i => string.Equals(_fileSystem.GetValidFilename(i.Name).Trim(), validFilename, StringComparison.OrdinalIgnoreCase)); + var existing = RootFolder + .GetRecursiveChildren(i => i is T && string.Equals(_fileSystem.GetValidFilename(i.Name).Trim(), validFilename, StringComparison.OrdinalIgnoreCase)) + .Cast<T>() + .FirstOrDefault(); if (existing != null) { @@ -925,7 +933,15 @@ namespace MediaBrowser.Server.Implementations.Library if (!fileInfo.Exists) { - fileInfo = Directory.CreateDirectory(path); + try + { + fileInfo = Directory.CreateDirectory(path); + } + catch (UnauthorizedAccessException ex) + { + _logger.Error("Error creating directory {0}", ex, path); + throw new Exception(string.Format("Error creating directory {0}", path), ex); + } isNew = true; } @@ -968,76 +984,6 @@ namespace MediaBrowser.Server.Implementations.Library } /// <summary> - /// Validates the artists. - /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="progress">The progress.</param> - /// <returns>Task.</returns> - public Task ValidateArtists(CancellationToken cancellationToken, IProgress<double> progress) - { - // Ensure the location is unavailable. - Directory.CreateDirectory(ConfigurationManager.ApplicationPaths.ArtistsPath); - - return new ArtistsValidator(this, _userManager, _logger).Run(progress, cancellationToken); - } - - /// <summary> - /// Validates the music genres. - /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="progress">The progress.</param> - /// <returns>Task.</returns> - public Task ValidateMusicGenres(CancellationToken cancellationToken, IProgress<double> progress) - { - // Ensure the location is unavailable. - Directory.CreateDirectory(ConfigurationManager.ApplicationPaths.MusicGenrePath); - - return new MusicGenresValidator(this, _logger).Run(progress, cancellationToken); - } - - /// <summary> - /// Validates the game genres. - /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="progress">The progress.</param> - /// <returns>Task.</returns> - public Task ValidateGameGenres(CancellationToken cancellationToken, IProgress<double> progress) - { - // Ensure the location is unavailable. - Directory.CreateDirectory(ConfigurationManager.ApplicationPaths.GameGenrePath); - - return new GameGenresValidator(this, _userManager, _logger).Run(progress, cancellationToken); - } - - /// <summary> - /// Validates the studios. - /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="progress">The progress.</param> - /// <returns>Task.</returns> - public Task ValidateStudios(CancellationToken cancellationToken, IProgress<double> progress) - { - // Ensure the location is unavailable. - Directory.CreateDirectory(ConfigurationManager.ApplicationPaths.StudioPath); - - return new StudiosValidator(this, _userManager, _logger).Run(progress, cancellationToken); - } - - /// <summary> - /// Validates the genres. - /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="progress">The progress.</param> - /// <returns>Task.</returns> - public Task ValidateGenres(CancellationToken cancellationToken, IProgress<double> progress) - { - // Ensure the location is unavailable. - Directory.CreateDirectory(ConfigurationManager.ApplicationPaths.GenrePath); - - return new GenresValidator(this, _userManager, _logger).Run(progress, cancellationToken); - } - - /// <summary> /// Reloads the root media folder /// </summary> /// <param name="progress">The progress.</param> @@ -1152,7 +1098,7 @@ namespace MediaBrowser.Server.Implementations.Library try { - await task.Run(innerProgress, cancellationToken); + await task.Run(innerProgress, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { @@ -1176,7 +1122,7 @@ namespace MediaBrowser.Server.Implementations.Library /// Gets the default view. /// </summary> /// <returns>IEnumerable{VirtualFolderInfo}.</returns> - public IEnumerable<VirtualFolderInfo> GetDefaultVirtualFolders() + public IEnumerable<VirtualFolderInfo> GetVirtualFolders() { return GetView(ConfigurationManager.ApplicationPaths.DefaultUserViewsPath); } @@ -1184,16 +1130,6 @@ namespace MediaBrowser.Server.Implementations.Library /// <summary> /// Gets the view. /// </summary> - /// <param name="user">The user.</param> - /// <returns>IEnumerable{VirtualFolderInfo}.</returns> - public IEnumerable<VirtualFolderInfo> GetVirtualFolders(User user) - { - return GetDefaultVirtualFolders(); - } - - /// <summary> - /// Gets the view. - /// </summary> /// <param name="path">The path.</param> /// <returns>IEnumerable{VirtualFolderInfo}.</returns> private IEnumerable<VirtualFolderInfo> GetView(string path) @@ -1637,7 +1573,7 @@ namespace MediaBrowser.Server.Implementations.Library CancellationToken cancellationToken) { var path = Path.Combine(ConfigurationManager.ApplicationPaths.ItemsByNamePath, - "views"); + "views"); path = Path.Combine(path, _fileSystem.GetValidFilename(type)); @@ -1708,7 +1644,7 @@ namespace MediaBrowser.Server.Implementations.Library var id = GetNewItemId("7_namedview_" + name + user.Id.ToString("N") + parentId, typeof(UserView)); - var path = BaseItem.GetInternalMetadataPathForId(id); + var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", "specialviews", id.ToString("N")); var item = GetItemById(id) as UserView; @@ -1754,7 +1690,7 @@ namespace MediaBrowser.Server.Implementations.Library public bool IsVideoFile(string path) { - var resolver = new VideoResolver(GetNamingOptions(), new Naming.Logging.NullLogger()); + var resolver = new VideoResolver(GetNamingOptions(), new PatternsLogger()); return resolver.IsVideoFile(path); } @@ -1772,7 +1708,7 @@ namespace MediaBrowser.Server.Implementations.Library public bool FillMissingEpisodeNumbersFromPath(Episode episode) { var resolver = new EpisodeResolver(GetNamingOptions(), - new Naming.Logging.NullLogger()); + new PatternsLogger()); var fileType = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd || episode.VideoType == VideoType.HdDvd ? FileInfoType.Directory : @@ -1910,7 +1846,7 @@ namespace MediaBrowser.Server.Implementations.Library public ItemLookupInfo ParseName(string name) { - var resolver = new VideoResolver(GetNamingOptions(), new Naming.Logging.NullLogger()); + var resolver = new VideoResolver(GetNamingOptions(), new PatternsLogger()); var result = resolver.CleanDateTime(name); var cleanName = resolver.CleanString(result.Name); @@ -1929,7 +1865,7 @@ namespace MediaBrowser.Server.Implementations.Library .SelectMany(i => i.EnumerateFiles("*", SearchOption.TopDirectoryOnly)) .ToList(); - var videoListResolver = new VideoListResolver(GetNamingOptions(), new Naming.Logging.NullLogger()); + var videoListResolver = new VideoListResolver(GetNamingOptions(), new PatternsLogger()); var videos = videoListResolver.Resolve(fileSystemChildren.Select(i => new PortableFileInfo { @@ -1982,7 +1918,7 @@ namespace MediaBrowser.Server.Implementations.Library .SelectMany(i => i.EnumerateFiles("*", SearchOption.TopDirectoryOnly)) .ToList(); - var videoListResolver = new VideoListResolver(GetNamingOptions(), new Naming.Logging.NullLogger()); + var videoListResolver = new VideoListResolver(GetNamingOptions(), new PatternsLogger()); var videos = videoListResolver.Resolve(fileSystemChildren.Select(i => new PortableFileInfo { @@ -2020,7 +1956,7 @@ namespace MediaBrowser.Server.Implementations.Library private void SetExtraTypeFromFilename(Video item) { - var resolver = new ExtraResolver(GetNamingOptions(), new Naming.Logging.NullLogger(), new RegexProvider()); + var resolver = new ExtraResolver(GetNamingOptions(), new PatternsLogger(), new RegexProvider()); var result = resolver.GetExtraInfo(item.Path); diff --git a/MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs index 9196bf734..b72406730 100644 --- a/MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs +++ b/MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using MediaBrowser.Controller.Channels; +using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Channels; @@ -25,8 +24,8 @@ namespace MediaBrowser.Server.Implementations.Library public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) { var items = _libraryManager.RootFolder - .RecursiveChildren - .OfType<IHasTrailers>() + .GetRecursiveChildren(i => i is IHasTrailers) + .Cast<IHasTrailers>() .ToList(); var channelTrailerResult = await _channelManager.GetAllMediaInternal(new AllChannelMediaQuery diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs new file mode 100644 index 000000000..a45757d13 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -0,0 +1,51 @@ +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; +using MediaBrowser.Model.Entities; +using System.Collections.Generic; +using System.Linq; + +namespace MediaBrowser.Server.Implementations.Library +{ + public class MediaSourceManager : IMediaSourceManager + { + private readonly IItemRepository _itemRepo; + + public MediaSourceManager(IItemRepository itemRepo) + { + _itemRepo = itemRepo; + } + + public IEnumerable<MediaStream> GetMediaStreams(MediaStreamQuery query) + { + var list = _itemRepo.GetMediaStreams(query) + .ToList(); + + foreach (var stream in list) + { + stream.SupportsExternalStream = StreamSupportsExternalStream(stream); + } + + return list; + } + + private bool StreamSupportsExternalStream(MediaStream stream) + { + if (stream.IsExternal) + { + return true; + } + + if (stream.IsTextSubtitleStream) + { + return InternalTextStreamSupportsExternalStream(stream); + } + + return false; + } + + private bool InternalTextStreamSupportsExternalStream(MediaStream stream) + { + return true; + } + } +} diff --git a/MediaBrowser.Server.Implementations/Library/MusicManager.cs b/MediaBrowser.Server.Implementations/Library/MusicManager.cs index b8c29c19b..7733e7d37 100644 --- a/MediaBrowser.Server.Implementations/Library/MusicManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MusicManager.cs @@ -32,8 +32,8 @@ namespace MediaBrowser.Server.Implementations.Library var artist = _libraryManager.GetArtist(name); var genres = user.RootFolder - .GetRecursiveChildren(user) - .OfType<Audio>() + .GetRecursiveChildren(user, i => i is Audio) + .Cast<Audio>() .Where(i => i.HasArtist(name)) .SelectMany(i => i.Genres) .Concat(artist.Genres) @@ -45,8 +45,8 @@ namespace MediaBrowser.Server.Implementations.Library public IEnumerable<Audio> GetInstantMixFromAlbum(MusicAlbum item, User user) { var genres = item - .GetRecursiveChildren(user, true) - .OfType<Audio>() + .GetRecursiveChildren(user, i => i is Audio) + .Cast<Audio>() .SelectMany(i => i.Genres) .Concat(item.Genres) .Distinct(StringComparer.OrdinalIgnoreCase); @@ -57,8 +57,8 @@ namespace MediaBrowser.Server.Implementations.Library public IEnumerable<Audio> GetInstantMixFromPlaylist(Playlist item, User user) { var genres = item - .GetRecursiveChildren(user, true) - .OfType<Audio>() + .GetRecursiveChildren(user, i => i is Audio) + .Cast<Audio>() .SelectMany(i => i.Genres) .Concat(item.Genres) .Distinct(StringComparer.OrdinalIgnoreCase); @@ -68,12 +68,13 @@ namespace MediaBrowser.Server.Implementations.Library public IEnumerable<Audio> GetInstantMixFromGenres(IEnumerable<string> genres, User user) { - var inputItems = user.RootFolder.GetRecursiveChildren(user); + var inputItems = user.RootFolder + .GetRecursiveChildren(user, i => i is Audio); var genresDictionary = genres.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); return inputItems - .OfType<Audio>() + .Cast<Audio>() .Select(i => new Tuple<Audio, int>(i, i.Genres.Count(genresDictionary.ContainsKey))) .Where(i => i.Item2 > 0) .OrderByDescending(i => i.Item2) @@ -82,5 +83,40 @@ namespace MediaBrowser.Server.Implementations.Library .Take(100) .OrderBy(i => Guid.NewGuid()); } + + public IEnumerable<Audio> GetInstantMixFromItem(BaseItem item, User user) + { + var genre = item as MusicGenre; + if (genre != null) + { + return GetInstantMixFromGenres(new[] { item.Name }, user); + } + + var playlist = item as Playlist; + if (playlist != null) + { + return GetInstantMixFromPlaylist(playlist, user); + } + + var album = item as MusicAlbum; + if (album != null) + { + return GetInstantMixFromAlbum(album, user); + } + + var artist = item as MusicArtist; + if (artist != null) + { + return GetInstantMixFromArtist(artist.Name, user); + } + + var song = item as Audio; + if (song != null) + { + return GetInstantMixFromSong(song, user); + } + + return new Audio[] { }; + } } } diff --git a/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs b/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs index 03e28d7ba..b6a93408a 100644 --- a/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs +++ b/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs @@ -39,12 +39,6 @@ namespace MediaBrowser.Server.Implementations.Library item.Id = libraryManager.GetNewItemId(item.Path, item.GetType()); - // If the resolver didn't specify this - if (string.IsNullOrEmpty(item.DisplayMediaType)) - { - item.DisplayMediaType = item.GetType().Name; - } - item.IsLocked = item.Path.IndexOf("[dontfetchmeta]", StringComparison.OrdinalIgnoreCase) != -1 || item.Parents.Any(i => i.IsLocked); @@ -79,12 +73,6 @@ namespace MediaBrowser.Server.Implementations.Library item.Id = libraryManager.GetNewItemId(item.Path, item.GetType()); - // If the resolver didn't specify this - if (string.IsNullOrEmpty(item.DisplayMediaType)) - { - item.DisplayMediaType = item.GetType().Name; - } - // Make sure the item has a name EnsureName(item, args.FileInfo); diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs index 7c8ddabeb..0abdc4296 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs @@ -6,7 +6,7 @@ using MediaBrowser.Controller.Resolvers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Naming.Audio; -using MediaBrowser.Naming.Common; +using MediaBrowser.Server.Implementations.Logging; using System; using System.Collections.Generic; using System.IO; @@ -169,7 +169,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio { var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions(); - var parser = new AlbumParser(namingOptions, new Naming.Logging.NullLogger()); + var parser = new AlbumParser(namingOptions, new PatternsLogger()); var result = parser.ParseMultiPart(path); return result.IsMultiPart; diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs index 1a4d35af5..3333719b7 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs @@ -7,6 +7,7 @@ using MediaBrowser.Naming.Video; using System; using System.IO; using System.Linq; +using MediaBrowser.Server.Implementations.Logging; namespace MediaBrowser.Server.Implementations.Library.Resolvers { @@ -47,7 +48,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers var namingOptions = ((LibraryManager)LibraryManager).GetNamingOptions(); // If the path is a file check for a matching extensions - var parser = new Naming.Video.VideoResolver(namingOptions, new Naming.Logging.NullLogger()); + var parser = new Naming.Video.VideoResolver(namingOptions, new PatternsLogger()); if (args.IsDirectory) { @@ -233,7 +234,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers { var namingOptions = ((LibraryManager)LibraryManager).GetNamingOptions(); - var resolver = new Format3DParser(namingOptions, new Naming.Logging.NullLogger()); + var resolver = new Format3DParser(namingOptions, new PatternsLogger()); var result = resolver.Parse(video.Path); Set3DFormat(video, result.Is3D, result.Format3D); diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs index 67b9d546f..e3447afc9 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs @@ -4,7 +4,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Model.Entities; using System; using System.IO; -using System.Linq; namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies { @@ -46,17 +45,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies return null; } - private bool IsInvalid(string collectionType) - { - var validCollectionTypes = new[] - { - CollectionType.Movies, - CollectionType.BoxSets - }; - - return !validCollectionTypes.Contains(collectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase); - } - /// <summary> /// Sets the initial item values. /// </summary> diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index 4c0767b08..95dcee98a 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -1,13 +1,14 @@ -using MediaBrowser.Common.Extensions; -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Resolvers; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Extensions; using MediaBrowser.Naming.IO; using MediaBrowser.Naming.Video; +using MediaBrowser.Server.Implementations.Logging; using System; using System.Collections.Generic; using System.IO; @@ -111,7 +112,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies var namingOptions = ((LibraryManager)LibraryManager).GetNamingOptions(); - var resolver = new VideoListResolver(namingOptions, new Naming.Logging.NullLogger()); + var resolver = new VideoListResolver(namingOptions, new PatternsLogger()); var resolverResult = resolver.Resolve(files.Select(i => new PortableFileInfo { FullName = i.FullName, @@ -125,7 +126,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies Items = videos }; - var isInMixedFolder = resolverResult.Count > 0; + var isInMixedFolder = resolverResult.Count > 1; foreach (var video in resolverResult) { @@ -436,7 +437,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies } var namingOptions = ((LibraryManager)LibraryManager).GetNamingOptions(); - var resolver = new StackResolver(namingOptions, new Naming.Logging.NullLogger()); + var resolver = new StackResolver(namingOptions, new PatternsLogger()); var result = resolver.ResolveDirectories(folderPaths); diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs index 0a41a6c04..31b2d8b0f 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs @@ -1,4 +1,5 @@ using MediaBrowser.Common.IO; +using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Resolvers; @@ -11,10 +12,12 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers class SpecialFolderResolver : FolderResolver<Folder> { private readonly IFileSystem _fileSystem; + private readonly IServerApplicationPaths _appPaths; - public SpecialFolderResolver(IFileSystem fileSystem) + public SpecialFolderResolver(IFileSystem fileSystem, IServerApplicationPaths appPaths) { _fileSystem = fileSystem; + _appPaths = appPaths; } /// <summary> @@ -39,7 +42,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers { return new AggregateFolder(); } - if (args.IsRoot) + if (string.Equals(args.Path, _appPaths.DefaultUserViewsPath, StringComparison.OrdinalIgnoreCase)) { return new UserRootFolder(); //if we got here and still a root - must be user root } diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs index ff05c29ee..7371ca5a9 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs @@ -12,6 +12,7 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Naming.Common; using MediaBrowser.Naming.IO; using MediaBrowser.Naming.TV; +using MediaBrowser.Server.Implementations.Logging; using EpisodeInfo = MediaBrowser.Controller.Providers.EpisodeInfo; namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV @@ -152,7 +153,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV .ToList(); } - var episodeResolver = new Naming.TV.EpisodeResolver(namingOptions, new Naming.Logging.NullLogger()); + var episodeResolver = new Naming.TV.EpisodeResolver(namingOptions, new PatternsLogger()); var episodeInfo = episodeResolver.Resolve(fullName, FileInfoType.File, false); if (episodeInfo != null && episodeInfo.EpisodeNumber.HasValue) { diff --git a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs index 1c92f6c4a..51cad7a35 100644 --- a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs +++ b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs @@ -35,20 +35,19 @@ namespace MediaBrowser.Server.Implementations.Library { IEnumerable<BaseItem> inputItems; + Func<BaseItem, bool> filter = i => !(i is ICollectionFolder); + if (string.IsNullOrWhiteSpace(query.UserId)) { - inputItems = _libraryManager.RootFolder.RecursiveChildren; + inputItems = _libraryManager.RootFolder.GetRecursiveChildren(filter); } else { var user = _userManager.GetUserById(query.UserId); - inputItems = user.RootFolder.GetRecursiveChildren(user, true); + inputItems = user.RootFolder.GetRecursiveChildren(user, filter); } - - inputItems = inputItems.Where(i => !(i is ICollectionFolder)); - inputItems = _libraryManager.ReplaceVideosWithPrimaryVersions(inputItems); var results = await GetSearchHints(inputItems, query).ConfigureAwait(false); diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs index 3b6de5998..b8bc8585e 100644 --- a/MediaBrowser.Server.Implementations/Library/UserManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.Events; using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; @@ -70,8 +71,9 @@ namespace MediaBrowser.Server.Implementations.Library private readonly Func<IDtoService> _dtoServiceFactory; private readonly Func<IConnectManager> _connectFactory; private readonly IServerApplicationHost _appHost; + private readonly IFileSystem _fileSystem; - public UserManager(ILogger logger, IServerConfigurationManager configurationManager, IUserRepository userRepository, IXmlSerializer xmlSerializer, INetworkManager networkManager, Func<IImageProcessor> imageProcessorFactory, Func<IDtoService> dtoServiceFactory, Func<IConnectManager> connectFactory, IServerApplicationHost appHost, IJsonSerializer jsonSerializer) + public UserManager(ILogger logger, IServerConfigurationManager configurationManager, IUserRepository userRepository, IXmlSerializer xmlSerializer, INetworkManager networkManager, Func<IImageProcessor> imageProcessorFactory, Func<IDtoService> dtoServiceFactory, Func<IConnectManager> connectFactory, IServerApplicationHost appHost, IJsonSerializer jsonSerializer, IFileSystem fileSystem) { _logger = logger; UserRepository = userRepository; @@ -82,6 +84,7 @@ namespace MediaBrowser.Server.Implementations.Library _connectFactory = connectFactory; _appHost = appHost; _jsonSerializer = jsonSerializer; + _fileSystem = fileSystem; ConfigurationManager = configurationManager; Users = new List<User>(); @@ -204,7 +207,7 @@ namespace MediaBrowser.Server.Implementations.Library { return username; } - + // Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.) var builder = new StringBuilder(); @@ -272,9 +275,9 @@ namespace MediaBrowser.Server.Implementations.Library private string GetLocalPasswordHash(User user) { - return string.IsNullOrEmpty(user.LocalPassword) + return string.IsNullOrEmpty(user.EasyPassword) ? GetSha1String(string.Empty) - : user.LocalPassword; + : user.EasyPassword; } private bool IsPasswordEmpty(string passwordHash) @@ -329,22 +332,12 @@ namespace MediaBrowser.Server.Implementations.Library { if (!user.Configuration.HasMigratedToPolicy) { - user.Policy.AccessSchedules = user.Configuration.AccessSchedules; - user.Policy.BlockedChannels = user.Configuration.BlockedChannels; - user.Policy.BlockedMediaFolders = user.Configuration.BlockedMediaFolders; - user.Policy.BlockedTags = user.Configuration.BlockedTags; user.Policy.BlockUnratedItems = user.Configuration.BlockUnratedItems; user.Policy.EnableContentDeletion = user.Configuration.EnableContentDeletion; user.Policy.EnableLiveTvAccess = user.Configuration.EnableLiveTvAccess; user.Policy.EnableLiveTvManagement = user.Configuration.EnableLiveTvManagement; user.Policy.EnableMediaPlayback = user.Configuration.EnableMediaPlayback; - user.Policy.EnableRemoteControlOfOtherUsers = user.Configuration.EnableRemoteControlOfOtherUsers; - user.Policy.EnableSharedDeviceControl = user.Configuration.EnableSharedDeviceControl; - user.Policy.EnableUserPreferenceAccess = user.Configuration.EnableUserPreferenceAccess; user.Policy.IsAdministrator = user.Configuration.IsAdministrator; - user.Policy.IsDisabled = user.Configuration.IsDisabled; - user.Policy.IsHidden = user.Configuration.IsHidden; - user.Policy.MaxParentalRating = user.Configuration.MaxParentalRating; await UpdateUserPolicy(user, user.Policy, false); @@ -362,18 +355,20 @@ namespace MediaBrowser.Server.Implementations.Library var passwordHash = GetPasswordHash(user); - var hasConfiguredDefaultPassword = !IsPasswordEmpty(passwordHash); + var hasConfiguredPassword = !IsPasswordEmpty(passwordHash); + var hasConfiguredEasyPassword = !IsPasswordEmpty(GetLocalPasswordHash(user)); var hasPassword = user.Configuration.EnableLocalPassword && !string.IsNullOrEmpty(remoteEndPoint) && _networkManager.IsInLocalNetwork(remoteEndPoint) ? - !IsPasswordEmpty(GetLocalPasswordHash(user)) : - hasConfiguredDefaultPassword; + hasConfiguredEasyPassword : + hasConfiguredPassword; var dto = new UserDto { Id = user.Id.ToString("N"), Name = user.Name, HasPassword = hasPassword, - HasConfiguredPassword = hasConfiguredDefaultPassword, + HasConfiguredPassword = hasConfiguredPassword, + HasConfiguredEasyPassword = hasConfiguredEasyPassword, LastActivityDate = user.LastActivityDate, LastLoginDate = user.LastLoginDate, Configuration = user.Configuration, @@ -407,6 +402,21 @@ namespace MediaBrowser.Server.Implementations.Library return dto; } + public UserDto GetOfflineUserDto(User user, string deviceId) + { + var dto = GetUserDto(user); + + var offlinePasswordHash = GetLocalPasswordHash(user); + dto.HasPassword = !IsPasswordEmpty(offlinePasswordHash); + + // Hash the pin with the device Id to create a unique result for this device + dto.OfflinePassword = GetSha1String(offlinePasswordHash + deviceId); + + dto.ServerName = _appHost.FriendlyName; + + return dto; + } + private string GetImageCacheTag(BaseItem item, ItemImageInfo image) { try @@ -591,7 +601,7 @@ namespace MediaBrowser.Server.Implementations.Library try { - File.Delete(configPath); + _fileSystem.DeleteFile(configPath); } catch (IOException ex) { @@ -620,18 +630,11 @@ namespace MediaBrowser.Server.Implementations.Library return ChangePassword(user, GetSha1String(string.Empty)); } - /// <summary> - /// Changes the password. - /// </summary> - /// <param name="user">The user.</param> - /// <param name="newPasswordSha1">The new password sha1.</param> - /// <returns>Task.</returns> - /// <exception cref="System.ArgumentNullException"> - /// user - /// or - /// newPassword - /// </exception> - /// <exception cref="System.ArgumentException">Passwords for guests cannot be changed.</exception> + public Task ResetEasyPassword(User user) + { + return ChangeEasyPassword(user, GetSha1String(string.Empty)); + } + public async Task ChangePassword(User user, string newPasswordSha1) { if (user == null) @@ -655,6 +658,29 @@ namespace MediaBrowser.Server.Implementations.Library EventHelper.FireEventIfNotNull(UserPasswordChanged, this, new GenericEventArgs<User>(user), _logger); } + public async Task ChangeEasyPassword(User user, string newPasswordSha1) + { + if (user == null) + { + throw new ArgumentNullException("user"); + } + if (string.IsNullOrWhiteSpace(newPasswordSha1)) + { + throw new ArgumentNullException("newPasswordSha1"); + } + + if (user.ConnectLinkType.HasValue && user.ConnectLinkType.Value == UserLinkType.Guest) + { + throw new ArgumentException("Passwords for guests cannot be changed."); + } + + user.EasyPassword = newPasswordSha1; + + await UpdateUser(user).ConfigureAwait(false); + + EventHelper.FireEventIfNotNull(UserPasswordChanged, this, new GenericEventArgs<User>(user), _logger); + } + /// <summary> /// Instantiates the new user. /// </summary> @@ -703,12 +729,11 @@ namespace MediaBrowser.Server.Implementations.Library var text = new StringBuilder(); - var info = _appHost.GetSystemInfo(); - var localAddress = info.LocalAddress ?? string.Empty; + var localAddress = _appHost.LocalApiUrl ?? string.Empty; text.AppendLine("Use your web browser to visit:"); text.AppendLine(string.Empty); - text.AppendLine(localAddress + "/mediabrowser/web/forgotpasswordpin.html"); + text.AppendLine(localAddress + "/web/forgotpasswordpin.html"); text.AppendLine(string.Empty); text.AppendLine("Enter the following pin code:"); text.AppendLine(string.Empty); @@ -817,7 +842,7 @@ namespace MediaBrowser.Server.Implementations.Library { try { - File.Delete(PasswordResetFile); + _fileSystem.DeleteFile(PasswordResetFile); } catch { @@ -881,7 +906,7 @@ namespace MediaBrowser.Server.Implementations.Library var json = _jsonSerializer.SerializeToString(userPolicy); userPolicy = _jsonSerializer.DeserializeFromString<UserPolicy>(json); } - + var path = GetPolifyFilePath(user); Directory.CreateDirectory(Path.GetDirectoryName(path)); @@ -909,7 +934,7 @@ namespace MediaBrowser.Server.Implementations.Library { lock (_policySyncLock) { - File.Delete(path); + _fileSystem.DeleteFile(path); } } catch (IOException) @@ -971,14 +996,14 @@ namespace MediaBrowser.Server.Implementations.Library var path = GetConfigurationFilePath(user); // The xml serializer will output differently if the type is not exact - if (config.GetType() != typeof (UserConfiguration)) + if (config.GetType() != typeof(UserConfiguration)) { var json = _jsonSerializer.SerializeToString(config); config = _jsonSerializer.DeserializeFromString<UserConfiguration>(json); } Directory.CreateDirectory(Path.GetDirectoryName(path)); - + lock (_configSyncLock) { _xmlSerializer.SerializeToFile(config, path); @@ -991,4 +1016,4 @@ namespace MediaBrowser.Server.Implementations.Library } } } -} +}
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs index 46c32cc56..2ec9e8a4f 100644 --- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs @@ -1,6 +1,6 @@ -using MediaBrowser.Common.IO; -using MediaBrowser.Controller; -using MediaBrowser.Controller.Channels; +using MediaBrowser.Controller.Channels; +using MediaBrowser.Controller.Collections; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; @@ -16,6 +16,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MoreLinq; namespace MediaBrowser.Server.Implementations.Library { @@ -23,24 +24,24 @@ namespace MediaBrowser.Server.Implementations.Library { private readonly ILibraryManager _libraryManager; private readonly ILocalizationManager _localizationManager; - private readonly IFileSystem _fileSystem; private readonly IUserManager _userManager; private readonly IChannelManager _channelManager; private readonly ILiveTvManager _liveTvManager; - private readonly IServerApplicationPaths _appPaths; private readonly IPlaylistManager _playlists; + private readonly ICollectionManager _collectionManager; + private readonly IServerConfigurationManager _config; - public UserViewManager(ILibraryManager libraryManager, ILocalizationManager localizationManager, IFileSystem fileSystem, IUserManager userManager, IChannelManager channelManager, ILiveTvManager liveTvManager, IServerApplicationPaths appPaths, IPlaylistManager playlists) + public UserViewManager(ILibraryManager libraryManager, ILocalizationManager localizationManager, IUserManager userManager, IChannelManager channelManager, ILiveTvManager liveTvManager, IPlaylistManager playlists, ICollectionManager collectionManager, IServerConfigurationManager config) { _libraryManager = libraryManager; _localizationManager = localizationManager; - _fileSystem = fileSystem; _userManager = userManager; _channelManager = channelManager; _liveTvManager = liveTvManager; - _appPaths = appPaths; _playlists = playlists; + _collectionManager = collectionManager; + _config = config; } public async Task<IEnumerable<Folder>> GetUserViews(UserViewQuery query, CancellationToken cancellationToken) @@ -56,7 +57,9 @@ namespace MediaBrowser.Server.Implementations.Library var excludeFolderIds = user.Configuration.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).ToList(); - var standaloneFolders = folders.Where(i => UserView.IsExcludedFromGrouping(i) || excludeFolderIds.Contains(i.Id)).ToList(); + var standaloneFolders = folders + .Where(i => UserView.IsExcludedFromGrouping(i) || excludeFolderIds.Contains(i.Id)) + .ToList(); var foldersWithViewTypes = folders .Except(standaloneFolders) @@ -88,11 +91,9 @@ namespace MediaBrowser.Server.Implementations.Library list.Add(await GetUserView(CollectionType.Games, string.Empty, cancellationToken).ConfigureAwait(false)); } - if (user.Configuration.DisplayCollectionsView && - folders - .Except(standaloneFolders) - .SelectMany(i => i.GetRecursiveChildren(user, false)).OfType<BoxSet>().Any()) + if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase))) { + //list.Add(_collectionManager.GetCollectionsFolder(user.Id.ToString("N"))); list.Add(await GetUserView(CollectionType.BoxSets, string.Empty, cancellationToken).ConfigureAwait(false)); } @@ -166,5 +167,141 @@ namespace MediaBrowser.Server.Implementations.Library return _libraryManager.GetNamedView(name, type, sortName, cancellationToken); } + + public List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request) + { + var user = _userManager.GetUserById(request.UserId); + + var includeTypes = request.IncludeItemTypes; + + var currentUser = user; + + Func<BaseItem, bool> filter = i => + { + if (includeTypes.Length > 0) + { + if (!includeTypes.Contains(i.GetType().Name, StringComparer.OrdinalIgnoreCase)) + { + return false; + } + } + + if (request.IsPlayed.HasValue) + { + var val = request.IsPlayed.Value; + if (i.IsPlayed(currentUser) != val) + { + return false; + } + } + + return i.LocationType != LocationType.Virtual && !i.IsFolder; + }; + + // Avoid implicitly captured closure + var libraryItems = string.IsNullOrEmpty(request.ParentId) && user != null ? + GetItemsConfiguredForLatest(user, filter) : + GetAllLibraryItems(request.UserId, _userManager, _libraryManager, request.ParentId, filter); + + libraryItems = libraryItems.OrderByDescending(i => i.DateCreated); + + if (request.IsPlayed.HasValue) + { + var takeLimit = (request.Limit ?? 20) * 20; + libraryItems = libraryItems.Take(takeLimit); + } + + // Avoid implicitly captured closure + var items = libraryItems + .ToList(); + + var list = new List<Tuple<BaseItem, List<BaseItem>>>(); + + foreach (var item in items) + { + // Only grab the index container for media + var container = item.IsFolder || !request.GroupItems ? null : item.LatestItemsIndexContainer; + + if (container == null) + { + list.Add(new Tuple<BaseItem, List<BaseItem>>(null, new List<BaseItem> { item })); + } + else + { + var current = list.FirstOrDefault(i => i.Item1 != null && i.Item1.Id == container.Id); + + if (current != null) + { + current.Item2.Add(item); + } + else + { + list.Add(new Tuple<BaseItem, List<BaseItem>>(container, new List<BaseItem> { item })); + } + } + + if (list.Count >= request.Limit) + { + break; + } + } + + return list; + } + + protected IList<BaseItem> GetAllLibraryItems(string userId, IUserManager userManager, ILibraryManager libraryManager, string parentId, Func<BaseItem, bool> filter) + { + if (!string.IsNullOrEmpty(parentId)) + { + var folder = (Folder)libraryManager.GetItemById(new Guid(parentId)); + + if (!string.IsNullOrWhiteSpace(userId)) + { + var user = userManager.GetUserById(userId); + + if (user == null) + { + throw new ArgumentException("User not found"); + } + + return folder + .GetRecursiveChildren(user, filter) + .ToList(); + } + + return folder + .GetRecursiveChildren(filter); + } + if (!string.IsNullOrWhiteSpace(userId)) + { + var user = userManager.GetUserById(userId); + + if (user == null) + { + throw new ArgumentException("User not found"); + } + + return user + .RootFolder + .GetRecursiveChildren(user, filter) + .ToList(); + } + + return libraryManager + .RootFolder + .GetRecursiveChildren(filter); + } + + private IEnumerable<BaseItem> GetItemsConfiguredForLatest(User user, Func<BaseItem, bool> filter) + { + // Avoid implicitly captured closure + var currentUser = user; + + return user.RootFolder.GetChildren(user, true) + .OfType<Folder>() + .Where(i => !user.Configuration.LatestItemsExcludes.Contains(i.Id.ToString("N"))) + .SelectMany(i => i.GetRecursiveChildren(currentUser, filter)) + .DistinctBy(i => i.Id); + } } } diff --git a/MediaBrowser.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs index 60116ac61..079867ddd 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Logging; using System; using System.Threading; using System.Threading.Tasks; @@ -14,14 +15,16 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// The _library manager /// </summary> private readonly ILibraryManager _libraryManager; + private readonly ILogger _logger; /// <summary> /// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class. /// </summary> /// <param name="libraryManager">The library manager.</param> - public ArtistsPostScanTask(ILibraryManager libraryManager) + public ArtistsPostScanTask(ILibraryManager libraryManager, ILogger logger) { _libraryManager = libraryManager; + _logger = logger; } /// <summary> @@ -32,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// <returns>Task.</returns> public Task Run(IProgress<double> progress, CancellationToken cancellationToken) { - return ((LibraryManager)_libraryManager).ValidateArtists(cancellationToken, progress); + return new ArtistsValidator(_libraryManager, _logger).Run(progress, cancellationToken); } } } diff --git a/MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs index 5968d847e..7636833e4 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs @@ -1,7 +1,5 @@ -using MediaBrowser.Common.Progress; -using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; -using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; @@ -23,11 +21,6 @@ namespace MediaBrowser.Server.Implementations.Library.Validators private readonly ILibraryManager _libraryManager; /// <summary> - /// The _user manager - /// </summary> - private readonly IUserManager _userManager; - - /// <summary> /// The _logger /// </summary> private readonly ILogger _logger; @@ -36,12 +29,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class. /// </summary> /// <param name="libraryManager">The library manager.</param> - /// <param name="userManager">The user manager.</param> /// <param name="logger">The logger.</param> - public ArtistsValidator(ILibraryManager libraryManager, IUserManager userManager, ILogger logger) + public ArtistsValidator(ILibraryManager libraryManager, ILogger logger) { _libraryManager = libraryManager; - _userManager = userManager; _logger = logger; } @@ -53,58 +44,11 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// <returns>Task.</returns> public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) { - var allItems = _libraryManager.RootFolder.GetRecursiveChildren(); - - var allSongs = allItems.OfType<Audio>().ToList(); - - var innerProgress = new ActionableProgress<double>(); - - innerProgress.RegisterAction(pct => progress.Report(pct * .8)); - - var allArtists = await GetAllArtists(allSongs, cancellationToken, innerProgress).ConfigureAwait(false); - - progress.Report(80); - - var numComplete = 0; - - var numArtists = allArtists.Count; - - foreach (var artist in allArtists) - { - cancellationToken.ThrowIfCancellationRequested(); - - // Only do this for artists accessed by name. Folder-based artists get it from the normal refresh - if (artist.IsAccessedByName && !artist.LockedFields.Contains(MetadataFields.Genres)) - { - // Avoid implicitly captured closure - var artist1 = artist; - - artist.Genres = allSongs.Where(i => i.HasArtist(artist1.Name)) - .SelectMany(i => i.Genres) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToList(); - } - - numComplete++; - double percent = numComplete; - percent /= numArtists; - percent *= 20; - - progress.Report(80 + percent); - } - - progress.Report(100); - } + var allSongs = _libraryManager.RootFolder + .GetRecursiveChildren(i => !i.IsFolder && (i is IHasArtist)) + .Cast<IHasArtist>() + .ToList(); - /// <summary> - /// Gets all artists. - /// </summary> - /// <param name="allSongs">All songs.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="progress">The progress.</param> - /// <returns>Task{Artist[]}.</returns> - private async Task<List<MusicArtist>> GetAllArtists(IEnumerable<Audio> allSongs, CancellationToken cancellationToken, IProgress<double> progress) - { var allArtists = allSongs.SelectMany(i => i.AllArtists) .Distinct(StringComparer.OrdinalIgnoreCase) .ToList(); @@ -138,8 +82,6 @@ namespace MediaBrowser.Server.Implementations.Library.Validators progress.Report(100 * percent); } - - return returnArtists; } } } diff --git a/MediaBrowser.Server.Implementations/Library/Validators/BoxSetPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/BoxSetPostScanTask.cs deleted file mode 100644 index 86d88f7e0..000000000 --- a/MediaBrowser.Server.Implementations/Library/Validators/BoxSetPostScanTask.cs +++ /dev/null @@ -1,50 +0,0 @@ -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Library; -using System; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Server.Implementations.Library.Validators -{ - public class BoxSetPostScanTask : ILibraryPostScanTask - { - private readonly ILibraryManager _libraryManager; - - public BoxSetPostScanTask(ILibraryManager libraryManager) - { - _libraryManager = libraryManager; - } - - public Task Run(IProgress<double> progress, CancellationToken cancellationToken) - { - var items = _libraryManager.RootFolder.RecursiveChildren.ToList(); - - var boxsets = items.OfType<BoxSet>().ToList(); - - var numComplete = 0; - - foreach (var boxset in boxsets) - { - foreach (var child in boxset.Children.Concat(boxset.GetLinkedChildren()).OfType<ISupportsBoxSetGrouping>()) - { - var boxsetIdList = child.BoxSetIdList.ToList(); - if (!boxsetIdList.Contains(boxset.Id)) - { - boxsetIdList.Add(boxset.Id); - } - child.BoxSetIdList = boxsetIdList; - } - - numComplete++; - double percent = numComplete; - percent /= boxsets.Count; - progress.Report(percent * 100); - } - - progress.Report(100); - return Task.FromResult(true); - } - } -} diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs index ae6c863a7..8be2e436f 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Logging; using System; using System.Threading; using System.Threading.Tasks; @@ -14,14 +15,17 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// The _library manager /// </summary> private readonly ILibraryManager _libraryManager; + private readonly ILogger _logger; /// <summary> /// Initializes a new instance of the <see cref="GameGenresPostScanTask" /> class. /// </summary> /// <param name="libraryManager">The library manager.</param> - public GameGenresPostScanTask(ILibraryManager libraryManager) + /// <param name="logger">The logger.</param> + public GameGenresPostScanTask(ILibraryManager libraryManager, ILogger logger) { _libraryManager = libraryManager; + _logger = logger; } /// <summary> @@ -32,7 +36,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// <returns>Task.</returns> public Task Run(IProgress<double> progress, CancellationToken cancellationToken) { - return ((LibraryManager)_libraryManager).ValidateGameGenres(cancellationToken, progress); + return new GameGenresValidator(_libraryManager, _logger).Run(progress, cancellationToken); } } } diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs index 6b658e175..757936aa7 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs @@ -16,19 +16,13 @@ namespace MediaBrowser.Server.Implementations.Library.Validators private readonly ILibraryManager _libraryManager; /// <summary> - /// The _user manager - /// </summary> - private readonly IUserManager _userManager; - - /// <summary> /// The _logger /// </summary> private readonly ILogger _logger; - public GameGenresValidator(ILibraryManager libraryManager, IUserManager userManager, ILogger logger) + public GameGenresValidator(ILibraryManager libraryManager, ILogger logger) { _libraryManager = libraryManager; - _userManager = userManager; _logger = logger; } @@ -40,19 +34,16 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// <returns>Task.</returns> public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) { - var items = _libraryManager.RootFolder.RecursiveChildren.Where(i => (i is Game)) + var items = _libraryManager.RootFolder.GetRecursiveChildren(i => (i is Game)) .SelectMany(i => i.Genres) .Distinct(StringComparer.OrdinalIgnoreCase) .ToList(); - progress.Report(2); var numComplete = 0; var count = items.Count; foreach (var name in items) { - cancellationToken.ThrowIfCancellationRequested(); - try { var itemByName = _libraryManager.GetGameGenre(name); @@ -72,9 +63,9 @@ namespace MediaBrowser.Server.Implementations.Library.Validators numComplete++; double percent = numComplete; percent /= count; - percent *= 90; + percent *= 100; - progress.Report(percent + 10); + progress.Report(percent); } progress.Report(100); diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GenresPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/GenresPostScanTask.cs index f1d0ef370..a1c34676c 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/GenresPostScanTask.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/GenresPostScanTask.cs @@ -2,6 +2,7 @@ using System; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Logging; namespace MediaBrowser.Server.Implementations.Library.Validators { @@ -11,14 +12,17 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// The _library manager /// </summary> private readonly ILibraryManager _libraryManager; + private readonly ILogger _logger; /// <summary> /// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class. /// </summary> /// <param name="libraryManager">The library manager.</param> - public GenresPostScanTask(ILibraryManager libraryManager) + /// <param name="logger">The logger.</param> + public GenresPostScanTask(ILibraryManager libraryManager, ILogger logger) { _libraryManager = libraryManager; + _logger = logger; } /// <summary> @@ -29,7 +33,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// <returns>Task.</returns> public Task Run(IProgress<double> progress, CancellationToken cancellationToken) { - return ((LibraryManager)_libraryManager).ValidateGenres(cancellationToken, progress); + return new GenresValidator(_libraryManager, _logger).Run(progress, cancellationToken); } } } diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs index b0dee9aaf..3a06fac1b 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs @@ -17,19 +17,13 @@ namespace MediaBrowser.Server.Implementations.Library.Validators private readonly ILibraryManager _libraryManager; /// <summary> - /// The _user manager - /// </summary> - private readonly IUserManager _userManager; - - /// <summary> /// The _logger /// </summary> private readonly ILogger _logger; - public GenresValidator(ILibraryManager libraryManager, IUserManager userManager, ILogger logger) + public GenresValidator(ILibraryManager libraryManager, ILogger logger) { _libraryManager = libraryManager; - _userManager = userManager; _logger = logger; } @@ -41,19 +35,16 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// <returns>Task.</returns> public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) { - var items = _libraryManager.RootFolder.RecursiveChildren.Where(i => !(i is IHasMusicGenres) && !(i is Game)) + var items = _libraryManager.RootFolder.GetRecursiveChildren(i => !(i is IHasMusicGenres) && !(i is Game)) .SelectMany(i => i.Genres) .Distinct(StringComparer.OrdinalIgnoreCase) .ToList(); - progress.Report(2); var numComplete = 0; var count = items.Count; foreach (var name in items) { - cancellationToken.ThrowIfCancellationRequested(); - try { var itemByName = _libraryManager.GetGenre(name); @@ -73,9 +64,9 @@ namespace MediaBrowser.Server.Implementations.Library.Validators numComplete++; double percent = numComplete; percent /= count; - percent *= 90; + percent *= 100; - progress.Report(percent + 10); + progress.Report(percent); } progress.Report(100); diff --git a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs index 280dd90f4..dbcab0832 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Logging; using System; using System.Threading; using System.Threading.Tasks; @@ -14,14 +15,17 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// The _library manager /// </summary> private readonly ILibraryManager _libraryManager; + private readonly ILogger _logger; /// <summary> /// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class. /// </summary> /// <param name="libraryManager">The library manager.</param> - public MusicGenresPostScanTask(ILibraryManager libraryManager) + /// <param name="logger">The logger.</param> + public MusicGenresPostScanTask(ILibraryManager libraryManager, ILogger logger) { _libraryManager = libraryManager; + _logger = logger; } /// <summary> @@ -32,7 +36,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// <returns>Task.</returns> public Task Run(IProgress<double> progress, CancellationToken cancellationToken) { - return ((LibraryManager)_libraryManager).ValidateMusicGenres(cancellationToken, progress); + return new MusicGenresValidator(_libraryManager, _logger).Run(progress, cancellationToken); } } } diff --git a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs index aa6c6281e..25eddb48a 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs @@ -34,19 +34,16 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// <returns>Task.</returns> public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) { - var items = _libraryManager.RootFolder.RecursiveChildren.Where(i => (i is IHasMusicGenres)) + var items = _libraryManager.RootFolder.GetRecursiveChildren(i => (i is IHasMusicGenres)) .SelectMany(i => i.Genres) .Distinct(StringComparer.OrdinalIgnoreCase) .ToList(); - progress.Report(2); var numComplete = 0; var count = items.Count; foreach (var name in items) { - cancellationToken.ThrowIfCancellationRequested(); - try { var itemByName = _libraryManager.GetMusicGenre(name); @@ -66,9 +63,9 @@ namespace MediaBrowser.Server.Implementations.Library.Validators numComplete++; double percent = numComplete; percent /= count; - percent *= 90; + percent *= 100; - progress.Report(percent + 10); + progress.Report(percent); } progress.Report(100); diff --git a/MediaBrowser.Server.Implementations/Library/Validators/StudiosPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/StudiosPostScanTask.cs index 0f998b070..0ff609da1 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/StudiosPostScanTask.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/StudiosPostScanTask.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Logging; using System; using System.Threading; using System.Threading.Tasks; @@ -15,13 +16,16 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// </summary> private readonly ILibraryManager _libraryManager; + private readonly ILogger _logger; + /// <summary> /// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class. /// </summary> /// <param name="libraryManager">The library manager.</param> - public StudiosPostScanTask(ILibraryManager libraryManager) + public StudiosPostScanTask(ILibraryManager libraryManager, ILogger logger) { _libraryManager = libraryManager; + _logger = logger; } /// <summary> @@ -32,7 +36,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// <returns>Task.</returns> public Task Run(IProgress<double> progress, CancellationToken cancellationToken) { - return ((LibraryManager)_libraryManager).ValidateStudios(cancellationToken, progress); + return new StudiosValidator(_libraryManager, _logger).Run(progress, cancellationToken); } } } diff --git a/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs index a2ec9788c..5feebab9c 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs @@ -15,19 +15,13 @@ namespace MediaBrowser.Server.Implementations.Library.Validators private readonly ILibraryManager _libraryManager; /// <summary> - /// The _user manager - /// </summary> - private readonly IUserManager _userManager; - - /// <summary> /// The _logger /// </summary> private readonly ILogger _logger; - public StudiosValidator(ILibraryManager libraryManager, IUserManager userManager, ILogger logger) + public StudiosValidator(ILibraryManager libraryManager, ILogger logger) { _libraryManager = libraryManager; - _userManager = userManager; _logger = logger; } @@ -39,19 +33,16 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// <returns>Task.</returns> public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) { - var items = _libraryManager.RootFolder.RecursiveChildren + var items = _libraryManager.RootFolder.GetRecursiveChildren() .SelectMany(i => i.Studios) .Distinct(StringComparer.OrdinalIgnoreCase) .ToList(); - progress.Report(2); var numComplete = 0; var count = items.Count; foreach (var name in items) { - cancellationToken.ThrowIfCancellationRequested(); - try { var itemByName = _libraryManager.GetStudio(name); @@ -71,9 +62,9 @@ namespace MediaBrowser.Server.Implementations.Library.Validators numComplete++; double percent = numComplete; percent /= count; - percent *= 90; + percent *= 100; - progress.Report(percent + 10); + progress.Report(percent); } progress.Report(100); diff --git a/MediaBrowser.Server.Implementations/Library/Validators/YearsPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/YearsPostScanTask.cs index 78783db90..5ea5fb254 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/YearsPostScanTask.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/YearsPostScanTask.cs @@ -20,23 +20,21 @@ namespace MediaBrowser.Server.Implementations.Library.Validators public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) { - var allYears = _libraryManager.RootFolder.RecursiveChildren + var allYears = _libraryManager.RootFolder.GetRecursiveChildren(i => i.ProductionYear.HasValue) .Select(i => i.ProductionYear ?? -1) .Where(i => i > 0) .Distinct() .ToList(); - progress.Report(10); - var count = allYears.Count; var numComplete = 0; foreach (var yearNumber in allYears) { - var year = _libraryManager.GetYear(yearNumber); - try { + var year = _libraryManager.GetYear(yearNumber); + await year.RefreshMetadata(cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) @@ -46,15 +44,15 @@ namespace MediaBrowser.Server.Implementations.Library.Validators } catch (Exception ex) { - _logger.ErrorException("Error refreshing year {0}", ex, year); + _logger.ErrorException("Error refreshing year {0}", ex, yearNumber); } numComplete++; double percent = numComplete; percent /= count; - percent *= 90; + percent *= 100; - progress.Report(percent + 10); + progress.Report(percent); } } } |
