iptorrents.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. # VERSION: 1.01
  2. # AUTHORS: txtsd (thexerothermicsclerodermoid@gmail.com)
  3. # iptorrents.py - A plugin for qBittorrent to search on iptorrents.com
  4. # Copyright (C) 2019 txtsd <thexerothermicsclerodermoid@gmail.com>
  5. #
  6. # This program 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. # This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
  18. import gzip
  19. import io
  20. import logging
  21. import re
  22. import tempfile
  23. import urllib.request as request
  24. from http.cookiejar import CookieJar
  25. from urllib.error import URLError
  26. from urllib.parse import urlencode, quote
  27. from helpers import htmlentitydecode
  28. from novaprinter import prettyPrinter
  29. logger = logging.getLogger()
  30. logger.setLevel(logging.DEBUG)
  31. class iptorrents(object):
  32. # Login information ######################################################
  33. #
  34. # SET THESE VALUES!!
  35. #
  36. username = ""
  37. password = ""
  38. ###########################################################################
  39. url = 'https://iptorrents.com'
  40. name = 'IPTorrents'
  41. supported_categories = {
  42. 'all': '',
  43. 'movies': '72',
  44. 'tv': '73',
  45. 'music': '75',
  46. 'games': '74',
  47. 'anime': '60',
  48. 'software': '1',
  49. 'pictures': '36',
  50. 'books': '35'
  51. }
  52. def __init__(self):
  53. """
  54. Class initialization
  55. Requires personal login information
  56. """
  57. self.ua = 'Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0'
  58. self.session = None
  59. self._login()
  60. def _login(self):
  61. """Initiate a session and log into IPTorrents"""
  62. # Build opener
  63. cj = CookieJar()
  64. params = {
  65. 'username': self.username,
  66. 'password': self.password
  67. }
  68. session = request.build_opener(request.HTTPCookieProcessor(cj))
  69. # change user-agent
  70. session.addheaders.pop()
  71. session.addheaders.append(('User-Agent', self.ua))
  72. session.addheaders.append(('Referrer', self.url + '/login.php'))
  73. # send request
  74. try:
  75. logging.debug("Trying to connect using given credentials.")
  76. logging.debug(self.url + '/take_login.php')
  77. logging.debug(urlencode(params).encode('utf-8'))
  78. session.open(
  79. self.url + '/take_login.php',
  80. urlencode(params).encode('utf-8')
  81. )
  82. logging.debug("Connected using given credentials.")
  83. self.session = session
  84. except URLError as errno:
  85. print("Connection Error: {} {}".format(errno.code, errno.reason))
  86. return
  87. def _get_link(self, link):
  88. """Return the HTML content of url page as a string """
  89. try:
  90. logging.debug("Trying to open " + link)
  91. res = self.session.open(link)
  92. except URLError as errno:
  93. print("Connection Error: {} {}".format(errno.code, errno.reason))
  94. return ""
  95. charset = 'utf-8'
  96. info = res.info()
  97. _, charset = info['Content-Type'].split('charset=')
  98. data = res.read()
  99. data = data.decode(charset, 'replace')
  100. data = htmlentitydecode(data)
  101. return data
  102. def search_parse(self, link, page=1):
  103. """ Parses IPTorrents for search results and prints them"""
  104. logging.debug("Parsing " + link)
  105. data = self._get_link(link + '&p=' + str(page))
  106. _tor_table = re.search('<form>(<table id=torrents.+?)</form>', data)
  107. tor_table = _tor_table.groups()[0] if _tor_table else None
  108. results = re.finditer(
  109. r'<a class=" hv" href="(?P<desc_link>/details.+?)">(?P<name>.+?)</a>.+?href="(?P<link>/download.+?)".+?(?P<size>\d+?\.*?\d*? (|K|M|G)B)<.+?t_seeders">(?P<seeds>\d+).+?t_leechers">(?P<leech>\d+?)</t',
  110. tor_table
  111. )
  112. for result in results:
  113. entry = dict()
  114. entry['link'] = self.url + quote(result.group('link'))
  115. entry['name'] = result.group('name')
  116. entry['size'] = result.group('size')
  117. entry['seeds'] = result.group('seeds')
  118. entry['leech'] = result.group('leech')
  119. entry['engine_url'] = self.url
  120. entry['desc_link'] = self.url + result.group('desc_link')
  121. prettyPrinter(entry)
  122. _num_pages = re.search(r'<a>Page <b>(\d+)</b> of <b>(\d+)</b>', data)
  123. page = _num_pages.groups()[0] if _num_pages else None
  124. num_pages = _num_pages.groups()[1] if _num_pages else None
  125. if (page and num_pages) and (int(page) < int(num_pages)):
  126. next_page = int(page) + 1
  127. self.search_parse(link, next_page)
  128. def download_torrent(self, info):
  129. """
  130. Downloads torrent to a temp file and loads it in qBittorrent
  131. """
  132. file, path = tempfile.mkstemp('.torrent')
  133. url = info
  134. # self._login()
  135. try:
  136. logging.debug("Trying to download " + url)
  137. res = self.session.open(url)
  138. except URLError as errno:
  139. print("Connection Error: {} {}".format(errno.code, errno.reason))
  140. return ""
  141. data = res.read()
  142. if data[:2] == b'\x1f\x8b':
  143. # Data is gzip encoded, decode it
  144. logging.debug("Data is gzip encoded, decode it")
  145. compressedstream = io.BytesIO(data)
  146. gzipper = gzip.GzipFile(fileobj=compressedstream)
  147. extracted_data = gzipper.read()
  148. data = extracted_data
  149. with open(file, 'wb') as f:
  150. f.write(data)
  151. print(path + " " + url)
  152. def search(self, what, cat='all'):
  153. """
  154. Formats url according to category and calls search_parse()
  155. """
  156. if cat == 'all':
  157. url = "{0}/t?q={1}&o=seeders".format(
  158. self.url,
  159. what
  160. )
  161. else:
  162. url = "{0}/t?{1}=&q={2}&o=seeders".format(
  163. self.url,
  164. self.supported_categories[cat],
  165. what
  166. )
  167. self.search_parse(url)
  168. # For testing purposes.
  169. # Run with python -m engines.iptorrents
  170. if __name__ == "__main__":
  171. engine = iptorrents()
  172. engine.search('one+piece')
  173. # engine.download_torrent('')