Advertisement
Guest User

Untitled

a guest
Jun 2nd, 2017
92
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.22 KB | None | 0 0
  1. #!/usr/bin/env python
  2. import re
  3. import os
  4. import json
  5. import time
  6. import requests
  7. import mechanize
  8. import HTMLParser
  9. from cStringIO import StringIO
  10.  
  11. headers = {
  12. 'Connection': 'keep-alive',
  13. 'Cache-Control': 'max-age=0',
  14. 'User-Agent': 'PTHBetter crawler',
  15. 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  16. 'Accept-Encoding': 'gzip,deflate,sdch',
  17. 'Accept-Language': 'en-US,en;q=0.8',
  18. 'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3'}
  19.  
  20. # gazelle is picky about case in searches with &media=x
  21. media_search_map = {
  22. 'cd': 'CD',
  23. 'dvd': 'DVD',
  24. 'vinyl': 'Vinyl',
  25. 'soundboard': 'Soundboard',
  26. 'sacd': 'SACD',
  27. 'dat': 'DAT',
  28. 'web': 'WEB',
  29. 'blu-ray': 'Blu-ray'
  30. }
  31.  
  32. lossless_media = set(media_search_map.keys())
  33.  
  34. formats = {
  35. 'FLAC': {
  36. 'format': 'FLAC',
  37. 'encoding': 'Lossless'
  38. },
  39. 'V0': {
  40. 'format' : 'MP3',
  41. 'encoding' : 'V0 (VBR)'
  42. },
  43. '320': {
  44. 'format' : 'MP3',
  45. 'encoding' : '320'
  46. },
  47. 'V2': {
  48. 'format' : 'MP3',
  49. 'encoding' : 'V2 (VBR)'
  50. },
  51. }
  52.  
  53. def allowed_transcodes(torrent):
  54. """Some torrent types have transcoding restrictions."""
  55. preemphasis = re.search(r"""pre[- ]?emphasi(s(ed)?|zed)""", torrent['remasterTitle'], flags=re.IGNORECASE)
  56. if preemphasis:
  57. return []
  58. else:
  59. return formats.keys()
  60.  
  61. class LoginException(Exception):
  62. pass
  63.  
  64. class RequestException(Exception):
  65. pass
  66.  
  67. class WhatAPI:
  68. def __init__(self, username=None, password=None):
  69. self.session = requests.Session()
  70. self.session.headers.update(headers)
  71. self.username = username
  72. self.password = password
  73. self.authkey = None
  74. self.passkey = None
  75. self.userid = None
  76. self.tracker = "https://flacsfor.me/"
  77. self.last_request = time.time()
  78. self.rate_limit = 2.0 # seconds between requests
  79. self._login()
  80.  
  81. def _login(self):
  82. '''Logs in user and gets authkey from server'''
  83. loginpage = 'https://redacted.ch/login.php'
  84. data = {'username': self.username,
  85. 'password': self.password}
  86. r = self.session.post(loginpage, data=data)
  87. if r.status_code != 200:
  88. raise LoginException
  89. accountinfo = self.request('index')
  90. self.authkey = accountinfo['authkey']
  91. self.passkey = accountinfo['passkey']
  92. self.userid = accountinfo['id']
  93.  
  94. def logout(self):
  95. self.session.get("https://redacted.ch/logout.php?auth=%s" % self.authkey)
  96.  
  97. def request(self, action, **kwargs):
  98. '''Makes an AJAX request at a given action page'''
  99. while time.time() - self.last_request < self.rate_limit:
  100. time.sleep(0.1)
  101.  
  102. ajaxpage = 'https://redacted.ch/ajax.php'
  103. params = {'action': action}
  104. if self.authkey:
  105. params['auth'] = self.authkey
  106. params.update(kwargs)
  107. r = self.session.get(ajaxpage, params=params, allow_redirects=False)
  108. self.last_request = time.time()
  109. try:
  110. parsed = json.loads(r.content)
  111. if parsed['status'] != 'success':
  112. raise RequestException
  113. return parsed['response']
  114. except ValueError:
  115. raise RequestException
  116.  
  117. def request_html(self, action, **kwargs):
  118. while time.time() - self.last_request < self.rate_limit:
  119. time.sleep(0.1)
  120.  
  121. ajaxpage = 'https://redacted.ch/' + action
  122. if self.authkey:
  123. kwargs['auth'] = self.authkey
  124. r = self.session.get(ajaxpage, params=kwargs, allow_redirects=False)
  125. self.last_request = time.time()
  126. return r.content
  127.  
  128. def get_artist(self, id=None, format='MP3', best_seeded=True):
  129. res = self.request('artist', id=id)
  130. torrentgroups = res['torrentgroup']
  131. keep_releases = []
  132. for release in torrentgroups:
  133. torrents = release['torrent']
  134. best_torrent = torrents[0]
  135. keeptorrents = []
  136. for t in torrents:
  137. if t['format'] == format:
  138. if best_seeded:
  139. if t['seeders'] > best_torrent['seeders']:
  140. keeptorrents = [t]
  141. best_torrent = t
  142. else:
  143. keeptorrents.append(t)
  144. release['torrent'] = list(keeptorrents)
  145. if len(release['torrent']):
  146. keep_releases.append(release)
  147. res['torrentgroup'] = keep_releases
  148. return res
  149.  
  150. def snatched(self, skip=None, media=lossless_media):
  151. if not media.issubset(lossless_media):
  152. raise ValueError('Unsupported media type %s' % (media - lossless_media).pop())
  153.  
  154. # gazelle doesn't currently support multiple values per query
  155. # parameter, so we have to search a media type at a time;
  156. # unless it's all types, in which case we simply don't specify
  157. # a 'media' parameter (defaults to all types).
  158.  
  159. if media == lossless_media:
  160. media_params = ['']
  161. else:
  162. media_params = ['&media=%s' % media_search_map[m] for m in media]
  163.  
  164. url = 'https://redacted.ch/torrents.php?type=snatched&userid=%s&format=FLAC' % self.userid
  165. for mp in media_params:
  166. page = 1
  167. done = False
  168. pattern = re.compile('torrents.php\?id=(\d+)&amp;torrentid=(\d+)')
  169. while not done:
  170. content = self.session.get(url + mp + "&page=%s" % page).text
  171. for groupid, torrentid in pattern.findall(content):
  172. if skip is None or torrentid not in skip:
  173. yield int(groupid), int(torrentid)
  174. done = 'Next &gt;' not in content
  175. page += 1
  176.  
  177. def upload(self, group, torrent, new_torrent, format, description=[]):
  178. url = "https://redacted.ch/upload.php?groupid=%s" % group['group']['id']
  179. response = self.session.get(url)
  180. forms = mechanize.ParseFile(StringIO(response.text.encode('utf-8')), url)
  181. form = forms[-1]
  182. form.find_control('file_input').add_file(open(new_torrent), 'application/x-bittorrent', os.path.basename(new_torrent))
  183. if torrent['remastered']:
  184. form.find_control('remaster').set_single('1')
  185. form['remaster_year'] = str(torrent['remasterYear'])
  186. form['remaster_title'] = torrent['remasterTitle']
  187. form['remaster_record_label'] = torrent['remasterRecordLabel']
  188. form['remaster_catalogue_number'] = torrent['remasterCatalogueNumber']
  189.  
  190. form.find_control('format').set('1', formats[format]['format'])
  191. form.find_control('bitrate').set('1', formats[format]['encoding'])
  192. form.find_control('media').set('1', torrent['media'])
  193.  
  194. release_desc = '\n'.join(description)
  195. if release_desc:
  196. form['release_desc'] = release_desc
  197.  
  198. _, data, headers = form.click_request_data()
  199. return self.session.post(url, data=data, headers=dict(headers))
  200.  
  201. def set_24bit(self, torrent):
  202. url = "https://redacted.ch/torrents.php?action=edit&id=%s" % torrent['id']
  203. response = self.session.get(url)
  204. forms = mechanize.ParseFile(StringIO(response.text.encode('utf-8')), url)
  205. form = forms[-3]
  206. form.find_control('bitrate').set('1', '24bit Lossless')
  207. _, data, headers = form.click_request_data()
  208. return self.session.post(url, data=data, headers=dict(headers))
  209.  
  210. def release_url(self, group, torrent):
  211. return "https://redacted.ch/torrents.php?id=%s&torrentid=%s#torrent%s" % (group['group']['id'], torrent['id'], torrent['id'])
  212.  
  213. def permalink(self, torrent):
  214. return "https://redacted.ch/torrents.php?torrentid=%s" % torrent['id']
  215.  
  216. def get_better(self, search_type=3, tags=None):
  217. if tags is None:
  218. tags = []
  219. data = self.request('better', method='transcode', type=search_type, search=' '.join(tags))
  220. out = []
  221. for row in data:
  222. out.append({
  223. 'permalink': 'torrents.php?id={}'.format(row['torrentId']),
  224. 'id': row['torrentId'],
  225. 'torrent': row['downloadUrl'],
  226. })
  227. return out
  228.  
  229. def get_torrent(self, torrent_id):
  230. '''Downloads the torrent at torrent_id using the authkey and passkey'''
  231. while time.time() - self.last_request < self.rate_limit:
  232. time.sleep(0.1)
  233.  
  234. torrentpage = 'https://redacted.ch/torrents.php'
  235. params = {'action': 'download', 'id': torrent_id}
  236. if self.authkey:
  237. params['authkey'] = self.authkey
  238. params['torrent_pass'] = self.passkey
  239. r = self.session.get(torrentpage, params=params, allow_redirects=False)
  240.  
  241. self.last_request = time.time() + 2.0
  242. if r.status_code == 200 and 'application/x-bittorrent' in r.headers['content-type']:
  243. return r.content
  244. return None
  245.  
  246. def get_torrent_info(self, id):
  247. return self.request('torrent', id=id)['torrent']
  248.  
  249. def unescape(text):
  250. return HTMLParser.HTMLParser().unescape(text)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement