LiveTvService.cs 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Security.Cryptography;
  7. using System.Text;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. using MediaBrowser.Api.UserLibrary;
  11. using MediaBrowser.Common;
  12. using MediaBrowser.Common.Configuration;
  13. using MediaBrowser.Common.Net;
  14. using MediaBrowser.Controller.Configuration;
  15. using MediaBrowser.Controller.Dto;
  16. using MediaBrowser.Controller.Entities;
  17. using MediaBrowser.Controller.Entities.TV;
  18. using MediaBrowser.Controller.Library;
  19. using MediaBrowser.Controller.LiveTv;
  20. using MediaBrowser.Controller.Net;
  21. using MediaBrowser.Model.Dto;
  22. using MediaBrowser.Model.Entities;
  23. using MediaBrowser.Model.IO;
  24. using MediaBrowser.Model.LiveTv;
  25. using MediaBrowser.Model.Querying;
  26. using MediaBrowser.Model.Services;
  27. using Microsoft.Extensions.Logging;
  28. using Microsoft.Net.Http.Headers;
  29. namespace MediaBrowser.Api.LiveTv
  30. {
  31. /// <summary>
  32. /// This is insecure right now to avoid windows phone refactoring
  33. /// </summary>
  34. [Route("/LiveTv/Info", "GET", Summary = "Gets available live tv services.")]
  35. [Authenticated]
  36. public class GetLiveTvInfo : IReturn<LiveTvInfo>
  37. {
  38. }
  39. [Route("/LiveTv/Channels", "GET", Summary = "Gets available live tv channels.")]
  40. [Authenticated]
  41. public class GetChannels : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions
  42. {
  43. [ApiMember(Name = "Type", Description = "Optional filter by channel type.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  44. public ChannelType? Type { get; set; }
  45. [ApiMember(Name = "UserId", Description = "Optional filter by user and attach user data.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  46. public Guid UserId { get; set; }
  47. /// <summary>
  48. /// Skips over a given number of items within the results. Use for paging.
  49. /// </summary>
  50. /// <value>The start index.</value>
  51. [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")]
  52. public int? StartIndex { get; set; }
  53. [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
  54. public bool? IsMovie { get; set; }
  55. [ApiMember(Name = "IsSeries", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
  56. public bool? IsSeries { get; set; }
  57. [ApiMember(Name = "IsNews", Description = "Optional filter for news.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
  58. public bool? IsNews { get; set; }
  59. [ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
  60. public bool? IsKids { get; set; }
  61. [ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
  62. public bool? IsSports { get; set; }
  63. /// <summary>
  64. /// The maximum number of items to return
  65. /// </summary>
  66. /// <value>The limit.</value>
  67. [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
  68. public int? Limit { get; set; }
  69. [ApiMember(Name = "IsFavorite", Description = "Filter by channels that are favorites, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
  70. public bool? IsFavorite { get; set; }
  71. [ApiMember(Name = "IsLiked", Description = "Filter by channels that are liked, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
  72. public bool? IsLiked { get; set; }
  73. [ApiMember(Name = "IsDisliked", Description = "Filter by channels that are disliked, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
  74. public bool? IsDisliked { get; set; }
  75. [ApiMember(Name = "EnableFavoriteSorting", Description = "Incorporate favorite and like status into channel sorting.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
  76. public bool EnableFavoriteSorting { get; set; }
  77. [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
  78. public bool? EnableImages { get; set; }
  79. [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
  80. public int? ImageTypeLimit { get; set; }
  81. [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  82. public string EnableImageTypes { get; set; }
  83. /// <summary>
  84. /// Fields to return within the items, in addition to basic information
  85. /// </summary>
  86. /// <value>The fields.</value>
  87. [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, 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)]
  88. public string Fields { get; set; }
  89. [ApiMember(Name = "AddCurrentProgram", Description = "Optional. Adds current program info to each channel", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  90. public bool AddCurrentProgram { get; set; }
  91. [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
  92. public bool? EnableUserData { get; set; }
  93. public string SortBy { get; set; }
  94. public SortOrder? SortOrder { get; set; }
  95. /// <summary>
  96. /// Gets the order by.
  97. /// </summary>
  98. /// <returns>IEnumerable{ItemSortBy}.</returns>
  99. public string[] GetOrderBy()
  100. {
  101. var val = SortBy;
  102. if (string.IsNullOrEmpty(val))
  103. {
  104. return Array.Empty<string>();
  105. }
  106. return val.Split(',');
  107. }
  108. public GetChannels()
  109. {
  110. AddCurrentProgram = true;
  111. }
  112. }
  113. [Route("/LiveTv/Channels/{Id}", "GET", Summary = "Gets a live tv channel")]
  114. [Authenticated]
  115. public class GetChannel : IReturn<BaseItemDto>
  116. {
  117. /// <summary>
  118. /// Gets or sets the id.
  119. /// </summary>
  120. /// <value>The id.</value>
  121. [ApiMember(Name = "Id", Description = "Channel Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
  122. public string Id { get; set; }
  123. [ApiMember(Name = "UserId", Description = "Optional attach user data.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  124. public Guid UserId { get; set; }
  125. }
  126. [Route("/LiveTv/Recordings", "GET", Summary = "Gets live tv recordings")]
  127. [Authenticated]
  128. public class GetRecordings : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions
  129. {
  130. [ApiMember(Name = "ChannelId", Description = "Optional filter by channel id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  131. public string ChannelId { get; set; }
  132. [ApiMember(Name = "UserId", Description = "Optional filter by user and attach user data.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  133. public Guid UserId { get; set; }
  134. [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")]
  135. public int? StartIndex { get; set; }
  136. [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
  137. public int? Limit { get; set; }
  138. [ApiMember(Name = "Status", Description = "Optional filter by recording status.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  139. public RecordingStatus? Status { get; set; }
  140. [ApiMember(Name = "Status", Description = "Optional filter by recordings that are in progress, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
  141. public bool? IsInProgress { get; set; }
  142. [ApiMember(Name = "SeriesTimerId", Description = "Optional filter by recordings belonging to a series timer", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  143. public string SeriesTimerId { get; set; }
  144. [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
  145. public bool? EnableImages { get; set; }
  146. [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
  147. public int? ImageTypeLimit { get; set; }
  148. [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  149. public string EnableImageTypes { get; set; }
  150. /// <summary>
  151. /// Fields to return within the items, in addition to basic information
  152. /// </summary>
  153. /// <value>The fields.</value>
  154. [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, 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)]
  155. public string Fields { get; set; }
  156. public bool EnableTotalRecordCount { get; set; }
  157. [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
  158. public bool? EnableUserData { get; set; }
  159. public bool? IsMovie { get; set; }
  160. public bool? IsSeries { get; set; }
  161. public bool? IsKids { get; set; }
  162. public bool? IsSports { get; set; }
  163. public bool? IsNews { get; set; }
  164. public bool? IsLibraryItem { get; set; }
  165. public GetRecordings()
  166. {
  167. EnableTotalRecordCount = true;
  168. }
  169. }
  170. [Route("/LiveTv/Recordings/Series", "GET", Summary = "Gets live tv recordings")]
  171. [Authenticated]
  172. public class GetRecordingSeries : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions
  173. {
  174. [ApiMember(Name = "ChannelId", Description = "Optional filter by channel id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  175. public string ChannelId { get; set; }
  176. [ApiMember(Name = "UserId", Description = "Optional filter by user and attach user data.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  177. public string UserId { get; set; }
  178. [ApiMember(Name = "GroupId", Description = "Optional filter by recording group.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  179. public string GroupId { get; set; }
  180. [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")]
  181. public int? StartIndex { get; set; }
  182. [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
  183. public int? Limit { get; set; }
  184. [ApiMember(Name = "Status", Description = "Optional filter by recording status.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  185. public RecordingStatus? Status { get; set; }
  186. [ApiMember(Name = "Status", Description = "Optional filter by recordings that are in progress, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
  187. public bool? IsInProgress { get; set; }
  188. [ApiMember(Name = "SeriesTimerId", Description = "Optional filter by recordings belonging to a series timer", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  189. public string SeriesTimerId { get; set; }
  190. [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
  191. public bool? EnableImages { get; set; }
  192. [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
  193. public int? ImageTypeLimit { get; set; }
  194. [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  195. public string EnableImageTypes { get; set; }
  196. /// <summary>
  197. /// Fields to return within the items, in addition to basic information
  198. /// </summary>
  199. /// <value>The fields.</value>
  200. [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, 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)]
  201. public string Fields { get; set; }
  202. public bool EnableTotalRecordCount { get; set; }
  203. [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
  204. public bool? EnableUserData { get; set; }
  205. public GetRecordingSeries()
  206. {
  207. EnableTotalRecordCount = true;
  208. }
  209. }
  210. [Route("/LiveTv/Recordings/Groups", "GET", Summary = "Gets live tv recording groups")]
  211. [Authenticated]
  212. public class GetRecordingGroups : IReturn<QueryResult<BaseItemDto>>
  213. {
  214. [ApiMember(Name = "UserId", Description = "Optional filter by user and attach user data.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  215. public string UserId { get; set; }
  216. }
  217. [Route("/LiveTv/Recordings/Folders", "GET", Summary = "Gets recording folders")]
  218. [Authenticated]
  219. public class GetRecordingFolders : IReturn<BaseItemDto[]>
  220. {
  221. [ApiMember(Name = "UserId", Description = "Optional filter by user and attach user data.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  222. public Guid UserId { get; set; }
  223. }
  224. [Route("/LiveTv/Recordings/{Id}", "GET", Summary = "Gets a live tv recording")]
  225. [Authenticated]
  226. public class GetRecording : IReturn<BaseItemDto>
  227. {
  228. [ApiMember(Name = "Id", Description = "Recording Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
  229. public string Id { get; set; }
  230. [ApiMember(Name = "UserId", Description = "Optional attach user data.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  231. public Guid UserId { get; set; }
  232. }
  233. [Route("/LiveTv/Tuners/{Id}/Reset", "POST", Summary = "Resets a tv tuner")]
  234. [Authenticated]
  235. public class ResetTuner : IReturnVoid
  236. {
  237. [ApiMember(Name = "Id", Description = "Tuner Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
  238. public string Id { get; set; }
  239. }
  240. [Route("/LiveTv/Timers/{Id}", "GET", Summary = "Gets a live tv timer")]
  241. [Authenticated]
  242. public class GetTimer : IReturn<TimerInfoDto>
  243. {
  244. [ApiMember(Name = "Id", Description = "Timer Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
  245. public string Id { get; set; }
  246. }
  247. [Route("/LiveTv/Timers/Defaults", "GET", Summary = "Gets default values for a new timer")]
  248. [Authenticated]
  249. public class GetDefaultTimer : IReturn<SeriesTimerInfoDto>
  250. {
  251. [ApiMember(Name = "ProgramId", Description = "Optional, to attach default values based on a program.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  252. public string ProgramId { get; set; }
  253. }
  254. [Route("/LiveTv/Timers", "GET", Summary = "Gets live tv timers")]
  255. [Authenticated]
  256. public class GetTimers : IReturn<QueryResult<TimerInfoDto>>
  257. {
  258. [ApiMember(Name = "ChannelId", Description = "Optional filter by channel id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  259. public string ChannelId { get; set; }
  260. [ApiMember(Name = "SeriesTimerId", Description = "Optional filter by timers belonging to a series timer", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  261. public string SeriesTimerId { get; set; }
  262. public bool? IsActive { get; set; }
  263. public bool? IsScheduled { get; set; }
  264. }
  265. [Route("/LiveTv/Programs", "GET,POST", Summary = "Gets available live tv epgs..")]
  266. [Authenticated]
  267. public class GetPrograms : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions
  268. {
  269. [ApiMember(Name = "ChannelIds", Description = "The channels to return guide information for.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
  270. public string ChannelIds { get; set; }
  271. [ApiMember(Name = "UserId", Description = "Optional filter by user id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
  272. public Guid UserId { get; set; }
  273. [ApiMember(Name = "MinStartDate", Description = "Optional. The minimum premiere date. Format = ISO", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
  274. public string MinStartDate { get; set; }
  275. [ApiMember(Name = "HasAired", Description = "Optional. Filter by programs that have completed airing, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
  276. public bool? HasAired { get; set; }
  277. public bool? IsAiring { get; set; }
  278. [ApiMember(Name = "MaxStartDate", Description = "Optional. The maximum premiere date. Format = ISO", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
  279. public string MaxStartDate { get; set; }
  280. [ApiMember(Name = "MinEndDate", Description = "Optional. The minimum premiere date. Format = ISO", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
  281. public string MinEndDate { get; set; }
  282. [ApiMember(Name = "MaxEndDate", Description = "Optional. The maximum premiere date. Format = ISO", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
  283. public string MaxEndDate { get; set; }
  284. [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
  285. public bool? IsMovie { get; set; }
  286. [ApiMember(Name = "IsSeries", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
  287. public bool? IsSeries { get; set; }
  288. [ApiMember(Name = "IsNews", Description = "Optional filter for news.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
  289. public bool? IsNews { get; set; }
  290. [ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
  291. public bool? IsKids { get; set; }
  292. [ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
  293. public bool? IsSports { get; set; }
  294. [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")]
  295. public int? StartIndex { get; set; }
  296. [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
  297. public int? Limit { get; set; }
  298. [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)]
  299. public string SortBy { get; set; }
  300. [ApiMember(Name = "SortOrder", Description = "Sort Order - Ascending,Descending", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  301. public string SortOrder { get; set; }
  302. [ApiMember(Name = "Genres", Description = "The genres to return guide information for.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
  303. public string Genres { get; set; }
  304. [ApiMember(Name = "GenreIds", Description = "The genres to return guide information for.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
  305. public string GenreIds { get; set; }
  306. [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
  307. public bool? EnableImages { get; set; }
  308. public bool EnableTotalRecordCount { get; set; }
  309. [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
  310. public int? ImageTypeLimit { get; set; }
  311. [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  312. public string EnableImageTypes { get; set; }
  313. [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
  314. public bool? EnableUserData { get; set; }
  315. public string SeriesTimerId { get; set; }
  316. public Guid LibrarySeriesId { get; set; }
  317. /// <summary>
  318. /// Fields to return within the items, in addition to basic information
  319. /// </summary>
  320. /// <value>The fields.</value>
  321. [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, 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)]
  322. public string Fields { get; set; }
  323. public GetPrograms()
  324. {
  325. EnableTotalRecordCount = true;
  326. }
  327. }
  328. [Route("/LiveTv/Programs/Recommended", "GET", Summary = "Gets available live tv epgs..")]
  329. [Authenticated]
  330. public class GetRecommendedPrograms : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions
  331. {
  332. public bool EnableTotalRecordCount { get; set; }
  333. public GetRecommendedPrograms()
  334. {
  335. EnableTotalRecordCount = true;
  336. }
  337. [ApiMember(Name = "UserId", Description = "Optional filter by user id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
  338. public Guid UserId { get; set; }
  339. [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
  340. public int? Limit { get; set; }
  341. [ApiMember(Name = "IsAiring", Description = "Optional. Filter by programs that are currently airing, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
  342. public bool? IsAiring { get; set; }
  343. [ApiMember(Name = "HasAired", Description = "Optional. Filter by programs that have completed airing, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
  344. public bool? HasAired { get; set; }
  345. [ApiMember(Name = "IsSeries", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
  346. public bool? IsSeries { get; set; }
  347. [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
  348. public bool? IsMovie { get; set; }
  349. [ApiMember(Name = "IsNews", Description = "Optional filter for news.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
  350. public bool? IsNews { get; set; }
  351. [ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
  352. public bool? IsKids { get; set; }
  353. [ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
  354. public bool? IsSports { get; set; }
  355. [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
  356. public bool? EnableImages { get; set; }
  357. [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
  358. public int? ImageTypeLimit { get; set; }
  359. [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  360. public string EnableImageTypes { get; set; }
  361. [ApiMember(Name = "GenreIds", Description = "The genres to return guide information for.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
  362. public string GenreIds { get; set; }
  363. /// <summary>
  364. /// Fields to return within the items, in addition to basic information
  365. /// </summary>
  366. /// <value>The fields.</value>
  367. [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, 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)]
  368. public string Fields { get; set; }
  369. [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
  370. public bool? EnableUserData { get; set; }
  371. }
  372. [Route("/LiveTv/Programs/{Id}", "GET", Summary = "Gets a live tv program")]
  373. [Authenticated]
  374. public class GetProgram : IReturn<BaseItemDto>
  375. {
  376. [ApiMember(Name = "Id", Description = "Program Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
  377. public string Id { get; set; }
  378. [ApiMember(Name = "UserId", Description = "Optional attach user data.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  379. public Guid UserId { get; set; }
  380. }
  381. [Route("/LiveTv/Recordings/{Id}", "DELETE", Summary = "Deletes a live tv recording")]
  382. [Authenticated]
  383. public class DeleteRecording : IReturnVoid
  384. {
  385. [ApiMember(Name = "Id", Description = "Recording Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
  386. public Guid Id { get; set; }
  387. }
  388. [Route("/LiveTv/Timers/{Id}", "DELETE", Summary = "Cancels a live tv timer")]
  389. [Authenticated]
  390. public class CancelTimer : IReturnVoid
  391. {
  392. [ApiMember(Name = "Id", Description = "Timer Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
  393. public string Id { get; set; }
  394. }
  395. [Route("/LiveTv/Timers/{Id}", "POST", Summary = "Updates a live tv timer")]
  396. [Authenticated]
  397. public class UpdateTimer : TimerInfoDto, IReturnVoid
  398. {
  399. }
  400. [Route("/LiveTv/Timers", "POST", Summary = "Creates a live tv timer")]
  401. [Authenticated]
  402. public class CreateTimer : TimerInfoDto, IReturnVoid
  403. {
  404. }
  405. [Route("/LiveTv/SeriesTimers/{Id}", "GET", Summary = "Gets a live tv series timer")]
  406. [Authenticated]
  407. public class GetSeriesTimer : IReturn<TimerInfoDto>
  408. {
  409. [ApiMember(Name = "Id", Description = "Timer Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
  410. public string Id { get; set; }
  411. }
  412. [Route("/LiveTv/SeriesTimers", "GET", Summary = "Gets live tv series timers")]
  413. [Authenticated]
  414. public class GetSeriesTimers : IReturn<QueryResult<SeriesTimerInfoDto>>
  415. {
  416. [ApiMember(Name = "SortBy", Description = "Optional. Sort by SortName or Priority", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
  417. public string SortBy { get; set; }
  418. [ApiMember(Name = "SortOrder", Description = "Optional. Sort in Ascending or Descending order", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
  419. public SortOrder SortOrder { get; set; }
  420. }
  421. [Route("/LiveTv/SeriesTimers/{Id}", "DELETE", Summary = "Cancels a live tv series timer")]
  422. [Authenticated]
  423. public class CancelSeriesTimer : IReturnVoid
  424. {
  425. [ApiMember(Name = "Id", Description = "Timer Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
  426. public string Id { get; set; }
  427. }
  428. [Route("/LiveTv/SeriesTimers/{Id}", "POST", Summary = "Updates a live tv series timer")]
  429. [Authenticated]
  430. public class UpdateSeriesTimer : SeriesTimerInfoDto, IReturnVoid
  431. {
  432. }
  433. [Route("/LiveTv/SeriesTimers", "POST", Summary = "Creates a live tv series timer")]
  434. [Authenticated]
  435. public class CreateSeriesTimer : SeriesTimerInfoDto, IReturnVoid
  436. {
  437. }
  438. [Route("/LiveTv/Recordings/Groups/{Id}", "GET", Summary = "Gets a recording group")]
  439. [Authenticated]
  440. public class GetRecordingGroup : IReturn<BaseItemDto>
  441. {
  442. [ApiMember(Name = "Id", Description = "Recording group Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
  443. public string Id { get; set; }
  444. }
  445. [Route("/LiveTv/GuideInfo", "GET", Summary = "Gets guide info")]
  446. [Authenticated]
  447. public class GetGuideInfo : IReturn<GuideInfo>
  448. {
  449. }
  450. [Route("/LiveTv/TunerHosts", "POST", Summary = "Adds a tuner host")]
  451. [Authenticated]
  452. public class AddTunerHost : TunerHostInfo, IReturn<TunerHostInfo>
  453. {
  454. }
  455. [Route("/LiveTv/TunerHosts", "DELETE", Summary = "Deletes a tuner host")]
  456. [Authenticated]
  457. public class DeleteTunerHost : IReturnVoid
  458. {
  459. [ApiMember(Name = "Id", Description = "Tuner host id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "DELETE")]
  460. public string Id { get; set; }
  461. }
  462. [Route("/LiveTv/ListingProviders/Default", "GET")]
  463. [Authenticated]
  464. public class GetDefaultListingProvider : ListingsProviderInfo, IReturn<ListingsProviderInfo>
  465. {
  466. }
  467. [Route("/LiveTv/ListingProviders", "POST", Summary = "Adds a listing provider")]
  468. [Authenticated]
  469. public class AddListingProvider : ListingsProviderInfo, IReturn<ListingsProviderInfo>
  470. {
  471. public bool ValidateLogin { get; set; }
  472. public bool ValidateListings { get; set; }
  473. public string Pw { get; set; }
  474. }
  475. [Route("/LiveTv/ListingProviders", "DELETE", Summary = "Deletes a listing provider")]
  476. [Authenticated]
  477. public class DeleteListingProvider : IReturnVoid
  478. {
  479. [ApiMember(Name = "Id", Description = "Provider id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "DELETE")]
  480. public string Id { get; set; }
  481. }
  482. [Route("/LiveTv/ListingProviders/Lineups", "GET", Summary = "Gets available lineups")]
  483. [Authenticated]
  484. public class GetLineups : IReturn<List<NameIdPair>>
  485. {
  486. [ApiMember(Name = "Id", Description = "Provider id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  487. public string Id { get; set; }
  488. [ApiMember(Name = "Type", Description = "Provider Type", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  489. public string Type { get; set; }
  490. [ApiMember(Name = "Location", Description = "Location", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  491. public string Location { get; set; }
  492. [ApiMember(Name = "Country", Description = "Country", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
  493. public string Country { get; set; }
  494. }
  495. [Route("/LiveTv/ListingProviders/SchedulesDirect/Countries", "GET", Summary = "Gets available lineups")]
  496. [Authenticated]
  497. public class GetSchedulesDirectCountries
  498. {
  499. }
  500. [Route("/LiveTv/ChannelMappingOptions")]
  501. [Authenticated]
  502. public class GetChannelMappingOptions
  503. {
  504. [ApiMember(Name = "Id", Description = "Provider id", IsRequired = true, DataType = "string", ParameterType = "query")]
  505. public string ProviderId { get; set; }
  506. }
  507. [Route("/LiveTv/ChannelMappings")]
  508. [Authenticated]
  509. public class SetChannelMapping
  510. {
  511. [ApiMember(Name = "Id", Description = "Provider id", IsRequired = true, DataType = "string", ParameterType = "query")]
  512. public string ProviderId { get; set; }
  513. public string TunerChannelId { get; set; }
  514. public string ProviderChannelId { get; set; }
  515. }
  516. public class ChannelMappingOptions
  517. {
  518. public List<TunerChannelMapping> TunerChannels { get; set; }
  519. public List<NameIdPair> ProviderChannels { get; set; }
  520. public NameValuePair[] Mappings { get; set; }
  521. public string ProviderName { get; set; }
  522. }
  523. [Route("/LiveTv/LiveStreamFiles/{Id}/stream.{Container}", "GET", Summary = "Gets a live tv channel")]
  524. public class GetLiveStreamFile
  525. {
  526. public string Id { get; set; }
  527. public string Container { get; set; }
  528. }
  529. [Route("/LiveTv/LiveRecordings/{Id}/stream", "GET", Summary = "Gets a live tv channel")]
  530. public class GetLiveRecordingFile
  531. {
  532. public string Id { get; set; }
  533. }
  534. [Route("/LiveTv/TunerHosts/Types", "GET")]
  535. [Authenticated]
  536. public class GetTunerHostTypes : IReturn<List<NameIdPair>>
  537. {
  538. }
  539. [Route("/LiveTv/Tuners/Discvover", "GET")]
  540. [Authenticated]
  541. public class DiscoverTuners : IReturn<List<TunerHostInfo>>
  542. {
  543. public bool NewDevicesOnly { get; set; }
  544. }
  545. public class LiveTvService : BaseApiService
  546. {
  547. private readonly ILiveTvManager _liveTvManager;
  548. private readonly IUserManager _userManager;
  549. private readonly IHttpClient _httpClient;
  550. private readonly ILibraryManager _libraryManager;
  551. private readonly IDtoService _dtoService;
  552. private readonly IAuthorizationContext _authContext;
  553. private readonly ISessionContext _sessionContext;
  554. private readonly IStreamHelper _streamHelper;
  555. private readonly IMediaSourceManager _mediaSourceManager;
  556. public LiveTvService(
  557. ILogger<LiveTvService> logger,
  558. IServerConfigurationManager serverConfigurationManager,
  559. IHttpResultFactory httpResultFactory,
  560. IMediaSourceManager mediaSourceManager,
  561. IStreamHelper streamHelper,
  562. ILiveTvManager liveTvManager,
  563. IUserManager userManager,
  564. IHttpClient httpClient,
  565. ILibraryManager libraryManager,
  566. IDtoService dtoService,
  567. IAuthorizationContext authContext,
  568. ISessionContext sessionContext)
  569. : base(logger, serverConfigurationManager, httpResultFactory)
  570. {
  571. _mediaSourceManager = mediaSourceManager;
  572. _streamHelper = streamHelper;
  573. _liveTvManager = liveTvManager;
  574. _userManager = userManager;
  575. _httpClient = httpClient;
  576. _libraryManager = libraryManager;
  577. _dtoService = dtoService;
  578. _authContext = authContext;
  579. _sessionContext = sessionContext;
  580. }
  581. public object Get(GetTunerHostTypes request)
  582. {
  583. var list = _liveTvManager.GetTunerHostTypes();
  584. return ToOptimizedResult(list);
  585. }
  586. public object Get(GetRecordingFolders request)
  587. {
  588. var user = request.UserId.Equals(Guid.Empty) ? null : _userManager.GetUserById(request.UserId);
  589. var folders = _liveTvManager.GetRecordingFolders(user);
  590. var returnArray = _dtoService.GetBaseItemDtos(folders, new DtoOptions(), user);
  591. var result = new QueryResult<BaseItemDto>
  592. {
  593. Items = returnArray,
  594. TotalRecordCount = returnArray.Count
  595. };
  596. return ToOptimizedResult(result);
  597. }
  598. public object Get(GetLiveRecordingFile request)
  599. {
  600. var path = _liveTvManager.GetEmbyTvActiveRecordingPath(request.Id);
  601. if (string.IsNullOrWhiteSpace(path))
  602. {
  603. throw new FileNotFoundException();
  604. }
  605. var outputHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
  606. {
  607. [HeaderNames.ContentType] = Model.Net.MimeTypes.GetMimeType(path)
  608. };
  609. return new ProgressiveFileCopier(_streamHelper, path, outputHeaders, Logger)
  610. {
  611. AllowEndOfFile = false
  612. };
  613. }
  614. public async Task<object> Get(DiscoverTuners request)
  615. {
  616. var result = await _liveTvManager.DiscoverTuners(request.NewDevicesOnly, CancellationToken.None).ConfigureAwait(false);
  617. return ToOptimizedResult(result);
  618. }
  619. public async Task<object> Get(GetLiveStreamFile request)
  620. {
  621. var liveStreamInfo = await _mediaSourceManager.GetDirectStreamProviderByUniqueId(request.Id, CancellationToken.None).ConfigureAwait(false);
  622. var directStreamProvider = liveStreamInfo;
  623. var outputHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
  624. {
  625. [HeaderNames.ContentType] = Model.Net.MimeTypes.GetMimeType("file." + request.Container)
  626. };
  627. return new ProgressiveFileCopier(directStreamProvider, _streamHelper, outputHeaders, Logger)
  628. {
  629. AllowEndOfFile = false
  630. };
  631. }
  632. public object Get(GetDefaultListingProvider request)
  633. {
  634. return ToOptimizedResult(new ListingsProviderInfo());
  635. }
  636. public async Task<object> Post(SetChannelMapping request)
  637. {
  638. return await _liveTvManager.SetChannelMapping(request.ProviderId, request.TunerChannelId, request.ProviderChannelId).ConfigureAwait(false);
  639. }
  640. public async Task<object> Get(GetChannelMappingOptions request)
  641. {
  642. var config = GetConfiguration();
  643. var listingsProviderInfo = config.ListingProviders.First(i => string.Equals(request.ProviderId, i.Id, StringComparison.OrdinalIgnoreCase));
  644. var listingsProviderName = _liveTvManager.ListingProviders.First(i => string.Equals(i.Type, listingsProviderInfo.Type, StringComparison.OrdinalIgnoreCase)).Name;
  645. var tunerChannels = await _liveTvManager.GetChannelsForListingsProvider(request.ProviderId, CancellationToken.None)
  646. .ConfigureAwait(false);
  647. var providerChannels = await _liveTvManager.GetChannelsFromListingsProviderData(request.ProviderId, CancellationToken.None)
  648. .ConfigureAwait(false);
  649. var mappings = listingsProviderInfo.ChannelMappings;
  650. var result = new ChannelMappingOptions
  651. {
  652. TunerChannels = tunerChannels.Select(i => _liveTvManager.GetTunerChannelMapping(i, mappings, providerChannels)).ToList(),
  653. ProviderChannels = providerChannels.Select(i => new NameIdPair
  654. {
  655. Name = i.Name,
  656. Id = i.Id
  657. }).ToList(),
  658. Mappings = mappings,
  659. ProviderName = listingsProviderName
  660. };
  661. return ToOptimizedResult(result);
  662. }
  663. public async Task<object> Get(GetSchedulesDirectCountries request)
  664. {
  665. // https://json.schedulesdirect.org/20141201/available/countries
  666. var response = await _httpClient.Get(new HttpRequestOptions
  667. {
  668. Url = "https://json.schedulesdirect.org/20141201/available/countries",
  669. BufferContent = false
  670. }).ConfigureAwait(false);
  671. return ResultFactory.GetResult(Request, response, "application/json");
  672. }
  673. private void AssertUserCanManageLiveTv()
  674. {
  675. var user = _sessionContext.GetUser(Request);
  676. if (user == null)
  677. {
  678. throw new SecurityException("Anonymous live tv management is not allowed.");
  679. }
  680. if (!user.Policy.EnableLiveTvManagement)
  681. {
  682. throw new SecurityException("The current user does not have permission to manage live tv.");
  683. }
  684. }
  685. public async Task<object> Post(AddListingProvider request)
  686. {
  687. if (request.Pw != null)
  688. {
  689. request.Password = GetHashedString(request.Pw);
  690. }
  691. request.Pw = null;
  692. var result = await _liveTvManager.SaveListingProvider(request, request.ValidateLogin, request.ValidateListings).ConfigureAwait(false);
  693. return ToOptimizedResult(result);
  694. }
  695. /// <summary>
  696. /// Gets the hashed string.
  697. /// </summary>
  698. private string GetHashedString(string str)
  699. {
  700. // SchedulesDirect requires a SHA1 hash of the user's password
  701. // https://github.com/SchedulesDirect/JSON-Service/wiki/API-20141201#obtain-a-token
  702. using (SHA1 sha = SHA1.Create())
  703. {
  704. return Hex.Encode(
  705. sha.ComputeHash(Encoding.UTF8.GetBytes(str)));
  706. }
  707. }
  708. public void Delete(DeleteListingProvider request)
  709. {
  710. _liveTvManager.DeleteListingsProvider(request.Id);
  711. }
  712. public async Task<object> Post(AddTunerHost request)
  713. {
  714. var result = await _liveTvManager.SaveTunerHost(request).ConfigureAwait(false);
  715. return ToOptimizedResult(result);
  716. }
  717. public void Delete(DeleteTunerHost request)
  718. {
  719. var config = GetConfiguration();
  720. config.TunerHosts = config.TunerHosts.Where(i => !string.Equals(request.Id, i.Id, StringComparison.OrdinalIgnoreCase)).ToArray();
  721. ServerConfigurationManager.SaveConfiguration("livetv", config);
  722. }
  723. private LiveTvOptions GetConfiguration()
  724. {
  725. return ServerConfigurationManager.GetConfiguration<LiveTvOptions>("livetv");
  726. }
  727. private void UpdateConfiguration(LiveTvOptions options)
  728. {
  729. ServerConfigurationManager.SaveConfiguration("livetv", options);
  730. }
  731. public async Task<object> Get(GetLineups request)
  732. {
  733. var info = await _liveTvManager.GetLineups(request.Type, request.Id, request.Country, request.Location).ConfigureAwait(false);
  734. return ToOptimizedResult(info);
  735. }
  736. public object Get(GetLiveTvInfo request)
  737. {
  738. var info = _liveTvManager.GetLiveTvInfo(CancellationToken.None);
  739. return ToOptimizedResult(info);
  740. }
  741. public object Get(GetChannels request)
  742. {
  743. var options = GetDtoOptions(_authContext, request);
  744. var channelResult = _liveTvManager.GetInternalChannels(new LiveTvChannelQuery
  745. {
  746. ChannelType = request.Type,
  747. UserId = request.UserId,
  748. StartIndex = request.StartIndex,
  749. Limit = request.Limit,
  750. IsFavorite = request.IsFavorite,
  751. IsLiked = request.IsLiked,
  752. IsDisliked = request.IsDisliked,
  753. EnableFavoriteSorting = request.EnableFavoriteSorting,
  754. IsMovie = request.IsMovie,
  755. IsSeries = request.IsSeries,
  756. IsNews = request.IsNews,
  757. IsKids = request.IsKids,
  758. IsSports = request.IsSports,
  759. SortBy = request.GetOrderBy(),
  760. SortOrder = request.SortOrder ?? SortOrder.Ascending,
  761. AddCurrentProgram = request.AddCurrentProgram
  762. }, options, CancellationToken.None);
  763. var user = request.UserId.Equals(Guid.Empty) ? null : _userManager.GetUserById(request.UserId);
  764. RemoveFields(options);
  765. options.AddCurrentProgram = request.AddCurrentProgram;
  766. var returnArray = _dtoService.GetBaseItemDtos(channelResult.Items, options, user);
  767. var result = new QueryResult<BaseItemDto>
  768. {
  769. Items = returnArray,
  770. TotalRecordCount = channelResult.TotalRecordCount
  771. };
  772. return ToOptimizedResult(result);
  773. }
  774. private void RemoveFields(DtoOptions options)
  775. {
  776. var fields = options.Fields.ToList();
  777. fields.Remove(ItemFields.CanDelete);
  778. fields.Remove(ItemFields.CanDownload);
  779. fields.Remove(ItemFields.DisplayPreferencesId);
  780. fields.Remove(ItemFields.Etag);
  781. options.Fields = fields.ToArray();
  782. }
  783. public object Get(GetChannel request)
  784. {
  785. var user = _userManager.GetUserById(request.UserId);
  786. var item = string.IsNullOrEmpty(request.Id) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(request.Id);
  787. var dtoOptions = GetDtoOptions(_authContext, request);
  788. var result = _dtoService.GetBaseItemDto(item, dtoOptions, user);
  789. return ToOptimizedResult(result);
  790. }
  791. public async Task<object> Get(GetPrograms request)
  792. {
  793. var user = request.UserId.Equals(Guid.Empty) ? null : _userManager.GetUserById(request.UserId);
  794. var query = new InternalItemsQuery(user)
  795. {
  796. ChannelIds = ApiEntryPoint.Split(request.ChannelIds, ',', true).Select(i => new Guid(i)).ToArray(),
  797. HasAired = request.HasAired,
  798. IsAiring = request.IsAiring,
  799. EnableTotalRecordCount = request.EnableTotalRecordCount
  800. };
  801. if (!string.IsNullOrEmpty(request.MinStartDate))
  802. {
  803. query.MinStartDate = DateTime.Parse(request.MinStartDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
  804. }
  805. if (!string.IsNullOrEmpty(request.MinEndDate))
  806. {
  807. query.MinEndDate = DateTime.Parse(request.MinEndDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
  808. }
  809. if (!string.IsNullOrEmpty(request.MaxStartDate))
  810. {
  811. query.MaxStartDate = DateTime.Parse(request.MaxStartDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
  812. }
  813. if (!string.IsNullOrEmpty(request.MaxEndDate))
  814. {
  815. query.MaxEndDate = DateTime.Parse(request.MaxEndDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
  816. }
  817. query.StartIndex = request.StartIndex;
  818. query.Limit = request.Limit;
  819. query.OrderBy = BaseItemsRequest.GetOrderBy(request.SortBy, request.SortOrder);
  820. query.IsNews = request.IsNews;
  821. query.IsMovie = request.IsMovie;
  822. query.IsSeries = request.IsSeries;
  823. query.IsKids = request.IsKids;
  824. query.IsSports = request.IsSports;
  825. query.SeriesTimerId = request.SeriesTimerId;
  826. query.Genres = (request.Genres ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
  827. query.GenreIds = GetGuids(request.GenreIds);
  828. if (!request.LibrarySeriesId.Equals(Guid.Empty))
  829. {
  830. query.IsSeries = true;
  831. var series = _libraryManager.GetItemById(request.LibrarySeriesId) as Series;
  832. if (series != null)
  833. {
  834. query.Name = series.Name;
  835. }
  836. }
  837. var result = await _liveTvManager.GetPrograms(query, GetDtoOptions(_authContext, request), CancellationToken.None).ConfigureAwait(false);
  838. return ToOptimizedResult(result);
  839. }
  840. public object Get(GetRecommendedPrograms request)
  841. {
  842. var user = _userManager.GetUserById(request.UserId);
  843. var query = new InternalItemsQuery(user)
  844. {
  845. IsAiring = request.IsAiring,
  846. Limit = request.Limit,
  847. HasAired = request.HasAired,
  848. IsSeries = request.IsSeries,
  849. IsMovie = request.IsMovie,
  850. IsKids = request.IsKids,
  851. IsNews = request.IsNews,
  852. IsSports = request.IsSports,
  853. EnableTotalRecordCount = request.EnableTotalRecordCount
  854. };
  855. query.GenreIds = GetGuids(request.GenreIds);
  856. var result = _liveTvManager.GetRecommendedPrograms(query, GetDtoOptions(_authContext, request), CancellationToken.None);
  857. return ToOptimizedResult(result);
  858. }
  859. public object Post(GetPrograms request)
  860. {
  861. return Get(request);
  862. }
  863. public object Get(GetRecordings request)
  864. {
  865. var options = GetDtoOptions(_authContext, request);
  866. var result = _liveTvManager.GetRecordings(new RecordingQuery
  867. {
  868. ChannelId = request.ChannelId,
  869. UserId = request.UserId,
  870. StartIndex = request.StartIndex,
  871. Limit = request.Limit,
  872. Status = request.Status,
  873. SeriesTimerId = request.SeriesTimerId,
  874. IsInProgress = request.IsInProgress,
  875. EnableTotalRecordCount = request.EnableTotalRecordCount,
  876. IsMovie = request.IsMovie,
  877. IsNews = request.IsNews,
  878. IsSeries = request.IsSeries,
  879. IsKids = request.IsKids,
  880. IsSports = request.IsSports,
  881. IsLibraryItem = request.IsLibraryItem,
  882. Fields = request.GetItemFields(),
  883. ImageTypeLimit = request.ImageTypeLimit,
  884. EnableImages = request.EnableImages
  885. }, options);
  886. return ToOptimizedResult(result);
  887. }
  888. public object Get(GetRecordingSeries request)
  889. {
  890. return ToOptimizedResult(new QueryResult<BaseItemDto>());
  891. }
  892. public object Get(GetRecording request)
  893. {
  894. var user = _userManager.GetUserById(request.UserId);
  895. var item = string.IsNullOrEmpty(request.Id) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(request.Id);
  896. var dtoOptions = GetDtoOptions(_authContext, request);
  897. var result = _dtoService.GetBaseItemDto(item, dtoOptions, user);
  898. return ToOptimizedResult(result);
  899. }
  900. public async Task<object> Get(GetTimer request)
  901. {
  902. var result = await _liveTvManager.GetTimer(request.Id, CancellationToken.None).ConfigureAwait(false);
  903. return ToOptimizedResult(result);
  904. }
  905. public async Task<object> Get(GetTimers request)
  906. {
  907. var result = await _liveTvManager.GetTimers(new TimerQuery
  908. {
  909. ChannelId = request.ChannelId,
  910. SeriesTimerId = request.SeriesTimerId,
  911. IsActive = request.IsActive,
  912. IsScheduled = request.IsScheduled
  913. }, CancellationToken.None).ConfigureAwait(false);
  914. return ToOptimizedResult(result);
  915. }
  916. public void Delete(DeleteRecording request)
  917. {
  918. AssertUserCanManageLiveTv();
  919. _libraryManager.DeleteItem(_libraryManager.GetItemById(request.Id), new DeleteOptions
  920. {
  921. DeleteFileLocation = false
  922. });
  923. }
  924. public Task Delete(CancelTimer request)
  925. {
  926. AssertUserCanManageLiveTv();
  927. return _liveTvManager.CancelTimer(request.Id);
  928. }
  929. public Task Post(UpdateTimer request)
  930. {
  931. AssertUserCanManageLiveTv();
  932. return _liveTvManager.UpdateTimer(request, CancellationToken.None);
  933. }
  934. public async Task<object> Get(GetSeriesTimers request)
  935. {
  936. var result = await _liveTvManager.GetSeriesTimers(new SeriesTimerQuery
  937. {
  938. SortOrder = request.SortOrder,
  939. SortBy = request.SortBy
  940. }, CancellationToken.None).ConfigureAwait(false);
  941. return ToOptimizedResult(result);
  942. }
  943. public async Task<object> Get(GetSeriesTimer request)
  944. {
  945. var result = await _liveTvManager.GetSeriesTimer(request.Id, CancellationToken.None).ConfigureAwait(false);
  946. return ToOptimizedResult(result);
  947. }
  948. public Task Delete(CancelSeriesTimer request)
  949. {
  950. AssertUserCanManageLiveTv();
  951. return _liveTvManager.CancelSeriesTimer(request.Id);
  952. }
  953. public Task Post(UpdateSeriesTimer request)
  954. {
  955. AssertUserCanManageLiveTv();
  956. return _liveTvManager.UpdateSeriesTimer(request, CancellationToken.None);
  957. }
  958. public async Task<object> Get(GetDefaultTimer request)
  959. {
  960. if (string.IsNullOrEmpty(request.ProgramId))
  961. {
  962. var result = await _liveTvManager.GetNewTimerDefaults(CancellationToken.None).ConfigureAwait(false);
  963. return ToOptimizedResult(result);
  964. }
  965. else
  966. {
  967. var result = await _liveTvManager.GetNewTimerDefaults(request.ProgramId, CancellationToken.None).ConfigureAwait(false);
  968. return ToOptimizedResult(result);
  969. }
  970. }
  971. public async Task<object> Get(GetProgram request)
  972. {
  973. var user = request.UserId.Equals(Guid.Empty) ? null : _userManager.GetUserById(request.UserId);
  974. var result = await _liveTvManager.GetProgram(request.Id, CancellationToken.None, user).ConfigureAwait(false);
  975. return ToOptimizedResult(result);
  976. }
  977. public Task Post(CreateSeriesTimer request)
  978. {
  979. AssertUserCanManageLiveTv();
  980. return _liveTvManager.CreateSeriesTimer(request, CancellationToken.None);
  981. }
  982. public Task Post(CreateTimer request)
  983. {
  984. AssertUserCanManageLiveTv();
  985. return _liveTvManager.CreateTimer(request, CancellationToken.None);
  986. }
  987. public object Get(GetRecordingGroups request)
  988. {
  989. return ToOptimizedResult(new QueryResult<BaseItemDto>());
  990. }
  991. public object Get(GetRecordingGroup request)
  992. {
  993. throw new FileNotFoundException();
  994. }
  995. public object Get(GetGuideInfo request)
  996. {
  997. return ToOptimizedResult(_liveTvManager.GetGuideInfo());
  998. }
  999. public Task Post(ResetTuner request)
  1000. {
  1001. AssertUserCanManageLiveTv();
  1002. return _liveTvManager.ResetTuner(request.Id, CancellationToken.None);
  1003. }
  1004. }
  1005. }