diff options
| author | Luke <luke.pulverenti@gmail.com> | 2015-04-15 23:29:34 -0400 |
|---|---|---|
| committer | Luke <luke.pulverenti@gmail.com> | 2015-04-15 23:29:34 -0400 |
| commit | 73688e3fcc2dea07bd11ff842276906942407c45 (patch) | |
| tree | 8425c2f5d6e6b3a3bfbdf7c8b1c9e6c2d8bd2983 /MediaBrowser.Server.Implementations | |
| parent | 9b451f9095c61858347072e1651fcd9c327fc59d (diff) | |
| parent | c7b95a251317fdb01d160cc3dcaf5d23779437d4 (diff) | |
Merge pull request #1082 from MediaBrowser/dev
3.0.5582.2
Diffstat (limited to 'MediaBrowser.Server.Implementations')
7 files changed, 178 insertions, 85 deletions
diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index c4501564f..190b8fcf4 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -357,7 +357,10 @@ namespace MediaBrowser.Server.Implementations.Dto : item.CanDownload(user); } - + if (fields.Contains(ItemFields.Etag)) + { + dto.Etag = item.GetEtag(user); + } return dto; } diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 02c16d0d4..8285fb7e5 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1678,11 +1678,6 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentNullException("name"); } - if (string.IsNullOrWhiteSpace(viewType)) - { - throw new ArgumentNullException("viewType"); - } - var id = GetNewItemId("37_namedview_" + name + user.Id.ToString("N") + (parentId ?? string.Empty), typeof(UserView)); var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N")); @@ -1716,6 +1711,12 @@ namespace MediaBrowser.Server.Implementations.Library isNew = true; } + if (!string.Equals(viewType, item.ViewType, StringComparison.OrdinalIgnoreCase)) + { + item.ViewType = viewType; + await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false); + } + var refresh = isNew || (DateTime.UtcNow - item.DateLastSaved).TotalHours >= 12; if (refresh) diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs index 757f08562..d5d0af74c 100644 --- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs @@ -53,6 +53,7 @@ namespace MediaBrowser.Server.Implementations.Library .ToList(); var excludeFolderIds = user.Configuration.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).ToList(); + var plainFolderIds = user.Configuration.PlainFolderViews.Select(i => new Guid(i)).ToList(); var standaloneFolders = folders .Where(i => UserView.IsExcludedFromGrouping(i) || excludeFolderIds.Contains(i.Id)) @@ -72,13 +73,17 @@ namespace MediaBrowser.Server.Implementations.Library var collectionFolder = folder as ICollectionFolder; var folderViewType = collectionFolder == null ? null : collectionFolder.CollectionType; - if (string.IsNullOrWhiteSpace(folderViewType)) + if (plainFolderIds.Contains(folder.Id)) { - list.Add(folder); + list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, false, string.Empty, user, cancellationToken).ConfigureAwait(false)); + } + else if (!string.IsNullOrWhiteSpace(folderViewType)) + { + list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, true, string.Empty, user, cancellationToken).ConfigureAwait(false)); } else { - list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, string.Empty, user, cancellationToken).ConfigureAwait(false)); + list.Add(folder); } } } @@ -87,44 +92,57 @@ namespace MediaBrowser.Server.Implementations.Library list.AddRange(standaloneFolders); } - if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase)) || - foldersWithViewTypes.Any(i => string.IsNullOrWhiteSpace(i.CollectionType))) + var parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.CollectionType)) + .ToList(); + + if (parents.Count > 0) { - list.Add(await GetUserView(CollectionType.TvShows, string.Empty, user, cancellationToken).ConfigureAwait(false)); + list.Add(await GetUserView(parents, 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))) + parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase) || string.Equals(i.CollectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.CollectionType)) + .ToList(); + + if (parents.Count > 0) { - list.Add(await GetUserView(CollectionType.Music, string.Empty, user, cancellationToken).ConfigureAwait(false)); + list.Add(await GetUserView(parents, 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))) + parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.CollectionType)) + .ToList(); + + if (parents.Count > 0) { - list.Add(await GetUserView(CollectionType.Movies, string.Empty, user, cancellationToken).ConfigureAwait(false)); + list.Add(await GetUserView(parents, CollectionType.Movies, string.Empty, user, cancellationToken).ConfigureAwait(false)); } - if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Games, StringComparison.OrdinalIgnoreCase))) + parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.Games, StringComparison.OrdinalIgnoreCase)) + .ToList(); + + if (parents.Count > 0) { - list.Add(await GetUserView(CollectionType.Games, string.Empty, user, cancellationToken).ConfigureAwait(false)); + list.Add(await GetUserView(parents, CollectionType.Games, string.Empty, user, cancellationToken).ConfigureAwait(false)); } - if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase))) + parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase)) + .ToList(); + + if (parents.Count > 0) { - //list.Add(_collectionManager.GetCollectionsFolder(user.Id.ToString("N"))); - list.Add(await GetUserView(CollectionType.BoxSets, string.Empty, user, cancellationToken).ConfigureAwait(false)); + list.Add(await GetUserView(parents, CollectionType.BoxSets, string.Empty, user, cancellationToken).ConfigureAwait(false)); } - if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))) + parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase)) + .ToList(); + + if (parents.Count > 0) { - //list.Add(_playlists.GetPlaylistsFolder(user.Id.ToString("N"))); - list.Add(await GetUserView(CollectionType.Playlists, string.Empty, user, cancellationToken).ConfigureAwait(false)); + list.Add(await GetUserView(parents, CollectionType.Playlists, string.Empty, user, cancellationToken).ConfigureAwait(false)); } if (user.Configuration.DisplayFoldersView) { - list.Add(await GetUserView(CollectionType.Folders, "zz_" + CollectionType.Folders, user, cancellationToken).ConfigureAwait(false)); + list.Add(await GetUserView(new List<ICollectionFolder>(), CollectionType.Folders, "zz_" + CollectionType.Folders, user, cancellationToken).ConfigureAwait(false)); } if (query.IncludeExternalContent) @@ -151,7 +169,7 @@ 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 GetUserView(CollectionType.LiveTv, string.Empty, user, cancellationToken).ConfigureAwait(false)); + list.Add(await GetUserView(new List<ICollectionFolder>(), CollectionType.LiveTv, string.Empty, user, cancellationToken).ConfigureAwait(false)); } } @@ -182,16 +200,42 @@ namespace MediaBrowser.Server.Implementations.Library return GetUserSubView(name, parentId, type, user, sortName, cancellationToken); } - public Task<UserView> GetUserView(string type, string sortName, User user, CancellationToken cancellationToken) + public async Task<UserView> GetUserView(List<ICollectionFolder> parents, string viewType, string sortName, User user, CancellationToken cancellationToken) { - var name = _localizationManager.GetLocalizedString("ViewType" + type); + if (parents.Count == 1 && parents.All(i => string.Equals(i.CollectionType, viewType, StringComparison.OrdinalIgnoreCase))) + { + var name = parents[0].Name; + var parentId = parents[0].Id; - return _libraryManager.GetNamedView(user, name, type, sortName, cancellationToken); + var enableRichView = !user.Configuration.PlainFolderViews.Contains(parentId.ToString("N"), StringComparer.OrdinalIgnoreCase); + + if (_config.Configuration.EnableUserSpecificUserViews) + { + viewType = enableRichView ? viewType : null; + var view = await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false); + + if (view.ParentId != parentId) + { + view.ParentId = parentId; + await view.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false); + } + return view; + } + + viewType = enableRichView ? viewType : CollectionType.Folders; + return await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false); + } + else + { + var name = _localizationManager.GetLocalizedString("ViewType" + viewType); + + return await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false); + } } - public Task<UserView> GetUserView(Guid parentId, string name, string type, string sortName, User user, CancellationToken cancellationToken) + public Task<UserView> GetUserView(Guid parentId, string name, string viewType, bool enableRichView, string sortName, User user, CancellationToken cancellationToken) { - return _libraryManager.GetNamedView(user, name, parentId.ToString("N"), type, sortName, cancellationToken); + return _libraryManager.GetNamedView(user, name, parentId.ToString("N"), viewType, sortName, cancellationToken); } public List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request) @@ -317,7 +361,7 @@ namespace MediaBrowser.Server.Implementations.Library .RootFolder .GetRecursiveChildren(filter); } - + private IEnumerable<BaseItem> GetItemsConfiguredForLatest(User user, Func<BaseItem, bool> filter) { // Avoid implicitly captured closure diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index d704277c1..5791da1ea 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -54,11 +54,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv new ConcurrentDictionary<string, LiveStreamData>(); private List<Guid> _channelIdList = new List<Guid>(); - private Dictionary<Guid, LiveTvProgram> _programs = new Dictionary<Guid, LiveTvProgram>(); + private Dictionary<Guid, LiveTvProgram> _programs; private readonly ConcurrentDictionary<Guid, bool> _refreshedPrograms = new ConcurrentDictionary<Guid, bool>(); - private readonly SemaphoreSlim _refreshSemaphore = new SemaphoreSlim(1, 1); - public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager) { _config = config; @@ -109,6 +107,37 @@ namespace MediaBrowser.Server.Implementations.LiveTv _taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>(); } + private readonly object _programsDataLock = new object(); + private Dictionary<Guid, LiveTvProgram> GetProgramsDictionary() + { + if (_programs == null) + { + lock (_programsDataLock) + { + if (_programs == null) + { + var dict = new Dictionary<Guid, LiveTvProgram>(); + + foreach (var item in _itemRepo.GetItemsOfType(typeof (LiveTvProgram)) + .Cast<LiveTvProgram>() + .ToList()) + { + dict[item.Id] = item; + } + + _programs = dict; + } + } + } + + return _programs; + } + + private IEnumerable<LiveTvProgram> GetPrograms() + { + return GetProgramsDictionary().Values; + } + public async Task<QueryResult<LiveTvChannel>> GetInternalChannels(LiveTvChannelQuery query, CancellationToken cancellationToken) { var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId); @@ -260,7 +289,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv LiveTvProgram obj = null; - _programs.TryGetValue(guid, out obj); + GetProgramsDictionary().TryGetValue(guid, out obj); if (obj != null) { @@ -597,7 +626,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv item.ProductionYear = info.ProductionYear; item.PremiereDate = item.PremiereDate ?? info.OriginalAirDate; - + await item.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); return item; @@ -691,7 +720,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv public async Task<QueryResult<ProgramInfoDto>> GetPrograms(ProgramQuery query, CancellationToken cancellationToken) { - IEnumerable<LiveTvProgram> programs = _programs.Values; + IEnumerable<LiveTvProgram> programs = GetPrograms(); if (query.MinEndDate.HasValue) { @@ -806,7 +835,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv public async Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, CancellationToken cancellationToken) { - IEnumerable<LiveTvProgram> programs = _programs.Values; + IEnumerable<LiveTvProgram> programs = GetPrograms(); var user = _userManager.GetUserById(query.UserId); @@ -995,24 +1024,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv internal async Task RefreshChannels(IProgress<double> progress, CancellationToken cancellationToken) { - await _refreshSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - - try - { - var innerProgress = new ActionableProgress<double>(); - innerProgress.RegisterAction(p => progress.Report(p * .9)); - await RefreshChannelsInternal(innerProgress, cancellationToken).ConfigureAwait(false); + var innerProgress = new ActionableProgress<double>(); + innerProgress.RegisterAction(p => progress.Report(p * .9)); + await RefreshChannelsInternal(innerProgress, cancellationToken).ConfigureAwait(false); - innerProgress = new ActionableProgress<double>(); - innerProgress.RegisterAction(p => progress.Report(90 + (p * .1))); - await CleanDatabaseInternal(progress, cancellationToken).ConfigureAwait(false); + innerProgress = new ActionableProgress<double>(); + innerProgress.RegisterAction(p => progress.Report(90 + (p * .1))); + await CleanDatabaseInternal(progress, cancellationToken).ConfigureAwait(false); - RefreshIfNeeded(_programs.Values.Where(i => (i.StartDate - DateTime.UtcNow).TotalDays <= 1).ToList()); - } - finally - { - _refreshSemaphore.Release(); - } + RefreshIfNeeded(GetPrograms().Where(i => (i.StartDate - DateTime.UtcNow).TotalDays <= 1).ToList()); } private async Task RefreshChannelsInternal(IProgress<double> progress, CancellationToken cancellationToken) @@ -1136,7 +1156,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv progress.Report(80 * percent + 10); } - _programs = programs.ToDictionary(i => i.Id); + lock (_programsDataLock) + { + _programs = programs.ToDictionary(i => i.Id); + } + _refreshedPrograms.Clear(); progress.Report(90); @@ -1147,28 +1171,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv progress.Report(100); } - public async Task CleanDatabase(IProgress<double> progress, CancellationToken cancellationToken) - { - await _refreshSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - - try - { - await DeleteOldPrograms(_programs.Keys.ToList(), progress, cancellationToken).ConfigureAwait(false); - } - finally - { - _refreshSemaphore.Release(); - } - } - private Task CleanDatabaseInternal(IProgress<double> progress, CancellationToken cancellationToken) { - return DeleteOldPrograms(_programs.Keys.ToList(), progress, cancellationToken); + return DeleteOldPrograms(GetProgramsDictionary().Keys.ToList(), progress, cancellationToken); } private async Task DeleteOldPrograms(List<Guid> currentIdList, IProgress<double> progress, CancellationToken cancellationToken) { - var list = _itemRepo.GetItemsOfType(typeof(LiveTvProgram)).ToList(); + var list = _itemRepo.GetItemIdsOfType(typeof(LiveTvProgram)).ToList(); var numComplete = 0; @@ -1549,7 +1559,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv { var now = DateTime.UtcNow; - var program = _programs.Values + var program = GetPrograms() .Where(i => string.Equals(externalChannelId, i.ExternalChannelId, StringComparison.OrdinalIgnoreCase)) .OrderBy(i => i.StartDate) .SkipWhile(i => now >= (i.EndDate ?? DateTime.MinValue)) @@ -1742,7 +1752,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv { var dtoOptions = new DtoOptions(); dtoOptions.Fields.Remove(ItemFields.SyncInfo); - + var recordingResult = await GetRecordings(new RecordingQuery { UserId = query.UserId @@ -1855,13 +1865,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv public GuideInfo GetGuideInfo() { - var programs = _programs.ToList(); + var programs = GetPrograms().OrderBy(i => i.StartDate).ToList(); - var startDate = _programs.Count == 0 ? DateTime.MinValue : - programs.Select(i => i.Value.StartDate).Min(); + var startDate = programs.Count == 0 ? + DateTime.MinValue : + programs[0].StartDate; - var endDate = programs.Count == 0 ? DateTime.MinValue : - programs.Select(i => i.Value.StartDate).Max(); + var endDate = programs.Count == 0 ? + DateTime.MinValue : + programs[programs.Count - 1].StartDate; return new GuideInfo { diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index bfd23243a..1affc43bf 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1430,5 +1430,8 @@ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.", "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.", "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?", - "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences." + "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.", + "HeaderViewStyles": "View Styles", + "LabelSelectViewStyles": "Enable rich presentations for:", + "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders." } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 12ce60d45..61432d00f 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -522,7 +522,7 @@ namespace MediaBrowser.Server.Implementations.Persistence } } - public IEnumerable<Guid> GetItemsOfType(Type type) + public IEnumerable<BaseItem> GetItemsOfType(Type type) { if (type == null) { @@ -530,7 +530,37 @@ namespace MediaBrowser.Server.Implementations.Persistence } CheckDisposed(); - + + using (var cmd = _connection.CreateCommand()) + { + cmd.CommandText = "select type,data from TypedBaseItems where type = @type"; + + cmd.Parameters.Add(cmd, "@type", DbType.String).Value = type.FullName; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) + { + var item = GetItem(reader); + + if (item != null) + { + yield return item; + } + } + } + } + } + + public IEnumerable<Guid> GetItemIdsOfType(Type type) + { + if (type == null) + { + throw new ArgumentNullException("type"); + } + + CheckDisposed(); + using (var cmd = _connection.CreateCommand()) { cmd.CommandText = "select guid from TypedBaseItems where type = @type"; diff --git a/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs b/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs index 90135acfe..992f1d16c 100644 --- a/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs +++ b/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs @@ -205,7 +205,7 @@ namespace MediaBrowser.Server.Implementations.Sync { Condition = ProfileConditionType.LessThanEqual, Property = ProfileConditionValue.AudioChannels, - Value = "5", + Value = "6", IsRequired = false }, new ProfileCondition |
