LiveTvController.cs 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics.CodeAnalysis;
  4. using System.Linq;
  5. using System.Net.Mime;
  6. using System.Security.Cryptography;
  7. using System.Text;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. using Jellyfin.Api.Constants;
  11. using Jellyfin.Api.Extensions;
  12. using Jellyfin.Api.Helpers;
  13. using Jellyfin.Api.Models.LiveTvDtos;
  14. using Jellyfin.Data.Enums;
  15. using MediaBrowser.Common;
  16. using MediaBrowser.Common.Configuration;
  17. using MediaBrowser.Common.Net;
  18. using MediaBrowser.Controller.Configuration;
  19. using MediaBrowser.Controller.Dto;
  20. using MediaBrowser.Controller.Entities;
  21. using MediaBrowser.Controller.Entities.TV;
  22. using MediaBrowser.Controller.Library;
  23. using MediaBrowser.Controller.LiveTv;
  24. using MediaBrowser.Controller.Net;
  25. using MediaBrowser.Model.Dto;
  26. using MediaBrowser.Model.Entities;
  27. using MediaBrowser.Model.IO;
  28. using MediaBrowser.Model.LiveTv;
  29. using MediaBrowser.Model.Querying;
  30. using Microsoft.AspNetCore.Authorization;
  31. using Microsoft.AspNetCore.Http;
  32. using Microsoft.AspNetCore.Mvc;
  33. namespace Jellyfin.Api.Controllers
  34. {
  35. /// <summary>
  36. /// Live tv controller.
  37. /// </summary>
  38. public class LiveTvController : BaseJellyfinApiController
  39. {
  40. private readonly ILiveTvManager _liveTvManager;
  41. private readonly IUserManager _userManager;
  42. private readonly IHttpClient _httpClient;
  43. private readonly ILibraryManager _libraryManager;
  44. private readonly IDtoService _dtoService;
  45. private readonly IAuthorizationContext _authContext;
  46. private readonly ISessionContext _sessionContext;
  47. private readonly IStreamHelper _streamHelper;
  48. private readonly IMediaSourceManager _mediaSourceManager;
  49. private readonly IConfigurationManager _configurationManager;
  50. /// <summary>
  51. /// Initializes a new instance of the <see cref="LiveTvController"/> class.
  52. /// </summary>
  53. /// <param name="liveTvManager">Instance of the <see cref="ILiveTvManager"/> interface.</param>
  54. /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
  55. /// <param name="httpClient">Instance of the <see cref="IHttpClient"/> interface.</param>
  56. /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
  57. /// <param name="dtoService">Instance of the <see cref="IDtoService"/> interface.</param>
  58. /// <param name="authContext">Instance of the <see cref="IAuthorizationContext"/> interface.</param>
  59. /// <param name="sessionContext">Instance of the <see cref="ISessionContext"/> interface.</param>
  60. /// <param name="streamHelper">Instance of the <see cref="IStreamHelper"/> interface.</param>
  61. /// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param>
  62. /// <param name="configurationManager">Instance of the <see cref="IConfigurationManager"/> interface.</param>
  63. public LiveTvController(
  64. ILiveTvManager liveTvManager,
  65. IUserManager userManager,
  66. IHttpClient httpClient,
  67. ILibraryManager libraryManager,
  68. IDtoService dtoService,
  69. IAuthorizationContext authContext,
  70. ISessionContext sessionContext,
  71. IStreamHelper streamHelper,
  72. IMediaSourceManager mediaSourceManager,
  73. IConfigurationManager configurationManager)
  74. {
  75. _liveTvManager = liveTvManager;
  76. _userManager = userManager;
  77. _httpClient = httpClient;
  78. _libraryManager = libraryManager;
  79. _dtoService = dtoService;
  80. _authContext = authContext;
  81. _sessionContext = sessionContext;
  82. _streamHelper = streamHelper;
  83. _mediaSourceManager = mediaSourceManager;
  84. _configurationManager = configurationManager;
  85. }
  86. /// <summary>
  87. /// Gets available live tv services.
  88. /// </summary>
  89. /// <response code="200">Available live tv services returned.</response>
  90. /// <returns>
  91. /// An <see cref="OkResult"/> containing the available live tv services.
  92. /// </returns>
  93. [HttpGet("Info")]
  94. [ProducesResponseType(StatusCodes.Status200OK)]
  95. [Authorize(Policy = Policies.DefaultAuthorization)]
  96. public ActionResult<LiveTvInfo> GetLiveTvInfo()
  97. {
  98. return _liveTvManager.GetLiveTvInfo(CancellationToken.None);
  99. }
  100. /// <summary>
  101. /// Gets available live tv channels.
  102. /// </summary>
  103. /// <param name="type">Optional. Filter by channel type.</param>
  104. /// <param name="userId">Optional. Filter by user and attach user data.</param>
  105. /// <param name="startIndex">Optional. The record index to start at. All items with a lower index will be dropped from the results.</param>
  106. /// <param name="isMovie">Optional. Filter for movies.</param>
  107. /// <param name="isSeries">Optional. Filter for series.</param>
  108. /// <param name="isNews">Optional. Filter for news.</param>
  109. /// <param name="isKids">Optional. Filter for kids.</param>
  110. /// <param name="isSports">Optional. Filter for sports.</param>
  111. /// <param name="limit">Optional. The maximum number of records to return.</param>
  112. /// <param name="isFavorite">Optional. Filter by channels that are favorites, or not.</param>
  113. /// <param name="isLiked">Optional. Filter by channels that are liked, or not.</param>
  114. /// <param name="isDisliked">Optional. Filter by channels that are disliked, or not.</param>
  115. /// <param name="enableFavoriteSorting">Optional. Incorporate favorite and like status into channel sorting.</param>
  116. /// <param name="enableImages">Optional. Include image information in output.</param>
  117. /// <param name="imageTypeLimit">Optional. The max number of images to return, per image type.</param>
  118. /// <param name="enableImageTypes">"Optional. The image types to include in the output.</param>
  119. /// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.</param>
  120. /// <param name="enableUserData">Optional. Include user data.</param>
  121. /// <param name="sortBy">Optional. Key to sort by.</param>
  122. /// <param name="sortOrder">Optional. Sort order.</param>
  123. /// <param name="addCurrentProgram">Optional. Adds current program info to each channel.</param>
  124. /// <response code="200">Available live tv channels returned.</response>
  125. /// <returns>
  126. /// An <see cref="OkResult"/> containing the resulting available live tv channels.
  127. /// </returns>
  128. [HttpGet("Channels")]
  129. [ProducesResponseType(StatusCodes.Status200OK)]
  130. [Authorize(Policy = Policies.DefaultAuthorization)]
  131. public ActionResult<QueryResult<BaseItemDto>> GetChannels(
  132. [FromQuery] ChannelType? type,
  133. [FromQuery] Guid userId,
  134. [FromQuery] int? startIndex,
  135. [FromQuery] bool? isMovie,
  136. [FromQuery] bool? isSeries,
  137. [FromQuery] bool? isNews,
  138. [FromQuery] bool? isKids,
  139. [FromQuery] bool? isSports,
  140. [FromQuery] int? limit,
  141. [FromQuery] bool? isFavorite,
  142. [FromQuery] bool? isLiked,
  143. [FromQuery] bool? isDisliked,
  144. [FromQuery] bool enableFavoriteSorting,
  145. [FromQuery] bool? enableImages,
  146. [FromQuery] int? imageTypeLimit,
  147. [FromQuery] string enableImageTypes,
  148. [FromQuery] string fields,
  149. [FromQuery] bool? enableUserData,
  150. [FromQuery] string sortBy,
  151. [FromQuery] SortOrder? sortOrder,
  152. [FromQuery] bool addCurrentProgram = true)
  153. {
  154. var dtoOptions = new DtoOptions()
  155. .AddItemFields(fields)
  156. .AddClientFields(Request)
  157. .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
  158. var channelResult = _liveTvManager.GetInternalChannels(
  159. new LiveTvChannelQuery
  160. {
  161. ChannelType = type,
  162. UserId = userId,
  163. StartIndex = startIndex,
  164. Limit = limit,
  165. IsFavorite = isFavorite,
  166. IsLiked = isLiked,
  167. IsDisliked = isDisliked,
  168. EnableFavoriteSorting = enableFavoriteSorting,
  169. IsMovie = isMovie,
  170. IsSeries = isSeries,
  171. IsNews = isNews,
  172. IsKids = isKids,
  173. IsSports = isSports,
  174. SortBy = RequestHelpers.Split(sortBy, ',', true),
  175. SortOrder = sortOrder ?? SortOrder.Ascending,
  176. AddCurrentProgram = addCurrentProgram
  177. },
  178. dtoOptions,
  179. CancellationToken.None);
  180. var user = userId.Equals(Guid.Empty)
  181. ? null
  182. : _userManager.GetUserById(userId);
  183. var fieldsList = dtoOptions.Fields.ToList();
  184. fieldsList.Remove(ItemFields.CanDelete);
  185. fieldsList.Remove(ItemFields.CanDownload);
  186. fieldsList.Remove(ItemFields.DisplayPreferencesId);
  187. fieldsList.Remove(ItemFields.Etag);
  188. dtoOptions.Fields = fieldsList.ToArray();
  189. dtoOptions.AddCurrentProgram = addCurrentProgram;
  190. var returnArray = _dtoService.GetBaseItemDtos(channelResult.Items, dtoOptions, user);
  191. return new QueryResult<BaseItemDto>
  192. {
  193. Items = returnArray,
  194. TotalRecordCount = channelResult.TotalRecordCount
  195. };
  196. }
  197. /// <summary>
  198. /// Gets a live tv channel.
  199. /// </summary>
  200. /// <param name="channelId">Channel id.</param>
  201. /// <param name="userId">Optional. Attach user data.</param>
  202. /// <response code="200">Live tv channel returned.</response>
  203. /// <returns>An <see cref="OkResult"/> containing the live tv channel.</returns>
  204. [HttpGet("Channels/{channelId}")]
  205. [ProducesResponseType(StatusCodes.Status200OK)]
  206. [Authorize(Policy = Policies.DefaultAuthorization)]
  207. public ActionResult<BaseItemDto> GetChannel([FromRoute] Guid channelId, [FromQuery] Guid userId)
  208. {
  209. var user = _userManager.GetUserById(userId);
  210. var item = channelId.Equals(Guid.Empty)
  211. ? _libraryManager.GetUserRootFolder()
  212. : _libraryManager.GetItemById(channelId);
  213. var dtoOptions = new DtoOptions()
  214. .AddClientFields(Request);
  215. return _dtoService.GetBaseItemDto(item, dtoOptions, user);
  216. }
  217. /// <summary>
  218. /// Gets live tv recordings.
  219. /// </summary>
  220. /// <param name="channelId">Optional. Filter by channel id.</param>
  221. /// <param name="userId">Optional. Filter by user and attach user data.</param>
  222. /// <param name="startIndex">Optional. The record index to start at. All items with a lower index will be dropped from the results.</param>
  223. /// <param name="limit">Optional. The maximum number of records to return.</param>
  224. /// <param name="status">Optional. Filter by recording status.</param>
  225. /// <param name="isInProgress">Optional. Filter by recordings that are in progress, or not.</param>
  226. /// <param name="seriesTimerId">Optional. Filter by recordings belonging to a series timer.</param>
  227. /// <param name="enableImages">Optional. Include image information in output.</param>
  228. /// <param name="imageTypeLimit">Optional. The max number of images to return, per image type.</param>
  229. /// <param name="enableImageTypes">Optional. The image types to include in the output.</param>
  230. /// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.</param>
  231. /// <param name="enableUserData">Optional. Include user data.</param>
  232. /// <param name="isMovie">Optional. Filter for movies.</param>
  233. /// <param name="isSeries">Optional. Filter for series.</param>
  234. /// <param name="isKids">Optional. Filter for kids.</param>
  235. /// <param name="isSports">Optional. Filter for sports.</param>
  236. /// <param name="isNews">Optional. Filter for news.</param>
  237. /// <param name="isLibraryItem">Optional. Filter for is library item.</param>
  238. /// <param name="enableTotalRecordCount">Optional. Return total record count.</param>
  239. /// <response code="200">Live tv recordings returned.</response>
  240. /// <returns>An <see cref="OkResult"/> containing the live tv recordings.</returns>
  241. [HttpGet("Recordings")]
  242. [ProducesResponseType(StatusCodes.Status200OK)]
  243. [Authorize(Policy = Policies.DefaultAuthorization)]
  244. public ActionResult<QueryResult<BaseItemDto>> GetRecordings(
  245. [FromQuery] string channelId,
  246. [FromQuery] Guid userId,
  247. [FromQuery] int? startIndex,
  248. [FromQuery] int? limit,
  249. [FromQuery] RecordingStatus? status,
  250. [FromQuery] bool? isInProgress,
  251. [FromQuery] string seriesTimerId,
  252. [FromQuery] bool? enableImages,
  253. [FromQuery] int? imageTypeLimit,
  254. [FromQuery] string enableImageTypes,
  255. [FromQuery] string fields,
  256. [FromQuery] bool? enableUserData,
  257. [FromQuery] bool? isMovie,
  258. [FromQuery] bool? isSeries,
  259. [FromQuery] bool? isKids,
  260. [FromQuery] bool? isSports,
  261. [FromQuery] bool? isNews,
  262. [FromQuery] bool? isLibraryItem,
  263. [FromQuery] bool enableTotalRecordCount = true)
  264. {
  265. var dtoOptions = new DtoOptions()
  266. .AddItemFields(fields)
  267. .AddClientFields(Request)
  268. .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
  269. return _liveTvManager.GetRecordings(
  270. new RecordingQuery
  271. {
  272. ChannelId = channelId,
  273. UserId = userId,
  274. StartIndex = startIndex,
  275. Limit = limit,
  276. Status = status,
  277. SeriesTimerId = seriesTimerId,
  278. IsInProgress = isInProgress,
  279. EnableTotalRecordCount = enableTotalRecordCount,
  280. IsMovie = isMovie,
  281. IsNews = isNews,
  282. IsSeries = isSeries,
  283. IsKids = isKids,
  284. IsSports = isSports,
  285. IsLibraryItem = isLibraryItem,
  286. Fields = RequestHelpers.GetItemFields(fields),
  287. ImageTypeLimit = imageTypeLimit,
  288. EnableImages = enableImages
  289. }, dtoOptions);
  290. }
  291. /// <summary>
  292. /// Gets live tv recording series.
  293. /// </summary>
  294. /// <param name="channelId">Optional. Filter by channel id.</param>
  295. /// <param name="userId">Optional. Filter by user and attach user data.</param>
  296. /// <param name="groupId">Optional. Filter by recording group.</param>
  297. /// <param name="startIndex">Optional. The record index to start at. All items with a lower index will be dropped from the results.</param>
  298. /// <param name="limit">Optional. The maximum number of records to return.</param>
  299. /// <param name="status">Optional. Filter by recording status.</param>
  300. /// <param name="isInProgress">Optional. Filter by recordings that are in progress, or not.</param>
  301. /// <param name="seriesTimerId">Optional. Filter by recordings belonging to a series timer.</param>
  302. /// <param name="enableImages">Optional. Include image information in output.</param>
  303. /// <param name="imageTypeLimit">Optional. The max number of images to return, per image type.</param>
  304. /// <param name="enableImageTypes">Optional. The image types to include in the output.</param>
  305. /// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.</param>
  306. /// <param name="enableUserData">Optional. Include user data.</param>
  307. /// <param name="enableTotalRecordCount">Optional. Return total record count.</param>
  308. /// <response code="200">Live tv recordings returned.</response>
  309. /// <returns>An <see cref="OkResult"/> containing the live tv recordings.</returns>
  310. [HttpGet("Recordings/Series")]
  311. [ProducesResponseType(StatusCodes.Status200OK)]
  312. [Authorize(Policy = Policies.DefaultAuthorization)]
  313. [Obsolete("This endpoint is obsolete.")]
  314. [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "channelId", Justification = "Imported from ServiceStack")]
  315. [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Imported from ServiceStack")]
  316. [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "groupId", Justification = "Imported from ServiceStack")]
  317. [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "startIndex", Justification = "Imported from ServiceStack")]
  318. [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "limit", Justification = "Imported from ServiceStack")]
  319. [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "status", Justification = "Imported from ServiceStack")]
  320. [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "isInProgress", Justification = "Imported from ServiceStack")]
  321. [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "seriesTimerId", Justification = "Imported from ServiceStack")]
  322. [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "enableImages", Justification = "Imported from ServiceStack")]
  323. [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageTypeLimit", Justification = "Imported from ServiceStack")]
  324. [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "enableImageTypes", Justification = "Imported from ServiceStack")]
  325. [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "fields", Justification = "Imported from ServiceStack")]
  326. [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "enableUserData", Justification = "Imported from ServiceStack")]
  327. [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "enableTotalRecordCount", Justification = "Imported from ServiceStack")]
  328. public ActionResult<QueryResult<BaseItemDto>> GetRecordingsSeries(
  329. [FromQuery] string channelId,
  330. [FromQuery] Guid userId,
  331. [FromQuery] string groupId,
  332. [FromQuery] int? startIndex,
  333. [FromQuery] int? limit,
  334. [FromQuery] RecordingStatus? status,
  335. [FromQuery] bool? isInProgress,
  336. [FromQuery] string seriesTimerId,
  337. [FromQuery] bool? enableImages,
  338. [FromQuery] int? imageTypeLimit,
  339. [FromQuery] string enableImageTypes,
  340. [FromQuery] string fields,
  341. [FromQuery] bool? enableUserData,
  342. [FromQuery] bool enableTotalRecordCount = true)
  343. {
  344. return new QueryResult<BaseItemDto>();
  345. }
  346. /// <summary>
  347. /// Gets live tv recording groups.
  348. /// </summary>
  349. /// <param name="userId">Optional. Filter by user and attach user data.</param>
  350. /// <response code="200">Recording groups returned.</response>
  351. /// <returns>An <see cref="OkResult"/> containing the recording groups.</returns>
  352. [HttpGet("Recordings/Groups")]
  353. [ProducesResponseType(StatusCodes.Status200OK)]
  354. [Authorize(Policy = Policies.DefaultAuthorization)]
  355. [Obsolete("This endpoint is obsolete.")]
  356. [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Imported from ServiceStack")]
  357. public ActionResult<QueryResult<BaseItemDto>> GetRecordingGroups([FromQuery] Guid userId)
  358. {
  359. return new QueryResult<BaseItemDto>();
  360. }
  361. /// <summary>
  362. /// Gets recording folders.
  363. /// </summary>
  364. /// <param name="userId">Optional. Filter by user and attach user data.</param>
  365. /// <response code="200">Recording folders returned.</response>
  366. /// <returns>An <see cref="OkResult"/> containing the recording folders.</returns>
  367. [HttpGet("Recordings/Folders")]
  368. [ProducesResponseType(StatusCodes.Status200OK)]
  369. [Authorize(Policy = Policies.DefaultAuthorization)]
  370. public ActionResult<QueryResult<BaseItemDto>> GetRecordingFolders([FromQuery] Guid userId)
  371. {
  372. var user = userId.Equals(Guid.Empty) ? null : _userManager.GetUserById(userId);
  373. var folders = _liveTvManager.GetRecordingFolders(user);
  374. var returnArray = _dtoService.GetBaseItemDtos(folders, new DtoOptions(), user);
  375. return new QueryResult<BaseItemDto>
  376. {
  377. Items = returnArray,
  378. TotalRecordCount = returnArray.Count
  379. };
  380. }
  381. /// <summary>
  382. /// Gets a live tv recording.
  383. /// </summary>
  384. /// <param name="recordingId">Recording id.</param>
  385. /// <param name="userId">Optional. Attach user data.</param>
  386. /// <response code="200">Recording returned.</response>
  387. /// <returns>An <see cref="OkResult"/> containing the live tv recording.</returns>
  388. [HttpGet("Recordings/{recordingId}")]
  389. [ProducesResponseType(StatusCodes.Status200OK)]
  390. [Authorize(Policy = Policies.DefaultAuthorization)]
  391. public ActionResult<BaseItemDto> GetRecording([FromRoute] Guid recordingId, [FromQuery] Guid userId)
  392. {
  393. var user = _userManager.GetUserById(userId);
  394. var item = recordingId.Equals(Guid.Empty) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(recordingId);
  395. var dtoOptions = new DtoOptions()
  396. .AddClientFields(Request);
  397. return _dtoService.GetBaseItemDto(item, dtoOptions, user);
  398. }
  399. /// <summary>
  400. /// Resets a tv tuner.
  401. /// </summary>
  402. /// <param name="tunerId">Tuner id.</param>
  403. /// <response code="204">Tuner reset.</response>
  404. /// <returns>A <see cref="NoContentResult"/>.</returns>
  405. [HttpPost("Tuners/{tunerId}/Reset")]
  406. [ProducesResponseType(StatusCodes.Status204NoContent)]
  407. [Authorize(Policy = Policies.DefaultAuthorization)]
  408. public ActionResult ResetTuner([FromRoute] string tunerId)
  409. {
  410. AssertUserCanManageLiveTv();
  411. _liveTvManager.ResetTuner(tunerId, CancellationToken.None);
  412. return NoContent();
  413. }
  414. /// <summary>
  415. /// Gets a timer.
  416. /// </summary>
  417. /// <param name="timerId">Timer id.</param>
  418. /// <response code="200">Timer returned.</response>
  419. /// <returns>
  420. /// A <see cref="Task"/> containing an <see cref="OkResult"/> which contains the timer.
  421. /// </returns>
  422. [HttpGet("Timers/{timerId}")]
  423. [ProducesResponseType(StatusCodes.Status200OK)]
  424. [Authorize(Policy = Policies.DefaultAuthorization)]
  425. public async Task<ActionResult<TimerInfoDto>> GetTimer(string timerId)
  426. {
  427. return await _liveTvManager.GetTimer(timerId, CancellationToken.None).ConfigureAwait(false);
  428. }
  429. /// <summary>
  430. /// Gets the default values for a new timer.
  431. /// </summary>
  432. /// <param name="programId">Optional. To attach default values based on a program.</param>
  433. /// <response code="200">Default values returned.</response>
  434. /// <returns>
  435. /// A <see cref="Task"/> containing an <see cref="OkResult"/> which contains the default values for a timer.
  436. /// </returns>
  437. [HttpGet("Timers/Defaults")]
  438. [ProducesResponseType(StatusCodes.Status200OK)]
  439. [Authorize(Policy = Policies.DefaultAuthorization)]
  440. public async Task<ActionResult<SeriesTimerInfoDto>> GetDefaultTimer([FromQuery] string programId)
  441. {
  442. return string.IsNullOrEmpty(programId)
  443. ? await _liveTvManager.GetNewTimerDefaults(CancellationToken.None).ConfigureAwait(false)
  444. : await _liveTvManager.GetNewTimerDefaults(programId, CancellationToken.None).ConfigureAwait(false);
  445. }
  446. /// <summary>
  447. /// Gets the live tv timers.
  448. /// </summary>
  449. /// <param name="channelId">Optional. Filter by channel id.</param>
  450. /// <param name="seriesTimerId">Optional. Filter by timers belonging to a series timer.</param>
  451. /// <param name="isActive">Optional. Filter by timers that are active.</param>
  452. /// <param name="isScheduled">Optional. Filter by timers that are scheduled.</param>
  453. /// <returns>
  454. /// A <see cref="Task"/> containing an <see cref="OkResult"/> which contains the live tv timers.
  455. /// </returns>
  456. [HttpGet("Timers")]
  457. [ProducesResponseType(StatusCodes.Status200OK)]
  458. [Authorize(Policy = Policies.DefaultAuthorization)]
  459. public async Task<ActionResult<QueryResult<TimerInfoDto>>> GetTimers(
  460. [FromQuery] string channelId,
  461. [FromQuery] string seriesTimerId,
  462. [FromQuery] bool? isActive,
  463. [FromQuery] bool? isScheduled)
  464. {
  465. return await _liveTvManager.GetTimers(
  466. new TimerQuery
  467. {
  468. ChannelId = channelId,
  469. SeriesTimerId = seriesTimerId,
  470. IsActive = isActive,
  471. IsScheduled = isScheduled
  472. }, CancellationToken.None)
  473. .ConfigureAwait(false);
  474. }
  475. /// <summary>
  476. /// Gets available live tv epgs.
  477. /// </summary>
  478. /// <param name="channelIds">The channels to return guide information for.</param>
  479. /// <param name="userId">Optional. Filter by user id.</param>
  480. /// <param name="minStartDate">Optional. The minimum premiere start date.</param>
  481. /// <param name="hasAired">Optional. Filter by programs that have completed airing, or not.</param>
  482. /// <param name="isAiring">Optional. Filter by programs that are currently airing, or not.</param>
  483. /// <param name="maxStartDate">Optional. The maximum premiere start date.</param>
  484. /// <param name="minEndDate">Optional. The minimum premiere end date.</param>
  485. /// <param name="maxEndDate">Optional. The maximum premiere end date.</param>
  486. /// <param name="isMovie">Optional. Filter for movies.</param>
  487. /// <param name="isSeries">Optional. Filter for series.</param>
  488. /// <param name="isNews">Optional. Filter for news.</param>
  489. /// <param name="isKids">Optional. Filter for kids.</param>
  490. /// <param name="isSports">Optional. Filter for sports.</param>
  491. /// <param name="startIndex">Optional. The record index to start at. All items with a lower index will be dropped from the results.</param>
  492. /// <param name="limit">Optional. The maximum number of records to return.</param>
  493. /// <param name="sortBy">Optional. Specify one or more sort orders, comma delimited. Options: Name, StartDate.</param>
  494. /// <param name="sortOrder">Sort Order - Ascending,Descending.</param>
  495. /// <param name="genres">The genres to return guide information for.</param>
  496. /// <param name="genreIds">The genre ids to return guide information for.</param>
  497. /// <param name="enableImages">Optional. Include image information in output.</param>
  498. /// <param name="imageTypeLimit">Optional. The max number of images to return, per image type.</param>
  499. /// <param name="enableImageTypes">Optional. The image types to include in the output.</param>
  500. /// <param name="enableUserData">Optional. Include user data.</param>
  501. /// <param name="seriesTimerId">Optional. Filter by series timer id.</param>
  502. /// <param name="librarySeriesId">Optional. Filter by library series id.</param>
  503. /// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.</param>
  504. /// <param name="enableTotalRecordCount">Retrieve total record count.</param>
  505. /// <response code="200">Live tv epgs returned.</response>
  506. /// <returns>
  507. /// A <see cref="Task"/> containing a <see cref="OkResult"/> which contains the live tv epgs.
  508. /// </returns>
  509. [HttpGet("Programs")]
  510. [ProducesResponseType(StatusCodes.Status200OK)]
  511. [Authorize(Policy = Policies.DefaultAuthorization)]
  512. public async Task<ActionResult<QueryResult<BaseItemDto>>> GetPrograms(
  513. [FromQuery] string channelIds,
  514. [FromQuery] Guid userId,
  515. [FromQuery] DateTime? minStartDate,
  516. [FromQuery] bool? hasAired,
  517. [FromQuery] bool? isAiring,
  518. [FromQuery] DateTime? maxStartDate,
  519. [FromQuery] DateTime? minEndDate,
  520. [FromQuery] DateTime? maxEndDate,
  521. [FromQuery] bool? isMovie,
  522. [FromQuery] bool? isSeries,
  523. [FromQuery] bool? isNews,
  524. [FromQuery] bool? isKids,
  525. [FromQuery] bool? isSports,
  526. [FromQuery] int? startIndex,
  527. [FromQuery] int? limit,
  528. [FromQuery] string sortBy,
  529. [FromQuery] string sortOrder,
  530. [FromQuery] string genres,
  531. [FromQuery] string genreIds,
  532. [FromQuery] bool? enableImages,
  533. [FromQuery] int? imageTypeLimit,
  534. [FromQuery] string enableImageTypes,
  535. [FromQuery] bool? enableUserData,
  536. [FromQuery] string seriesTimerId,
  537. [FromQuery] Guid librarySeriesId,
  538. [FromQuery] string fields,
  539. [FromQuery] bool enableTotalRecordCount = true)
  540. {
  541. var user = userId.Equals(Guid.Empty) ? null : _userManager.GetUserById(userId);
  542. var query = new InternalItemsQuery(user)
  543. {
  544. ChannelIds = RequestHelpers.Split(channelIds, ',', true)
  545. .Select(i => new Guid(i)).ToArray(),
  546. HasAired = hasAired,
  547. IsAiring = isAiring,
  548. EnableTotalRecordCount = enableTotalRecordCount,
  549. MinStartDate = minStartDate,
  550. MinEndDate = minEndDate,
  551. MaxStartDate = maxStartDate,
  552. MaxEndDate = maxEndDate,
  553. StartIndex = startIndex,
  554. Limit = limit,
  555. OrderBy = RequestHelpers.GetOrderBy(sortBy, sortOrder),
  556. IsNews = isNews,
  557. IsMovie = isMovie,
  558. IsSeries = isSeries,
  559. IsKids = isKids,
  560. IsSports = isSports,
  561. SeriesTimerId = seriesTimerId,
  562. Genres = RequestHelpers.Split(genres, ',', true),
  563. GenreIds = RequestHelpers.GetGuids(genreIds)
  564. };
  565. if (!librarySeriesId.Equals(Guid.Empty))
  566. {
  567. query.IsSeries = true;
  568. if (_libraryManager.GetItemById(librarySeriesId) is Series series)
  569. {
  570. query.Name = series.Name;
  571. }
  572. }
  573. var dtoOptions = new DtoOptions()
  574. .AddItemFields(fields)
  575. .AddClientFields(Request)
  576. .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
  577. return await _liveTvManager.GetPrograms(query, dtoOptions, CancellationToken.None).ConfigureAwait(false);
  578. }
  579. /// <summary>
  580. /// Gets available live tv epgs.
  581. /// </summary>
  582. /// <param name="body">Request body.</param>
  583. /// <response code="200">Live tv epgs returned.</response>
  584. /// <returns>
  585. /// A <see cref="Task"/> containing a <see cref="OkResult"/> which contains the live tv epgs.
  586. /// </returns>
  587. [HttpPost("Programs")]
  588. [ProducesResponseType(StatusCodes.Status200OK)]
  589. [Authorize(Policy = Policies.DefaultAuthorization)]
  590. public async Task<ActionResult<QueryResult<BaseItemDto>>> GetPrograms([FromBody] GetProgramsDto body)
  591. {
  592. var user = body.UserId.Equals(Guid.Empty) ? null : _userManager.GetUserById(body.UserId);
  593. var query = new InternalItemsQuery(user)
  594. {
  595. ChannelIds = RequestHelpers.Split(body.ChannelIds, ',', true)
  596. .Select(i => new Guid(i)).ToArray(),
  597. HasAired = body.HasAired,
  598. IsAiring = body.IsAiring,
  599. EnableTotalRecordCount = body.EnableTotalRecordCount,
  600. MinStartDate = body.MinStartDate,
  601. MinEndDate = body.MinEndDate,
  602. MaxStartDate = body.MaxStartDate,
  603. MaxEndDate = body.MaxEndDate,
  604. StartIndex = body.StartIndex,
  605. Limit = body.Limit,
  606. OrderBy = RequestHelpers.GetOrderBy(body.SortBy, body.SortOrder),
  607. IsNews = body.IsNews,
  608. IsMovie = body.IsMovie,
  609. IsSeries = body.IsSeries,
  610. IsKids = body.IsKids,
  611. IsSports = body.IsSports,
  612. SeriesTimerId = body.SeriesTimerId,
  613. Genres = RequestHelpers.Split(body.Genres, ',', true),
  614. GenreIds = RequestHelpers.GetGuids(body.GenreIds)
  615. };
  616. if (!body.LibrarySeriesId.Equals(Guid.Empty))
  617. {
  618. query.IsSeries = true;
  619. if (_libraryManager.GetItemById(body.LibrarySeriesId) is Series series)
  620. {
  621. query.Name = series.Name;
  622. }
  623. }
  624. var dtoOptions = new DtoOptions()
  625. .AddItemFields(body.Fields)
  626. .AddClientFields(Request)
  627. .AddAdditionalDtoOptions(body.EnableImages, body.EnableUserData, body.ImageTypeLimit, body.EnableImageTypes);
  628. return await _liveTvManager.GetPrograms(query, dtoOptions, CancellationToken.None).ConfigureAwait(false);
  629. }
  630. /// <summary>
  631. /// Gets recommended live tv epgs.
  632. /// </summary>
  633. /// <param name="userId">Optional. filter by user id.</param>
  634. /// <param name="limit">Optional. The maximum number of records to return.</param>
  635. /// <param name="isAiring">Optional. Filter by programs that are currently airing, or not.</param>
  636. /// <param name="hasAired">Optional. Filter by programs that have completed airing, or not.</param>
  637. /// <param name="isSeries">Optional. Filter for series.</param>
  638. /// <param name="isMovie">Optional. Filter for movies.</param>
  639. /// <param name="isNews">Optional. Filter for news.</param>
  640. /// <param name="isKids">Optional. Filter for kids.</param>
  641. /// <param name="isSports">Optional. Filter for sports.</param>
  642. /// <param name="enableImages">Optional. Include image information in output.</param>
  643. /// <param name="imageTypeLimit">Optional. The max number of images to return, per image type.</param>
  644. /// <param name="enableImageTypes">Optional. The image types to include in the output.</param>
  645. /// <param name="genreIds">The genres to return guide information for.</param>
  646. /// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.</param>
  647. /// <param name="enableUserData">Optional. include user data.</param>
  648. /// <param name="enableTotalRecordCount">Retrieve total record count.</param>
  649. /// <response code="200">Recommended epgs returned.</response>
  650. /// <returns>A <see cref="OkResult"/> containing the queryresult of recommended epgs.</returns>
  651. [HttpGet("Programs/Recommended")]
  652. [Authorize(Policy = Policies.DefaultAuthorization)]
  653. [ProducesResponseType(StatusCodes.Status200OK)]
  654. public ActionResult<QueryResult<BaseItemDto>> GetRecommendedPrograms(
  655. [FromQuery] Guid userId,
  656. [FromQuery] int? limit,
  657. [FromQuery] bool? isAiring,
  658. [FromQuery] bool? hasAired,
  659. [FromQuery] bool? isSeries,
  660. [FromQuery] bool? isMovie,
  661. [FromQuery] bool? isNews,
  662. [FromQuery] bool? isKids,
  663. [FromQuery] bool? isSports,
  664. [FromQuery] bool? enableImages,
  665. [FromQuery] int? imageTypeLimit,
  666. [FromQuery] string enableImageTypes,
  667. [FromQuery] string genreIds,
  668. [FromQuery] string fields,
  669. [FromQuery] bool? enableUserData,
  670. [FromQuery] bool enableTotalRecordCount = true)
  671. {
  672. var user = _userManager.GetUserById(userId);
  673. var query = new InternalItemsQuery(user)
  674. {
  675. IsAiring = isAiring,
  676. Limit = limit,
  677. HasAired = hasAired,
  678. IsSeries = isSeries,
  679. IsMovie = isMovie,
  680. IsKids = isKids,
  681. IsNews = isNews,
  682. IsSports = isSports,
  683. EnableTotalRecordCount = enableTotalRecordCount,
  684. GenreIds = RequestHelpers.GetGuids(genreIds)
  685. };
  686. var dtoOptions = new DtoOptions()
  687. .AddItemFields(fields)
  688. .AddClientFields(Request)
  689. .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
  690. return _liveTvManager.GetRecommendedPrograms(query, dtoOptions, CancellationToken.None);
  691. }
  692. /// <summary>
  693. /// Deletes a live tv recording.
  694. /// </summary>
  695. /// <param name="recordingId">Recording id.</param>
  696. /// <response code="204">Recording deleted.</response>
  697. /// <response code="404">Item not found.</response>
  698. /// <returns>A <see cref="NoContentResult"/> on success, or a <see cref="NotFoundResult"/> if item not found.</returns>
  699. [HttpDelete("Recordings/{recordingId}")]
  700. [Authorize(Policy = Policies.DefaultAuthorization)]
  701. [ProducesResponseType(StatusCodes.Status204NoContent)]
  702. [ProducesResponseType(StatusCodes.Status404NotFound)]
  703. public ActionResult DeleteRecording([FromRoute] Guid recordingId)
  704. {
  705. AssertUserCanManageLiveTv();
  706. var item = _libraryManager.GetItemById(recordingId);
  707. if (item == null)
  708. {
  709. return NotFound();
  710. }
  711. _libraryManager.DeleteItem(item, new DeleteOptions
  712. {
  713. DeleteFileLocation = false
  714. });
  715. return NoContent();
  716. }
  717. /// <summary>
  718. /// Cancels a live tv timer.
  719. /// </summary>
  720. /// <param name="timerId">Timer id.</param>
  721. /// <response code="204">Timer deleted.</response>
  722. /// <returns>A <see cref="NoContentResult"/>.</returns>
  723. [HttpDelete("Timers/{timerId}")]
  724. [Authorize(Policy = Policies.DefaultAuthorization)]
  725. [ProducesResponseType(StatusCodes.Status204NoContent)]
  726. public async Task<ActionResult> CancelTimer([FromRoute] string timerId)
  727. {
  728. AssertUserCanManageLiveTv();
  729. await _liveTvManager.CancelTimer(timerId).ConfigureAwait(false);
  730. return NoContent();
  731. }
  732. /// <summary>
  733. /// Updates a live tv timer.
  734. /// </summary>
  735. /// <param name="timerId">Timer id.</param>
  736. /// <param name="timerInfo">New timer info.</param>
  737. /// <response code="204">Timer updated.</response>
  738. /// <returns>A <see cref="NoContentResult"/>.</returns>
  739. [HttpPost("Timers/{timerId}")]
  740. [Authorize(Policy = Policies.DefaultAuthorization)]
  741. [ProducesResponseType(StatusCodes.Status204NoContent)]
  742. public async Task<ActionResult> UpdateTimer([FromRoute] string timerId, [FromBody] TimerInfoDto timerInfo)
  743. {
  744. AssertUserCanManageLiveTv();
  745. await _liveTvManager.UpdateTimer(timerInfo, CancellationToken.None).ConfigureAwait(false);
  746. return NoContent();
  747. }
  748. /// <summary>
  749. /// Creates a live tv timer.
  750. /// </summary>
  751. /// <param name="timerInfo">New timer info.</param>
  752. /// <response code="204">Timer created.</response>
  753. /// <returns>A <see cref="NoContentResult"/>.</returns>
  754. [HttpPost("Timers")]
  755. [Authorize(Policy = Policies.DefaultAuthorization)]
  756. [ProducesResponseType(StatusCodes.Status204NoContent)]
  757. public async Task<ActionResult> CreateTimer([FromBody] TimerInfoDto timerInfo)
  758. {
  759. AssertUserCanManageLiveTv();
  760. await _liveTvManager.CreateTimer(timerInfo, CancellationToken.None).ConfigureAwait(false);
  761. return NoContent();
  762. }
  763. /// <summary>
  764. /// Gets a live tv series timer.
  765. /// </summary>
  766. /// <param name="timerId">Timer id.</param>
  767. /// <response code="200">Series timer returned.</response>
  768. /// <response code="404">Series timer not found.</response>
  769. /// <returns>A <see cref="OkResult"/> on success, or a <see cref="NotFoundResult"/> if timer not found.</returns>
  770. [HttpGet("SeriesTimers/{timerId}")]
  771. [Authorize(Policy = Policies.DefaultAuthorization)]
  772. [ProducesResponseType(StatusCodes.Status200OK)]
  773. [ProducesResponseType(StatusCodes.Status404NotFound)]
  774. public async Task<ActionResult<SeriesTimerInfoDto>> GetSeriesTimer([FromRoute] string timerId)
  775. {
  776. var timer = await _liveTvManager.GetSeriesTimer(timerId, CancellationToken.None).ConfigureAwait(false);
  777. if (timer == null)
  778. {
  779. return NotFound();
  780. }
  781. return timer;
  782. }
  783. /// <summary>
  784. /// Gets live tv series timers.
  785. /// </summary>
  786. /// <param name="sortBy">Optional. Sort by SortName or Priority.</param>
  787. /// <param name="sortOrder">Optional. Sort in Ascending or Descending order.</param>
  788. /// <response code="200">Timers returned.</response>
  789. /// <returns>An <see cref="OkResult"/> of live tv series timers.</returns>
  790. [HttpGet("SeriesTimers")]
  791. [Authorize(Policy = Policies.DefaultAuthorization)]
  792. [ProducesResponseType(StatusCodes.Status200OK)]
  793. public async Task<ActionResult<QueryResult<SeriesTimerInfoDto>>> GetSeriesTimers([FromQuery] string sortBy, [FromQuery] SortOrder sortOrder)
  794. {
  795. return await _liveTvManager.GetSeriesTimers(
  796. new SeriesTimerQuery
  797. {
  798. SortOrder = sortOrder,
  799. SortBy = sortBy
  800. }, CancellationToken.None).ConfigureAwait(false);
  801. }
  802. /// <summary>
  803. /// Cancels a live tv series timer.
  804. /// </summary>
  805. /// <param name="timerId">Timer id.</param>
  806. /// <response code="204">Timer cancelled.</response>
  807. /// <returns>A <see cref="NoContentResult"/>.</returns>
  808. [HttpDelete("SeriesTimers/{timerId}")]
  809. [Authorize(Policy = Policies.DefaultAuthorization)]
  810. [ProducesResponseType(StatusCodes.Status204NoContent)]
  811. public async Task<ActionResult> CancelSeriesTimer([FromRoute] string timerId)
  812. {
  813. AssertUserCanManageLiveTv();
  814. await _liveTvManager.CancelSeriesTimer(timerId).ConfigureAwait(false);
  815. return NoContent();
  816. }
  817. /// <summary>
  818. /// Updates a live tv series timer.
  819. /// </summary>
  820. /// <param name="timerId">Timer id.</param>
  821. /// <param name="seriesTimerInfo">New series timer info.</param>
  822. /// <response code="204">Series timer updated.</response>
  823. /// <returns>A <see cref="NoContentResult"/>.</returns>
  824. [HttpPost("SeriesTimers/{timerId}")]
  825. [Authorize(Policy = Policies.DefaultAuthorization)]
  826. [ProducesResponseType(StatusCodes.Status204NoContent)]
  827. public async Task<ActionResult> UpdateSeriesTimer([FromRoute] string timerId, [FromBody] SeriesTimerInfoDto seriesTimerInfo)
  828. {
  829. AssertUserCanManageLiveTv();
  830. await _liveTvManager.UpdateSeriesTimer(seriesTimerInfo, CancellationToken.None).ConfigureAwait(false);
  831. return NoContent();
  832. }
  833. /// <summary>
  834. /// Creates a live tv series timer.
  835. /// </summary>
  836. /// <param name="seriesTimerInfo">New series timer info.</param>
  837. /// <response code="204">Series timer info created.</response>
  838. /// <returns>A <see cref="NoContentResult"/>.</returns>
  839. [HttpPost("SeriesTimers")]
  840. [Authorize(Policy = Policies.DefaultAuthorization)]
  841. [ProducesResponseType(StatusCodes.Status204NoContent)]
  842. public async Task<ActionResult> CreateSeriesTimer([FromBody] SeriesTimerInfoDto seriesTimerInfo)
  843. {
  844. AssertUserCanManageLiveTv();
  845. await _liveTvManager.CreateSeriesTimer(seriesTimerInfo, CancellationToken.None).ConfigureAwait(false);
  846. return NoContent();
  847. }
  848. /// <summary>
  849. /// Get recording group.
  850. /// </summary>
  851. /// <param name="groupId">Group id.</param>
  852. /// <returns>A <see cref="NotFoundResult"/>.</returns>
  853. [HttpGet("Recordings/Groups/{groupId}")]
  854. [Authorize(Policy = Policies.DefaultAuthorization)]
  855. [ProducesResponseType(StatusCodes.Status404NotFound)]
  856. [Obsolete("This endpoint is obsolete.")]
  857. public ActionResult<BaseItemDto> GetRecordingGroup([FromQuery] Guid groupId)
  858. {
  859. return NotFound();
  860. }
  861. /// <summary>
  862. /// Get guid info.
  863. /// </summary>
  864. /// <response code="200">Guid info returned.</response>
  865. /// <returns>An <see cref="OkResult"/> containing the guide info.</returns>
  866. [HttpGet("GuideInfo")]
  867. [Authorize(Policy = Policies.DefaultAuthorization)]
  868. [ProducesResponseType(StatusCodes.Status200OK)]
  869. public ActionResult<GuideInfo> GetGuideInfo()
  870. {
  871. return _liveTvManager.GetGuideInfo();
  872. }
  873. /// <summary>
  874. /// Adds a tuner host.
  875. /// </summary>
  876. /// <param name="tunerHostInfo">New tuner host.</param>
  877. /// <response code="200">Created tuner host returned.</response>
  878. /// <returns>A <see cref="OkResult"/> containing the created tuner host.</returns>
  879. [HttpPost("TunerHosts")]
  880. [Authorize(Policy = Policies.DefaultAuthorization)]
  881. [ProducesResponseType(StatusCodes.Status200OK)]
  882. public async Task<ActionResult<TunerHostInfo>> AddTunerHost([FromBody] TunerHostInfo tunerHostInfo)
  883. {
  884. return await _liveTvManager.SaveTunerHost(tunerHostInfo).ConfigureAwait(false);
  885. }
  886. /// <summary>
  887. /// Deletes a tuner host.
  888. /// </summary>
  889. /// <param name="id">Tuner host id.</param>
  890. /// <response code="204">Tuner host deleted.</response>
  891. /// <returns>A <see cref="NoContentResult"/>.</returns>
  892. [HttpDelete("TunerHosts")]
  893. [Authorize(Policy = Policies.DefaultAuthorization)]
  894. [ProducesResponseType(StatusCodes.Status204NoContent)]
  895. public ActionResult DeleteTunerHost([FromQuery] string id)
  896. {
  897. var config = _configurationManager.GetConfiguration<LiveTvOptions>("livetv");
  898. config.TunerHosts = config.TunerHosts.Where(i => !string.Equals(id, i.Id, StringComparison.OrdinalIgnoreCase)).ToArray();
  899. _configurationManager.SaveConfiguration("livetv", config);
  900. return NoContent();
  901. }
  902. /// <summary>
  903. /// Gets default listings provider info.
  904. /// </summary>
  905. /// <response code="200">Default listings provider info returned.</response>
  906. /// <returns>An <see cref="OkResult"/> containing the default listings provider info.</returns>
  907. [HttpGet("ListingProviders/Default")]
  908. [Authorize(Policy = Policies.DefaultAuthorization)]
  909. [ProducesResponseType(StatusCodes.Status200OK)]
  910. public ActionResult<ListingsProviderInfo> GetDefaultListingProvider()
  911. {
  912. return new ListingsProviderInfo();
  913. }
  914. /// <summary>
  915. /// Adds a listings provider.
  916. /// </summary>
  917. /// <param name="validateLogin">Validate login.</param>
  918. /// <param name="validateListings">Validate listings.</param>
  919. /// <param name="pw">Password.</param>
  920. /// <param name="listingsProviderInfo">New listings info.</param>
  921. /// <response code="200">Created listings provider returned.</response>
  922. /// <returns>A <see cref="OkResult"/> containing the created listings provider.</returns>
  923. [HttpGet("ListingProviders")]
  924. [Authorize(Policy = Policies.DefaultAuthorization)]
  925. [ProducesResponseType(StatusCodes.Status200OK)]
  926. public async Task<ActionResult<ListingsProviderInfo>> AddListingProvider(
  927. [FromQuery] bool validateLogin,
  928. [FromQuery] bool validateListings,
  929. [FromQuery] string pw,
  930. [FromBody] ListingsProviderInfo listingsProviderInfo)
  931. {
  932. using var sha = SHA1.Create();
  933. if (!string.IsNullOrEmpty(pw))
  934. {
  935. listingsProviderInfo.Password = Hex.Encode(sha.ComputeHash(Encoding.UTF8.GetBytes(pw)));
  936. }
  937. return await _liveTvManager.SaveListingProvider(listingsProviderInfo, validateLogin, validateListings).ConfigureAwait(false);
  938. }
  939. /// <summary>
  940. /// Delete listing provider.
  941. /// </summary>
  942. /// <param name="id">Listing provider id.</param>
  943. /// <response code="204">Listing provider deleted.</response>
  944. /// <returns>A <see cref="NoContentResult"/>.</returns>
  945. [HttpGet("ListingProviders")]
  946. [Authorize(Policy = Policies.DefaultAuthorization)]
  947. [ProducesResponseType(StatusCodes.Status204NoContent)]
  948. public ActionResult DeleteListingProvider([FromQuery] string id)
  949. {
  950. _liveTvManager.DeleteListingsProvider(id);
  951. return NoContent();
  952. }
  953. /// <summary>
  954. /// Gets available lineups.
  955. /// </summary>
  956. /// <param name="id">Provider id.</param>
  957. /// <param name="type">Provider type.</param>
  958. /// <param name="location">Location.</param>
  959. /// <param name="country">Country.</param>
  960. /// <response code="200">Available lineups returned.</response>
  961. /// <returns>A <see cref="OkResult"/> containing the available lineups.</returns>
  962. [HttpGet("ListingProviders/Lineups")]
  963. [Authorize(Policy = Policies.DefaultAuthorization)]
  964. [ProducesResponseType(StatusCodes.Status200OK)]
  965. public async Task<ActionResult<IEnumerable<NameIdPair>>> GetLineups(
  966. [FromQuery] string id,
  967. [FromQuery] string type,
  968. [FromQuery] string location,
  969. [FromQuery] string country)
  970. {
  971. return await _liveTvManager.GetLineups(type, id, country, location).ConfigureAwait(false);
  972. }
  973. /// <summary>
  974. /// Gets available countries.
  975. /// </summary>
  976. /// <response code="200">Available countries returned.</response>
  977. /// <returns>A <see cref="FileResult"/> containing the available countries.</returns>
  978. [HttpGet("ListingProviders/SchedulesDirect/Countries")]
  979. [Authorize(Policy = Policies.DefaultAuthorization)]
  980. [ProducesResponseType(StatusCodes.Status200OK)]
  981. public async Task<ActionResult> GetSchedulesDirectCountries()
  982. {
  983. // https://json.schedulesdirect.org/20141201/available/countries
  984. var response = await _httpClient.Get(new HttpRequestOptions
  985. {
  986. Url = "https://json.schedulesdirect.org/20141201/available/countries",
  987. BufferContent = false
  988. }).ConfigureAwait(false);
  989. return File(response, MediaTypeNames.Application.Json);
  990. }
  991. /// <summary>
  992. /// Get channel mapping options.
  993. /// </summary>
  994. /// <param name="providerId">Provider id.</param>
  995. /// <response code="200">Channel mapping options returned.</response>
  996. /// <returns>An <see cref="OkResult"/> containing the channel mapping options.</returns>
  997. [HttpGet("ChannelMappingOptions")]
  998. [Authorize(Policy = Policies.DefaultAuthorization)]
  999. [ProducesResponseType(StatusCodes.Status200OK)]
  1000. public async Task<ActionResult<ChannelMappingOptionsDto>> GetChannelMappingOptions([FromQuery] string providerId)
  1001. {
  1002. var config = _configurationManager.GetConfiguration<LiveTvOptions>("livetv");
  1003. var listingsProviderInfo = config.ListingProviders.First(i => string.Equals(providerId, i.Id, StringComparison.OrdinalIgnoreCase));
  1004. var listingsProviderName = _liveTvManager.ListingProviders.First(i => string.Equals(i.Type, listingsProviderInfo.Type, StringComparison.OrdinalIgnoreCase)).Name;
  1005. var tunerChannels = await _liveTvManager.GetChannelsForListingsProvider(providerId, CancellationToken.None)
  1006. .ConfigureAwait(false);
  1007. var providerChannels = await _liveTvManager.GetChannelsFromListingsProviderData(providerId, CancellationToken.None)
  1008. .ConfigureAwait(false);
  1009. var mappings = listingsProviderInfo.ChannelMappings;
  1010. return new ChannelMappingOptionsDto
  1011. {
  1012. TunerChannels = tunerChannels.Select(i => _liveTvManager.GetTunerChannelMapping(i, mappings, providerChannels)).ToList(),
  1013. ProviderChannels = providerChannels.Select(i => new NameIdPair
  1014. {
  1015. Name = i.Name,
  1016. Id = i.Id
  1017. }).ToList(),
  1018. Mappings = mappings,
  1019. ProviderName = listingsProviderName
  1020. };
  1021. }
  1022. /// <summary>
  1023. /// Set channel mappings.
  1024. /// </summary>
  1025. /// <param name="providerId">Provider id.</param>
  1026. /// <param name="tunerChannelId">Tuner channel id.</param>
  1027. /// <param name="providerChannelId">Provider channel id.</param>
  1028. /// <response code="200">Created channel mapping returned.</response>
  1029. /// <returns>An <see cref="OkResult"/> containing the created channel mapping.</returns>
  1030. [HttpPost("ChannelMappings")]
  1031. [Authorize(Policy = Policies.DefaultAuthorization)]
  1032. [ProducesResponseType(StatusCodes.Status200OK)]
  1033. public async Task<ActionResult<TunerChannelMapping>> SetChannelMapping(
  1034. [FromQuery] string providerId,
  1035. [FromQuery] string tunerChannelId,
  1036. [FromQuery] string providerChannelId)
  1037. {
  1038. return await _liveTvManager.SetChannelMapping(providerId, tunerChannelId, providerChannelId).ConfigureAwait(false);
  1039. }
  1040. /// <summary>
  1041. /// Get tuner host types.
  1042. /// </summary>
  1043. /// <response code="200">Tuner host types returned.</response>
  1044. /// <returns>An <see cref="OkResult"/> containing the tuner host types.</returns>
  1045. [HttpGet("TunerHosts/Types")]
  1046. [Authorize(Policy = Policies.DefaultAuthorization)]
  1047. [ProducesResponseType(StatusCodes.Status200OK)]
  1048. public ActionResult<IEnumerable<NameIdPair>> GetTunerHostTypes()
  1049. {
  1050. return _liveTvManager.GetTunerHostTypes();
  1051. }
  1052. /// <summary>
  1053. /// Discover tuners.
  1054. /// </summary>
  1055. /// <param name="newDevicesOnly">Only discover new tuners.</param>
  1056. /// <response code="200">Tuners returned.</response>
  1057. /// <returns>An <see cref="OkResult"/> containing the tuners.</returns>
  1058. [HttpGet("Tuners/Discvover")]
  1059. [Authorize(Policy = Policies.DefaultAuthorization)]
  1060. [ProducesResponseType(StatusCodes.Status200OK)]
  1061. public async Task<ActionResult<IEnumerable<TunerHostInfo>>> DiscoverTuners([FromQuery] bool newDevicesOnly)
  1062. {
  1063. return await _liveTvManager.DiscoverTuners(newDevicesOnly, CancellationToken.None).ConfigureAwait(false);
  1064. }
  1065. private void AssertUserCanManageLiveTv()
  1066. {
  1067. var user = _sessionContext.GetUser(Request);
  1068. if (user == null)
  1069. {
  1070. throw new SecurityException("Anonymous live tv management is not allowed.");
  1071. }
  1072. if (!user.HasPermission(PermissionKind.EnableLiveTvManagement))
  1073. {
  1074. throw new SecurityException("The current user does not have permission to manage live tv.");
  1075. }
  1076. }
  1077. }
  1078. }