PageRenderTime 30ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/JMMServer/JMMServer/Providers/TvDB/TvDBHelper.cs

https://bitbucket.org/gibwar/jmm-test
C# | 1087 lines | 745 code | 193 blank | 149 comment | 131 complexity | 020ea696d470b085230b5a9503eb8416 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Net;
  6. using JMMServer.ImageDownload;
  7. using System.Xml;
  8. using NLog;
  9. using System.IO;
  10. using ICSharpCode.SharpZipLib.Zip;
  11. using JMMServer.Entities;
  12. using JMMServer.Repositories;
  13. using JMMServer.Commands;
  14. namespace JMMServer.Providers.TvDB
  15. {
  16. public class TvDBHelper
  17. {
  18. // http://thetvdb.com
  19. //API Key: B178B8940CAF4A2C
  20. private static Logger logger = LogManager.GetCurrentClassLogger();
  21. private bool initialised = false;
  22. private static UTF8Encoding enc = new UTF8Encoding();
  23. static Dictionary<int, WebClient> webClientList = new Dictionary<int, WebClient>();
  24. static int nDownloadGUIDGenerator = 1;
  25. public string urlMirrorsList
  26. {
  27. get { return @"http://www.thetvdb.com/api/" + Constants.TvDBURLs.apiKey + @"/mirrors.xml"; }
  28. }
  29. public string urlServerTime
  30. {
  31. get { return @"http://www.thetvdb.com/api/Updates.php?type=none"; }
  32. }
  33. public string urlUpdatesList
  34. {
  35. get { return @"http://www.thetvdb.com/api/Updates.php?type=all&time={0}"; }
  36. }
  37. private string urlMirror = "http://thetvdb.com";
  38. public string UrlMirror
  39. {
  40. get
  41. {
  42. Init();
  43. return urlMirror;
  44. }
  45. }
  46. public static string URLMirror
  47. {
  48. get
  49. {
  50. return "http://thetvdb.com"; // they have said now that this will never change
  51. }
  52. }
  53. public static string GetRootImagesPath()
  54. {
  55. return ImageUtils.GetTvDBImagePath();
  56. }
  57. private string serverTime = "";
  58. public TvDBHelper()
  59. {
  60. }
  61. public string CurrentServerTime
  62. {
  63. get
  64. {
  65. try
  66. {
  67. string xmlServerTime = Utils.DownloadWebPage(urlServerTime);
  68. XmlDocument docServer = new XmlDocument();
  69. docServer.LoadXml(xmlServerTime);
  70. string serverTime = docServer["Items"]["Time"].InnerText;
  71. return serverTime;
  72. }
  73. catch
  74. {
  75. return "";
  76. }
  77. }
  78. }
  79. private void Init()
  80. {
  81. try
  82. {
  83. if (initialised) return;
  84. // 01. try and download the list of mirrors
  85. string xmlMirrors = Utils.DownloadWebPage(urlMirrorsList);
  86. XmlDocument xmlDoc = new XmlDocument();
  87. xmlDoc.LoadXml(xmlMirrors);
  88. XmlNodeList mirrorItems = xmlDoc["Mirrors"].GetElementsByTagName("Mirror");
  89. if (mirrorItems.Count <= 0)
  90. return;
  91. string id = mirrorItems[0]["id"].InnerText;
  92. urlMirror = mirrorItems[0]["mirrorpath"].InnerText;
  93. string typemask = mirrorItems[0]["typemask"].InnerText;
  94. logger.Info("TVDB Mirror: {0}", urlMirror);
  95. // 02. get the server time
  96. string xmlServerTime = Utils.DownloadWebPage(urlServerTime);
  97. XmlDocument docServer = new XmlDocument();
  98. docServer.LoadXml(xmlServerTime);
  99. serverTime = docServer["Items"]["Time"].InnerText;
  100. logger.Info("serverTime: {0}", serverTime);
  101. initialised = true;
  102. }
  103. catch (Exception ex)
  104. {
  105. logger.ErrorException("Error in TVDBHelper.Init: " + ex.ToString(), ex);
  106. }
  107. }
  108. public static bool ConfirmTvDBOnline()
  109. {
  110. TvDB_Series tvser = GetSeriesInfoOnline(73255);
  111. if (tvser == null)
  112. return false;
  113. else
  114. return true;
  115. }
  116. public static TvDB_Series GetSeriesInfoOnline(int seriesID)
  117. {
  118. try
  119. {
  120. //Init();
  121. string url = string.Format(Constants.TvDBURLs.urlSeriesBaseXML, URLMirror, Constants.TvDBURLs.apiKey, seriesID, ServerSettings.TvDB_Language);
  122. logger.Trace("GetSeriesInfo: {0}", url);
  123. // Search for a series
  124. string xmlSeries = Utils.DownloadWebPage(url);
  125. logger.Trace("GetSeriesInfo RESULT: {0}", xmlSeries);
  126. if (xmlSeries.Trim().Length == 0) return null;
  127. XmlDocument docSeries = new XmlDocument();
  128. docSeries.LoadXml(xmlSeries);
  129. TvDB_Series tvSeries = null;
  130. if (docSeries != null)
  131. {
  132. TvDB_SeriesRepository repSeries = new TvDB_SeriesRepository();
  133. tvSeries = repSeries.GetByTvDBID(seriesID);
  134. if (tvSeries == null)
  135. tvSeries = new TvDB_Series();
  136. tvSeries.PopulateFromSeriesInfo(docSeries);
  137. repSeries.Save(tvSeries);
  138. }
  139. return tvSeries;
  140. }
  141. catch (Exception ex)
  142. {
  143. logger.ErrorException("Error in TVDBHelper.GetSeriesInfoOnline: " + ex.ToString(), ex);
  144. }
  145. return null;
  146. }
  147. public XmlDocument GetSeriesBannersOnline(int seriesID)
  148. {
  149. try
  150. {
  151. Init();
  152. string url = string.Format(Constants.TvDBURLs.urlBannersXML, urlMirror, Constants.TvDBURLs.apiKey, seriesID);
  153. logger.Trace("GetSeriesBannersOnline: {0}", url);
  154. // Search for a series
  155. string xmlSeries = Utils.DownloadWebPage(url);
  156. XmlDocument docBanners = new XmlDocument();
  157. docBanners.LoadXml(xmlSeries);
  158. return docBanners;
  159. }
  160. catch (Exception ex)
  161. {
  162. logger.ErrorException("Error in TVDBHelper.GetSeriesBannersOnline: " + ex.ToString(), ex);
  163. }
  164. return null;
  165. }
  166. public Dictionary<string, XmlDocument> GetFullSeriesInfo(int seriesID)
  167. {
  168. try
  169. {
  170. Init();
  171. string url = string.Format(Constants.TvDBURLs.urlFullSeriesData, urlMirror, Constants.TvDBURLs.apiKey, seriesID, ServerSettings.TvDB_Language);
  172. logger.Trace("GetFullSeriesInfo: {0}", url);
  173. Stream data = Utils.DownloadWebBinary(url);
  174. if (data != null)
  175. {
  176. // this will get following xml files: en.xml, actors.xml, banners.xml
  177. return DecompressZipToXmls(data);
  178. }
  179. else
  180. logger.Trace("GetFullSeriesInfo: data was null");
  181. }
  182. catch (Exception ex)
  183. {
  184. logger.ErrorException("Error in TVDBHelper.GetFullSeriesInfo: " + ex.ToString(), ex);
  185. }
  186. return null;
  187. }
  188. private static Dictionary<string, XmlDocument> DecompressZipToXmls(Stream s)
  189. {
  190. int bytes = 2048;
  191. byte[] data = new byte[2048];
  192. Dictionary<string, XmlDocument> docsInZip = new Dictionary<string, XmlDocument>();
  193. ZipInputStream zis = new ZipInputStream(s);
  194. ZipEntry currEntry = null;
  195. StringBuilder b = new StringBuilder();
  196. while ((currEntry = zis.GetNextEntry()) != null)
  197. {
  198. //BaseConfig.MyAnimeLog.Write("Decompressing Entry: {0}", currEntry.Name);
  199. XmlDocument d = new XmlDocument();
  200. while ((bytes = zis.Read(data, 0, data.Length)) > 0)
  201. b.Append(enc.GetString(data, 0, bytes));
  202. //BaseConfig.MyAnimeLog.Write("Decompression done, now loading as XML...");
  203. try
  204. {
  205. d.LoadXml(b.ToString());
  206. //BaseConfig.MyAnimeLog.Write("Loaded as valid XML");
  207. docsInZip.Add(currEntry.Name, d);
  208. }
  209. catch (XmlException e)
  210. {
  211. logger.ErrorException("Error in TVDBHelper.DecompressZipToXmls: " + e.ToString(), e);
  212. }
  213. b.Remove(0, b.Length);
  214. }
  215. return docsInZip;
  216. }
  217. public List<TvDB_ImageFanart> GetFanart(int seriesID, bool forceRefresh)
  218. {
  219. List<TvDB_ImageFanart> fanarts = new List<TvDB_ImageFanart>();
  220. if (forceRefresh)
  221. {
  222. fanarts = GetFanartOnline(seriesID);
  223. }
  224. else
  225. {
  226. TvDB_ImageFanartRepository repFanart = new TvDB_ImageFanartRepository();
  227. fanarts = repFanart.GetBySeriesID(seriesID);
  228. if (fanarts.Count == 0)
  229. fanarts = GetFanartOnline(seriesID);
  230. }
  231. return fanarts;
  232. }
  233. public List<TvDB_ImageFanart> GetFanartOnline(int seriesID)
  234. {
  235. List<TvDB_ImageFanart> fanarts = new List<TvDB_ImageFanart>();
  236. XmlDocument doc = GetSeriesBannersOnline(seriesID);
  237. List<object> banners = ParseBanners(seriesID, doc);
  238. foreach (object obj in banners)
  239. {
  240. if (obj.GetType() == typeof(TvDB_ImageFanart))
  241. fanarts.Add((TvDB_ImageFanart)obj);
  242. }
  243. return fanarts;
  244. }
  245. public List<TvDB_ImageWideBanner> GetWideBannersOnline(int seriesID)
  246. {
  247. List<TvDB_ImageWideBanner> wideBanners = new List<TvDB_ImageWideBanner>();
  248. XmlDocument doc = GetSeriesBannersOnline(seriesID);
  249. List<object> banners = ParseBanners(seriesID, doc);
  250. foreach (object obj in banners)
  251. {
  252. if (obj.GetType() == typeof(TvDB_ImageWideBanner))
  253. wideBanners.Add((TvDB_ImageWideBanner)obj);
  254. }
  255. return wideBanners;
  256. }
  257. public List<TvDB_ImagePoster> GetPostersOnline(int seriesID)
  258. {
  259. //BaseConfig.MyAnimeLog.Write("Getting posters online: {0}", seriesID);
  260. List<TvDB_ImagePoster> posters = new List<TvDB_ImagePoster>();
  261. XmlDocument doc = GetSeriesBannersOnline(seriesID);
  262. List<object> banners = ParseBanners(seriesID, doc);
  263. foreach (object obj in banners)
  264. {
  265. if (obj.GetType() == typeof(TvDB_ImagePoster))
  266. posters.Add((TvDB_ImagePoster)obj);
  267. }
  268. return posters;
  269. }
  270. public List<TvDBLanguage> GetLanguages()
  271. {
  272. List<TvDBLanguage> languages = new List<TvDBLanguage>();
  273. try
  274. {
  275. Init();
  276. string url = string.Format(Constants.TvDBURLs.urlLanguagesXML, urlMirror, Constants.TvDBURLs.apiKey);
  277. logger.Trace("GetLanguages: {0}", url);
  278. // Search for a series
  279. string xmlSeries = Utils.DownloadWebPage(url);
  280. XmlDocument docLanguages = new XmlDocument();
  281. docLanguages.LoadXml(xmlSeries);
  282. XmlNodeList lanItems = docLanguages["Languages"].GetElementsByTagName("Language");
  283. //BaseConfig.MyAnimeLog.Write("Found {0} banner nodes", bannerItems.Count);
  284. if (lanItems.Count <= 0)
  285. return languages;
  286. foreach (XmlNode node in lanItems)
  287. {
  288. TvDBLanguage lan = new TvDBLanguage();
  289. lan.Name = node["name"].InnerText.Trim();
  290. lan.Abbreviation = node["abbreviation"].InnerText.Trim();
  291. languages.Add(lan);
  292. }
  293. }
  294. catch (Exception ex)
  295. {
  296. logger.ErrorException("Error in TVDBHelper.GetSeriesBannersOnline: " + ex.ToString(), ex);
  297. }
  298. return languages;
  299. }
  300. public void DownloadAutomaticImages(int seriesID, bool forceDownload)
  301. {
  302. XmlDocument doc = GetSeriesBannersOnline(seriesID);
  303. DownloadAutomaticImages(doc, seriesID, forceDownload);
  304. }
  305. public void DownloadAutomaticImages(XmlDocument doc, int seriesID, bool forceDownload)
  306. {
  307. List<object> banners = ParseBanners(seriesID, doc);
  308. int numFanartDownloaded = 0;
  309. int numPostersDownloaded = 0;
  310. int numBannersDownloaded = 0;
  311. foreach (object obj in banners)
  312. {
  313. if (obj.GetType() == typeof(TvDB_ImageFanart))
  314. {
  315. TvDB_ImageFanart img = obj as TvDB_ImageFanart;
  316. if (ServerSettings.TvDB_AutoFanart && numFanartDownloaded < ServerSettings.TvDB_AutoFanartAmount)
  317. {
  318. bool fileExists = File.Exists(img.FullImagePath);
  319. if (!fileExists || (fileExists && forceDownload))
  320. {
  321. CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(img.TvDB_ImageFanartID, JMMImageType.TvDB_FanArt, forceDownload);
  322. cmd.Save();
  323. numFanartDownloaded++;
  324. }
  325. }
  326. }
  327. if (obj.GetType() == typeof(TvDB_ImagePoster))
  328. {
  329. TvDB_ImagePoster img = obj as TvDB_ImagePoster;
  330. if (ServerSettings.TvDB_AutoPosters && numPostersDownloaded < ServerSettings.TvDB_AutoPostersAmount)
  331. {
  332. bool fileExists = File.Exists(img.FullImagePath);
  333. if (!fileExists || (fileExists && forceDownload))
  334. {
  335. CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(img.TvDB_ImagePosterID, JMMImageType.TvDB_Cover, forceDownload);
  336. cmd.Save();
  337. numPostersDownloaded++;
  338. }
  339. }
  340. }
  341. if (obj.GetType() == typeof(TvDB_ImageWideBanner))
  342. {
  343. TvDB_ImageWideBanner img = obj as TvDB_ImageWideBanner;
  344. if (ServerSettings.TvDB_AutoWideBanners && numBannersDownloaded < ServerSettings.TvDB_AutoWideBannersAmount)
  345. {
  346. bool fileExists = File.Exists(img.FullImagePath);
  347. if (!fileExists || (fileExists && forceDownload))
  348. {
  349. CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(img.TvDB_ImageWideBannerID, JMMImageType.TvDB_Banner, forceDownload);
  350. cmd.Save();
  351. numBannersDownloaded++;
  352. }
  353. }
  354. }
  355. }
  356. }
  357. private List<object> ParseBanners(int seriesID, XmlDocument xmlDoc)
  358. {
  359. List<object> banners = new List<object>();
  360. try
  361. {
  362. XmlNodeList bannerItems = xmlDoc["Banners"].GetElementsByTagName("Banner");
  363. //BaseConfig.MyAnimeLog.Write("Found {0} banner nodes", bannerItems.Count);
  364. if (bannerItems.Count <= 0)
  365. return banners;
  366. // banner types
  367. // series = wide banner
  368. // fanart = fanart
  369. // poster = filmstrip poster/dvd cover
  370. TvDB_ImageFanartRepository repFanart = new TvDB_ImageFanartRepository();
  371. TvDB_ImagePosterRepository repPosters = new TvDB_ImagePosterRepository();
  372. TvDB_ImageWideBannerRepository repWideBanners = new TvDB_ImageWideBannerRepository();
  373. List<int> validFanartIDs = new List<int>();
  374. List<int> validPosterIDs = new List<int>();
  375. List<int> validBannerIDs = new List<int>();
  376. foreach (XmlNode node in bannerItems)
  377. {
  378. JMMImageType imageType = JMMImageType.TvDB_Cover;
  379. string bannerType = node["BannerType"].InnerText.Trim().ToUpper();
  380. string bannerType2 = node["BannerType2"].InnerText.Trim().ToUpper();
  381. if (bannerType == "FANART")
  382. imageType = JMMImageType.TvDB_FanArt;
  383. else if (bannerType == "POSTER")
  384. imageType = JMMImageType.TvDB_Cover;
  385. else if (bannerType == "SEASON")
  386. {
  387. if (bannerType2 == "SEASON")
  388. imageType = JMMImageType.TvDB_Cover;
  389. else
  390. imageType = JMMImageType.TvDB_Banner;
  391. }
  392. else if (bannerType == "SERIES")
  393. {
  394. if (bannerType2 == "SEASONWIDE" || bannerType2 == "GRAPHICAL" || bannerType2 == "TEXT" || bannerType2 == "BLANK")
  395. imageType = JMMImageType.TvDB_Banner;
  396. else
  397. imageType = JMMImageType.TvDB_Cover;
  398. }
  399. if (imageType == JMMImageType.TvDB_FanArt)
  400. {
  401. int id = int.Parse(node["id"].InnerText);
  402. TvDB_ImageFanart img = repFanart.GetByTvDBID(id);
  403. if (img == null)
  404. {
  405. img = new TvDB_ImageFanart();
  406. img.Enabled = 1;
  407. }
  408. img.Populate(seriesID, node);
  409. repFanart.Save(img);
  410. banners.Add(img);
  411. validFanartIDs.Add(id);
  412. }
  413. if (imageType == JMMImageType.TvDB_Banner)
  414. {
  415. int id = int.Parse(node["id"].InnerText);
  416. TvDB_ImageWideBanner img = repWideBanners.GetByTvDBID(id);
  417. if (img == null)
  418. {
  419. img = new TvDB_ImageWideBanner();
  420. img.Enabled = 1;
  421. }
  422. img.Populate(seriesID, node, TvDBImageNodeType.Series);
  423. repWideBanners.Save(img);
  424. banners.Add(img);
  425. validBannerIDs.Add(id);
  426. }
  427. if (imageType == JMMImageType.TvDB_Cover)
  428. {
  429. int id = int.Parse(node["id"].InnerText);
  430. TvDB_ImagePoster img = repPosters.GetByTvDBID(id);
  431. if (img == null)
  432. {
  433. img = new TvDB_ImagePoster();
  434. img.Enabled = 1;
  435. }
  436. TvDBImageNodeType nodeType = TvDBImageNodeType.Series;
  437. if (bannerType == "SEASON") nodeType = TvDBImageNodeType.Season;
  438. img.Populate(seriesID, node, nodeType);
  439. repPosters.Save(img);
  440. banners.Add(img);
  441. validPosterIDs.Add(id);
  442. }
  443. }
  444. // delete any banners from the database which are no longer valid
  445. foreach (TvDB_ImageFanart img in repFanart.GetBySeriesID(seriesID))
  446. {
  447. if (!validFanartIDs.Contains(img.Id))
  448. repFanart.Delete(img.TvDB_ImageFanartID);
  449. }
  450. foreach (TvDB_ImagePoster img in repPosters.GetBySeriesID(seriesID))
  451. {
  452. if (!validPosterIDs.Contains(img.Id))
  453. repPosters.Delete(img.TvDB_ImagePosterID);
  454. }
  455. foreach (TvDB_ImageWideBanner img in repWideBanners.GetBySeriesID(seriesID))
  456. {
  457. if (!validBannerIDs.Contains(img.Id))
  458. repWideBanners.Delete(img.TvDB_ImageWideBannerID);
  459. }
  460. }
  461. catch (Exception ex)
  462. {
  463. logger.ErrorException("Error in ParseBanners: " + ex.ToString(), ex);
  464. }
  465. return banners;
  466. }
  467. public List<TVDBSeriesSearchResult> SearchSeries(string criteria)
  468. {
  469. List<TVDBSeriesSearchResult> results = new List<TVDBSeriesSearchResult>();
  470. try
  471. {
  472. Init();
  473. if (!initialised) return results;
  474. // Search for a series
  475. string url = string.Format(Constants.TvDBURLs.urlSeriesSearch, criteria);
  476. logger.Trace("Search TvDB Series: {0}", url);
  477. string xmlSeries = Utils.DownloadWebPage(url);
  478. XmlDocument docSeries = new XmlDocument();
  479. docSeries.LoadXml(xmlSeries);
  480. bool hasData = docSeries["Data"].HasChildNodes;
  481. if (hasData)
  482. {
  483. XmlNodeList seriesItems = docSeries["Data"].GetElementsByTagName("Series");
  484. foreach (XmlNode series in seriesItems)
  485. {
  486. TVDBSeriesSearchResult searchResult = new TVDBSeriesSearchResult(series);
  487. results.Add(searchResult);
  488. }
  489. }
  490. }
  491. catch (Exception ex)
  492. {
  493. logger.ErrorException("Error in SearchSeries: " + ex.ToString(), ex);
  494. }
  495. return results;
  496. }
  497. public static List<int> GetUpdatedSeriesList(string serverTime)
  498. {
  499. List<int> seriesList = new List<int>();
  500. try
  501. {
  502. string url = string.Format(Constants.TvDBURLs.urlUpdatesList, URLMirror, serverTime);
  503. // Search for a series
  504. string xmlUpdateList = Utils.DownloadWebPage(url);
  505. //BaseConfig.MyAnimeLog.Write("GetSeriesInfo RESULT: {0}", xmlSeries);
  506. XmlDocument docUpdates = new XmlDocument();
  507. docUpdates.LoadXml(xmlUpdateList);
  508. XmlNodeList nodes = docUpdates["Items"].GetElementsByTagName("Series");
  509. foreach (XmlNode node in nodes)
  510. {
  511. string sid = node.InnerText;
  512. int id = -1;
  513. int.TryParse(sid, out id);
  514. if (id > 0) seriesList.Add(id);
  515. //BaseConfig.MyAnimeLog.Write("Updated series: {0}", sid);
  516. }
  517. return seriesList;
  518. }
  519. catch (Exception ex)
  520. {
  521. logger.ErrorException("Error in GetUpdatedSeriesList: " + ex.ToString(), ex);
  522. return seriesList;
  523. }
  524. }
  525. /// <summary>
  526. /// Updates the followung
  527. /// 1. Series Info
  528. /// 2. Episode Info
  529. /// 3. Episode Images
  530. /// 4. Fanart, Poster and Wide Banner Images
  531. /// </summary>
  532. /// <param name="seriesID"></param>
  533. /// <param name="forceRefresh"></param>
  534. public void UpdateAllInfoAndImages(int seriesID, bool forceRefresh, bool downloadImages)
  535. {
  536. TvDB_EpisodeRepository repEpisodes = new TvDB_EpisodeRepository();
  537. TvDB_SeriesRepository repSeries = new TvDB_SeriesRepository();
  538. string fileName = string.Format("{0}.xml", ServerSettings.TvDB_Language);
  539. Dictionary<string, XmlDocument> docSeries = GetFullSeriesInfo(seriesID);
  540. if (docSeries.ContainsKey(fileName))
  541. {
  542. try
  543. {
  544. // update the series info
  545. XmlDocument xmlDoc = docSeries[fileName];
  546. if (xmlDoc != null)
  547. {
  548. TvDB_Series tvSeries = repSeries.GetByTvDBID(seriesID);
  549. if (tvSeries == null)
  550. tvSeries = new TvDB_Series();
  551. tvSeries.PopulateFromSeriesInfo(xmlDoc);
  552. repSeries.Save(tvSeries);
  553. }
  554. if (downloadImages)
  555. {
  556. // get all fanart, posters and wide banners
  557. if (docSeries.ContainsKey("banners.xml"))
  558. {
  559. XmlDocument xmlDocBanners = docSeries["banners.xml"];
  560. if (xmlDocBanners != null)
  561. DownloadAutomaticImages(xmlDocBanners, seriesID, forceRefresh);
  562. }
  563. }
  564. // update all the episodes and download episode images
  565. XmlNodeList episodeItems = xmlDoc["Data"].GetElementsByTagName("Episode");
  566. logger.Trace("Found {0} Episode nodes", episodeItems.Count.ToString());
  567. List<int> existingEpIds = new List<int>();
  568. foreach (XmlNode node in episodeItems)
  569. {
  570. try
  571. {
  572. // the episode id
  573. int id = int.Parse(node["id"].InnerText.Trim());
  574. existingEpIds.Add(id);
  575. TvDB_Episode ep = repEpisodes.GetByTvDBID(id);
  576. if (ep == null)
  577. ep = new TvDB_Episode();
  578. ep.Populate(node);
  579. repEpisodes.Save(ep);
  580. //BaseConfig.MyAnimeLog.Write("Refreshing episode info for: {0}", ep.ToString());
  581. if (downloadImages)
  582. {
  583. // download the image for this episode
  584. if (!string.IsNullOrEmpty(ep.Filename))
  585. {
  586. bool fileExists = File.Exists(ep.FullImagePath);
  587. if (!fileExists || (fileExists && forceRefresh))
  588. {
  589. CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(ep.TvDB_EpisodeID, JMMImageType.TvDB_Episode, forceRefresh);
  590. cmd.Save();
  591. }
  592. }
  593. }
  594. }
  595. catch (Exception ex)
  596. {
  597. logger.ErrorException("Error in TVDBHelper.GetEpisodes: " + ex.ToString(), ex);
  598. }
  599. }
  600. // get all the existing tvdb episodes, to see if any have been deleted
  601. List<TvDB_Episode> allEps = repEpisodes.GetBySeriesID(seriesID);
  602. foreach (TvDB_Episode oldEp in allEps)
  603. {
  604. if (!existingEpIds.Contains(oldEp.Id))
  605. repEpisodes.Delete(oldEp.TvDB_EpisodeID);
  606. }
  607. }
  608. catch (Exception ex)
  609. {
  610. logger.ErrorException("Error in TVDBHelper.GetEpisodes: " + ex.ToString(), ex);
  611. }
  612. }
  613. }
  614. public static void LinkAniDBTvDB(int animeID, int tvDBID, int seasonNumber, bool fromWebCache)
  615. {
  616. CrossRef_AniDB_TvDBRepository repCrossRef = new CrossRef_AniDB_TvDBRepository();
  617. CrossRef_AniDB_TvDB xrefTemp = repCrossRef.GetByTvDBID(tvDBID, seasonNumber);
  618. if (xrefTemp != null)
  619. {
  620. string msg = string.Format("Not using TvDB link as one already exists {0} ({1}) - {2}", tvDBID, seasonNumber, animeID);
  621. logger.Warn(msg);
  622. return;
  623. }
  624. // check if we have this information locally
  625. // if not download it now
  626. TvDB_SeriesRepository repSeries = new TvDB_SeriesRepository();
  627. TvDB_Series tvSeries = repSeries.GetByTvDBID(tvDBID);
  628. if (tvSeries == null)
  629. {
  630. // we download the series info here just so that we have the basic info in the
  631. // database before the queued task runs later
  632. tvSeries = GetSeriesInfoOnline(tvDBID);
  633. }
  634. // download and update series info, episode info and episode images
  635. // will also download fanart, posters and wide banners
  636. CommandRequest_TvDBUpdateSeriesAndEpisodes cmdSeriesEps = new CommandRequest_TvDBUpdateSeriesAndEpisodes(tvDBID, false);
  637. cmdSeriesEps.Save();
  638. CrossRef_AniDB_TvDB xref = repCrossRef.GetByAnimeID(animeID);
  639. if (xref == null)
  640. xref = new CrossRef_AniDB_TvDB();
  641. xref.AnimeID = animeID;
  642. if (fromWebCache)
  643. xref.CrossRefSource = (int)CrossRefSource.WebCache;
  644. else
  645. xref.CrossRefSource = (int)CrossRefSource.User;
  646. xref.TvDBID = tvDBID;
  647. xref.TvDBSeasonNumber = seasonNumber;
  648. repCrossRef.Save(xref);
  649. StatsCache.Instance.UpdateUsingAnime(animeID);
  650. logger.Trace("Changed tvdb association: {0}", animeID);
  651. CommandRequest_WebCacheSendXRefAniDBTvDB req = new CommandRequest_WebCacheSendXRefAniDBTvDB(xref.CrossRef_AniDB_TvDBID);
  652. req.Save();
  653. }
  654. public static void LinkAniDBTvDBEpisode(int aniDBID, int tvDBID, int animeID)
  655. {
  656. CrossRef_AniDB_TvDB_EpisodeRepository repCrossRef = new CrossRef_AniDB_TvDB_EpisodeRepository();
  657. CrossRef_AniDB_TvDB_Episode xref = repCrossRef.GetByAniDBEpisodeID(aniDBID);
  658. if (xref == null)
  659. xref = new CrossRef_AniDB_TvDB_Episode();
  660. xref.AnimeID = animeID;
  661. xref.AniDBEpisodeID = aniDBID;
  662. xref.TvDBEpisodeID = tvDBID;
  663. repCrossRef.Save(xref);
  664. StatsCache.Instance.UpdateUsingAnime(animeID);
  665. logger.Trace("Changed tvdb episode association: {0}", aniDBID);
  666. }
  667. // Removes all TVDB information from a series, bringing it back to a blank state.
  668. public static void RemoveLinkAniDBTvDB(AnimeSeries ser)
  669. {
  670. CrossRef_AniDB_TvDBRepository repCrossRef = new CrossRef_AniDB_TvDBRepository();
  671. CrossRef_AniDB_TvDB xref = repCrossRef.GetByAnimeID(ser.AniDB_ID);
  672. if (xref == null) return;
  673. repCrossRef.Delete(xref.CrossRef_AniDB_TvDBID);
  674. StatsCache.Instance.UpdateUsingAnime(ser.AniDB_ID);
  675. CommandRequest_WebCacheDeleteXRefAniDBTvDB req = new CommandRequest_WebCacheDeleteXRefAniDBTvDB(ser.AniDB_ID);
  676. req.Save();
  677. }
  678. public static void DownloadAllEpisodes()
  679. {
  680. CrossRef_AniDB_TvDBRepository repCrossRef = new CrossRef_AniDB_TvDBRepository();
  681. List<CrossRef_AniDB_TvDB> allCrossRefs = repCrossRef.GetAll();
  682. List<int> tvDBIDs = new List<int>();
  683. foreach (CrossRef_AniDB_TvDB xref in allCrossRefs)
  684. {
  685. if (!tvDBIDs.Contains(xref.TvDBID)) tvDBIDs.Add(xref.TvDBID);
  686. }
  687. DownloadAllEpisodes(tvDBIDs);
  688. }
  689. public static void DownloadAllEpisodes(List<int> tvDBIDs)
  690. {
  691. foreach (int tvid in tvDBIDs)
  692. {
  693. CommandRequest_TvDBUpdateSeriesAndEpisodes cmd = new CommandRequest_TvDBUpdateSeriesAndEpisodes(tvid, false);
  694. cmd.Save();
  695. }
  696. }
  697. public static void ScanForMatches()
  698. {
  699. AnimeSeriesRepository repSeries = new AnimeSeriesRepository();
  700. List<AnimeSeries> allSeries = repSeries.GetAll();
  701. CrossRef_AniDB_TvDBRepository repCrossRef = new CrossRef_AniDB_TvDBRepository();
  702. List<CrossRef_AniDB_TvDB> allCrossRefs = repCrossRef.GetAll();
  703. List<int> alreadyLinked = new List<int>();
  704. foreach (CrossRef_AniDB_TvDB xref in allCrossRefs)
  705. {
  706. alreadyLinked.Add(xref.AnimeID);
  707. }
  708. foreach (AnimeSeries ser in allSeries)
  709. {
  710. if (alreadyLinked.Contains(ser.AniDB_ID)) continue;
  711. AniDB_Anime anime = ser.GetAnime();
  712. if (anime!= null)
  713. {
  714. logger.Trace("Found anime without tvDB association: " + anime.MainTitle);
  715. if (!anime.SearchOnTvDB) continue;
  716. if (anime.IsTvDBLinkDisabled)
  717. {
  718. logger.Trace("Skipping scan tvDB link because it is disabled: " + anime.MainTitle);
  719. continue;
  720. }
  721. }
  722. CommandRequest_TvDBSearchAnime cmd = new CommandRequest_TvDBSearchAnime(ser.AniDB_ID, false);
  723. cmd.Save();
  724. }
  725. }
  726. public static void UpdateAllInfo(bool force)
  727. {
  728. CrossRef_AniDB_TvDBRepository repCrossRef = new CrossRef_AniDB_TvDBRepository();
  729. List<CrossRef_AniDB_TvDB> allCrossRefs = repCrossRef.GetAll();
  730. List<int> alreadyLinked = new List<int>();
  731. foreach (CrossRef_AniDB_TvDB xref in allCrossRefs)
  732. {
  733. CommandRequest_TvDBUpdateSeriesAndEpisodes cmd = new CommandRequest_TvDBUpdateSeriesAndEpisodes(xref.TvDBID, force);
  734. cmd.Save();
  735. }
  736. }
  737. /// <summary>
  738. /// Used to get a list of TvDB Series ID's that require updating
  739. /// </summary>
  740. /// <param name="tvDBIDs">The list Of Series ID's that need to be updated. Pass in an empty list</param>
  741. /// <returns>The current server time before the update started</returns>
  742. public string IncrementalTvDBUpdate(ref List<int> tvDBIDs, ref bool tvDBOnline)
  743. {
  744. // check if we have record of doing an automated update for the TvDB previously
  745. // if we have then we have kept a record of the server time and can do a delta update
  746. // otherwise we need to do a full update and keep a record of the time
  747. List<int> allTvDBIDs = new List<int>();
  748. tvDBIDs = new List<int>();
  749. tvDBOnline = true;
  750. try
  751. {
  752. CrossRef_AniDB_TvDBRepository repCrossRef = new CrossRef_AniDB_TvDBRepository();
  753. AnimeSeriesRepository repSeries = new AnimeSeriesRepository();
  754. // record the tvdb server time when we started
  755. // we record the time now instead of after we finish, to include any possible misses
  756. string currentTvDBServerTime = CurrentServerTime;
  757. if (currentTvDBServerTime.Length == 0)
  758. {
  759. tvDBOnline = false;
  760. return currentTvDBServerTime;
  761. }
  762. foreach (AnimeSeries ser in repSeries.GetAll())
  763. {
  764. CrossRef_AniDB_TvDB xref = ser.GetCrossRefTvDB();
  765. if (xref == null) continue;
  766. if (!allTvDBIDs.Contains(xref.TvDBID)) allTvDBIDs.Add(xref.TvDBID);
  767. }
  768. // get the time we last did a TvDB update
  769. // if this is the first time it will be null
  770. // update the anidb info ever 24 hours
  771. ScheduledUpdateRepository repSched = new ScheduledUpdateRepository();
  772. ScheduledUpdate sched = repSched.GetByUpdateType((int)ScheduledUpdateType.TvDBInfo);
  773. string lastServerTime = "";
  774. if (sched != null)
  775. {
  776. TimeSpan ts = DateTime.Now - sched.LastUpdate;
  777. logger.Trace("Last tvdb info update was {0} hours ago", ts.TotalHours.ToString());
  778. if (!string.IsNullOrEmpty(sched.UpdateDetails))
  779. lastServerTime = sched.UpdateDetails;
  780. // the UpdateDetails field for this type will actually contain the last server time from
  781. // TheTvDB that a full update was performed
  782. }
  783. // get a list of updates from TvDB since that time
  784. if (lastServerTime.Length > 0)
  785. {
  786. List<int> seriesList = GetUpdatedSeriesList(lastServerTime);
  787. logger.Trace("{0} series have been updated since last download", seriesList.Count.ToString());
  788. logger.Trace("{0} TvDB series locally", allTvDBIDs.Count.ToString());
  789. foreach (int id in seriesList)
  790. {
  791. if (allTvDBIDs.Contains(id)) tvDBIDs.Add(id);
  792. }
  793. logger.Trace("{0} TvDB local series have been updated since last download", tvDBIDs.Count.ToString());
  794. }
  795. else
  796. {
  797. // use the full list
  798. tvDBIDs = allTvDBIDs;
  799. }
  800. return currentTvDBServerTime;
  801. }
  802. catch (Exception ex)
  803. {
  804. logger.ErrorException("IncrementalTvDBUpdate: "+ ex.ToString(), ex);
  805. return "";
  806. }
  807. }
  808. /*public static void RemoveEpisodeAssociation(int aniDB_EpisodeID)
  809. {
  810. CrossRef_Episode_AniDB_TvDB xref = new CrossRef_Episode_AniDB_TvDB();
  811. if (xref.Load(aniDB_EpisodeID))
  812. {
  813. xref.Delete();
  814. }
  815. }
  816. public static TvDB_Episode PromptForEpisode(int tvDBID, AniDB_Episode aniep)
  817. {
  818. // get all the seasons for this episode
  819. try
  820. {
  821. Dictionary<int, int> seasons = new Dictionary<int, int>();
  822. List<int> seasonNumbers = new List<int>();
  823. List<string[]> info = TvDB_Episode.GetFromTvDBID(tvDBID);
  824. if (info.Count == 0)
  825. {
  826. GUIDialogOK dlgOK = (GUIDialogOK)GUIWindowManager.GetWindow((int)GUIWindow.Window.WINDOW_DIALOG_OK);
  827. if (null == dlgOK)
  828. return null;
  829. dlgOK.SetHeading("Error");
  830. dlgOK.SetLine(1, string.Empty);
  831. dlgOK.SetLine(2, "No series found");
  832. dlgOK.DoModal(GUIWindowManager.ActiveWindow);
  833. return null;
  834. }
  835. IDialogbox dlg2 = (IDialogbox)GUIWindowManager.GetWindow((int)GUIWindow.Window.WINDOW_DIALOG_MENU);
  836. dlg2.Reset();
  837. dlg2.SetHeading("Select Season");
  838. GUIListItem pItem2 = null;
  839. for (int i = 0; i < info.Count; i++)
  840. {
  841. int id = int.Parse(info[i][0]);
  842. int season = int.Parse(info[i][1]);
  843. seasons[id] = season;
  844. seasonNumbers.Add(season);
  845. pItem2 = new GUIListItem(string.Format("Season {0}", season.ToString()));
  846. dlg2.Add(pItem2);
  847. }
  848. dlg2.DoModal(GUIWindowManager.ActiveWindow);
  849. if (dlg2.SelectedId > 0)
  850. {
  851. int season = seasonNumbers[dlg2.SelectedId - 1];
  852. List<TvDB_Episode> eps = TvDB_Episode.GetEpisodesForSeason(tvDBID, season);
  853. IDialogbox dlg3 = (IDialogbox)GUIWindowManager.GetWindow((int)GUIWindow.Window.WINDOW_DIALOG_MENU);
  854. dlg3.Reset();
  855. dlg3.SetHeading(string.Format("{0} - {1}", aniep.EpisodeNumber, aniep.DefaultEpisodeName));
  856. GUIListItem pItem3 = null;
  857. foreach (TvDB_Episode ep in eps)
  858. {
  859. pItem3 = new GUIListItem(string.Format("Ep: {0} - {1}", ep.EpisodeNumber, ep.EpisodeName));
  860. dlg3.Add(pItem3);
  861. }
  862. dlg3.DoModal(GUIWindowManager.ActiveWindow);
  863. if (dlg3.SelectedId > 0)
  864. {
  865. TvDB_Episode selEp = eps[dlg3.SelectedId - 1];
  866. CrossRef_Episode_AniDB_TvDB xref = new CrossRef_Episode_AniDB_TvDB();
  867. if (!xref.Load(aniep.EpisodeID))
  868. {
  869. xref.AniDB_ID = aniep.EpisodeID;
  870. }
  871. xref.TvDB_ID = selEp.Id;
  872. xref.Save();
  873. XMLService.Send_CrossRef_Episode_AniDB_TvDB(xref);
  874. }
  875. }
  876. }
  877. catch (Exception ex)
  878. {
  879. BaseConfig.MyAnimeLog.Write("Error in PromptForEpisode: {0}", ex.ToString());
  880. return null;
  881. }
  882. return null;
  883. }*/
  884. }
  885. }