From 235b838fbe262f3f41cd64c8506d067c9ef9253e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 29 Nov 2013 11:58:24 -0500 Subject: [PATCH] support deleting and canceling live tv recordings and timers --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 31 +++++++++ .../ScheduledTasks/ScheduledTaskService.cs | 32 ++++++++-- .../ScheduledTasksWebSocketListener.cs | 6 +- MediaBrowser.Api/TvShowsService.cs | 64 ++++++++++++++----- .../BaseApplicationHost.cs | 2 +- .../HttpClientManager/HttpClientManager.cs | 3 +- .../Tasks/DeleteCacheFileTask.cs | 1 - .../ScheduledTasks/IScheduledTask.cs | 5 ++ .../ScheduledTasks/ScheduledTaskHelpers.cs | 12 +++- .../LiveTv/ILiveTvManager.cs | 14 ++++ .../LiveTv/ILiveTvService.cs | 8 --- .../LiveTv/RecordingInfo.cs | 6 ++ MediaBrowser.Controller/LiveTv/TimerInfo.cs | 18 ++---- MediaBrowser.Model/LiveTv/RecordingStatus.cs | 7 ++ MediaBrowser.Model/LiveTv/TimerInfoDto.cs | 24 +++---- MediaBrowser.Model/Querying/EpisodeQuery.cs | 13 ++-- MediaBrowser.Model/Tasks/TaskInfo.cs | 6 ++ .../LiveTv/LiveTvManager.cs | 57 ++++++++++++++++- .../LiveTv/RefreshChannelsScheduledTask.cs | 9 ++- .../Native/HttpClientFactory.cs | 7 +- MediaBrowser.WebDashboard/ApiClient.js | 20 +++++- .../MediaBrowser.WebDashboard.csproj | 4 +- MediaBrowser.WebDashboard/packages.config | 2 +- Nuget/MediaBrowser.Common.Internal.nuspec | 4 +- Nuget/MediaBrowser.Common.nuspec | 2 +- Nuget/MediaBrowser.Server.Core.nuspec | 4 +- 26 files changed, 280 insertions(+), 81 deletions(-) diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 2961c920f8..4cd75afca5 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -1,4 +1,5 @@ using System.Threading; +using System.Threading.Tasks; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Querying; @@ -82,6 +83,22 @@ namespace MediaBrowser.Api.LiveTv public string UserId { get; set; } } + [Route("/LiveTv/Recordings/{Id}", "DELETE")] + [Api(Description = "Deletes a live tv recording")] + public class DeleteRecording : IReturnVoid + { + [ApiMember(Name = "Id", Description = "Recording Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string Id { get; set; } + } + + [Route("/LiveTv/Timers/{Id}", "DELETE")] + [Api(Description = "Cancels a live tv timer")] + public class CancelTimer : IReturnVoid + { + [ApiMember(Name = "Id", Description = "Timer Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string Id { get; set; } + } + public class LiveTvService : BaseApiService { private readonly ILiveTvManager _liveTvManager; @@ -176,5 +193,19 @@ namespace MediaBrowser.Api.LiveTv return ToOptimizedResult(result); } + + public void Delete(DeleteRecording request) + { + var task = _liveTvManager.DeleteRecording(request.Id); + + Task.WaitAll(task); + } + + public void Delete(CancelTimer request) + { + var task = _liveTvManager.CancelTimer(request.Id); + + Task.WaitAll(task); + } } } \ No newline at end of file diff --git a/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs b/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs index 2674529e51..d17a38e073 100644 --- a/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs +++ b/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs @@ -31,7 +31,8 @@ namespace MediaBrowser.Api.ScheduledTasks [Api(Description = "Gets scheduled tasks")] public class GetScheduledTasks : IReturn> { - + [ApiMember(Name = "IsHidden", Description = "Optional filter tasks that are hidden, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] + public bool? IsHidden { get; set; } } /// @@ -112,10 +113,33 @@ namespace MediaBrowser.Api.ScheduledTasks /// IEnumerable{TaskInfo}. public object Get(GetScheduledTasks request) { - var result = TaskManager.ScheduledTasks.OrderBy(i => i.Name) - .Select(ScheduledTaskHelpers.GetTaskInfo).ToList(); + IEnumerable result = TaskManager.ScheduledTasks + .OrderBy(i => i.Name); - return ToOptimizedResult(result); + if (request.IsHidden.HasValue) + { + var val = request.IsHidden.Value; + + result = result.Where(i => + { + var isHidden = false; + + var configurableTask = i.ScheduledTask as IConfigurableScheduledTask; + + if (configurableTask != null) + { + isHidden = configurableTask.IsHidden; + } + + return isHidden == val; + }); + } + + var infos = result + .Select(ScheduledTaskHelpers.GetTaskInfo) + .ToList(); + + return ToOptimizedResult(infos); } /// diff --git a/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs b/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs index 20634301a3..c143635bfa 100644 --- a/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs +++ b/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs @@ -46,8 +46,10 @@ namespace MediaBrowser.Api.ScheduledTasks /// Task{IEnumerable{TaskInfo}}. protected override Task> GetDataToSend(object state) { - return Task.FromResult(TaskManager.ScheduledTasks.OrderBy(i => i.Name) - .Select(ScheduledTaskHelpers.GetTaskInfo)); + return Task.FromResult(TaskManager.ScheduledTasks + .OrderBy(i => i.Name) + .Select(ScheduledTaskHelpers.GetTaskInfo) + .Where(i => !i.IsHidden)); } } } diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs index 95bde2d283..23b8efa7bd 100644 --- a/MediaBrowser.Api/TvShowsService.cs +++ b/MediaBrowser.Api/TvShowsService.cs @@ -81,8 +81,11 @@ namespace MediaBrowser.Api [ApiMember(Name = "Season", Description = "Optional filter by season number.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public int? Season { get; set; } - [ApiMember(Name = "ExcludeLocationTypes", Description = "Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] - public string ExcludeLocationTypes { get; set; } + [ApiMember(Name = "IsMissing", Description = "Optional filter by items that are missing episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] + public bool? IsMissing { get; set; } + + [ApiMember(Name = "IsVirtualUnaired", Description = "Optional filter by items that are virtual unaired episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] + public bool? IsVirtualUnaired { get; set; } } [Route("/Shows/{Id}/Seasons", "GET")] @@ -106,11 +109,14 @@ namespace MediaBrowser.Api [ApiMember(Name = "Id", Description = "The series id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] public Guid Id { get; set; } - [ApiMember(Name = "ExcludeLocationTypes", Description = "Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] - public string ExcludeLocationTypes { get; set; } - [ApiMember(Name = "IsSpecialSeason", Description = "Optional. Filter by special season.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool? IsSpecialSeason { get; set; } + + [ApiMember(Name = "IsMissing", Description = "Optional filter by items that are missing episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] + public bool? IsMissing { get; set; } + + [ApiMember(Name = "IsVirtualUnaired", Description = "Optional filter by items that are virtual unaired episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] + public bool? IsVirtualUnaired { get; set; } } /// @@ -380,12 +386,7 @@ namespace MediaBrowser.Api } } - // ExcludeLocationTypes - if (!string.IsNullOrEmpty(request.ExcludeLocationTypes)) - { - var vals = request.ExcludeLocationTypes.Split(','); - seasons = seasons.Where(f => !vals.Contains(f.LocationType.ToString(), StringComparer.OrdinalIgnoreCase)); - } + seasons = FilterVirtualSeasons(request, seasons); seasons = _libraryManager.Sort(seasons, user, new[] { sortOrder }, SortOrder.Ascending) .Cast(); @@ -400,6 +401,34 @@ namespace MediaBrowser.Api }; } + private IEnumerable FilterVirtualSeasons(GetSeasons request, IEnumerable items) + { + if (request.IsMissing.HasValue && request.IsVirtualUnaired.HasValue) + { + var isMissing = request.IsMissing.Value; + var isVirtualUnaired = request.IsVirtualUnaired.Value; + + if (!isMissing && !isVirtualUnaired) + { + return items.Where(i => !i.IsMissingOrVirtualUnaired); + } + } + + if (request.IsMissing.HasValue) + { + var val = request.IsMissing.Value; + items = items.Where(i => i.IsMissingSeason == val); + } + + if (request.IsVirtualUnaired.HasValue) + { + var val = request.IsVirtualUnaired.Value; + items = items.Where(i => i.IsVirtualUnaired == val); + } + + return items; + } + public object Get(GetEpisodes request) { var user = _userManager.GetUserById(request.UserId); @@ -431,11 +460,16 @@ namespace MediaBrowser.Api episodes = episodes.Where(i => !i.IsVirtualUnaired); } - // ExcludeLocationTypes - if (!string.IsNullOrEmpty(request.ExcludeLocationTypes)) + if (request.IsMissing.HasValue) { - var vals = request.ExcludeLocationTypes.Split(','); - episodes = episodes.Where(f => !vals.Contains(f.LocationType.ToString(), StringComparer.OrdinalIgnoreCase)); + var val = request.IsMissing.Value; + episodes = episodes.Where(i => i.IsMissingEpisode == val); + } + + if (request.IsVirtualUnaired.HasValue) + { + var val = request.IsVirtualUnaired.Value; + episodes = episodes.Where(i => i.IsVirtualUnaired == val); } episodes = _libraryManager.Sort(episodes, user, new[] { sortOrder }, SortOrder.Ascending) diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs index ee22b7baa2..f1d8c94e55 100644 --- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs +++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs @@ -218,7 +218,7 @@ namespace MediaBrowser.Common.Implementations try { // Increase the max http request limit - ServicePointManager.DefaultConnectionLimit = Math.Max(48, ServicePointManager.DefaultConnectionLimit); + ServicePointManager.DefaultConnectionLimit = Math.Max(96, ServicePointManager.DefaultConnectionLimit); } catch (Exception ex) { diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs index 0d6ba5c1da..181c83fd3a 100644 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Configuration; +using System.Reflection; +using MediaBrowser.Common.Configuration; using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Model.Logging; diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs index e04cadfc5a..6d886bc696 100644 --- a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs @@ -29,7 +29,6 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks /// /// Initializes a new instance of the class. /// - /// The app paths. public DeleteCacheFileTask(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem) { ApplicationPaths = appPaths; diff --git a/MediaBrowser.Common/ScheduledTasks/IScheduledTask.cs b/MediaBrowser.Common/ScheduledTasks/IScheduledTask.cs index 351e96c7d5..2ee4fb4b50 100644 --- a/MediaBrowser.Common/ScheduledTasks/IScheduledTask.cs +++ b/MediaBrowser.Common/ScheduledTasks/IScheduledTask.cs @@ -42,4 +42,9 @@ namespace MediaBrowser.Common.ScheduledTasks /// IEnumerable{BaseTaskTrigger}. IEnumerable GetDefaultTriggers(); } + + public interface IConfigurableScheduledTask + { + bool IsHidden { get; } + } } diff --git a/MediaBrowser.Common/ScheduledTasks/ScheduledTaskHelpers.cs b/MediaBrowser.Common/ScheduledTasks/ScheduledTaskHelpers.cs index f316509869..39148166bc 100644 --- a/MediaBrowser.Common/ScheduledTasks/ScheduledTaskHelpers.cs +++ b/MediaBrowser.Common/ScheduledTasks/ScheduledTaskHelpers.cs @@ -16,6 +16,15 @@ namespace MediaBrowser.Common.ScheduledTasks /// TaskInfo. public static TaskInfo GetTaskInfo(IScheduledTaskWorker task) { + var isHidden = false; + + var configurableTask = task.ScheduledTask as IConfigurableScheduledTask; + + if (configurableTask != null) + { + isHidden = configurableTask.IsHidden; + } + return new TaskInfo { Name = task.Name, @@ -25,7 +34,8 @@ namespace MediaBrowser.Common.ScheduledTasks LastExecutionResult = task.LastExecutionResult, Triggers = task.Triggers.Select(GetTriggerInfo).ToList(), Description = task.Description, - Category = task.Category + Category = task.Category, + IsHidden = isHidden }; } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 7938c38ec9..d5b9cea270 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -24,6 +24,20 @@ namespace MediaBrowser.Controller.LiveTv /// Task. Task ScheduleRecording(string programId); + /// + /// Deletes the recording. + /// + /// The identifier. + /// Task. + Task DeleteRecording(string id); + + /// + /// Cancels the timer. + /// + /// The identifier. + /// Task. + Task CancelTimer(string id); + /// /// Adds the parts. /// diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs index e903ad5ec6..9bc032af35 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs @@ -47,14 +47,6 @@ namespace MediaBrowser.Controller.LiveTv /// Task. Task CreateTimerAsync(TimerInfo info, CancellationToken cancellationToken); - /// - /// Updates the timer asynchronous. - /// - /// The information. - /// The cancellation token. - /// Task. - Task UpdateTimerAsync(TimerInfo info, CancellationToken cancellationToken); - /// /// Gets the channel image asynchronous. /// diff --git a/MediaBrowser.Controller/LiveTv/RecordingInfo.cs b/MediaBrowser.Controller/LiveTv/RecordingInfo.cs index f0daac5f91..88d093f645 100644 --- a/MediaBrowser.Controller/LiveTv/RecordingInfo.cs +++ b/MediaBrowser.Controller/LiveTv/RecordingInfo.cs @@ -40,6 +40,12 @@ namespace MediaBrowser.Controller.LiveTv /// public DateTime EndDate { get; set; } + /// + /// Gets or sets the program identifier. + /// + /// The program identifier. + public string ProgramId { get; set; } + /// /// Gets or sets the status. /// diff --git a/MediaBrowser.Controller/LiveTv/TimerInfo.cs b/MediaBrowser.Controller/LiveTv/TimerInfo.cs index f0f936b526..7401dafec9 100644 --- a/MediaBrowser.Controller/LiveTv/TimerInfo.cs +++ b/MediaBrowser.Controller/LiveTv/TimerInfo.cs @@ -1,6 +1,5 @@ using MediaBrowser.Model.LiveTv; using System; -using System.Collections.Generic; namespace MediaBrowser.Controller.LiveTv { @@ -21,6 +20,12 @@ namespace MediaBrowser.Controller.LiveTv /// public string ChannelName { get; set; } + /// + /// Gets or sets the program identifier. + /// + /// The program identifier. + public string ProgramId { get; set; } + /// /// Name of the recording. /// @@ -52,16 +57,5 @@ namespace MediaBrowser.Controller.LiveTv /// /// true if this instance is recurring; otherwise, false. public bool IsRecurring { get; set; } - - /// - /// Gets or sets the recurring days. - /// - /// The recurring days. - public List RecurringDays { get; set; } - - public TimerInfo() - { - RecurringDays = new List(); - } } } diff --git a/MediaBrowser.Model/LiveTv/RecordingStatus.cs b/MediaBrowser.Model/LiveTv/RecordingStatus.cs index b8af8f6e22..7789773407 100644 --- a/MediaBrowser.Model/LiveTv/RecordingStatus.cs +++ b/MediaBrowser.Model/LiveTv/RecordingStatus.cs @@ -10,4 +10,11 @@ namespace MediaBrowser.Model.LiveTv Conflicted, Deleted } + + public enum RecurrenceType + { + Manual, + NewProgramEvents, + AllProgramEvents + } } diff --git a/MediaBrowser.Model/LiveTv/TimerInfoDto.cs b/MediaBrowser.Model/LiveTv/TimerInfoDto.cs index 6a8339031a..ddefce59e2 100644 --- a/MediaBrowser.Model/LiveTv/TimerInfoDto.cs +++ b/MediaBrowser.Model/LiveTv/TimerInfoDto.cs @@ -1,11 +1,10 @@ using System; -using System.Collections.Generic; namespace MediaBrowser.Model.LiveTv { public class TimerInfoDto { - /// + /// /// Id of the recording. /// public string Id { get; set; } @@ -15,7 +14,7 @@ namespace MediaBrowser.Model.LiveTv /// /// The external identifier. public string ExternalId { get; set; } - + /// /// ChannelId of the recording. /// @@ -26,6 +25,12 @@ namespace MediaBrowser.Model.LiveTv /// public string ChannelName { get; set; } + /// + /// Gets or sets the program identifier. + /// + /// The program identifier. + public string ProgramId { get; set; } + /// /// Name of the recording. /// @@ -57,16 +62,5 @@ namespace MediaBrowser.Model.LiveTv /// /// true if this instance is recurring; otherwise, false. public bool IsRecurring { get; set; } - - /// - /// Gets or sets the recurring days. - /// - /// The recurring days. - public List RecurringDays { get; set; } - - public TimerInfoDto() - { - RecurringDays = new List(); - } - } + } } diff --git a/MediaBrowser.Model/Querying/EpisodeQuery.cs b/MediaBrowser.Model/Querying/EpisodeQuery.cs index 406ac9844f..56c50da7f7 100644 --- a/MediaBrowser.Model/Querying/EpisodeQuery.cs +++ b/MediaBrowser.Model/Querying/EpisodeQuery.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Model.Entities; - + namespace MediaBrowser.Model.Querying { public class EpisodeQuery @@ -8,7 +7,9 @@ namespace MediaBrowser.Model.Querying public string SeriesId { get; set; } - public LocationType[] ExcludeLocationTypes { get; set; } + public bool? IsMissing { get; set; } + + public bool? IsVirtualUnaired { get; set; } public int? SeasonNumber { get; set; } @@ -17,7 +18,6 @@ namespace MediaBrowser.Model.Querying public EpisodeQuery() { Fields = new ItemFields[] { }; - ExcludeLocationTypes = new LocationType[] { }; } } @@ -27,7 +27,9 @@ namespace MediaBrowser.Model.Querying public string SeriesId { get; set; } - public LocationType[] ExcludeLocationTypes { get; set; } + public bool? IsMissing { get; set; } + + public bool? IsVirtualUnaired { get; set; } public ItemFields[] Fields { get; set; } @@ -36,7 +38,6 @@ namespace MediaBrowser.Model.Querying public SeasonQuery() { Fields = new ItemFields[] { }; - ExcludeLocationTypes = new LocationType[] { }; } } } diff --git a/MediaBrowser.Model/Tasks/TaskInfo.cs b/MediaBrowser.Model/Tasks/TaskInfo.cs index dee4fea7fc..a7d500303d 100644 --- a/MediaBrowser.Model/Tasks/TaskInfo.cs +++ b/MediaBrowser.Model/Tasks/TaskInfo.cs @@ -56,6 +56,12 @@ namespace MediaBrowser.Model.Tasks /// The category. public string Category { get; set; } + /// + /// Gets or sets a value indicating whether this instance is hidden. + /// + /// true if this instance is hidden; otherwise, false. + public bool IsHidden { get; set; } + /// /// Initializes a new instance of the class. /// diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 00ac83f15c..4d3d877889 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -397,6 +397,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv Status = info.Status }; + if (!string.IsNullOrEmpty(info.ProgramId)) + { + dto.ProgramId = GetInternalProgramIdId(service.Name, info.ProgramId).ToString("N"); + } + return dto; } @@ -503,13 +508,61 @@ namespace MediaBrowser.Server.Implementations.LiveTv ExternalId = info.Id, ChannelId = GetInternalChannelId(service.Name, info.ChannelId).ToString("N"), Status = info.Status, - IsRecurring = info.IsRecurring, - RecurringDays = info.RecurringDays + IsRecurring = info.IsRecurring }; + if (!string.IsNullOrEmpty(info.ProgramId)) + { + dto.ProgramId = GetInternalProgramIdId(service.Name, info.ProgramId).ToString("N"); + } + return dto; } + public async Task DeleteRecording(string recordingId) + { + var recordings = await GetRecordings(new RecordingQuery + { + }, CancellationToken.None).ConfigureAwait(false); + + var recording = recordings.Items + .FirstOrDefault(i => string.Equals(recordingId, i.Id, StringComparison.OrdinalIgnoreCase)); + + if (recording == null) + { + throw new ResourceNotFoundException(string.Format("Recording with Id {0} not found", recordingId)); + } + + var channel = GetChannel(recording.ChannelId); + + var service = GetServices(channel.ServiceName, null) + .First(); + + await service.DeleteRecordingAsync(recording.ExternalId, CancellationToken.None).ConfigureAwait(false); + } + + public async Task CancelTimer(string id) + { + var timers = await GetTimers(new TimerQuery + { + + }, CancellationToken.None).ConfigureAwait(false); + + var timer = timers.Items + .FirstOrDefault(i => string.Equals(id, i.Id, StringComparison.OrdinalIgnoreCase)); + + if (timer == null) + { + throw new ResourceNotFoundException(string.Format("Timer with Id {0} not found", id)); + } + + var channel = GetChannel(timer.ChannelId); + + var service = GetServices(channel.ServiceName, null) + .First(); + + await service.CancelTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false); + } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs b/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs index c3803d9bbc..00bf9e55ba 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace MediaBrowser.Server.Implementations.LiveTv { - class RefreshChannelsScheduledTask : IScheduledTask + class RefreshChannelsScheduledTask : IScheduledTask, IConfigurableScheduledTask { private readonly ILiveTvManager _liveTvManager; @@ -33,7 +33,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv public Task Execute(System.Threading.CancellationToken cancellationToken, IProgress progress) { - var manager = (LiveTvManager) _liveTvManager; + var manager = (LiveTvManager)_liveTvManager; return manager.RefreshChannels(progress, cancellationToken); } @@ -50,5 +50,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv new IntervalTrigger{ Interval = TimeSpan.FromHours(2)} }; } + + public bool IsHidden + { + get { return _liveTvManager.Services.Count == 0; } + } } } diff --git a/MediaBrowser.ServerApplication/Native/HttpClientFactory.cs b/MediaBrowser.ServerApplication/Native/HttpClientFactory.cs index 57f00ba03b..368c60254b 100644 --- a/MediaBrowser.ServerApplication/Native/HttpClientFactory.cs +++ b/MediaBrowser.ServerApplication/Native/HttpClientFactory.cs @@ -17,14 +17,19 @@ namespace MediaBrowser.ServerApplication.Native /// HttpClient. public static HttpClient GetHttpClient(bool enableHttpCompression) { - return new HttpClient(new WebRequestHandler + var client = new HttpClient(new WebRequestHandler { CachePolicy = new RequestCachePolicy(RequestCacheLevel.Revalidate), AutomaticDecompression = enableHttpCompression ? DecompressionMethods.Deflate : DecompressionMethods.None + }) { Timeout = TimeSpan.FromSeconds(20) }; + + client.DefaultRequestHeaders.Add("Connection", "Keep-Alive"); + + return client; } } } diff --git a/MediaBrowser.WebDashboard/ApiClient.js b/MediaBrowser.WebDashboard/ApiClient.js index 36476511ec..de96c4de94 100644 --- a/MediaBrowser.WebDashboard/ApiClient.js +++ b/MediaBrowser.WebDashboard/ApiClient.js @@ -506,6 +506,20 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi }); }; + self.createLiveTvTimer = function (options) { + + if (!options) { + throw new Error("null options"); + } + + var url = self.getUrl("LiveTv/Timers", options); + + return self.ajax({ + type: "POST", + url: url + }); + }; + /** * Gets the current server status */ @@ -1019,9 +1033,11 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi /** * Gets the server's scheduled tasks */ - self.getScheduledTasks = function () { + self.getScheduledTasks = function (options) { - var url = self.getUrl("ScheduledTasks"); + options = options || {}; + + var url = self.getUrl("ScheduledTasks", options); return self.ajax({ type: "GET", diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 5585e0db5e..4aca619aa3 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -284,10 +284,10 @@ PreserveNewest - + PreserveNewest - + PreserveNewest diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config index 25938a358a..a839ece186 100644 --- a/MediaBrowser.WebDashboard/packages.config +++ b/MediaBrowser.WebDashboard/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index 51bdf43d66..77765ddc62 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.252 + 3.0.253 MediaBrowser.Common.Internal Luke ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption. Copyright © Media Browser 2013 - + diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index 6ccfca542e..ac6b606cda 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.252 + 3.0.253 MediaBrowser.Common Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index de9b90a461..a6c1bee112 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.252 + 3.0.253 Media Browser.Server.Core Media Browser Team ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains core components required to build plugins for Media Browser Server. Copyright © Media Browser 2013 - +