PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/src/backends/thetvdbbackend.py

https://github.com/aleximplode/Show-Tracker
Python | 296 lines | 264 code | 20 blank | 12 comment | 6 complexity | f54282dce226809bf61fb128f6c5bbc9 MD5 | raw file
  1. from PyQt4.QtCore import QString
  2. from PyQt4.QtXml import QDomDocument
  3. from random import choice
  4. from urlparse import urljoin
  5. from io import BytesIO
  6. from zipfile import ZipFile
  7. from time import strptime, mktime
  8. from datetime import datetime
  9. import os.path
  10. from src.backends.backend import backend
  11. from src.dataclasses import show, season, episode
  12. class thetvdbbackend(backend):
  13. ''' A backend to the thetvdb.com API '''
  14. def __init__(self, settings):
  15. '''
  16. @type settings: L{src.settings.settings}
  17. '''
  18. backend.__init__(self, settings)
  19. # Load site mirrors for xml, banners, zip files
  20. self.__mirrors = [[], [], []]
  21. self.__loadmirrors()
  22. def searchshow(self, name):
  23. '''
  24. @type name: str
  25. @rtype: list
  26. '''
  27. data = self._request('http://www.thetvdb.com/api/GetSeries.php?seriesname=%s' % name)
  28. xml = QDomDocument()
  29. xml.setContent(data)
  30. showsxml = xml.elementsByTagName('Series')
  31. shows = []
  32. for i in range(len(showsxml)):
  33. newshow = show()
  34. newshow.id = unicode(QString(showsxml.at(i).toElement().elementsByTagName('seriesid').at(0).childNodes().at(0).toText().data()))
  35. newshow.name = unicode(QString(showsxml.at(i).toElement().elementsByTagName('SeriesName').at(0).childNodes().at(0).toText().data()))
  36. newshow.description = unicode(QString(showsxml.at(i).toElement().elementsByTagName('Overview').at(0).childNodes().at(0).toText().data()))
  37. newshow.image = unicode(QString(showsxml.at(i).toElement().elementsByTagName('banner').at(0).firstChild().toText().data()))
  38. newshow.data = showsxml.at(i).toElement()
  39. if len(newshow.image):
  40. self._download(urljoin(urljoin(choice(self.__mirrors[1]), '/banners/'), newshow.image), newshow.image)
  41. shows.append(newshow)
  42. return shows
  43. def getlocalshows(self):
  44. '''
  45. @rtype: list
  46. '''
  47. shows = []
  48. if self._storage.exists('shows'):
  49. showdirs = self._storage.listdir('shows')
  50. for showdir in showdirs:
  51. data = self._storage.getdata('shows/%s/en.xml' % showdir)
  52. if data != None:
  53. xml = QDomDocument()
  54. xml.setContent(data)
  55. showxml = xml.elementsByTagName('Series').at(0)
  56. newshow = show()
  57. newshow.id = unicode(QString(showxml.toElement().elementsByTagName('id').at(0).childNodes().at(0).toText().data()))
  58. newshow.name = unicode(QString(showxml.toElement().elementsByTagName('SeriesName').at(0).childNodes().at(0).toText().data()))
  59. newshow.description = unicode(QString(showxml.toElement().elementsByTagName('Overview').at(0).childNodes().at(0).toText().data()))
  60. newshow.image = unicode(QString(showxml.toElement().elementsByTagName('banner').at(0).firstChild().toText().data()))
  61. newshow.data = showxml.toElement()
  62. newshow.actors = unicode(QString(showxml.toElement().elementsByTagName('Actors').at(0).childNodes().at(0).toText().data())).strip('|').split('|')
  63. newshow.contentrating = unicode(QString(showxml.toElement().elementsByTagName('ContentRating').at(0).childNodes().at(0).toText().data()))
  64. firstaired = unicode(QString(showxml.toElement().elementsByTagName('FirstAired').at(0).childNodes().at(0).toText().data()))
  65. if firstaired != '':
  66. newshow.firstaired = datetime.fromtimestamp(mktime(strptime(firstaired, '%Y-%m-%d')))
  67. else:
  68. newshow.firstaired = datetime.now()
  69. newshow.genre = unicode(QString(showxml.toElement().elementsByTagName('Genre').at(0).childNodes().at(0).toText().data())).strip('|').split('|')
  70. newshow.imdb = unicode(QString(showxml.toElement().elementsByTagName('IMDB_ID').at(0).childNodes().at(0).toText().data()))
  71. newshow.network = unicode(QString(showxml.toElement().elementsByTagName('Network').at(0).childNodes().at(0).toText().data()))
  72. rating = unicode(QString(
  73. showxml.toElement().elementsByTagName('Rating').at(0).childNodes().at(0).toText().data()))
  74. if rating != '':
  75. newshow.rating = float(rating)
  76. else:
  77. newshow.rating = 0.0
  78. newshow.runtime = int(unicode(QString(showxml.toElement().elementsByTagName('Runtime').at(0).childNodes().at(0).toText().data())))
  79. newshow.status = unicode(QString(showxml.toElement().elementsByTagName('Status').at(0).childNodes().at(0).toText().data()))
  80. shows.append(newshow)
  81. return shows
  82. def addshow(self, id):
  83. '''
  84. @type id: str
  85. '''
  86. if not self._storage.exists('shows/%s' % id):
  87. self.updateshow(id)
  88. def updateshow(self, id):
  89. '''
  90. @type id: str
  91. '''
  92. zipdata = self._request(urljoin(choice(self.__mirrors[2]), '/api/%s/series/%s/all/en.zip' % (self.__apikey(), id)))
  93. zipio = BytesIO()
  94. zipio.write(bytes(zipdata))
  95. zipfile = ZipFile(zipio)
  96. for info in zipfile.infolist():
  97. data = zipfile.open(info).read()
  98. self._storage.savedata('shows/%s/%s' % (id, info.filename), data)
  99. zipfile.close()
  100. if self._storage.exists('shows/%s/en.xml' % id):
  101. data = self._storage.getdata('shows/%s/en.xml' % id)
  102. xml = QDomDocument()
  103. xml.setContent(data)
  104. showxml = xml.elementsByTagName('Series').at(0)
  105. imageurl = unicode(QString(showxml.toElement().elementsByTagName('banner').at(0).childNodes().at(0).toText().data()))
  106. if len(imageurl) > 0 and not self._storage.exists(imageurl):
  107. self._download(urljoin(urljoin(choice(self.__mirrors[1]), '/banners/'), imageurl), imageurl)
  108. if self._storage.exists('shows/%s/banners.xml' % id):
  109. data = self._storage.getdata('shows/%s/banners.xml' % id)
  110. xml = QDomDocument()
  111. xml.setContent(data)
  112. bannersxml = xml.elementsByTagName('Banner')
  113. bannerslist = {}
  114. for bannernum in range(bannersxml.count()):
  115. language = unicode(QString(bannersxml.at(bannernum).toElement().elementsByTagName('Language').at(0).childNodes().at(0).toText().data()))
  116. if language == 'en':
  117. bannertype = unicode(QString(bannersxml.at(bannernum).toElement().elementsByTagName('BannerType').at(0).childNodes().at(0).toText().data()))
  118. if bannertype == 'season':
  119. bannertype2 = unicode(QString(bannersxml.at(bannernum).toElement().elementsByTagName('BannerType2').at(0).childNodes().at(0).toText().data()))
  120. if bannertype2 == 'seasonwide':
  121. bannerpath = unicode(QString(bannersxml.at(bannernum).toElement().elementsByTagName('BannerPath').at(0).childNodes().at(0).toText().data()))
  122. rating = QString(bannersxml.at(bannernum).toElement().elementsByTagName('BannerPath').at(0).childNodes().at(0).toText().data()).toInt()[0]
  123. bannerseasoniditems = os.path.splitext(os.path.basename(bannerpath))[0].split('-')
  124. bannerseasonid = '-'.join((bannerseasoniditems[0], bannerseasoniditems[1]))
  125. if not bannerseasonid in bannerslist:
  126. bannerslist[bannerseasonid] = []
  127. bannerslist[bannerseasonid].append((bannerpath, rating))
  128. for (bannerseasonid, banners) in bannerslist.iteritems():
  129. sortedbanners = sorted(banners, key = lambda item: item[1])
  130. if len(sortedbanners[0][0]) > 0 and not self._storage.exists('seasonbanners/%s%s' % (bannerseasonid, os.path.splitext(sortedbanners[0][0])[1])):
  131. self._download(urljoin(urljoin(choice(self.__mirrors[1]), '/banners/'), sortedbanners[0][0]), 'seasonbanners/%s%s' % (bannerseasonid, os.path.splitext(sortedbanners[0][0])[1]))
  132. def getlocalseasons(self, id):
  133. '''
  134. @type id: str
  135. @rtype: list
  136. '''
  137. seasons = {}
  138. if self._storage.exists('shows/%s/en.xml' % id):
  139. data = self._storage.getdata('shows/%s/en.xml' % id)
  140. xml = QDomDocument()
  141. xml.setContent(data)
  142. episodes = xml.elementsByTagName('Episode')
  143. for episode in range(episodes.count()):
  144. seasonid = unicode(QString(episodes.at(episode).toElement().elementsByTagName('seasonid').at(0).childNodes().at(0).toText().data()))
  145. seasonnum = QString(episodes.at(episode).toElement().elementsByTagName('SeasonNumber').at(0).childNodes().at(0).toText().data()).toInt()
  146. if seasonnum[1]:
  147. if seasonnum[0] > 0:
  148. if not seasonid in seasons:
  149. newseason = season()
  150. newseason.id = seasonid
  151. newseason.number = seasonnum[0]
  152. newseason.image = 'seasonbanners/%s-%d.jpg' % (id, newseason.number)
  153. newseason.showid = id
  154. seasons[seasonid] = newseason
  155. return sorted(seasons.values(), key = lambda item: item.number)
  156. def getlocalepisodes(self, showid, seasonid):
  157. '''
  158. @type showid: str
  159. @type seasonid: str
  160. @rtype: list
  161. '''
  162. episodes = []
  163. if self._storage.exists('shows/%s/en.xml' % showid):
  164. data = self._storage.getdata('shows/%s/en.xml' % showid)
  165. xml = QDomDocument()
  166. xml.setContent(data)
  167. episodelist = xml.elementsByTagName('Episode')
  168. for episodenum in range(episodelist.count()):
  169. if seasonid == unicode(QString(episodelist.at(episodenum).toElement().elementsByTagName('seasonid').at(0).childNodes().at(0).toText().data())):
  170. newepisode = episode()
  171. number = QString(episodelist.at(episodenum).toElement().elementsByTagName('EpisodeNumber').at(0).childNodes().at(0).toText().data()).toInt()
  172. if number[1]:
  173. newepisode.number = number[0]
  174. else:
  175. newepisode.number = 0
  176. if newepisode.number > 0:
  177. newepisode.id = unicode(QString(episodelist.at(episodenum).toElement().elementsByTagName('id').at(0).childNodes().at(0).toText().data()))
  178. newepisode.name = unicode(QString(episodelist.at(episodenum).toElement().elementsByTagName('EpisodeName').at(0).childNodes().at(0).toText().data()))
  179. newepisode.description = unicode(QString(episodelist.at(episodenum).toElement().elementsByTagName('Overview').at(0).childNodes().at(0).toText().data()))
  180. datestring = unicode(QString(episodelist.at(episodenum).toElement().elementsByTagName('FirstAired').at(0).childNodes().at(0).toText().data()))
  181. if len(datestring) > 0:
  182. newepisode.date = datetime.fromtimestamp(mktime(strptime(datestring, '%Y-%m-%d')))
  183. newepisode.showid = showid
  184. newepisode.seasonid = seasonid
  185. newepisode.watched = self.getwatched(newepisode.showid, newepisode.seasonid, newepisode.id)
  186. episodes.append(newepisode)
  187. return sorted(episodes, key = lambda item: item.number)
  188. def removeshow(self, id):
  189. '''
  190. @type id: str
  191. '''
  192. self._storage.removedir('shows/%s' % id)
  193. def __apikey(self):
  194. '''
  195. @rtype: str
  196. '''
  197. return self._getsetting('apikey', str, 'C66331E1E6D28F85')
  198. def __loadmirrors(self):
  199. data = self._request('http://www.thetvdb.com/api/%s/mirrors.xml' % self.__apikey())
  200. xml = QDomDocument()
  201. xml.setContent(data)
  202. mirrors = xml.elementsByTagName('Mirror')
  203. for i in range(len(mirrors)):
  204. typemask = QString(mirrors.at(i).toElement().elementsByTagName('typemask').at(0).childNodes().at(0).toText().data()).toInt()
  205. mirrorpath = unicode(QString(mirrors.at(i).toElement().elementsByTagName('mirrorpath').at(0).childNodes().at(0).toText().data()))
  206. if typemask[1]:
  207. if typemask[0] & 1:
  208. self.__mirrors[0].append(mirrorpath)
  209. if typemask[0] & 2:
  210. self.__mirrors[1].append(mirrorpath)
  211. if typemask[0] & 4:
  212. self.__mirrors[2].append(mirrorpath)