diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index 9112518b86..27881d12ba 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -269,6 +269,19 @@ namespace MediaBrowser.Api.Images
public Guid Id { get; set; }
}
+ [Route("/LiveTv/Channels/{Id}/Images/{Type}", "DELETE")]
+ [Route("/LiveTv/Channels/{Id}/Images/{Type}/{Index}", "DELETE")]
+ [Api(Description = "Deletes an item image")]
+ public class DeleteChannelImage : DeleteImageRequest, IReturnVoid
+ {
+ ///
+ /// Gets or sets the id.
+ ///
+ /// The id.
+ [ApiMember(Name = "Id", Description = "Channel Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
+ public string Id { get; set; }
+ }
+
///
/// Class PostUserImage
///
@@ -344,6 +357,25 @@ namespace MediaBrowser.Api.Images
public Stream RequestStream { get; set; }
}
+ [Route("/LiveTv/Channels/{Id}/Images/{Type}", "POST")]
+ [Route("/LiveTv/Channels/{Id}/Images/{Type}/{Index}", "POST")]
+ [Api(Description = "Posts an item image")]
+ public class PostChannelImage : DeleteImageRequest, IRequiresRequestStream, IReturnVoid
+ {
+ ///
+ /// Gets or sets the id.
+ ///
+ /// The id.
+ [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
+ public string Id { get; set; }
+
+ ///
+ /// The raw Http Request Input Stream
+ ///
+ /// The request stream.
+ public Stream RequestStream { get; set; }
+ }
+
///
/// Class ImageService
///
@@ -622,6 +654,20 @@ namespace MediaBrowser.Api.Images
Task.WaitAll(task);
}
+ public void Post(PostChannelImage request)
+ {
+ var pathInfo = PathInfo.Parse(RequestContext.PathInfo);
+ var id = pathInfo.GetArgumentValue(2);
+
+ request.Type = (ImageType)Enum.Parse(typeof(ImageType), pathInfo.GetArgumentValue(4), true);
+
+ var item = _liveTv.GetChannel(id);
+
+ var task = PostImage(item, request.RequestStream, request.Type, RequestContext.ContentType);
+
+ Task.WaitAll(task);
+ }
+
///
/// Deletes the specified request.
///
@@ -648,6 +694,15 @@ namespace MediaBrowser.Api.Images
Task.WaitAll(task);
}
+ public void Delete(DeleteChannelImage request)
+ {
+ var item = _liveTv.GetChannel(request.Id);
+
+ var task = item.DeleteImage(request.Type, request.Index);
+
+ Task.WaitAll(task);
+ }
+
///
/// Deletes the specified request.
///
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index db50f463d4..2961c920f8 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -57,6 +57,17 @@ namespace MediaBrowser.Api.LiveTv
public string ChannelId { get; set; }
}
+ [Route("/LiveTv/Timers", "GET")]
+ [Api(Description = "Gets live tv timers")]
+ public class GetTimers : IReturn>
+ {
+ [ApiMember(Name = "ServiceName", Description = "Optional filter by service.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string ServiceName { get; set; }
+
+ [ApiMember(Name = "ChannelId", Description = "Optional filter by channel id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string ChannelId { get; set; }
+ }
+
[Route("/LiveTv/Programs", "GET")]
[Api(Description = "Gets available live tv epgs..")]
public class GetPrograms : IReturn>
@@ -153,5 +164,17 @@ namespace MediaBrowser.Api.LiveTv
return ToOptimizedResult(result);
}
+
+ public object Get(GetTimers request)
+ {
+ var result = _liveTvManager.GetTimers(new TimerQuery
+ {
+ ChannelId = request.ChannelId,
+ ServiceName = request.ServiceName
+
+ }, CancellationToken.None).Result;
+
+ return ToOptimizedResult(result);
+ }
}
}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
index 91634b4bfb..7938c38ec9 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
@@ -45,6 +45,14 @@ namespace MediaBrowser.Controller.LiveTv
/// QueryResult{RecordingInfoDto}.
Task> GetRecordings(RecordingQuery query, CancellationToken cancellationToken);
+ ///
+ /// Gets the timers.
+ ///
+ /// The query.
+ /// The cancellation token.
+ /// Task{QueryResult{TimerInfoDto}}.
+ Task> GetTimers(TimerQuery query, CancellationToken cancellationToken);
+
///
/// Gets the channel.
///
diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
index 6962cb470b..67888aa46d 100644
--- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
+++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
@@ -251,6 +251,9 @@
LiveTv\RecordingStatus.cs
+
+ LiveTv\TimerInfoDto.cs
+
Logging\ILogger.cs
diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
index 0bf2684bfd..cfe4a5462f 100644
--- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
+++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
@@ -238,6 +238,9 @@
LiveTv\RecordingStatus.cs
+
+ LiveTv\TimerInfoDto.cs
+
Logging\ILogger.cs
diff --git a/MediaBrowser.Model/LiveTv/RecordingQuery.cs b/MediaBrowser.Model/LiveTv/RecordingQuery.cs
index 8c83b0fcbd..0820c7785e 100644
--- a/MediaBrowser.Model/LiveTv/RecordingQuery.cs
+++ b/MediaBrowser.Model/LiveTv/RecordingQuery.cs
@@ -17,4 +17,19 @@
/// The name of the service.
public string ServiceName { get; set; }
}
+
+ public class TimerQuery
+ {
+ ///
+ /// Gets or sets the channel identifier.
+ ///
+ /// The channel identifier.
+ public string ChannelId { get; set; }
+
+ ///
+ /// Gets or sets the name of the service.
+ ///
+ /// The name of the service.
+ public string ServiceName { get; set; }
+ }
}
diff --git a/MediaBrowser.Model/LiveTv/TimerInfoDto.cs b/MediaBrowser.Model/LiveTv/TimerInfoDto.cs
new file mode 100644
index 0000000000..6a8339031a
--- /dev/null
+++ b/MediaBrowser.Model/LiveTv/TimerInfoDto.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Model.LiveTv
+{
+ public class TimerInfoDto
+ {
+ ///
+ /// Id of the recording.
+ ///
+ public string Id { get; set; }
+
+ ///
+ /// Gets or sets the external identifier.
+ ///
+ /// The external identifier.
+ public string ExternalId { get; set; }
+
+ ///
+ /// ChannelId of the recording.
+ ///
+ public string ChannelId { get; set; }
+
+ ///
+ /// ChannelName of the recording.
+ ///
+ public string ChannelName { get; set; }
+
+ ///
+ /// Name of the recording.
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Description of the recording.
+ ///
+ public string Description { get; set; }
+
+ ///
+ /// The start date of the recording, in UTC.
+ ///
+ public DateTime StartDate { get; set; }
+
+ ///
+ /// The end date of the recording, in UTC.
+ ///
+ public DateTime EndDate { get; set; }
+
+ ///
+ /// Gets or sets the status.
+ ///
+ /// The status.
+ public RecordingStatus Status { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether this instance is recurring.
+ ///
+ /// 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/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index 1cbdc60efa..103e583aed 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -66,6 +66,7 @@
+
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
index 12241876a1..00ac83f15c 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -417,7 +417,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
.ToList();
}
- var returnArray = list.ToArray();
+ var returnArray = list.OrderByDescending(i => i.StartDate)
+ .ToArray();
return new QueryResult
{
@@ -451,5 +452,64 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
throw new NotImplementedException();
}
+
+ public async Task> GetTimers(TimerQuery query, CancellationToken cancellationToken)
+ {
+ var list = new List();
+
+ foreach (var service in GetServices(query.ServiceName, query.ChannelId))
+ {
+ var timers = await GetTimers(service, cancellationToken).ConfigureAwait(false);
+
+ list.AddRange(timers);
+ }
+
+ if (!string.IsNullOrEmpty(query.ChannelId))
+ {
+ list = list.Where(i => string.Equals(i.ChannelId, query.ChannelId))
+ .ToList();
+ }
+
+ var returnArray = list.OrderByDescending(i => i.StartDate)
+ .ToArray();
+
+ return new QueryResult
+ {
+ Items = returnArray,
+ TotalRecordCount = returnArray.Length
+ };
+ }
+
+ private async Task> GetTimers(ILiveTvService service, CancellationToken cancellationToken)
+ {
+ var timers = await service.GetTimersAsync(cancellationToken).ConfigureAwait(false);
+
+ return timers.Select(i => GetTimerInfoDto(i, service));
+ }
+
+ private TimerInfoDto GetTimerInfoDto(TimerInfo info, ILiveTvService service)
+ {
+ var id = service.Name + info.ChannelId + info.Id;
+ id = id.GetMD5().ToString("N");
+
+ var dto = new TimerInfoDto
+ {
+ ChannelName = info.ChannelName,
+ Description = info.Description,
+ EndDate = info.EndDate,
+ Name = info.Name,
+ StartDate = info.StartDate,
+ Id = id,
+ ExternalId = info.Id,
+ ChannelId = GetInternalChannelId(service.Name, info.ChannelId).ToString("N"),
+ Status = info.Status,
+ IsRecurring = info.IsRecurring,
+ RecurringDays = info.RecurringDays
+ };
+
+ return dto;
+ }
+
+
}
}
diff --git a/MediaBrowser.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs b/MediaBrowser.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs
index bdc343dea6..76971342a0 100644
--- a/MediaBrowser.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs
+++ b/MediaBrowser.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs
@@ -22,7 +22,7 @@ namespace MediaBrowser.Server.Implementations.Sorting
if (val != 0)
{
- return val;
+ //return val;
}
}
@@ -49,8 +49,8 @@ namespace MediaBrowser.Server.Implementations.Sorting
private int Compare(Episode x, Episode y)
{
- var isXSpecial = (x.ParentIndexNumber ?? -1) == 0;
- var isYSpecial = (y.ParentIndexNumber ?? -1) == 0;
+ var isXSpecial = (x.PhysicalSeasonNumber ?? -1) == 0;
+ var isYSpecial = (y.PhysicalSeasonNumber ?? -1) == 0;
if (isXSpecial && isYSpecial)
{
@@ -67,12 +67,12 @@ namespace MediaBrowser.Server.Implementations.Sorting
return CompareEpisodeToSpecial(x, y);
}
- return CompareEpisodeToSpecial(x, y) * -1;
+ return CompareEpisodeToSpecial(y, x) * -1;
}
private int CompareEpisodeToSpecial(Episode x, Episode y)
{
- var xSeason = x.ParentIndexNumber ?? -1;
+ var xSeason = x.PhysicalSeasonNumber ?? -1;
var ySeason = y.AirsAfterSeasonNumber ?? y.AirsBeforeSeasonNumber ?? -1;
if (xSeason != ySeason)
@@ -85,8 +85,9 @@ namespace MediaBrowser.Server.Implementations.Sorting
// Compare episode number
// Add 1 to to non-specials to account for AirsBeforeEpisodeNumber
- var xEpisode = (x.IndexNumber ?? 0) * 1000 + 1;
- var yEpisode = (y.AirsBeforeEpisodeNumber ?? 0) * 1000;
+ var xEpisode = x.IndexNumber ?? -1;
+ xEpisode++;
+ var yEpisode = y.AirsBeforeEpisodeNumber ?? 10000;
return xEpisode.CompareTo(yEpisode);
}
@@ -119,8 +120,8 @@ namespace MediaBrowser.Server.Implementations.Sorting
private int CompareEpisodes(Episode x, Episode y)
{
- var xValue = ((x.ParentIndexNumber ?? -1) * 1000) + (x.IndexNumber ?? -1);
- var yValue = ((y.ParentIndexNumber ?? -1) * 1000) + (y.IndexNumber ?? -1);
+ var xValue = ((x.PhysicalSeasonNumber ?? -1) * 1000) + (x.IndexNumber ?? -1);
+ var yValue = ((y.PhysicalSeasonNumber ?? -1) * 1000) + (y.IndexNumber ?? -1);
return xValue.CompareTo(yValue);
}
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index f24283e70d..cfacffe087 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -119,9 +119,9 @@
..\packages\Hardcodet.Wpf.TaskbarNotification.1.0.4.0\lib\net40\Hardcodet.Wpf.TaskbarNotification.dll
-
+
False
- ..\packages\MediaBrowser.IsoMounting.3.0.61\lib\net45\MediaBrowser.IsoMounter.dll
+ ..\packages\MediaBrowser.IsoMounting.3.0.65\lib\net45\MediaBrowser.IsoMounter.dll
False
@@ -129,7 +129,7 @@
False
- ..\packages\MediaBrowser.IsoMounting.3.0.61\lib\net45\pfmclrapi.dll
+ ..\packages\MediaBrowser.IsoMounting.3.0.65\lib\net45\pfmclrapi.dll
False
diff --git a/MediaBrowser.ServerApplication/packages.config b/MediaBrowser.ServerApplication/packages.config
index 0893a1b38a..e01ca1f672 100644
--- a/MediaBrowser.ServerApplication/packages.config
+++ b/MediaBrowser.ServerApplication/packages.config
@@ -1,7 +1,7 @@
-
+
diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs
index 2b74eebb0c..69f05631f3 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardService.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs
@@ -430,7 +430,7 @@ namespace MediaBrowser.WebDashboard.Api
"http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js",
"http://code.jquery.com/mobile/1.3.2/jquery.mobile-1.3.2.min.js",
"scripts/all.js" + versionString,
- "thirdparty/jstree1.0fix2/jquery.jstree.js"
+ "thirdparty/jstree1.0fix3/jquery.jstree.js"
};
var tags = files.Select(s => string.Format("", s)).ToArray();
@@ -483,6 +483,7 @@ namespace MediaBrowser.WebDashboard.Api
"livetvchannels.js",
"livetvguide.js",
"livetvrecordings.js",
+ "livetvtimers.js",
"loginpage.js",
"logpage.js",
"medialibrarypage.js",
diff --git a/MediaBrowser.WebDashboard/ApiClient.js b/MediaBrowser.WebDashboard/ApiClient.js
index e63eb4d2b1..69f3f020cf 100644
--- a/MediaBrowser.WebDashboard/ApiClient.js
+++ b/MediaBrowser.WebDashboard/ApiClient.js
@@ -380,7 +380,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
self.getLiveTvServices = function (options) {
- var url = self.getUrl("/LiveTv/Services", options || {});
+ var url = self.getUrl("LiveTv/Services", options || {});
return self.ajax({
type: "GET",
@@ -395,7 +395,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
throw new Error("null id");
}
- var url = self.getUrl("/LiveTv/Channels/" + id);
+ var url = self.getUrl("LiveTv/Channels/" + id);
return self.ajax({
type: "GET",
@@ -406,7 +406,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
self.getLiveTvChannels = function (options) {
- var url = self.getUrl("/LiveTv/Channels", options || {});
+ var url = self.getUrl("LiveTv/Channels", options || {});
return self.ajax({
type: "GET",
@@ -417,7 +417,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
self.getLiveTvPrograms = function (options) {
- var url = self.getUrl("/LiveTv/Programs", options || {});
+ var url = self.getUrl("LiveTv/Programs", options || {});
return self.ajax({
type: "GET",
@@ -428,7 +428,76 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
self.getLiveTvRecordings = function (options) {
- var url = self.getUrl("/LiveTv/Recordings", options || {});
+ var url = self.getUrl("LiveTv/Recordings", options || {});
+
+ return self.ajax({
+ type: "GET",
+ url: url,
+ dataType: "json"
+ });
+ };
+
+ self.getLiveTvRecording = function (id) {
+
+ if (!id) {
+ throw new Error("null id");
+ }
+
+ var url = self.getUrl("LiveTv/Recordings/" + id);
+
+ return self.ajax({
+ type: "GET",
+ url: url,
+ dataType: "json"
+ });
+ };
+
+ self.deleteLiveTvRecording = function (id) {
+
+ if (!id) {
+ throw new Error("null id");
+ }
+
+ var url = self.getUrl("LiveTv/Recordings/" + id);
+
+ return self.ajax({
+ type: "DELETE",
+ url: url
+ });
+ };
+
+ self.cancelLiveTvTimer = function (id) {
+
+ if (!id) {
+ throw new Error("null id");
+ }
+
+ var url = self.getUrl("LiveTv/Timers/" + id);
+
+ return self.ajax({
+ type: "DELETE",
+ url: url
+ });
+ };
+
+ self.getLiveTvTimers = function (options) {
+
+ var url = self.getUrl("LiveTv/Timers", options || {});
+
+ return self.ajax({
+ type: "GET",
+ url: url,
+ dataType: "json"
+ });
+ };
+
+ self.getLiveTvTimer = function (id) {
+
+ if (!id) {
+ throw new Error("null id");
+ }
+
+ var url = self.getUrl("LiveTv/Timers/" + id);
return self.ajax({
type: "GET",
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index 54e70cb9ab..5585e0db5e 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -80,9 +80,18 @@
+
+ PreserveNewest
+
+
+ PreserveNewest
+
PreserveNewest
+
+ PreserveNewest
+
PreserveNewest
@@ -281,18 +290,6 @@
PreserveNewest
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
PreserveNewest
@@ -350,6 +347,9 @@
PreserveNewest
+
+ PreserveNewest
+
PreserveNewest
@@ -595,76 +595,76 @@
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
-
+
PreserveNewest
diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config
index ab57a48b15..35511052f4 100644
--- a/MediaBrowser.WebDashboard/packages.config
+++ b/MediaBrowser.WebDashboard/packages.config
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file