PageRenderTime 43ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/sickbeard/providers/iptorrents.py

https://github.com/nesitech/Sick-Beard
Python | 262 lines | 201 code | 41 blank | 20 comment | 21 complexity | bcb15f86c98819759a7baf49d9764ba2 MD5 | raw file
Possible License(s): GPL-3.0, MPL-2.0-no-copyleft-exception, Unlicense
  1. # Author: Idan Gutman
  2. # URL: http://code.google.com/p/sickbeard/
  3. #
  4. # This file is part of Sick Beard.
  5. #
  6. # Sick Beard is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # Sick Beard is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with Sick Beard. If not, see <http://www.gnu.org/licenses/>.
  18. import re
  19. import sickbeard
  20. import generic
  21. from sickbeard.common import Quality
  22. from sickbeard import logger
  23. from sickbeard import tvcache
  24. from sickbeard import show_name_helpers
  25. from sickbeard.common import Overview
  26. from sickbeard.exceptions import ex
  27. from lib import requests
  28. from bs4 import BeautifulSoup
  29. class IPTorrentsProvider(generic.TorrentProvider):
  30. urls = {'base_url' : 'http://www.iptorrents.com/',
  31. 'login' : 'http://www.iptorrents.com/torrents/',
  32. 'detail' : 'http://www.iptorrents.com/details.php?id=%s',
  33. 'search' : 'http://www.iptorrents.com/torrents/?l%d=1%s&q=%s&qf=ti',
  34. 'download' : 'http://www.iptorrents.com/download.php/%s/%s.torrent',
  35. }
  36. def __init__(self):
  37. generic.TorrentProvider.__init__(self, "IPTorrents")
  38. self.supportsBacklog = True
  39. self.cache = IPTorrentsCache(self)
  40. self.url = self.urls['base_url']
  41. self.session = None
  42. self.categories = 73
  43. def isEnabled(self):
  44. return sickbeard.IPTORRENTS
  45. def imageName(self):
  46. return 'iptorrents.png'
  47. def getQuality(self, item):
  48. quality = Quality.nameQuality(item[0])
  49. return quality
  50. def _doLogin(self):
  51. login_params = {'username': sickbeard.IPTORRENTS_USERNAME,
  52. 'password': sickbeard.IPTORRENTS_PASSWORD,
  53. 'login': 'submit',
  54. }
  55. self.session = requests.Session()
  56. try:
  57. response = self.session.post(self.urls['login'], data=login_params, timeout=30)
  58. except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError), e:
  59. logger.log(u'Unable to connect to ' + self.name + ' provider: ' +ex(e), logger.ERROR)
  60. return False
  61. if re.search('tries left', response.text) \
  62. or re.search('<title>IPT</title>', response.text) \
  63. or response.status_code == 401:
  64. logger.log(u'Invalid username or password for ' + self.name + ' Check your settings', logger.ERROR)
  65. return False
  66. return True
  67. def _get_season_search_strings(self, show, season=None):
  68. search_string = {'Episode': []}
  69. if not show:
  70. return []
  71. seasonEp = show.getAllEpisodes(season)
  72. wantedEp = [x for x in seasonEp if show.getOverview(x.status) in (Overview.WANTED, Overview.QUAL)]
  73. #If Every episode in Season is a wanted Episode then search for Season first
  74. if wantedEp == seasonEp and not show.air_by_date:
  75. search_string = {'Season': [], 'Episode': []}
  76. for show_name in set(show_name_helpers.allPossibleShowNames(show)):
  77. ep_string = show_name +' S%02d' % int(season) #1) ShowName SXX
  78. search_string['Season'].append(ep_string)
  79. #Building the search string with the episodes we need
  80. for ep_obj in wantedEp:
  81. search_string['Episode'] += self._get_episode_search_strings(ep_obj)[0]['Episode']
  82. #If no Episode is needed then return an empty list
  83. if not search_string['Episode']:
  84. return []
  85. return [search_string]
  86. def _get_episode_search_strings(self, ep_obj):
  87. search_string = {'Episode': []}
  88. if not ep_obj:
  89. return []
  90. if ep_obj.show.air_by_date:
  91. for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)):
  92. ep_string = show_name_helpers.sanitizeSceneName(show_name) +' '+ str(ep_obj.airdate)
  93. search_string['Episode'].append(ep_string)
  94. else:
  95. for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)):
  96. ep_string = show_name_helpers.sanitizeSceneName(show_name) +' '+ \
  97. sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.season, 'episodenumber': ep_obj.episode}
  98. search_string['Episode'].append(ep_string)
  99. return [search_string]
  100. def _doSearch(self, search_params, show=None):
  101. results = []
  102. items = {'Season': [], 'Episode': []}
  103. if not self._doLogin():
  104. return
  105. freeleech = '&free=on' if sickbeard.IPTORRENTS_FREELEECH else ''
  106. for mode in search_params.keys():
  107. for search_string in search_params[mode]:
  108. searchURL = self.urls['search'] % (self.categories, freeleech, search_string)
  109. logger.log(u"Search string: " + searchURL, logger.DEBUG)
  110. data = self.getURL(searchURL)
  111. if not data:
  112. return []
  113. html = BeautifulSoup(data)
  114. try:
  115. if html.find(text='Nothing found!'):
  116. logger.log(u"No results found for: " + search_string + "(" + searchURL + ")", logger.DEBUG)
  117. return []
  118. result_table = html.find('table', attrs = {'class' : 'torrents'})
  119. if not result_table:
  120. logger.log(u"No results found for: " + search_string + "(" + searchURL + ")", logger.DEBUG)
  121. return []
  122. entries = result_table.find_all('tr')
  123. for result in entries[1:]:
  124. torrent = result.find_all('td')[1].find('a')
  125. torrent_id = int(torrent['href'].replace('/details.php?id=', ''))
  126. torrent_name = torrent.string
  127. torrent_download_url = self.urls['download'] % (torrent_id, torrent_name.replace(' ', '.'))
  128. torrent_details_url = self.urls['detail'] % (torrent_id)
  129. torrent_seeders = int(result.find('td', attrs = {'class' : 'ac t_seeders'}).string)
  130. torrent_leechers = int(result.find('td', attrs = {'class' : 'ac t_leechers'}).string)
  131. #Filter unseeded torrent
  132. if torrent_seeders == 0 or not torrent_name \
  133. or not show_name_helpers.filterBadReleases(torrent_name):
  134. continue
  135. item = torrent_name, torrent_download_url, torrent_id, torrent_seeders, torrent_leechers
  136. logger.log(u"Found result: " + torrent_name + "(" + searchURL + ")", logger.DEBUG)
  137. items[mode].append(item)
  138. except:
  139. logger.log(u"Failed to parsing " + self.name + " page url: " + searchURL, logger.ERROR)
  140. #For each search mode sort all the items by seeders
  141. items[mode].sort(key=lambda tup: tup[3], reverse=True)
  142. results += items[mode]
  143. return results
  144. def _get_title_and_url(self, item):
  145. title, url, id, seeders, leechers = item
  146. if url:
  147. url = str(url).replace('&amp;','&')
  148. return (title, url)
  149. def getURL(self, url, headers=None):
  150. if not self.session:
  151. self._doLogin()
  152. if not headers:
  153. headers = []
  154. try:
  155. response = self.session.get(url)
  156. except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError), e:
  157. logger.log(u"Error loading "+self.name+" URL: " + ex(e), logger.ERROR)
  158. return None
  159. return response.content
  160. class IPTorrentsCache(tvcache.TVCache):
  161. def __init__(self, provider):
  162. tvcache.TVCache.__init__(self, provider)
  163. # only poll IPTorrents every 20 minutes max
  164. self.minTime = 20
  165. def _getData(self):
  166. freeleech = '&free=on' if sickbeard.IPTORRENTS_FREELEECH else ''
  167. #url for the last 50 tv-show
  168. url = self.provider.urls['search'] % (self.provider.categories, freeleech, "")
  169. logger.log(u"IPTorrents cache update URL: "+ url, logger.DEBUG)
  170. data = self.provider.getURL(url)
  171. return data
  172. def _parseItem(self, item):
  173. (title, url) = item
  174. if not title or not url:
  175. return
  176. logger.log(u"Adding item to cache: "+title, logger.DEBUG)
  177. self._addCacheEntry(title, url)
  178. provider = IPTorrentsProvider()