mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-09 03:04:24 -04:00
fixes #839 - Support getting latest channel items
This commit is contained in:
parent
918034d803
commit
9e57e16aa9
@ -107,6 +107,53 @@ namespace MediaBrowser.Api
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Route("/Channels/Items/Latest", "GET", Summary = "Gets channel items")]
|
||||||
|
public class GetLatestChannelItems : IReturn<QueryResult<BaseItemDto>>, IHasItemFields
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the user id.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The user id.</value>
|
||||||
|
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||||
|
public string UserId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Skips over a given number of items within the results. Use for paging.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The start index.</value>
|
||||||
|
[ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||||
|
public int? StartIndex { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum number of items to return
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The limit.</value>
|
||||||
|
[ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||||
|
public int? Limit { get; set; }
|
||||||
|
|
||||||
|
[ApiMember(Name = "Filters", Description = "Optional. Specify additional filters to apply. This allows multiple, comma delimeted. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsResumable, Likes, Dislikes", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||||
|
public string Filters { get; set; }
|
||||||
|
|
||||||
|
[ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||||
|
public string Fields { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the filters.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>IEnumerable{ItemFilter}.</returns>
|
||||||
|
public IEnumerable<ItemFilter> GetFilters()
|
||||||
|
{
|
||||||
|
var val = Filters;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(val))
|
||||||
|
{
|
||||||
|
return new ItemFilter[] { };
|
||||||
|
}
|
||||||
|
|
||||||
|
return val.Split(',').Select(v => (ItemFilter)Enum.Parse(typeof(ItemFilter), v, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Route("/Channels/Folder", "GET", Summary = "Gets the users channel folder, along with configured images")]
|
[Route("/Channels/Folder", "GET", Summary = "Gets the users channel folder, along with configured images")]
|
||||||
public class GetChannelFolder : IReturn<BaseItemDto>
|
public class GetChannelFolder : IReturn<BaseItemDto>
|
||||||
{
|
{
|
||||||
@ -173,5 +220,20 @@ namespace MediaBrowser.Api
|
|||||||
|
|
||||||
return ToOptimizedResult(result);
|
return ToOptimizedResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object Get(GetLatestChannelItems request)
|
||||||
|
{
|
||||||
|
var result = _channelManager.GetLatestChannelItems(new AllChannelMediaQuery
|
||||||
|
{
|
||||||
|
Limit = request.Limit,
|
||||||
|
StartIndex = request.StartIndex,
|
||||||
|
UserId = request.UserId,
|
||||||
|
Filters = request.GetFilters().ToArray(),
|
||||||
|
Fields = request.GetItemFields().ToList()
|
||||||
|
|
||||||
|
}, CancellationToken.None).Result;
|
||||||
|
|
||||||
|
return ToOptimizedResult(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,14 @@ namespace MediaBrowser.Controller.Channels
|
|||||||
/// <returns>Task{QueryResult{BaseItemDto}}.</returns>
|
/// <returns>Task{QueryResult{BaseItemDto}}.</returns>
|
||||||
Task<QueryResult<BaseItemDto>> GetAllMedia(AllChannelMediaQuery query, CancellationToken cancellationToken);
|
Task<QueryResult<BaseItemDto>> GetAllMedia(AllChannelMediaQuery query, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the latest media.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="query">The query.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>Task{QueryResult{BaseItemDto}}.</returns>
|
||||||
|
Task<QueryResult<BaseItemDto>> GetLatestChannelItems(AllChannelMediaQuery query, CancellationToken cancellationToken);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the channel items.
|
/// Gets the channel items.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -63,10 +63,10 @@ namespace MediaBrowser.Model.Channels
|
|||||||
public bool CanFilter { get; set; }
|
public bool CanFilter { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether this instance can download all media.
|
/// Gets or sets a value indicating whether [supports content downloading].
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value><c>true</c> if this instance can download all media; otherwise, <c>false</c>.</value>
|
/// <value><c>true</c> if [supports content downloading]; otherwise, <c>false</c>.</value>
|
||||||
public bool CanDownloadAllMedia { get; set; }
|
public bool SupportsContentDownloading { get; set; }
|
||||||
|
|
||||||
public ChannelFeatures()
|
public ChannelFeatures()
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
namespace MediaBrowser.Model.Channels
|
using MediaBrowser.Model.Querying;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Model.Channels
|
||||||
{
|
{
|
||||||
public class ChannelQuery
|
public class ChannelQuery
|
||||||
{
|
{
|
||||||
@ -54,7 +57,13 @@
|
|||||||
ChannelIds = new string[] { };
|
ChannelIds = new string[] { };
|
||||||
|
|
||||||
ContentTypes = new ChannelMediaContentType[] { };
|
ContentTypes = new ChannelMediaContentType[] { };
|
||||||
|
|
||||||
|
Filters = new ItemFilter[] { };
|
||||||
|
Fields = new List<ItemFields>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ItemFilter[] Filters { get; set; }
|
||||||
|
public List<ItemFields> Fields { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -335,7 +335,7 @@ namespace MediaBrowser.Providers.Manager
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (provider is IRemoteImageProvider)
|
if (provider is IRemoteImageProvider || provider is IDynamicImageProvider)
|
||||||
{
|
{
|
||||||
if (!ConfigurationManager.Configuration.EnableInternetProviders)
|
if (!ConfigurationManager.Configuration.EnableInternetProviders)
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
|
using MediaBrowser.Common.Progress;
|
||||||
using MediaBrowser.Common.ScheduledTasks;
|
using MediaBrowser.Common.ScheduledTasks;
|
||||||
using MediaBrowser.Controller.Channels;
|
using MediaBrowser.Controller.Channels;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
@ -9,6 +10,7 @@ using MediaBrowser.Model.Channels;
|
|||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -26,8 +28,9 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||||||
private readonly IHttpClient _httpClient;
|
private readonly IHttpClient _httpClient;
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly ILibraryManager _libraryManager;
|
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;
|
_manager = manager;
|
||||||
_config = config;
|
_config = config;
|
||||||
@ -35,6 +38,7 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||||||
_httpClient = httpClient;
|
_httpClient = httpClient;
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
|
_userManager = userManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name
|
public string Name
|
||||||
@ -55,51 +59,96 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||||||
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
|
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
|
||||||
{
|
{
|
||||||
CleanChannelContent(cancellationToken);
|
CleanChannelContent(cancellationToken);
|
||||||
progress.Report(5);
|
|
||||||
|
|
||||||
await DownloadChannelContent(cancellationToken, progress).ConfigureAwait(false);
|
var users = _userManager.Users.Select(i => i.Id.ToString("N")).ToList();
|
||||||
progress.Report(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task DownloadChannelContent(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
|
|
||||||
|
|
||||||
}, cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var path = _manager.ChannelDownloadPath;
|
|
||||||
|
|
||||||
var numComplete = 0;
|
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 async Task DownloadContent(string user,
|
||||||
|
CancellationToken cancellationToken,
|
||||||
|
IProgress<double> progress)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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 DownloadAllChannelContent(string userId,
|
||||||
|
CancellationToken cancellationToken,
|
||||||
|
IProgress<double> progress)
|
||||||
|
{
|
||||||
|
var result = await _manager.GetAllMedia(new AllChannelMediaQuery
|
||||||
|
{
|
||||||
|
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)
|
foreach (var item in result.Items)
|
||||||
|
{
|
||||||
|
if (_config.Configuration.ChannelOptions.DownloadingChannels.Contains(item.ChannelId))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -113,12 +162,15 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||||||
{
|
{
|
||||||
_logger.ErrorException("Error downloading channel content for {0}", ex, item.Name);
|
_logger.ErrorException("Error downloading channel content for {0}", ex, item.Name);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
numComplete++;
|
numComplete++;
|
||||||
double percent = numComplete;
|
double percent = numComplete;
|
||||||
percent /= result.Items.Length;
|
percent /= result.Items.Length;
|
||||||
progress.Report(percent * 95 + 5);
|
progress.Report(percent * 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
progress.Report(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DownloadChannelItem(BaseItemDto item,
|
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>
|
/// <summary>
|
||||||
/// Deletes the cache files from directory with a last write time less than a given date
|
/// Deletes the cache files from directory with a last write time less than a given date
|
||||||
/// </summary>
|
/// </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
|
public bool IsHidden
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return !_manager.GetAllChannelFeatures()
|
return !_manager.GetAllChannelFeatures().Any();
|
||||||
.Any(i => i.CanDownloadAllMedia && _config.Configuration.ChannelOptions.DownloadingChannels.Contains(i.Id));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <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
|
public bool IsEnabled
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -53,6 +53,14 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||||||
_localization = localization;
|
_localization = localization;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TimeSpan CacheLength
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return TimeSpan.FromDays(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void AddParts(IEnumerable<IChannel> channels, IEnumerable<IChannelFactory> factories)
|
public void AddParts(IEnumerable<IChannel> channels, IEnumerable<IChannelFactory> factories)
|
||||||
{
|
{
|
||||||
_channels = channels.ToArray();
|
_channels = channels.ToArray();
|
||||||
@ -443,6 +451,7 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||||||
InternalChannelFeatures features)
|
InternalChannelFeatures features)
|
||||||
{
|
{
|
||||||
var isIndexable = provider is IIndexableChannel;
|
var isIndexable = provider is IIndexableChannel;
|
||||||
|
var supportsLatest = provider is ISupportsLatestMedia;
|
||||||
|
|
||||||
return new ChannelFeatures
|
return new ChannelFeatures
|
||||||
{
|
{
|
||||||
@ -453,10 +462,10 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||||||
MaxPageSize = features.MaxPageSize,
|
MaxPageSize = features.MaxPageSize,
|
||||||
MediaTypes = features.MediaTypes,
|
MediaTypes = features.MediaTypes,
|
||||||
SupportsSortOrderToggle = features.SupportsSortOrderToggle,
|
SupportsSortOrderToggle = features.SupportsSortOrderToggle,
|
||||||
SupportsLatestMedia = provider is ISupportsLatestMedia,
|
SupportsLatestMedia = supportsLatest,
|
||||||
Name = channel.Name,
|
Name = channel.Name,
|
||||||
Id = channel.Id.ToString("N"),
|
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));
|
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)
|
public async Task<QueryResult<BaseItemDto>> GetAllMedia(AllChannelMediaQuery query, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var user = string.IsNullOrWhiteSpace(query.UserId)
|
var user = string.IsNullOrWhiteSpace(query.UserId)
|
||||||
@ -480,11 +588,16 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||||||
|
|
||||||
if (query.ChannelIds.Length > 0)
|
if (query.ChannelIds.Length > 0)
|
||||||
{
|
{
|
||||||
|
// Avoid implicitly captured closure
|
||||||
|
var ids = query.ChannelIds;
|
||||||
channels = channels
|
channels = channels
|
||||||
.Where(i => query.ChannelIds.Contains(GetInternalChannelId(i.Name).ToString("N")))
|
.Where(i => ids.Contains(GetInternalChannelId(i.Name).ToString("N")))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Avoid implicitly captured closure
|
||||||
|
var userId = query.UserId;
|
||||||
|
|
||||||
var tasks = channels
|
var tasks = channels
|
||||||
.Select(async i =>
|
.Select(async i =>
|
||||||
{
|
{
|
||||||
@ -496,7 +609,7 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||||||
{
|
{
|
||||||
var result = await indexable.GetAllMedia(new InternalAllChannelMediaQuery
|
var result = await indexable.GetAllMedia(new InternalAllChannelMediaQuery
|
||||||
{
|
{
|
||||||
UserId = query.UserId
|
UserId = userId
|
||||||
|
|
||||||
}, cancellationToken).ConfigureAwait(false);
|
}, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
@ -546,12 +659,7 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||||||
|
|
||||||
var internalItems = await Task.WhenAll(itemTasks).ConfigureAwait(false);
|
var internalItems = await Task.WhenAll(itemTasks).ConfigureAwait(false);
|
||||||
|
|
||||||
// Get everything
|
var returnItemArray = internalItems.Select(i => _dtoService.GetBaseItemDto(i, query.Fields, user))
|
||||||
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))
|
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
return new QueryResult<BaseItemDto>
|
return new QueryResult<BaseItemDto>
|
||||||
@ -641,7 +749,7 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||||||
{
|
{
|
||||||
var userId = user.Id.ToString("N");
|
var userId = user.Id.ToString("N");
|
||||||
|
|
||||||
var cacheLength = TimeSpan.FromDays(1);
|
var cacheLength = CacheLength;
|
||||||
var cachePath = GetChannelDataCachePath(channel, userId, folderId, sortField, sortDescending);
|
var cachePath = GetChannelDataCachePath(channel, userId, folderId, sortField, sortDescending);
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -147,5 +147,6 @@
|
|||||||
"ButtonRemove": "Remove",
|
"ButtonRemove": "Remove",
|
||||||
"LabelChapterDownloaders": "Chapter downloaders:",
|
"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.",
|
"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"
|
||||||
}
|
}
|
@ -785,11 +785,13 @@
|
|||||||
"LabelHomePageSection1": "Home page section one:",
|
"LabelHomePageSection1": "Home page section one:",
|
||||||
"LabelHomePageSection2": "Home page section two:",
|
"LabelHomePageSection2": "Home page section two:",
|
||||||
"LabelHomePageSection3": "Home page section three:",
|
"LabelHomePageSection3": "Home page section three:",
|
||||||
|
"LabelHomePageSection4": "Home page section four:",
|
||||||
"OptionMyLibraryButtons": "My library (buttons)",
|
"OptionMyLibraryButtons": "My library (buttons)",
|
||||||
"OptionMyLibrary": "My library",
|
"OptionMyLibrary": "My library",
|
||||||
"OptionMyLibrarySmall": "My library (small)",
|
"OptionMyLibrarySmall": "My library (small)",
|
||||||
"OptionResumablemedia": "Resume",
|
"OptionResumablemedia": "Resume",
|
||||||
"OptionLatestMedia": "Latest media",
|
"OptionLatestMedia": "Latest media",
|
||||||
|
"OptionLatestChannelMedia": "Latest channel items",
|
||||||
"OptionNone": "None",
|
"OptionNone": "None",
|
||||||
"HeaderLiveTv": "Live TV",
|
"HeaderLiveTv": "Live TV",
|
||||||
"HeaderReports": "Reports",
|
"HeaderReports": "Reports",
|
||||||
|
@ -538,6 +538,7 @@ namespace MediaBrowser.WebDashboard.Api
|
|||||||
"autoorganizetv.js",
|
"autoorganizetv.js",
|
||||||
"autoorganizelog.js",
|
"autoorganizelog.js",
|
||||||
"channels.js",
|
"channels.js",
|
||||||
|
"channelslatest.js",
|
||||||
"channelitems.js",
|
"channelitems.js",
|
||||||
"channelsettings.js",
|
"channelsettings.js",
|
||||||
"dashboardgeneral.js",
|
"dashboardgeneral.js",
|
||||||
|
@ -106,6 +106,9 @@
|
|||||||
<Content Include="dashboard-ui\channelsettings.html">
|
<Content Include="dashboard-ui\channelsettings.html">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="dashboard-ui\channelslatest.html">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="dashboard-ui\css\chromecast.css">
|
<Content Include="dashboard-ui\css\chromecast.css">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
@ -622,6 +625,9 @@
|
|||||||
<Content Include="dashboard-ui\scripts\channelsettings.js">
|
<Content Include="dashboard-ui\scripts\channelsettings.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="dashboard-ui\scripts\channelslatest.js">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="dashboard-ui\scripts\chromecast.js">
|
<Content Include="dashboard-ui\scripts\chromecast.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user