diff options
Diffstat (limited to 'MediaBrowser.Server.Implementations/Library')
8 files changed, 402 insertions, 73 deletions
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index e6e6b8c74..1f82e7ef1 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1584,15 +1584,22 @@ namespace MediaBrowser.Server.Implementations.Library .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i)); } - public async Task<UserView> GetNamedView(string name, - string type, + public async Task<UserView> GetNamedView(User user, + string name, + string viewType, string sortName, CancellationToken cancellationToken) { + if (ConfigurationManager.Configuration.EnableUserSpecificUserViews) + { + return await GetNamedViewInternal(user, name, null, viewType, sortName, cancellationToken) + .ConfigureAwait(false); + } + var path = Path.Combine(ConfigurationManager.ApplicationPaths.ItemsByNamePath, "views"); - path = Path.Combine(path, _fileSystem.GetValidFilename(type)); + path = Path.Combine(path, _fileSystem.GetValidFilename(viewType)); var id = GetNewItemId(path + "_namedview_" + name, typeof(UserView)); @@ -1611,7 +1618,7 @@ namespace MediaBrowser.Server.Implementations.Library Id = id, DateCreated = DateTime.UtcNow, Name = name, - ViewType = type, + ViewType = viewType, ForcedSortName = sortName }; @@ -1627,31 +1634,38 @@ namespace MediaBrowser.Server.Implementations.Library if (refresh) { - await item.RefreshMetadata(new MetadataRefreshOptions - { - ForceSave = true - - }, cancellationToken).ConfigureAwait(false); + await item.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None).ConfigureAwait(false); + _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions()); } return item; } - public async Task<UserView> GetSpecialFolder(User user, + public Task<UserView> GetNamedView(User user, string name, string parentId, string viewType, string sortName, CancellationToken cancellationToken) { - if (string.IsNullOrWhiteSpace(name)) + if (string.IsNullOrWhiteSpace(parentId)) { - throw new ArgumentNullException("name"); + throw new ArgumentNullException("parentId"); } - if (string.IsNullOrWhiteSpace(parentId)) + return GetNamedViewInternal(user, name, parentId, viewType, sortName, cancellationToken); + } + + private async Task<UserView> GetNamedViewInternal(User user, + string name, + string parentId, + string viewType, + string sortName, + CancellationToken cancellationToken) + { + if (string.IsNullOrWhiteSpace(name)) { - throw new ArgumentNullException("parentId"); + throw new ArgumentNullException("name"); } if (string.IsNullOrWhiteSpace(viewType)) @@ -1659,13 +1673,13 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentNullException("viewType"); } - var id = GetNewItemId("7_namedview_" + name + user.Id.ToString("N") + parentId, typeof(UserView)); + var id = GetNewItemId("37_namedview_" + name + user.Id.ToString("N") + (parentId ?? string.Empty), typeof(UserView)); - var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", "specialviews", id.ToString("N")); + var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N")); var item = GetItemById(id) as UserView; - var refresh = false; + var isNew = false; if (item == null) { @@ -1679,27 +1693,24 @@ namespace MediaBrowser.Server.Implementations.Library Name = name, ViewType = viewType, ForcedSortName = sortName, - UserId = user.Id, - ParentId = new Guid(parentId) + UserId = user.Id }; + if (!string.IsNullOrWhiteSpace(parentId)) + { + item.ParentId = new Guid(parentId); + } + await CreateItem(item, cancellationToken).ConfigureAwait(false); - refresh = true; + isNew = true; } - if (!refresh && item != null) - { - refresh = (DateTime.UtcNow - item.DateLastSaved).TotalHours >= 24; - } + var refresh = isNew || (DateTime.UtcNow - item.DateLastSaved).TotalHours >= 6; if (refresh) { - await item.RefreshMetadata(new MetadataRefreshOptions - { - ForceSave = true - - }, cancellationToken).ConfigureAwait(false); + _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions()); } return item; @@ -1846,6 +1857,10 @@ namespace MediaBrowser.Server.Implementations.Library { var options = new ExtendedNamingOptions(); + // These cause apps to have problems + options.AudioFileExtensions.Remove(".m3u"); + options.AudioFileExtensions.Remove(".wpl"); + if (!ConfigurationManager.Configuration.EnableAudioArchiveFiles) { options.AudioFileExtensions.Remove(".rar"); diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs index a45757d13..2880c9e16 100644 --- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -1,18 +1,43 @@ -using MediaBrowser.Controller.Library; +using System.IO; +using MediaBrowser.Controller.Channels; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Persistence; +using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; +using System; using System.Collections.Generic; using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.Server.Implementations.Library { public class MediaSourceManager : IMediaSourceManager { private readonly IItemRepository _itemRepo; + private readonly IUserManager _userManager; + private readonly ILibraryManager _libraryManager; + private readonly IChannelManager _channelManager; - public MediaSourceManager(IItemRepository itemRepo) + private IMediaSourceProvider[] _providers; + private readonly ILogger _logger; + + public MediaSourceManager(IItemRepository itemRepo, IUserManager userManager, ILibraryManager libraryManager, IChannelManager channelManager, ILogger logger) { _itemRepo = itemRepo; + _userManager = userManager; + _libraryManager = libraryManager; + _channelManager = channelManager; + _logger = logger; + } + + public void AddParts(IEnumerable<IMediaSourceProvider> providers) + { + _providers = providers.ToArray(); } public IEnumerable<MediaStream> GetMediaStreams(MediaStreamQuery query) @@ -47,5 +72,223 @@ namespace MediaBrowser.Server.Implementations.Library { return true; } + + public IEnumerable<MediaStream> GetMediaStreams(string mediaSourceId) + { + var list = GetMediaStreams(new MediaStreamQuery + { + ItemId = new Guid(mediaSourceId) + }); + + return GetMediaStreamsForItem(list); + } + + public IEnumerable<MediaStream> GetMediaStreams(Guid itemId) + { + var list = GetMediaStreams(new MediaStreamQuery + { + ItemId = itemId + }); + + return GetMediaStreamsForItem(list); + } + + private IEnumerable<MediaStream> GetMediaStreamsForItem(IEnumerable<MediaStream> streams) + { + var list = streams.ToList(); + + var subtitleStreams = list + .Where(i => i.Type == MediaStreamType.Subtitle) + .ToList(); + + if (subtitleStreams.Count > 0) + { + var videoStream = list.FirstOrDefault(i => i.Type == MediaStreamType.Video); + + // This is abitrary but at some point it becomes too slow to extract subtitles on the fly + // We need to learn more about when this is the case vs. when it isn't + const int maxAllowedBitrateForExternalSubtitleStream = 10000000; + + var videoBitrate = videoStream == null ? maxAllowedBitrateForExternalSubtitleStream : videoStream.BitRate ?? maxAllowedBitrateForExternalSubtitleStream; + + foreach (var subStream in subtitleStreams) + { + var supportsExternalStream = StreamSupportsExternalStream(subStream); + + if (supportsExternalStream && videoBitrate >= maxAllowedBitrateForExternalSubtitleStream) + { + supportsExternalStream = false; + } + + subStream.SupportsExternalStream = supportsExternalStream; + } + } + + return list; + } + + public async Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, string userId, bool enablePathSubstitution, CancellationToken cancellationToken) + { + var item = _libraryManager.GetItemById(id); + IEnumerable<MediaSourceInfo> mediaSources; + + var hasMediaSources = (IHasMediaSources)item; + var channelItem = item as IChannelMediaItem; + + if (channelItem != null) + { + mediaSources = await _channelManager.GetChannelItemMediaSources(id, true, cancellationToken) + .ConfigureAwait(false); + } + else + { + if (string.IsNullOrWhiteSpace(userId)) + { + mediaSources = hasMediaSources.GetMediaSources(enablePathSubstitution); + } + else + { + var user = _userManager.GetUserById(userId); + mediaSources = GetStaticMediaSources(hasMediaSources, enablePathSubstitution, user); + } + } + + var dynamicMediaSources = await GetDynamicMediaSources(hasMediaSources, cancellationToken).ConfigureAwait(false); + + var list = new List<MediaSourceInfo>(); + + list.AddRange(mediaSources); + + foreach (var source in dynamicMediaSources) + { + source.SupportsTranscoding = false; + + if (source.Protocol == MediaProtocol.File) + { + source.SupportsDirectStream = File.Exists(source.Path); + } + + list.Add(source); + } + + return SortMediaSources(list); + } + + private async Task<IEnumerable<MediaSourceInfo>> GetDynamicMediaSources(IHasMediaSources item, CancellationToken cancellationToken) + { + var tasks = _providers.Select(i => GetDynamicMediaSources(item, i, cancellationToken)); + var results = await Task.WhenAll(tasks).ConfigureAwait(false); + + return results.SelectMany(i => i.ToList()); + } + + private async Task<IEnumerable<MediaSourceInfo>> GetDynamicMediaSources(IHasMediaSources item, IMediaSourceProvider provider, CancellationToken cancellationToken) + { + try + { + return await provider.GetMediaSources(item, cancellationToken).ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting media sources", ex); + return new List<MediaSourceInfo>(); + } + } + + public Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, bool enablePathSubstitution, CancellationToken cancellationToken) + { + return GetPlayackMediaSources(id, null, enablePathSubstitution, cancellationToken); + } + + public IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution) + { + if (item == null) + { + throw new ArgumentNullException("item"); + } + + if (!(item is Video)) + { + return item.GetMediaSources(enablePathSubstitution); + } + + return item.GetMediaSources(enablePathSubstitution); + } + + public IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user) + { + if (item == null) + { + throw new ArgumentNullException("item"); + } + + if (!(item is Video)) + { + return item.GetMediaSources(enablePathSubstitution); + } + + if (user == null) + { + throw new ArgumentNullException("user"); + } + + var sources = item.GetMediaSources(enablePathSubstitution).ToList(); + + foreach (var source in sources) + { + SetUserProperties(source, user); + } + + return sources; + } + + private void SetUserProperties(MediaSourceInfo source, User user) + { + var preferredAudio = string.IsNullOrEmpty(user.Configuration.AudioLanguagePreference) + ? new string[] { } + : new[] { user.Configuration.AudioLanguagePreference }; + + var preferredSubs = string.IsNullOrEmpty(user.Configuration.SubtitleLanguagePreference) + ? new List<string> { } + : new List<string> { user.Configuration.SubtitleLanguagePreference }; + + source.DefaultAudioStreamIndex = MediaStreamSelector.GetDefaultAudioStreamIndex(source.MediaStreams, preferredAudio, user.Configuration.PlayDefaultAudioTrack); + + var defaultAudioIndex = source.DefaultAudioStreamIndex; + var audioLangage = defaultAudioIndex == null + ? null + : source.MediaStreams.Where(i => i.Type == MediaStreamType.Audio && i.Index == defaultAudioIndex).Select(i => i.Language).FirstOrDefault(); + + source.DefaultSubtitleStreamIndex = MediaStreamSelector.GetDefaultSubtitleStreamIndex(source.MediaStreams, + preferredSubs, + user.Configuration.SubtitleMode, + audioLangage); + } + + private IEnumerable<MediaSourceInfo> SortMediaSources(IEnumerable<MediaSourceInfo> sources) + { + return sources.OrderBy(i => + { + if (i.VideoType.HasValue && i.VideoType.Value == VideoType.VideoFile) + { + return 0; + } + + return 1; + + }).ThenBy(i => i.Video3DFormat.HasValue ? 1 : 0) + .ThenByDescending(i => + { + var stream = i.VideoStream; + + return stream == null || stream.Width == null ? 0 : stream.Width.Value; + }) + .ToList(); + } + + public MediaSourceInfo GetStaticMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution) + { + return GetStaticMediaSources(item, enablePathSubstitution).FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase)); + } } } diff --git a/MediaBrowser.Server.Implementations/Library/MusicManager.cs b/MediaBrowser.Server.Implementations/Library/MusicManager.cs index 7733e7d37..3a854f2fe 100644 --- a/MediaBrowser.Server.Implementations/Library/MusicManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MusicManager.cs @@ -34,7 +34,7 @@ namespace MediaBrowser.Server.Implementations.Library var genres = user.RootFolder .GetRecursiveChildren(user, i => i is Audio) .Cast<Audio>() - .Where(i => i.HasArtist(name)) + .Where(i => i.HasAnyArtist(name)) .SelectMany(i => i.Genres) .Concat(artist.Genres) .Distinct(StringComparer.OrdinalIgnoreCase); diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index 95dcee98a..71daf2b0c 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -62,6 +62,11 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies return ResolveVideos<Video>(parent, files, directoryService, collectionType, false); } + if (string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase)) + { + return ResolveVideos<Video>(parent, files, directoryService, collectionType, false); + } + if (string.IsNullOrEmpty(collectionType)) { // Owned items should just use the plain video type @@ -225,6 +230,10 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies { item = ResolveVideo<Video>(args, false); } + else if (string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase)) + { + item = ResolveVideo<Video>(args, false); + } else if (string.IsNullOrEmpty(collectionType)) { if (args.HasParent<Series>()) @@ -358,6 +367,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies } var supportsMultiVersion = !string.Equals(collectionType, CollectionType.HomeVideos) && + !string.Equals(collectionType, CollectionType.Photos) && !string.Equals(collectionType, CollectionType.MusicVideos); var result = ResolveVideos<T>(parent, fileSystemEntries, directoryService, collectionType, supportsMultiVersion); @@ -474,7 +484,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies CollectionType.Movies, CollectionType.HomeVideos, CollectionType.MusicVideos, - CollectionType.Movies + CollectionType.Movies, + CollectionType.Photos }; return !validCollectionTypes.Contains(collectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase); diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs index 02960ea7e..b714e968b 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs @@ -30,7 +30,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers return null; } - protected static string[] ImageExtensions = { ".tiff", ".jpeg", ".jpg", ".png", ".aiff" }; + // Some common file name extensions for RAW picture files include: .cr2, .crw, .dng, .nef, .orf, .rw2, .pef, .arw, .sr2, .srf, and .tif. + protected static string[] ImageExtensions = { ".tiff", ".jpeg", ".jpg", ".png", ".aiff", ".cr2", ".crw", ".dng", ".nef", ".orf", ".pef", ".arw", ".webp" }; private static readonly string[] IgnoreFiles = { diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs index 7371ca5a9..3551b71b7 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs @@ -1,19 +1,18 @@ -using System.Collections.Generic; -using System.Linq; -using MediaBrowser.Common.IO; +using MediaBrowser.Common.IO; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Resolvers; using MediaBrowser.Model.Entities; -using System; -using System.IO; 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; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV { diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs index 59fecc857..b101f6ae1 100644 --- a/MediaBrowser.Server.Implementations/Library/UserManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs @@ -97,6 +97,7 @@ namespace MediaBrowser.Server.Implementations.Library /// </summary> public event EventHandler<GenericEventArgs<User>> UserUpdated; public event EventHandler<GenericEventArgs<User>> UserConfigurationUpdated; + public event EventHandler<GenericEventArgs<User>> UserLockedOut; /// <summary> /// Called when [user updated]. @@ -192,10 +193,10 @@ namespace MediaBrowser.Server.Implementations.Library public bool IsValidUsername(string username) { // Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.) - return username.All(IsValidCharacter); + return username.All(IsValidUsernameCharacter); } - private bool IsValidCharacter(char i) + private bool IsValidUsernameCharacter(char i) { return char.IsLetterOrDigit(i) || char.Equals(i, '-') || char.Equals(i, '_') || char.Equals(i, '\'') || char.Equals(i, '.'); @@ -213,7 +214,7 @@ namespace MediaBrowser.Server.Implementations.Library foreach (var c in username) { - if (IsValidCharacter(c)) + if (IsValidUsernameCharacter(c)) { builder.Append(c); } @@ -259,6 +260,11 @@ namespace MediaBrowser.Server.Implementations.Library { user.LastActivityDate = user.LastLoginDate = DateTime.UtcNow; await UpdateUser(user).ConfigureAwait(false); + await UpdateInvalidLoginAttemptCount(user, 0).ConfigureAwait(false); + } + else + { + await UpdateInvalidLoginAttemptCount(user, user.Policy.InvalidLoginAttemptCount + 1).ConfigureAwait(false); } _logger.Info("Authentication request for {0} {1}.", user.Name, (success ? "has succeeded" : "has been denied")); @@ -266,6 +272,38 @@ namespace MediaBrowser.Server.Implementations.Library return success; } + private async Task UpdateInvalidLoginAttemptCount(User user, int newValue) + { + if (user.Policy.InvalidLoginAttemptCount != newValue || newValue > 0) + { + user.Policy.InvalidLoginAttemptCount = newValue; + + var maxCount = user.Policy.IsAdministrator ? + 3 : + 5; + + var fireLockout = false; + + if (newValue >= maxCount) + { + //_logger.Debug("Disabling user {0} due to {1} unsuccessful login attempts.", user.Name, newValue.ToString(CultureInfo.InvariantCulture)); + //user.Policy.IsDisabled = true; + + //fireLockout = true; + } + + await UpdateUserPolicy(user, user.Policy, false).ConfigureAwait(false); + + if (fireLockout) + { + if (UserLockedOut != null) + { + EventHelper.FireEventIfNotNull(UserLockedOut, this, new GenericEventArgs<User>(user), _logger); + } + } + } + } + private string GetPasswordHash(User user) { return string.IsNullOrEmpty(user.Password) @@ -332,11 +370,6 @@ namespace MediaBrowser.Server.Implementations.Library { if (!user.Configuration.HasMigratedToPolicy) { - 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.IsAdministrator = user.Configuration.IsAdministrator; await UpdateUserPolicy(user, user.Policy, false); @@ -815,6 +848,12 @@ namespace MediaBrowser.Server.Implementations.Library foreach (var user in users) { await ResetPassword(user).ConfigureAwait(false); + + if (user.Policy.IsDisabled) + { + user.Policy.IsDisabled = false; + await UpdateUserPolicy(user, user.Policy, true).ConfigureAwait(false); + } usersReset.Add(user.Name); } } @@ -915,10 +954,6 @@ namespace MediaBrowser.Server.Implementations.Library } user.Configuration.IsAdministrator = user.Policy.IsAdministrator; - user.Configuration.EnableLiveTvManagement = user.Policy.EnableLiveTvManagement; - user.Configuration.EnableLiveTvAccess = user.Policy.EnableLiveTvAccess; - user.Configuration.EnableMediaPlayback = user.Policy.EnableMediaPlayback; - user.Configuration.EnableContentDeletion = user.Policy.EnableContentDeletion; await UpdateConfiguration(user, user.Configuration, true).ConfigureAwait(false); } diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs index a8ca1a2e0..e63a27551 100644 --- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs @@ -2,7 +2,6 @@ using MediaBrowser.Controller.Collections; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Localization; @@ -11,12 +10,12 @@ using MediaBrowser.Model.Channels; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Library; using MediaBrowser.Model.Querying; +using MoreLinq; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MoreLinq; namespace MediaBrowser.Server.Implementations.Library { @@ -53,8 +52,6 @@ namespace MediaBrowser.Server.Implementations.Library .OfType<Folder>() .ToList(); - var list = new List<Folder>(); - var excludeFolderIds = user.Configuration.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).ToList(); var standaloneFolders = folders @@ -66,46 +63,68 @@ namespace MediaBrowser.Server.Implementations.Library .OfType<ICollectionFolder>() .ToList(); - list.AddRange(standaloneFolders); + var list = new List<Folder>(); + + if (_config.Configuration.EnableUserSpecificUserViews) + { + foreach (var folder in standaloneFolders) + { + var collectionFolder = folder as ICollectionFolder; + var folderViewType = collectionFolder == null ? null : collectionFolder.CollectionType; + + if (string.IsNullOrWhiteSpace(folderViewType)) + { + list.Add(folder); + } + else + { + list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, string.Empty, user, cancellationToken).ConfigureAwait(false)); + } + } + } + else + { + list.AddRange(standaloneFolders); + } if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase)) || foldersWithViewTypes.Any(i => string.IsNullOrWhiteSpace(i.CollectionType))) { - list.Add(await GetUserView(CollectionType.TvShows, string.Empty, cancellationToken).ConfigureAwait(false)); + list.Add(await GetUserView(CollectionType.TvShows, string.Empty, user, cancellationToken).ConfigureAwait(false)); } if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase)) || foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))) { - list.Add(await GetUserView(CollectionType.Music, string.Empty, cancellationToken).ConfigureAwait(false)); + list.Add(await GetUserView(CollectionType.Music, string.Empty, user, cancellationToken).ConfigureAwait(false)); } if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase)) || foldersWithViewTypes.Any(i => string.IsNullOrWhiteSpace(i.CollectionType))) { - list.Add(await GetUserView(CollectionType.Movies, string.Empty, cancellationToken).ConfigureAwait(false)); + list.Add(await GetUserView(CollectionType.Movies, string.Empty, user, cancellationToken).ConfigureAwait(false)); } - if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Games, StringComparison.OrdinalIgnoreCase)) - || _config.Configuration.EnableLegacyCollectionInView) + if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Games, StringComparison.OrdinalIgnoreCase))) { - list.Add(await GetUserView(CollectionType.Games, string.Empty, cancellationToken).ConfigureAwait(false)); + list.Add(await GetUserView(CollectionType.Games, string.Empty, user, cancellationToken).ConfigureAwait(false)); } 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)); + list.Add(await GetUserView(CollectionType.BoxSets, string.Empty, user, cancellationToken).ConfigureAwait(false)); } if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))) { - list.Add(_playlists.GetPlaylistsFolder(user.Id.ToString("N"))); + //list.Add(_playlists.GetPlaylistsFolder(user.Id.ToString("N"))); + list.Add(await GetUserView(CollectionType.Playlists, string.Empty, user, cancellationToken).ConfigureAwait(false)); } if (user.Configuration.DisplayFoldersView) { - list.Add(await GetUserView(CollectionType.Folders, "zz_" + CollectionType.Folders, cancellationToken).ConfigureAwait(false)); + list.Add(await GetUserView(CollectionType.Folders, "zz_" + CollectionType.Folders, user, cancellationToken).ConfigureAwait(false)); } if (query.IncludeExternalContent) @@ -131,7 +150,8 @@ namespace MediaBrowser.Server.Implementations.Library if (_liveTvManager.GetEnabledUsers().Select(i => i.Id.ToString("N")).Contains(query.UserId)) { - list.Add(await _liveTvManager.GetInternalLiveTvFolder(query.UserId, cancellationToken).ConfigureAwait(false)); + //list.Add(await _liveTvManager.GetInternalLiveTvFolder(query.UserId, cancellationToken).ConfigureAwait(false)); + list.Add(await GetUserView(CollectionType.LiveTv, string.Empty, user, cancellationToken).ConfigureAwait(false)); } } @@ -150,23 +170,28 @@ namespace MediaBrowser.Server.Implementations.Library .ThenBy(i => i.SortName); } - public Task<UserView> GetUserView(string name, string parentId, string type, User user, string sortName, CancellationToken cancellationToken) + public Task<UserView> GetUserSubView(string name, string parentId, string type, User user, string sortName, CancellationToken cancellationToken) { - return _libraryManager.GetSpecialFolder(user, name, parentId, type, sortName, cancellationToken); + return _libraryManager.GetNamedView(user, name, parentId, type, sortName, cancellationToken); } - public Task<UserView> GetUserView(string parentId, string type, User user, string sortName, CancellationToken cancellationToken) + public Task<UserView> GetUserSubView(string parentId, string type, User user, string sortName, CancellationToken cancellationToken) { var name = _localizationManager.GetLocalizedString("ViewType" + type); - return GetUserView(name, parentId, type, user, sortName, cancellationToken); + return GetUserSubView(name, parentId, type, user, sortName, cancellationToken); } - public Task<UserView> GetUserView(string type, string sortName, CancellationToken cancellationToken) + public Task<UserView> GetUserView(string type, string sortName, User user, CancellationToken cancellationToken) { var name = _localizationManager.GetLocalizedString("ViewType" + type); - return _libraryManager.GetNamedView(name, type, sortName, cancellationToken); + return _libraryManager.GetNamedView(user, name, type, sortName, cancellationToken); + } + + public Task<UserView> GetUserView(Guid parentId, string name, string type, string sortName, User user, CancellationToken cancellationToken) + { + return _libraryManager.GetNamedView(user, name, parentId.ToString("N"), type, sortName, cancellationToken); } public List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request) |
