diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-06-15 19:30:04 -0400 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-06-15 19:30:04 -0400 |
| commit | 9e57e16aa9b8f0e639a106c83a2bed2756d8783c (patch) | |
| tree | 413ab13730350ee682c4fcc62cecec60a81f5fbc /MediaBrowser.Server.Implementations | |
| parent | 918034d803a6aa584a4a1a5a9a7027056d71a590 (diff) | |
fixes #839 - Support getting latest channel items
Diffstat (limited to 'MediaBrowser.Server.Implementations')
4 files changed, 239 insertions, 48 deletions
diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs b/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs index b689f153cf..fdc5cfd227 100644 --- a/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; +using MediaBrowser.Common.Progress; using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Configuration; @@ -9,6 +10,7 @@ using MediaBrowser.Model.Channels; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Querying; using System; using System.Collections.Generic; using System.IO; @@ -26,8 +28,9 @@ namespace MediaBrowser.Server.Implementations.Channels private readonly IHttpClient _httpClient; private readonly IFileSystem _fileSystem; private readonly ILibraryManager _libraryManager; + private readonly IUserManager _userManager; - public ChannelDownloadScheduledTask(IChannelManager manager, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient, IFileSystem fileSystem, ILibraryManager libraryManager) + public ChannelDownloadScheduledTask(IChannelManager manager, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient, IFileSystem fileSystem, ILibraryManager libraryManager, IUserManager userManager) { _manager = manager; _config = config; @@ -35,6 +38,7 @@ namespace MediaBrowser.Server.Implementations.Channels _httpClient = httpClient; _fileSystem = fileSystem; _libraryManager = libraryManager; + _userManager = userManager; } public string Name @@ -55,70 +59,118 @@ namespace MediaBrowser.Server.Implementations.Channels public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress) { CleanChannelContent(cancellationToken); - progress.Report(5); - await DownloadChannelContent(cancellationToken, progress).ConfigureAwait(false); + var users = _userManager.Users.Select(i => i.Id.ToString("N")).ToList(); + + var numComplete = 0; + + foreach (var user in users) + { + double percentPerUser = 1; + percentPerUser /= users.Count; + var startingPercent = numComplete * percentPerUser * 100; + + var innerProgress = new ActionableProgress<double>(); + innerProgress.RegisterAction(p => progress.Report(startingPercent + (.8 * p))); + + await DownloadContent(user, cancellationToken, innerProgress).ConfigureAwait(false); + + numComplete++; + double percent = numComplete; + percent /= users.Count; + progress.Report(percent * 100); + } + progress.Report(100); } - private void CleanChannelContent(CancellationToken cancellationToken) + private async Task DownloadContent(string user, + CancellationToken cancellationToken, + IProgress<double> progress) { - if (!_config.Configuration.ChannelOptions.MaxDownloadAge.HasValue) + var innerProgress = new ActionableProgress<double>(); + innerProgress.RegisterAction(p => progress.Report(0 + (.8 * p))); + await DownloadAllChannelContent(user, cancellationToken, innerProgress).ConfigureAwait(false); + progress.Report(80); + + innerProgress = new ActionableProgress<double>(); + innerProgress.RegisterAction(p => progress.Report(80 + (.2 * p))); + await DownloadLatestChannelContent(user, cancellationToken, progress).ConfigureAwait(false); + progress.Report(100); + } + + private async Task DownloadLatestChannelContent(string userId, + CancellationToken cancellationToken, + IProgress<double> progress) + { + var result = await _manager.GetLatestChannelItems(new AllChannelMediaQuery { - return; - } + UserId = userId - var minDateModified = DateTime.UtcNow.AddDays(0 - _config.Configuration.ChannelOptions.MaxDownloadAge.Value); + }, cancellationToken).ConfigureAwait(false); + + progress.Report(5); + + var innerProgress = new ActionableProgress<double>(); + innerProgress.RegisterAction(p => progress.Report(5 + (.95 * p))); var path = _manager.ChannelDownloadPath; - try - { - DeleteCacheFilesFromDirectory(cancellationToken, path, minDateModified, new Progress<double>()); - } - catch (DirectoryNotFoundException) - { - // No biggie here. Nothing to delete - } + await DownloadChannelContent(result, path, cancellationToken, innerProgress).ConfigureAwait(false); } - private async Task DownloadChannelContent(CancellationToken cancellationToken, IProgress<double> progress) + private async Task DownloadAllChannelContent(string userId, + CancellationToken cancellationToken, + IProgress<double> progress) { - if (_config.Configuration.ChannelOptions.DownloadingChannels.Length == 0) - { - return; - } - var result = await _manager.GetAllMedia(new AllChannelMediaQuery { - ChannelIds = _config.Configuration.ChannelOptions.DownloadingChannels + UserId = userId }, cancellationToken).ConfigureAwait(false); + progress.Report(5); + + var innerProgress = new ActionableProgress<double>(); + innerProgress.RegisterAction(p => progress.Report(5 + (.95 * p))); + var path = _manager.ChannelDownloadPath; + await DownloadChannelContent(result, path, cancellationToken, innerProgress).ConfigureAwait(false); + } + + private async Task DownloadChannelContent(QueryResult<BaseItemDto> result, + string path, + CancellationToken cancellationToken, + IProgress<double> progress) + { var numComplete = 0; foreach (var item in result.Items) { - try - { - await DownloadChannelItem(item, cancellationToken, path); - } - catch (OperationCanceledException) + if (_config.Configuration.ChannelOptions.DownloadingChannels.Contains(item.ChannelId)) { - break; - } - catch (Exception ex) - { - _logger.ErrorException("Error downloading channel content for {0}", ex, item.Name); + try + { + await DownloadChannelItem(item, cancellationToken, path); + } + catch (OperationCanceledException) + { + break; + } + catch (Exception ex) + { + _logger.ErrorException("Error downloading channel content for {0}", ex, item.Name); + } } numComplete++; double percent = numComplete; percent /= result.Items.Length; - progress.Report(percent * 95 + 5); + progress.Report(percent * 100); } + + progress.Report(100); } private async Task DownloadChannelItem(BaseItemDto item, @@ -212,6 +264,27 @@ namespace MediaBrowser.Server.Implementations.Channels }; } + private void CleanChannelContent(CancellationToken cancellationToken) + { + if (!_config.Configuration.ChannelOptions.MaxDownloadAge.HasValue) + { + return; + } + + var minDateModified = DateTime.UtcNow.AddDays(0 - _config.Configuration.ChannelOptions.MaxDownloadAge.Value); + + var path = _manager.ChannelDownloadPath; + + try + { + DeleteCacheFilesFromDirectory(cancellationToken, path, minDateModified, new Progress<double>()); + } + catch (DirectoryNotFoundException) + { + // No biggie here. Nothing to delete + } + } + /// <summary> /// Deletes the cache files from directory with a last write time less than a given date /// </summary> @@ -260,15 +333,22 @@ namespace MediaBrowser.Server.Implementations.Channels } } + /// <summary> + /// Gets a value indicating whether this instance is hidden. + /// </summary> + /// <value><c>true</c> if this instance is hidden; otherwise, <c>false</c>.</value> public bool IsHidden { get { - return !_manager.GetAllChannelFeatures() - .Any(i => i.CanDownloadAllMedia && _config.Configuration.ChannelOptions.DownloadingChannels.Contains(i.Id)); + return !_manager.GetAllChannelFeatures().Any(); } } + /// <summary> + /// Gets a value indicating whether this instance is enabled. + /// </summary> + /// <value><c>true</c> if this instance is enabled; otherwise, <c>false</c>.</value> public bool IsEnabled { get diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs index 553c683fd0..ad775b5764 100644 --- a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs +++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs @@ -53,6 +53,14 @@ namespace MediaBrowser.Server.Implementations.Channels _localization = localization; } + private TimeSpan CacheLength + { + get + { + return TimeSpan.FromDays(1); + } + } + public void AddParts(IEnumerable<IChannel> channels, IEnumerable<IChannelFactory> factories) { _channels = channels.ToArray(); @@ -443,6 +451,7 @@ namespace MediaBrowser.Server.Implementations.Channels InternalChannelFeatures features) { var isIndexable = provider is IIndexableChannel; + var supportsLatest = provider is ISupportsLatestMedia; return new ChannelFeatures { @@ -453,10 +462,10 @@ namespace MediaBrowser.Server.Implementations.Channels MaxPageSize = features.MaxPageSize, MediaTypes = features.MediaTypes, SupportsSortOrderToggle = features.SupportsSortOrderToggle, - SupportsLatestMedia = provider is ISupportsLatestMedia, + SupportsLatestMedia = supportsLatest, Name = channel.Name, Id = channel.Id.ToString("N"), - CanDownloadAllMedia = isIndexable + SupportsContentDownloading = isIndexable || supportsLatest }; } @@ -470,6 +479,105 @@ namespace MediaBrowser.Server.Implementations.Channels return ("Channel " + name).GetMBId(typeof(Channel)); } + public async Task<QueryResult<BaseItemDto>> GetLatestChannelItems(AllChannelMediaQuery query, CancellationToken cancellationToken) + { + var user = string.IsNullOrWhiteSpace(query.UserId) + ? null + : _userManager.GetUserById(new Guid(query.UserId)); + + var channels = _channels; + + if (query.ChannelIds.Length > 0) + { + // Avoid implicitly captured closure + var ids = query.ChannelIds; + channels = channels + .Where(i => ids.Contains(GetInternalChannelId(i.Name).ToString("N"))) + .ToArray(); + } + + // Avoid implicitly captured closure + var userId = query.UserId; + + var tasks = channels + .Select(async i => + { + var indexable = i as ISupportsLatestMedia; + + if (indexable != null) + { + try + { + var result = await indexable.GetLatestMedia(new ChannelLatestMediaSearch + { + UserId = userId + + }, cancellationToken).ConfigureAwait(false); + + var resultItems = result.ToList(); + + return new Tuple<IChannel, ChannelItemResult>(i, new ChannelItemResult + { + Items = resultItems, + TotalRecordCount = resultItems.Count + }); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting all media from {0}", ex, i.Name); + } + } + return new Tuple<IChannel, ChannelItemResult>(i, new ChannelItemResult { }); + }); + + var results = await Task.WhenAll(tasks).ConfigureAwait(false); + + var totalCount = results.Length; + + IEnumerable<Tuple<IChannel, ChannelItemInfo>> items = results + .SelectMany(i => i.Item2.Items.Select(m => new Tuple<IChannel, ChannelItemInfo>(i.Item1, m))) + .OrderBy(i => i.Item2.Name); + + if (query.ContentTypes.Length > 0) + { + // Avoid implicitly captured closure + var contentTypes = query.ContentTypes; + + items = items.Where(i => contentTypes.Contains(i.Item2.ContentType)); + } + + // Avoid implicitly captured closure + var token = cancellationToken; + var itemTasks = items.Select(i => + { + var channelProvider = i.Item1; + var channel = GetChannel(GetInternalChannelId(channelProvider.Name).ToString("N")); + return GetChannelItemEntity(i.Item2, channelProvider, channel, token); + }); + + IEnumerable<BaseItem> internalItems = await Task.WhenAll(itemTasks).ConfigureAwait(false); + + internalItems = ApplyFilters(internalItems, query.Filters, user); + + if (query.StartIndex.HasValue) + { + internalItems = internalItems.Skip(query.StartIndex.Value); + } + if (query.Limit.HasValue) + { + internalItems = internalItems.Take(query.Limit.Value); + } + + var returnItemArray = internalItems.Select(i => _dtoService.GetBaseItemDto(i, query.Fields, user)) + .ToArray(); + + return new QueryResult<BaseItemDto> + { + TotalRecordCount = totalCount, + Items = returnItemArray + }; + } + public async Task<QueryResult<BaseItemDto>> GetAllMedia(AllChannelMediaQuery query, CancellationToken cancellationToken) { var user = string.IsNullOrWhiteSpace(query.UserId) @@ -480,11 +588,16 @@ namespace MediaBrowser.Server.Implementations.Channels if (query.ChannelIds.Length > 0) { + // Avoid implicitly captured closure + var ids = query.ChannelIds; channels = channels - .Where(i => query.ChannelIds.Contains(GetInternalChannelId(i.Name).ToString("N"))) + .Where(i => ids.Contains(GetInternalChannelId(i.Name).ToString("N"))) .ToArray(); } + // Avoid implicitly captured closure + var userId = query.UserId; + var tasks = channels .Select(async i => { @@ -496,7 +609,7 @@ namespace MediaBrowser.Server.Implementations.Channels { var result = await indexable.GetAllMedia(new InternalAllChannelMediaQuery { - UserId = query.UserId + UserId = userId }, cancellationToken).ConfigureAwait(false); @@ -546,12 +659,7 @@ namespace MediaBrowser.Server.Implementations.Channels var internalItems = await Task.WhenAll(itemTasks).ConfigureAwait(false); - // Get everything - var fields = Enum.GetNames(typeof(ItemFields)) - .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)) - .ToList(); - - var returnItemArray = internalItems.Select(i => _dtoService.GetBaseItemDto(i, fields, user)) + var returnItemArray = internalItems.Select(i => _dtoService.GetBaseItemDto(i, query.Fields, user)) .ToArray(); return new QueryResult<BaseItemDto> @@ -641,7 +749,7 @@ namespace MediaBrowser.Server.Implementations.Channels { var userId = user.Id.ToString("N"); - var cacheLength = TimeSpan.FromDays(1); + var cacheLength = CacheLength; var cachePath = GetChannelDataCachePath(channel, userId, folderId, sortField, sortDescending); try diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json index 74c1791bab..d4c31a61e3 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json @@ -147,5 +147,6 @@ "ButtonRemove": "Remove", "LabelChapterDownloaders": "Chapter downloaders:", "LabelChapterDownloadersHelp": "Enable and rank your preferred chapter downloaders in order of priority. Lower priority downloaders will only be used to fill in missing information.", - "HeaderFavoriteAlbums": "Favorite Albums" + "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderLatestChannelMedia": "Latest Channel Items" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 5626238c14..af6a312e0a 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -785,11 +785,13 @@ "LabelHomePageSection1": "Home page section one:", "LabelHomePageSection2": "Home page section two:", "LabelHomePageSection3": "Home page section three:", + "LabelHomePageSection4": "Home page section four:", "OptionMyLibraryButtons": "My library (buttons)", "OptionMyLibrary": "My library", "OptionMyLibrarySmall": "My library (small)", "OptionResumablemedia": "Resume", "OptionLatestMedia": "Latest media", + "OptionLatestChannelMedia": "Latest channel items", "OptionNone": "None", "HeaderLiveTv": "Live TV", "HeaderReports": "Reports", |
