BaseHttpApiClient.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. using MediaBrowser.Model.Authentication;
  2. using MediaBrowser.Model.Configuration;
  3. using MediaBrowser.Model.DTO;
  4. using MediaBrowser.Model.Weather;
  5. using System;
  6. using System.IO;
  7. using System.Net;
  8. using System.Text;
  9. using System.Threading.Tasks;
  10. #if WINDOWS_PHONE
  11. using SharpGIS;
  12. #else
  13. using System.Net.Http;
  14. #endif
  15. namespace MediaBrowser.ApiInteraction
  16. {
  17. /// <summary>
  18. /// Provides api methods centered around an HttpClient
  19. /// </summary>
  20. public abstract class BaseHttpApiClient : BaseApiClient
  21. {
  22. #if WINDOWS_PHONE
  23. public BaseHttpApiClient()
  24. {
  25. HttpClient = new GZipWebClient();
  26. }
  27. private WebClient HttpClient { get; set; }
  28. #else
  29. protected BaseHttpApiClient(HttpClientHandler handler)
  30. : base()
  31. {
  32. handler.AutomaticDecompression = DecompressionMethods.Deflate;
  33. HttpClient = new HttpClient(handler);
  34. }
  35. private HttpClient HttpClient { get; set; }
  36. #endif
  37. /// <summary>
  38. /// Gets an image stream based on a url
  39. /// </summary>
  40. public Task<Stream> GetImageStreamAsync(string url)
  41. {
  42. return GetStreamAsync(url);
  43. }
  44. /// <summary>
  45. /// Gets a BaseItem
  46. /// </summary>
  47. public async Task<DtoBaseItem> GetItemAsync(Guid id, Guid userId)
  48. {
  49. string url = ApiUrl + "/item?userId=" + userId.ToString();
  50. if (id != Guid.Empty)
  51. {
  52. url += "&id=" + id.ToString();
  53. }
  54. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  55. {
  56. return DeserializeFromStream<DtoBaseItem>(stream);
  57. }
  58. }
  59. /// <summary>
  60. /// Gets all Users
  61. /// </summary>
  62. public async Task<DtoUser[]> GetAllUsersAsync()
  63. {
  64. string url = ApiUrl + "/users";
  65. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  66. {
  67. return DeserializeFromStream<DtoUser[]>(stream);
  68. }
  69. }
  70. /// <summary>
  71. /// Gets all Genres
  72. /// </summary>
  73. public async Task<IbnItem[]> GetAllGenresAsync(Guid userId)
  74. {
  75. string url = ApiUrl + "/genres?userId=" + userId.ToString();
  76. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  77. {
  78. return DeserializeFromStream<IbnItem[]>(stream);
  79. }
  80. }
  81. /// <summary>
  82. /// Gets in-progress items
  83. /// </summary>
  84. /// <param name="userId">The user id.</param>
  85. /// <param name="folderId">(Optional) Specify a folder Id to localize the search to a specific folder.</param>
  86. public async Task<DtoBaseItem[]> GetInProgressItemsItemsAsync(Guid userId, Guid? folderId = null)
  87. {
  88. string url = ApiUrl + "/itemlist?listtype=inprogressitems&userId=" + userId.ToString();
  89. if (folderId.HasValue)
  90. {
  91. url += "&id=" + folderId.ToString();
  92. }
  93. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  94. {
  95. return DeserializeFromStream<DtoBaseItem[]>(stream);
  96. }
  97. }
  98. /// <summary>
  99. /// Gets recently added items
  100. /// </summary>
  101. /// <param name="userId">The user id.</param>
  102. /// <param name="folderId">(Optional) Specify a folder Id to localize the search to a specific folder.</param>
  103. public async Task<DtoBaseItem[]> GetRecentlyAddedItemsAsync(Guid userId, Guid? folderId = null)
  104. {
  105. string url = ApiUrl + "/itemlist?listtype=recentlyaddeditems&userId=" + userId.ToString();
  106. if (folderId.HasValue)
  107. {
  108. url += "&id=" + folderId.ToString();
  109. }
  110. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  111. {
  112. return DeserializeFromStream<DtoBaseItem[]>(stream);
  113. }
  114. }
  115. /// <summary>
  116. /// Gets favorite items
  117. /// </summary>
  118. /// <param name="userId">The user id.</param>
  119. /// <param name="folderId">(Optional) Specify a folder Id to localize the search to a specific folder.</param>
  120. public async Task<DtoBaseItem[]> GetFavoriteItemsAsync(Guid userId, Guid? folderId = null)
  121. {
  122. string url = ApiUrl + "/itemlist?listtype=favorites&userId=" + userId.ToString();
  123. if (folderId.HasValue)
  124. {
  125. url += "&id=" + folderId.ToString();
  126. }
  127. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  128. {
  129. return DeserializeFromStream<DtoBaseItem[]>(stream);
  130. }
  131. }
  132. /// <summary>
  133. /// Gets recently added items that are unplayed.
  134. /// </summary>
  135. /// <param name="userId">The user id.</param>
  136. /// <param name="folderId">(Optional) Specify a folder Id to localize the search to a specific folder.</param>
  137. public async Task<DtoBaseItem[]> GetRecentlyAddedUnplayedItemsAsync(Guid userId, Guid? folderId = null)
  138. {
  139. string url = ApiUrl + "/itemlist?listtype=recentlyaddedunplayeditems&userId=" + userId.ToString();
  140. if (folderId.HasValue)
  141. {
  142. url += "&id=" + folderId.ToString();
  143. }
  144. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  145. {
  146. return DeserializeFromStream<DtoBaseItem[]>(stream);
  147. }
  148. }
  149. /// <summary>
  150. /// Gets all Years
  151. /// </summary>
  152. public async Task<IbnItem[]> GetAllYearsAsync(Guid userId)
  153. {
  154. string url = ApiUrl + "/years?userId=" + userId.ToString();
  155. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  156. {
  157. return DeserializeFromStream<IbnItem[]>(stream);
  158. }
  159. }
  160. /// <summary>
  161. /// Gets all items that contain a given Year
  162. /// </summary>
  163. /// <param name="folderId">(Optional) Specify a folder Id to localize the search to a specific folder.</param>
  164. public async Task<DtoBaseItem[]> GetItemsWithYearAsync(string name, Guid userId, Guid? folderId = null)
  165. {
  166. string url = ApiUrl + "/itemlist?listtype=itemswithyear&userId=" + userId.ToString() + "&name=" + name;
  167. if (folderId.HasValue)
  168. {
  169. url += "&id=" + folderId.ToString();
  170. }
  171. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  172. {
  173. return DeserializeFromStream<DtoBaseItem[]>(stream);
  174. }
  175. }
  176. /// <summary>
  177. /// Gets all items that contain a given Genre
  178. /// </summary>
  179. /// <param name="folderId">(Optional) Specify a folder Id to localize the search to a specific folder.</param>
  180. public async Task<DtoBaseItem[]> GetItemsWithGenreAsync(string name, Guid userId, Guid? folderId = null)
  181. {
  182. string url = ApiUrl + "/itemlist?listtype=itemswithgenre&userId=" + userId.ToString() + "&name=" + name;
  183. if (folderId.HasValue)
  184. {
  185. url += "&id=" + folderId.ToString();
  186. }
  187. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  188. {
  189. return DeserializeFromStream<DtoBaseItem[]>(stream);
  190. }
  191. }
  192. /// <summary>
  193. /// Gets all items that contain a given Person
  194. /// </summary>
  195. /// <param name="folderId">(Optional) Specify a folder Id to localize the search to a specific folder.</param>
  196. public async Task<DtoBaseItem[]> GetItemsWithPersonAsync(string name, Guid userId, Guid? folderId = null)
  197. {
  198. string url = ApiUrl + "/itemlist?listtype=itemswithperson&userId=" + userId.ToString() + "&name=" + name;
  199. if (folderId.HasValue)
  200. {
  201. url += "&id=" + folderId.ToString();
  202. }
  203. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  204. {
  205. return DeserializeFromStream<DtoBaseItem[]>(stream);
  206. }
  207. }
  208. /// <summary>
  209. /// Gets all items that contain a given Person
  210. /// </summary>
  211. /// <param name="folderId">(Optional) Specify a folder Id to localize the search to a specific folder.</param>
  212. public async Task<DtoBaseItem[]> GetItemsWithPersonAsync(string name, string personType, Guid userId, Guid? folderId = null)
  213. {
  214. string url = ApiUrl + "/itemlist?listtype=itemswithperson&userId=" + userId.ToString() + "&name=" + name;
  215. url += "&persontype=" + personType;
  216. if (folderId.HasValue)
  217. {
  218. url += "&id=" + folderId.ToString();
  219. }
  220. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  221. {
  222. return DeserializeFromStream<DtoBaseItem[]>(stream);
  223. }
  224. }
  225. /// <summary>
  226. /// Gets all studious
  227. /// </summary>
  228. public async Task<IbnItem[]> GetAllStudiosAsync(Guid userId)
  229. {
  230. string url = ApiUrl + "/studios?userId=" + userId.ToString();
  231. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  232. {
  233. return DeserializeFromStream<IbnItem[]>(stream);
  234. }
  235. }
  236. /// <summary>
  237. /// Gets all items that contain a given Studio
  238. /// </summary>
  239. /// <param name="folderId">(Optional) Specify a folder Id to localize the search to a specific folder.</param>
  240. public async Task<DtoBaseItem[]> GetItemsWithStudioAsync(string name, Guid userId, Guid? folderId = null)
  241. {
  242. string url = ApiUrl + "/itemlist?listtype=itemswithstudio&userId=" + userId.ToString() + "&name=" + name;
  243. if (folderId.HasValue)
  244. {
  245. url += "&id=" + folderId.ToString();
  246. }
  247. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  248. {
  249. return DeserializeFromStream<DtoBaseItem[]>(stream);
  250. }
  251. }
  252. /// <summary>
  253. /// Gets a studio
  254. /// </summary>
  255. public async Task<IbnItem> GetStudioAsync(Guid userId, string name)
  256. {
  257. string url = ApiUrl + "/studio?userId=" + userId.ToString() + "&name=" + name;
  258. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  259. {
  260. return DeserializeFromStream<IbnItem>(stream);
  261. }
  262. }
  263. /// <summary>
  264. /// Gets a genre
  265. /// </summary>
  266. public async Task<IbnItem> GetGenreAsync(Guid userId, string name)
  267. {
  268. string url = ApiUrl + "/genre?userId=" + userId.ToString() + "&name=" + name;
  269. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  270. {
  271. return DeserializeFromStream<IbnItem>(stream);
  272. }
  273. }
  274. /// <summary>
  275. /// Gets a person
  276. /// </summary>
  277. public async Task<IbnItem> GetPersonAsync(Guid userId, string name)
  278. {
  279. string url = ApiUrl + "/person?userId=" + userId.ToString() + "&name=" + name;
  280. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  281. {
  282. return DeserializeFromStream<IbnItem>(stream);
  283. }
  284. }
  285. /// <summary>
  286. /// Gets a year
  287. /// </summary>
  288. public async Task<IbnItem> GetYearAsync(Guid userId, int year)
  289. {
  290. string url = ApiUrl + "/year?userId=" + userId.ToString() + "&year=" + year;
  291. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  292. {
  293. return DeserializeFromStream<IbnItem>(stream);
  294. }
  295. }
  296. /// <summary>
  297. /// Gets a list of plugins installed on the server
  298. /// </summary>
  299. public async Task<PluginInfo[]> GetInstalledPluginsAsync()
  300. {
  301. string url = ApiUrl + "/plugins";
  302. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  303. {
  304. return DeserializeFromStream<PluginInfo[]>(stream);
  305. }
  306. }
  307. /// <summary>
  308. /// Gets a list of plugins installed on the server
  309. /// </summary>
  310. public Task<Stream> GetPluginAssemblyAsync(PluginInfo plugin)
  311. {
  312. string url = ApiUrl + "/pluginassembly?assemblyfilename=" + plugin.AssemblyFileName;
  313. return GetStreamAsync(url);
  314. }
  315. /// <summary>
  316. /// Gets the current server configuration
  317. /// </summary>
  318. public async Task<ServerConfiguration> GetServerConfigurationAsync()
  319. {
  320. string url = ApiUrl + "/ServerConfiguration";
  321. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  322. {
  323. return DeserializeFromStream<ServerConfiguration>(stream);
  324. }
  325. }
  326. /// <summary>
  327. /// Gets weather information for the default location as set in configuration
  328. /// </summary>
  329. public async Task<object> GetPluginConfigurationAsync(PluginInfo plugin, Type configurationType)
  330. {
  331. string url = ApiUrl + "/PluginConfiguration?assemblyfilename=" + plugin.AssemblyFileName;
  332. // At the moment this can't be retrieved in protobuf format
  333. SerializationFormats format = DataSerializer.CanDeSerializeJsv ? SerializationFormats.Jsv : SerializationFormats.Json;
  334. using (Stream stream = await GetSerializedStreamAsync(url, format).ConfigureAwait(false))
  335. {
  336. return DataSerializer.DeserializeFromStream(stream, format, configurationType);
  337. }
  338. }
  339. /// <summary>
  340. /// Gets the default user
  341. /// </summary>
  342. public async Task<DtoUser> GetDefaultUserAsync()
  343. {
  344. string url = ApiUrl + "/user";
  345. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  346. {
  347. return DeserializeFromStream<DtoUser>(stream);
  348. }
  349. }
  350. /// <summary>
  351. /// Gets a user by id
  352. /// </summary>
  353. public async Task<DtoUser> GetUserAsync(Guid id)
  354. {
  355. string url = ApiUrl + "/user?id=" + id.ToString();
  356. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  357. {
  358. return DeserializeFromStream<DtoUser>(stream);
  359. }
  360. }
  361. /// <summary>
  362. /// Gets weather information for the default location as set in configuration
  363. /// </summary>
  364. public async Task<WeatherInfo> GetWeatherInfoAsync()
  365. {
  366. string url = ApiUrl + "/weather";
  367. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  368. {
  369. return DeserializeFromStream<WeatherInfo>(stream);
  370. }
  371. }
  372. /// <summary>
  373. /// Gets weather information for a specific zip code
  374. /// </summary>
  375. public async Task<WeatherInfo> GetWeatherInfoAsync(string zipCode)
  376. {
  377. string url = ApiUrl + "/weather?zipcode=" + zipCode;
  378. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  379. {
  380. return DeserializeFromStream<WeatherInfo>(stream);
  381. }
  382. }
  383. /// <summary>
  384. /// Gets special features for a Movie
  385. /// </summary>
  386. public async Task<DtoBaseItem[]> GetMovieSpecialFeaturesAsync(Guid itemId, Guid userId)
  387. {
  388. string url = ApiUrl + "/MovieSpecialFeatures?id=" + itemId;
  389. url += "&userid=" + userId;
  390. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  391. {
  392. return DeserializeFromStream<DtoBaseItem[]>(stream);
  393. }
  394. }
  395. /// <summary>
  396. /// Updates played status for an item
  397. /// </summary>
  398. public async Task<DtoUserItemData> UpdatePlayedStatusAsync(Guid itemId, Guid userId, bool wasPlayed)
  399. {
  400. string url = ApiUrl + "/PlayedStatus?id=" + itemId;
  401. url += "&userid=" + userId;
  402. url += "&played=" + (wasPlayed ? "1" : "0");
  403. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  404. {
  405. return DeserializeFromStream<DtoUserItemData>(stream);
  406. }
  407. }
  408. /// <summary>
  409. /// Updates a user's favorite status for an item and returns the updated UserItemData object.
  410. /// </summary>
  411. public async Task<DtoUserItemData> UpdateFavoriteStatusAsync(Guid itemId, Guid userId, bool isFavorite)
  412. {
  413. string url = ApiUrl + "/favoritestatus?id=" + itemId;
  414. url += "&userid=" + userId;
  415. url += "&isfavorite=" + (isFavorite ? "1" : "0");
  416. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  417. {
  418. return DeserializeFromStream<DtoUserItemData>(stream);
  419. }
  420. }
  421. /// <summary>
  422. /// Clears a user's rating for an item
  423. /// </summary>
  424. public async Task<DtoUserItemData> ClearUserItemRatingAsync(Guid itemId, Guid userId)
  425. {
  426. string url = ApiUrl + "/UserItemRating?id=" + itemId;
  427. url += "&userid=" + userId;
  428. url += "&clear=1";
  429. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  430. {
  431. return DeserializeFromStream<DtoUserItemData>(stream);
  432. }
  433. }
  434. /// <summary>
  435. /// Updates a user's rating for an item, based on likes or dislikes
  436. /// </summary>
  437. public async Task<DtoUserItemData> UpdateUserItemRatingAsync(Guid itemId, Guid userId, bool likes)
  438. {
  439. string url = ApiUrl + "/UserItemRating?id=" + itemId;
  440. url += "&userid=" + userId;
  441. url += "&likes=" + (likes ? "1" : "0");
  442. using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
  443. {
  444. return DeserializeFromStream<DtoUserItemData>(stream);
  445. }
  446. }
  447. /// <summary>
  448. /// Authenticates a user and returns the result
  449. /// </summary>
  450. public async Task<AuthenticationResult> AuthenticateUserAsync(Guid userId, string password)
  451. {
  452. string url = ApiUrl + "/UserAuthentication?dataformat=" + SerializationFormat.ToString();
  453. // Create the post body
  454. string postContent = string.Format("userid={0}", userId);
  455. if (!string.IsNullOrEmpty(password))
  456. {
  457. postContent += "&password=" + password;
  458. }
  459. #if WINDOWS_PHONE
  460. HttpClient.Headers["Content-Type"] = "application/x-www-form-urlencoded";
  461. var result = await HttpClient.UploadStringTaskAsync(url, "POST", postContent);
  462. var byteArray = Encoding.UTF8.GetBytes(result);
  463. using (MemoryStream stream = new MemoryStream(byteArray))
  464. {
  465. return DeserializeFromStream<AuthenticationResult>(stream);
  466. }
  467. #else
  468. HttpContent content = new StringContent(postContent, Encoding.UTF8, "application/x-www-form-urlencoded");
  469. HttpResponseMessage msg = await HttpClient.PostAsync(url, content).ConfigureAwait(false);
  470. using (Stream stream = await msg.Content.ReadAsStreamAsync().ConfigureAwait(false))
  471. {
  472. return DeserializeFromStream<AuthenticationResult>(stream);
  473. }
  474. #endif
  475. }
  476. /// <summary>
  477. /// This is a helper around getting a stream from the server that contains serialized data
  478. /// </summary>
  479. private Task<Stream> GetSerializedStreamAsync(string url)
  480. {
  481. return GetSerializedStreamAsync(url, SerializationFormat);
  482. }
  483. /// <summary>
  484. /// This is a helper around getting a stream from the server that contains serialized data
  485. /// </summary>
  486. private Task<Stream> GetSerializedStreamAsync(string url, SerializationFormats serializationFormat)
  487. {
  488. if (url.IndexOf('?') == -1)
  489. {
  490. url += "?dataformat=" + serializationFormat.ToString();
  491. }
  492. else
  493. {
  494. url += "&dataformat=" + serializationFormat.ToString();
  495. }
  496. return GetStreamAsync(url);
  497. }
  498. /// <summary>
  499. /// This is just a helper around HttpClient
  500. /// </summary>
  501. private Task<Stream> GetStreamAsync(string url)
  502. {
  503. #if WINDOWS_PHONE
  504. return HttpClient.OpenReadTaskAsync(url);
  505. #else
  506. return HttpClient.GetStreamAsync(url);
  507. #endif
  508. }
  509. public override void Dispose()
  510. {
  511. #if !WINDOWS_PHONE
  512. HttpClient.Dispose();
  513. #endif
  514. }
  515. }
  516. }