BaseApiService.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. using System.Threading.Tasks;
  2. using MediaBrowser.Controller.Dto;
  3. using MediaBrowser.Controller.Entities;
  4. using MediaBrowser.Controller.Entities.Audio;
  5. using MediaBrowser.Controller.Library;
  6. using MediaBrowser.Controller.Net;
  7. using MediaBrowser.Controller.Session;
  8. using MediaBrowser.Model.Entities;
  9. using MediaBrowser.Model.Logging;
  10. using ServiceStack.Text.Controller;
  11. using ServiceStack.Web;
  12. using System;
  13. using System.Collections.Generic;
  14. using System.Linq;
  15. namespace MediaBrowser.Api
  16. {
  17. /// <summary>
  18. /// Class BaseApiService
  19. /// </summary>
  20. public class BaseApiService : IHasResultFactory, IRestfulService, IHasSession
  21. {
  22. /// <summary>
  23. /// Gets or sets the logger.
  24. /// </summary>
  25. /// <value>The logger.</value>
  26. public ILogger Logger { get; set; }
  27. /// <summary>
  28. /// Gets or sets the HTTP result factory.
  29. /// </summary>
  30. /// <value>The HTTP result factory.</value>
  31. public IHttpResultFactory ResultFactory { get; set; }
  32. /// <summary>
  33. /// Gets or sets the request context.
  34. /// </summary>
  35. /// <value>The request context.</value>
  36. public IRequest Request { get; set; }
  37. public ISessionContext SessionContext { get; set; }
  38. public IAuthorizationContext AuthorizationContext { get; set; }
  39. public IUserManager UserManager { get; set; }
  40. public string GetHeader(string name)
  41. {
  42. return Request.Headers[name];
  43. }
  44. /// <summary>
  45. /// To the optimized result.
  46. /// </summary>
  47. /// <typeparam name="T"></typeparam>
  48. /// <param name="result">The result.</param>
  49. /// <returns>System.Object.</returns>
  50. protected object ToOptimizedResult<T>(T result)
  51. where T : class
  52. {
  53. return ResultFactory.GetOptimizedResult(Request, result);
  54. }
  55. /// <summary>
  56. /// To the optimized result using cache.
  57. /// </summary>
  58. /// <typeparam name="T"></typeparam>
  59. /// <param name="cacheKey">The cache key.</param>
  60. /// <param name="lastDateModified">The last date modified.</param>
  61. /// <param name="cacheDuration">Duration of the cache.</param>
  62. /// <param name="factoryFn">The factory function.</param>
  63. /// <returns>System.Object.</returns>
  64. protected object ToOptimizedResultUsingCache<T>(Guid cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, Func<T> factoryFn)
  65. where T : class
  66. {
  67. return ResultFactory.GetOptimizedResultUsingCache(Request, cacheKey, lastDateModified, cacheDuration, factoryFn);
  68. }
  69. protected void AssertCanUpdateUser(string userId)
  70. {
  71. var auth = AuthorizationContext.GetAuthorizationInfo(Request);
  72. var authenticatedUser = UserManager.GetUserById(auth.UserId);
  73. // If they're going to update the record of another user, they must be an administrator
  74. if (!string.Equals(userId, auth.UserId, StringComparison.OrdinalIgnoreCase))
  75. {
  76. if (!authenticatedUser.Policy.IsAdministrator)
  77. {
  78. throw new SecurityException("Unauthorized access.");
  79. }
  80. }
  81. else
  82. {
  83. if (!authenticatedUser.Policy.EnableUserPreferenceAccess)
  84. {
  85. throw new SecurityException("Unauthorized access.");
  86. }
  87. }
  88. }
  89. /// <summary>
  90. /// To the optimized serialized result using cache.
  91. /// </summary>
  92. /// <typeparam name="T"></typeparam>
  93. /// <param name="result">The result.</param>
  94. /// <returns>System.Object.</returns>
  95. protected object ToOptimizedSerializedResultUsingCache<T>(T result)
  96. where T : class
  97. {
  98. return ToOptimizedResult(result);
  99. }
  100. /// <summary>
  101. /// Gets the session.
  102. /// </summary>
  103. /// <returns>SessionInfo.</returns>
  104. protected async Task<SessionInfo> GetSession()
  105. {
  106. var session = await SessionContext.GetSession(Request).ConfigureAwait(false);
  107. if (session == null)
  108. {
  109. throw new ArgumentException("Session not found.");
  110. }
  111. return session;
  112. }
  113. /// <summary>
  114. /// To the static file result.
  115. /// </summary>
  116. /// <param name="path">The path.</param>
  117. /// <returns>System.Object.</returns>
  118. protected object ToStaticFileResult(string path)
  119. {
  120. return ResultFactory.GetStaticFileResult(Request, path);
  121. }
  122. private readonly char[] _dashReplaceChars = { '?', '/', '&' };
  123. private const char SlugChar = '-';
  124. protected DtoOptions GetDtoOptions(object request)
  125. {
  126. var options = new DtoOptions();
  127. options.DeviceId = AuthorizationContext.GetAuthorizationInfo(Request).DeviceId;
  128. var hasFields = request as IHasItemFields;
  129. if (hasFields != null)
  130. {
  131. options.Fields = hasFields.GetItemFields().ToList();
  132. }
  133. var hasDtoOptions = request as IHasDtoOptions;
  134. if (hasDtoOptions != null)
  135. {
  136. options.EnableImages = hasDtoOptions.EnableImages ?? true;
  137. if (hasDtoOptions.ImageTypeLimit.HasValue)
  138. {
  139. options.ImageTypeLimit = hasDtoOptions.ImageTypeLimit.Value;
  140. }
  141. if (!string.IsNullOrWhiteSpace(hasDtoOptions.EnableImageTypes))
  142. {
  143. options.ImageTypes = (hasDtoOptions.EnableImageTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).Select(v => (ImageType)Enum.Parse(typeof(ImageType), v, true)).ToList();
  144. }
  145. }
  146. return options;
  147. }
  148. protected MusicArtist GetArtist(string name, ILibraryManager libraryManager)
  149. {
  150. return libraryManager.GetArtist(DeSlugArtistName(name, libraryManager));
  151. }
  152. protected Studio GetStudio(string name, ILibraryManager libraryManager)
  153. {
  154. return libraryManager.GetStudio(DeSlugStudioName(name, libraryManager));
  155. }
  156. protected Genre GetGenre(string name, ILibraryManager libraryManager)
  157. {
  158. return libraryManager.GetGenre(DeSlugGenreName(name, libraryManager));
  159. }
  160. protected MusicGenre GetMusicGenre(string name, ILibraryManager libraryManager)
  161. {
  162. return libraryManager.GetMusicGenre(DeSlugGenreName(name, libraryManager));
  163. }
  164. protected GameGenre GetGameGenre(string name, ILibraryManager libraryManager)
  165. {
  166. return libraryManager.GetGameGenre(DeSlugGameGenreName(name, libraryManager));
  167. }
  168. protected Person GetPerson(string name, ILibraryManager libraryManager)
  169. {
  170. return libraryManager.GetPerson(DeSlugPersonName(name, libraryManager));
  171. }
  172. protected IList<BaseItem> GetAllLibraryItems(Guid? userId, IUserManager userManager, ILibraryManager libraryManager, string parentId, Func<BaseItem,bool> filter)
  173. {
  174. if (!string.IsNullOrEmpty(parentId))
  175. {
  176. var folder = (Folder)libraryManager.GetItemById(new Guid(parentId));
  177. if (userId.HasValue)
  178. {
  179. var user = userManager.GetUserById(userId.Value);
  180. if (user == null)
  181. {
  182. throw new ArgumentException("User not found");
  183. }
  184. return folder
  185. .GetRecursiveChildren(user, filter)
  186. .ToList();
  187. }
  188. return folder
  189. .GetRecursiveChildren(filter);
  190. }
  191. if (userId.HasValue)
  192. {
  193. var user = userManager.GetUserById(userId.Value);
  194. if (user == null)
  195. {
  196. throw new ArgumentException("User not found");
  197. }
  198. return userManager
  199. .GetUserById(userId.Value)
  200. .RootFolder
  201. .GetRecursiveChildren(user, filter)
  202. .ToList();
  203. }
  204. return libraryManager
  205. .RootFolder
  206. .GetRecursiveChildren(filter);
  207. }
  208. /// <summary>
  209. /// Deslugs an artist name by finding the correct entry in the library
  210. /// </summary>
  211. /// <param name="name"></param>
  212. /// <param name="libraryManager"></param>
  213. /// <returns></returns>
  214. protected string DeSlugArtistName(string name, ILibraryManager libraryManager)
  215. {
  216. if (name.IndexOf(SlugChar) == -1)
  217. {
  218. return name;
  219. }
  220. return libraryManager.RootFolder
  221. .GetRecursiveChildren(i => i is IHasArtist)
  222. .Cast<IHasArtist>()
  223. .SelectMany(i => i.AllArtists)
  224. .Distinct(StringComparer.OrdinalIgnoreCase)
  225. .FirstOrDefault(i =>
  226. {
  227. i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar));
  228. return string.Equals(i, name, StringComparison.OrdinalIgnoreCase);
  229. }) ?? name;
  230. }
  231. /// <summary>
  232. /// Deslugs a genre name by finding the correct entry in the library
  233. /// </summary>
  234. protected string DeSlugGenreName(string name, ILibraryManager libraryManager)
  235. {
  236. if (name.IndexOf(SlugChar) == -1)
  237. {
  238. return name;
  239. }
  240. return libraryManager.RootFolder.GetRecursiveChildren()
  241. .SelectMany(i => i.Genres)
  242. .Distinct(StringComparer.OrdinalIgnoreCase)
  243. .FirstOrDefault(i =>
  244. {
  245. i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar));
  246. return string.Equals(i, name, StringComparison.OrdinalIgnoreCase);
  247. }) ?? name;
  248. }
  249. protected string DeSlugGameGenreName(string name, ILibraryManager libraryManager)
  250. {
  251. if (name.IndexOf(SlugChar) == -1)
  252. {
  253. return name;
  254. }
  255. return libraryManager.RootFolder
  256. .GetRecursiveChildren(i => i is Game)
  257. .SelectMany(i => i.Genres)
  258. .Distinct(StringComparer.OrdinalIgnoreCase)
  259. .FirstOrDefault(i =>
  260. {
  261. i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar));
  262. return string.Equals(i, name, StringComparison.OrdinalIgnoreCase);
  263. }) ?? name;
  264. }
  265. /// <summary>
  266. /// Deslugs a studio name by finding the correct entry in the library
  267. /// </summary>
  268. protected string DeSlugStudioName(string name, ILibraryManager libraryManager)
  269. {
  270. if (name.IndexOf(SlugChar) == -1)
  271. {
  272. return name;
  273. }
  274. return libraryManager.RootFolder
  275. .GetRecursiveChildren()
  276. .SelectMany(i => i.Studios)
  277. .Distinct(StringComparer.OrdinalIgnoreCase)
  278. .FirstOrDefault(i =>
  279. {
  280. i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar));
  281. return string.Equals(i, name, StringComparison.OrdinalIgnoreCase);
  282. }) ?? name;
  283. }
  284. /// <summary>
  285. /// Deslugs a person name by finding the correct entry in the library
  286. /// </summary>
  287. protected string DeSlugPersonName(string name, ILibraryManager libraryManager)
  288. {
  289. if (name.IndexOf(SlugChar) == -1)
  290. {
  291. return name;
  292. }
  293. return libraryManager.RootFolder
  294. .GetRecursiveChildren()
  295. .SelectMany(i => i.People)
  296. .Select(i => i.Name)
  297. .Distinct(StringComparer.OrdinalIgnoreCase)
  298. .FirstOrDefault(i =>
  299. {
  300. i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar));
  301. return string.Equals(i, name, StringComparison.OrdinalIgnoreCase);
  302. }) ?? name;
  303. }
  304. protected string GetPathValue(int index)
  305. {
  306. var pathInfo = PathInfo.Parse(Request.PathInfo);
  307. var first = pathInfo.GetArgumentValue<string>(0);
  308. // backwards compatibility
  309. if (string.Equals(first, "mediabrowser", StringComparison.OrdinalIgnoreCase))
  310. {
  311. index++;
  312. }
  313. return pathInfo.GetArgumentValue<string>(index);
  314. }
  315. /// <summary>
  316. /// Gets the name of the item by.
  317. /// </summary>
  318. /// <param name="name">The name.</param>
  319. /// <param name="type">The type.</param>
  320. /// <param name="libraryManager">The library manager.</param>
  321. /// <returns>Task{BaseItem}.</returns>
  322. protected BaseItem GetItemByName(string name, string type, ILibraryManager libraryManager)
  323. {
  324. BaseItem item;
  325. if (type.IndexOf("Person", StringComparison.OrdinalIgnoreCase) == 0)
  326. {
  327. item = GetPerson(name, libraryManager);
  328. }
  329. else if (type.IndexOf("Artist", StringComparison.OrdinalIgnoreCase) == 0)
  330. {
  331. item = GetArtist(name, libraryManager);
  332. }
  333. else if (type.IndexOf("Genre", StringComparison.OrdinalIgnoreCase) == 0)
  334. {
  335. item = GetGenre(name, libraryManager);
  336. }
  337. else if (type.IndexOf("MusicGenre", StringComparison.OrdinalIgnoreCase) == 0)
  338. {
  339. item = GetMusicGenre(name, libraryManager);
  340. }
  341. else if (type.IndexOf("GameGenre", StringComparison.OrdinalIgnoreCase) == 0)
  342. {
  343. item = GetGameGenre(name, libraryManager);
  344. }
  345. else if (type.IndexOf("Studio", StringComparison.OrdinalIgnoreCase) == 0)
  346. {
  347. item = GetStudio(name, libraryManager);
  348. }
  349. else if (type.IndexOf("Year", StringComparison.OrdinalIgnoreCase) == 0)
  350. {
  351. item = libraryManager.GetYear(int.Parse(name));
  352. }
  353. else
  354. {
  355. throw new ArgumentException();
  356. }
  357. return item;
  358. }
  359. }
  360. }