diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index f3fd8f42a..24c91e172 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -182,6 +182,24 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "MaxEndDate", Description = "Optional. The maximum premiere date. Format = ISO", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")] public string MaxEndDate { get; set; } + + [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsMovie { get; set; } + + [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; } + + [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 = "SortBy", Description = "Optional. Specify one or more sort orders, comma delimeted. Options: Name, StartDate", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] + public string SortBy { get; set; } + + [ApiMember(Name = "SortOrder", Description = "Sort Order - Ascending,Descending", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public SortOrder? SortOrder { get; set; } + + [ApiMember(Name = "Genres", Description = "The genres to return guide information for.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")] + public string Genres { get; set; } } [Route("/LiveTv/Programs/Recommended", "GET", Summary = "Gets available live tv epgs..")] @@ -199,6 +217,9 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "HasAired", Description = "Optional. Filter by programs that have completed airing, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool? HasAired { get; set; } + + [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] + public bool? IsMovie { get; set; } } [Route("/LiveTv/Programs/{Id}", "GET", Summary = "Gets a live tv program")] @@ -371,7 +392,7 @@ namespace MediaBrowser.Api.LiveTv { var query = new ProgramQuery { - ChannelIdList = (request.ChannelIds ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToArray(), + ChannelIds = (request.ChannelIds ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToArray(), UserId = request.UserId, HasAired = request.HasAired }; @@ -396,6 +417,13 @@ namespace MediaBrowser.Api.LiveTv query.MaxEndDate = DateTime.Parse(request.MaxEndDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime(); } + query.StartIndex = request.StartIndex; + query.Limit = request.Limit; + query.SortBy = (request.SortBy ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + query.SortOrder = request.SortOrder; + query.IsMovie = request.IsMovie; + query.Genres = (request.Genres ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + var result = await _liveTvManager.GetPrograms(query, CancellationToken.None).ConfigureAwait(false); return ToOptimizedSerializedResultUsingCache(result); @@ -408,7 +436,8 @@ namespace MediaBrowser.Api.LiveTv UserId = request.UserId, IsAiring = request.IsAiring, Limit = request.Limit, - HasAired = request.HasAired + HasAired = request.HasAired, + IsMovie = request.IsMovie }; var result = await _liveTvManager.GetRecommendedPrograms(query, CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index c8f618a03..dd6189bc5 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -239,6 +239,11 @@ namespace MediaBrowser.Controller.Entities get { return this.GetImagePath(ImageType.Primary); } } + public virtual bool IsInternetMetadataEnabled() + { + return ConfigurationManager.Configuration.EnableInternetProviders; + } + public virtual bool CanDelete() { var locationType = LocationType; diff --git a/MediaBrowser.Controller/Entities/IHasImages.cs b/MediaBrowser.Controller/Entities/IHasImages.cs index 5aafc8eb3..00a42271b 100644 --- a/MediaBrowser.Controller/Entities/IHasImages.cs +++ b/MediaBrowser.Controller/Entities/IHasImages.cs @@ -184,6 +184,12 @@ namespace MediaBrowser.Controller.Entities /// /// true if [always scan internal metadata path]; otherwise, false. bool AlwaysScanInternalMetadataPath { get; } + + /// + /// Determines whether [is internet metadata enabled]. + /// + /// true if [is internet metadata enabled]; otherwise, false. + bool IsInternetMetadataEnabled(); } public static class HasImagesExtensions diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index 2f9673db2..0b07d8b6d 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -1,5 +1,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Users; @@ -11,7 +12,7 @@ using System.Threading.Tasks; namespace MediaBrowser.Controller.LiveTv { - public class LiveTvProgram : BaseItem, ILiveTvItem + public class LiveTvProgram : BaseItem, ILiveTvItem, IHasLookupInfo { /// /// Gets the user data key. @@ -220,5 +221,23 @@ namespace MediaBrowser.Controller.LiveTv { return false; } + + public override bool IsInternetMetadataEnabled() + { + if (IsMovie) + { + var options = (LiveTvOptions)ConfigurationManager.GetConfiguration("livetv"); + return options.EnableMovieProviders; + } + + return false; + } + + public LiveTvProgramLookupInfo GetLookupInfo() + { + var info = GetItemLookupInfo(); + info.IsMovie = IsMovie; + return info; + } } } diff --git a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs index 4d7e5ee63..36f082b02 100644 --- a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs +++ b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs @@ -145,6 +145,12 @@ namespace MediaBrowser.Controller.LiveTv /// true if this instance is premiere; otherwise, false. public bool IsPremiere { get; set; } + /// + /// Gets or sets the production year. + /// + /// The production year. + public int? ProductionYear { get; set; } + public ProgramInfo() { Genres = new List(); diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 678d7841c..06f18729b 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -293,6 +293,7 @@ + diff --git a/MediaBrowser.Controller/Providers/LiveTvProgramLookupInfo.cs b/MediaBrowser.Controller/Providers/LiveTvProgramLookupInfo.cs new file mode 100644 index 000000000..4e2c11c22 --- /dev/null +++ b/MediaBrowser.Controller/Providers/LiveTvProgramLookupInfo.cs @@ -0,0 +1,9 @@ +using System; + +namespace MediaBrowser.Controller.Providers +{ + public class LiveTvProgramLookupInfo : ItemLookupInfo + { + public Boolean IsMovie { get; set; } + } +} diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 32a9c8d12..0cd5eda0c 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -3,5 +3,6 @@ public class LiveTvOptions { public int? GuideDays { get; set; } + public bool EnableMovieProviders { get; set; } } } \ No newline at end of file diff --git a/MediaBrowser.Model/LiveTv/ProgramQuery.cs b/MediaBrowser.Model/LiveTv/ProgramQuery.cs index 2d15a4c4b..bbd396c33 100644 --- a/MediaBrowser.Model/LiveTv/ProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/ProgramQuery.cs @@ -1,4 +1,5 @@ -using System; +using MediaBrowser.Model.Entities; +using System; namespace MediaBrowser.Model.LiveTv { @@ -7,11 +8,18 @@ namespace MediaBrowser.Model.LiveTv /// public class ProgramQuery { + public ProgramQuery() + { + ChannelIds = new string[] { }; + SortBy = new string[] { }; + Genres = new string[] { }; + } + /// - /// Gets or sets the channel identifier. + /// Gets or sets the channel ids. /// - /// The channel identifier. - public string[] ChannelIdList { get; set; } + /// The channel ids. + public string[] ChannelIds { get; set; } /// /// Gets or sets the user identifier. @@ -19,19 +27,64 @@ namespace MediaBrowser.Model.LiveTv /// The user identifier. public string UserId { get; set; } + /// + /// The earliest date for which a program starts to return + /// public DateTime? MinStartDate { get; set; } + /// + /// The latest date for which a program starts to return + /// public DateTime? MaxStartDate { get; set; } + /// + /// The earliest date for which a program ends to return + /// public DateTime? MinEndDate { get; set; } + /// + /// The latest date for which a program ends to return + /// public DateTime? MaxEndDate { get; set; } + /// + /// Used to specific whether to return movies or not + /// + /// If set to null, all programs will be returned + public bool? IsMovie { get; set; } + + /// + /// Skips over a given number of items within the results. Use for paging. + /// + public int? StartIndex { get; set; } + + /// + /// Gets or sets a value indicating whether this instance has aired. + /// + /// null if [has aired] contains no value, true if [has aired]; otherwise, false. public bool? HasAired { get; set; } - public ProgramQuery() - { - ChannelIdList = new string[] { }; - } + /// + /// The maximum number of items to return + /// + public int? Limit { get; set; } + + /// + /// What to sort the results by + /// + /// The sort by. + public string[] SortBy { get; set; } + + /// + /// The sort order to return results with + /// + /// The sort order. + public SortOrder? SortOrder { get; set; } + + /// + /// Limit results to items containing specific genres + /// + /// The genres. + public string[] Genres { get; set; } } -} +} \ No newline at end of file diff --git a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs index 907902123..9ba8e0e5f 100644 --- a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs @@ -25,5 +25,11 @@ /// /// The limit. public int? Limit { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is movie. + /// + /// null if [is movie] contains no value, true if [is movie]; otherwise, false. + public bool? IsMovie { get; set; } } } \ No newline at end of file diff --git a/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs b/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs index 5a7ae7594..f17389615 100644 --- a/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs +++ b/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs @@ -7,14 +7,16 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; namespace MediaBrowser.Providers.LiveTv { - public class ProgramMetadataService : MetadataService + public class ProgramMetadataService : MetadataService { - public ProgramMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager) + public ProgramMetadataService( + IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, + IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager) + : base( + serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager) { } @@ -25,6 +27,7 @@ namespace MediaBrowser.Providers.LiveTv /// The target. /// The locked fields. /// if set to true [replace data]. + /// protected override void MergeData(LiveTvProgram source, LiveTvProgram target, List lockedFields, bool replaceData, bool mergeMetadataSettings) { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 0c1372e41..c9ae47ad0 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -312,7 +312,7 @@ namespace MediaBrowser.Providers.Manager if (provider is IRemoteMetadataProvider) { - if (!ConfigurationManager.Configuration.EnableInternetProviders) + if (!item.IsInternetMetadataEnabled()) { return false; } @@ -360,7 +360,7 @@ namespace MediaBrowser.Providers.Manager if (provider is IRemoteImageProvider) { - if (!ConfigurationManager.Configuration.EnableInternetProviders) + if (!item.IsInternetMetadataEnabled()) { return false; } @@ -515,7 +515,7 @@ namespace MediaBrowser.Providers.Manager Type = MetadataPluginType.LocalMetadataProvider })); - if (ConfigurationManager.Configuration.EnableInternetProviders) + if (item.IsInternetMetadataEnabled()) { // Fetchers list.AddRange(providers.Where(i => (i is IRemoteMetadataProvider)).Select(i => new MetadataPlugin @@ -547,7 +547,7 @@ namespace MediaBrowser.Providers.Manager Type = MetadataPluginType.LocalImageProvider })); - var enableInternet = ConfigurationManager.Configuration.EnableInternetProviders; + var enableInternet = item.IsInternetMetadataEnabled(); // Fetchers list.AddRange(imageProviders.Where(i => i is IDynamicImageProvider || (enableInternet && i is IRemoteImageProvider)).Select(i => new MetadataPlugin diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 2df8f8e3c..3b5103f20 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -108,6 +108,7 @@ + diff --git a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs index 68cbf85e9..c23ed3786 100644 --- a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs +++ b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs @@ -17,7 +17,7 @@ using System.Threading.Tasks; namespace MediaBrowser.Providers.Movies { public class GenericMovieDbInfo - where T : Video, new() + where T : BaseItem, new() { private readonly ILogger _logger; private readonly IJsonSerializer _jsonSerializer; diff --git a/MediaBrowser.Providers/Movies/LiveTvMovieDbProvider.cs b/MediaBrowser.Providers/Movies/LiveTvMovieDbProvider.cs new file mode 100644 index 000000000..326450ad4 --- /dev/null +++ b/MediaBrowser.Providers/Movies/LiveTvMovieDbProvider.cs @@ -0,0 +1,43 @@ +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Providers; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Providers.Movies +{ + public class LiveTvMovieDbProvider : IRemoteMetadataProvider, IDisposable, IHasOrder + { + public Task> GetSearchResults(LiveTvProgramLookupInfo searchInfo, CancellationToken cancellationToken) + { + return MovieDbProvider.Current.GetMovieSearchResults(searchInfo, cancellationToken); + } + + public Task> GetMetadata(LiveTvProgramLookupInfo info, CancellationToken cancellationToken) + { + return MovieDbProvider.Current.GetItemMetadata(info, cancellationToken); + } + + public string Name + { + get { return "LiveTvMovieDbProvider"; } + } + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + return MovieDbProvider.Current.GetImageResponse(url, cancellationToken); + } + + public void Dispose() + { + } + + public int Order + { + get { return 1; } + } + } +} \ No newline at end of file diff --git a/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs b/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs index f5d5a6fb1..19b4939dd 100644 --- a/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs @@ -2,6 +2,7 @@ using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Channels; using MediaBrowser.Model.Dto; @@ -47,6 +48,13 @@ namespace MediaBrowser.Providers.Movies return true; } + // Supports images for tv movies + var tvProgram = item as LiveTvProgram; + if (tvProgram != null && tvProgram.IsMovie) + { + return true; + } + // Don't support local trailers return item is Movie || item is MusicVideo; } diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs index b8f9a7fa2..48b7140f8 100644 --- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs @@ -113,7 +113,7 @@ namespace MediaBrowser.Providers.Movies } public Task> GetItemMetadata(ItemLookupInfo id, CancellationToken cancellationToken) - where T : Video, new() + where T : BaseItem, new() { var movieDb = new GenericMovieDbInfo(_logger, _jsonSerializer, _libraryManager); diff --git a/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs b/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs index 758d0a6bd..7f804f9df 100644 --- a/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs +++ b/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs @@ -3,6 +3,7 @@ using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Channels; using MediaBrowser.Model.Entities; @@ -108,6 +109,13 @@ namespace MediaBrowser.Providers.Omdb } } + // Supports images for tv movies + var tvProgram = item as LiveTvProgram; + if (tvProgram != null && tvProgram.IsMovie) + { + return true; + } + return item is Movie; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 33f1a4dac..acff25e96 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -45,6 +45,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv private readonly ILibraryManager _libraryManager; private readonly ITaskManager _taskManager; private readonly IJsonSerializer _jsonSerializer; + private readonly IProviderManager _providerManager; private readonly IDtoService _dtoService; private readonly ILocalizationManager _localization; @@ -62,7 +63,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv private readonly SemaphoreSlim _refreshSemaphore = new SemaphoreSlim(1, 1); - public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, IFileSystem fileSystem, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer) + public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, IFileSystem fileSystem, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager) { _config = config; _fileSystem = fileSystem; @@ -73,6 +74,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv _taskManager = taskManager; _localization = localization; _jsonSerializer = jsonSerializer; + _providerManager = providerManager; _dtoService = dtoService; _userDataManager = userDataManager; @@ -237,7 +239,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv foreach (var channel in internalResult.Items) { - var currentProgram = await GetCurrentProgram(channel.ExternalId, cancellationToken).ConfigureAwait(false); + var currentProgram = GetCurrentProgram(channel.ExternalId); returnList.Add(_tvDtoService.GetChannelInfoDto(channel, currentProgram, user)); } @@ -261,7 +263,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv return _libraryManager.GetItemById(id) as LiveTvChannel; } - public async Task GetInternalProgram(string id, CancellationToken cancellationToken) + private LiveTvProgram GetInternalProgram(string id) { var guid = new Guid(id); @@ -271,37 +273,26 @@ namespace MediaBrowser.Server.Implementations.LiveTv if (obj != null) { - await RefreshIfNeeded(obj, cancellationToken).ConfigureAwait(false); + RefreshIfNeeded(obj); } return obj; } - private Task RefreshIfNeeded(IEnumerable programs, CancellationToken cancellationToken) - { - var list = programs.ToList(); - - Task.Run(async () => - { - foreach (var program in list) - { - await RefreshIfNeeded(program, CancellationToken.None).ConfigureAwait(false); - } - - }, cancellationToken); - - return Task.FromResult(true); - } - - private readonly Task _cachedTask = Task.FromResult(true); - private Task RefreshIfNeeded(LiveTvProgram program, CancellationToken cancellationToken) + private void RefreshIfNeeded(LiveTvProgram program) { if (!_refreshedPrograms.ContainsKey(program.Id)) { _refreshedPrograms.TryAdd(program.Id, true); - return program.RefreshMetadata(cancellationToken); + _providerManager.QueueRefresh(program.Id, new MetadataRefreshOptions()); } + } - return _cachedTask; + private void RefreshIfNeeded(IEnumerable programs) + { + foreach (var program in programs) + { + RefreshIfNeeded(program); + } } public async Task GetInternalRecording(string id, CancellationToken cancellationToken) @@ -528,6 +519,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv item.ProviderImageUrl = info.ImageUrl; item.RunTimeTicks = (info.EndDate - info.StartDate).Ticks; item.StartDate = info.StartDate; + item.ProductionYear = info.ProductionYear; return item; } @@ -607,7 +599,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv public async Task GetProgram(string id, CancellationToken cancellationToken, User user = null) { - var program = await GetInternalProgram(id, cancellationToken).ConfigureAwait(false); + var program = GetInternalProgram(id); var channel = GetChannel(program); @@ -656,9 +648,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv programs = programs.Where(i => i.HasAired == val); } - if (query.ChannelIdList.Length > 0) + if (query.ChannelIds.Length > 0) { - var guids = query.ChannelIdList.Select(i => new Guid(i)).ToList(); + var guids = query.ChannelIds.Select(i => new Guid(i)).ToList(); programs = programs.Where(i => { @@ -672,7 +664,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv } var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId); - if (user != null) { // Avoid implicitly captured closure @@ -680,6 +671,30 @@ namespace MediaBrowser.Server.Implementations.LiveTv programs = programs.Where(i => i.IsVisible(currentUser)); } + // Apply genre filter + if (query.Genres.Length > 0) + { + programs = programs.Where(p => p.Genres.Any(g => query.Genres.Contains(g, StringComparer.OrdinalIgnoreCase))); + } + + if (query.IsMovie.HasValue) + { + programs = programs.Where(p => p.IsMovie == query.IsMovie); + } + + programs = _libraryManager.Sort(programs, user, query.SortBy, query.SortOrder ?? SortOrder.Ascending) + .Cast(); + + if (query.StartIndex.HasValue) + { + programs = programs.Skip(query.StartIndex.Value); + } + + if (query.Limit.HasValue) + { + programs = programs.Take(query.Limit.Value); + } + var programList = programs.ToList(); var returnArray = programList @@ -691,7 +706,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv }) .ToArray(); - await RefreshIfNeeded(programList, cancellationToken).ConfigureAwait(false); + RefreshIfNeeded(programList); await AddRecordingInfo(returnArray, cancellationToken).ConfigureAwait(false); @@ -726,6 +741,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv programs = programs.Where(i => i.HasAired == val); } + if (query.IsMovie.HasValue) + { + programs = programs.Where(p => p.IsMovie == query.IsMovie.Value); + } + var serviceName = ActiveService.Name; var programList = programs.ToList(); @@ -747,7 +767,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv programList = programs.ToList(); - await RefreshIfNeeded(programList, cancellationToken).ConfigureAwait(false); + RefreshIfNeeded(programList); var returnArray = programList.ToArray(); @@ -1233,7 +1253,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv { var program = string.IsNullOrEmpty(i.ProgramId) ? null : - await GetInternalProgram(_tvDtoService.GetInternalProgramId(service.Name, i.ProgramId).ToString("N"), cancellationToken).ConfigureAwait(false); + GetInternalProgram(_tvDtoService.GetInternalProgramId(service.Name, i.ProgramId).ToString("N")); var channel = string.IsNullOrEmpty(i.ChannelId) ? null : GetInternalChannel(_tvDtoService.GetInternalChannelId(service.Name, i.ChannelId)); @@ -1366,14 +1386,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv { var channel = GetInternalChannel(id); - var currentProgram = await GetCurrentProgram(channel.ExternalId, cancellationToken).ConfigureAwait(false); + var currentProgram = GetCurrentProgram(channel.ExternalId); var dto = _tvDtoService.GetChannelInfoDto(channel, currentProgram, user); return dto; } - private async Task GetCurrentProgram(string externalChannelId, CancellationToken cancellationToken) + private LiveTvProgram GetCurrentProgram(string externalChannelId) { var now = DateTime.UtcNow; @@ -1385,7 +1405,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv if (program != null) { - await RefreshIfNeeded(program, cancellationToken).ConfigureAwait(false); + RefreshIfNeeded(program); } return program; @@ -1444,7 +1464,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv public async Task GetNewTimerDefaults(string programId, CancellationToken cancellationToken) { - var program = await GetInternalProgram(programId, cancellationToken).ConfigureAwait(false); + var program = GetInternalProgram(programId); var programDto = await GetProgram(programId, cancellationToken).ConfigureAwait(false); var defaults = await GetNewTimerDefaultsInternal(cancellationToken, program).ConfigureAwait(false); diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 0805c9ce9..e5b1e5a8b 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1389,5 +1389,7 @@ "LabelTagFilterMode": "Mode:", "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.", "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled", - "MessageReenableUser": "See below to reenable" + "MessageReenableUser": "See below to reenable", + "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:", + "OptionTVMovies": "TV Movies" } diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index a7de0fa34..e80f94e15 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -495,7 +495,7 @@ namespace MediaBrowser.Server.Startup.Common PlaylistManager = new PlaylistManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("PlaylistManager"), UserManager); RegisterSingleInstance(PlaylistManager); - LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, FileSystemManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer); + LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, FileSystemManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer, ProviderManager); RegisterSingleInstance(LiveTvManager); UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, PlaylistManager, CollectionManager, ServerConfigurationManager);