nzbToMedia/libs/custom/utorrent/client.py
Clinton Hall 5714540949
Fix uTorrent with Python3 (#1644)
* Remove temp workaround for Microsoft Azure python issues.
2019-08-02 13:02:46 +12:00

159 lines
4.8 KiB
Python

# coding=utf8
from __future__ import (
absolute_import,
division,
print_function,
unicode_literals,
)
import re
from six import StringIO, iteritems
from six.moves.http_cookiejar import CookieJar
from six.moves.urllib.request import (
HTTPBasicAuthHandler,
HTTPCookieProcessor,
Request,
build_opener,
install_opener,
)
from six.moves.urllib_parse import urlencode, urljoin
from .upload import MultiPartForm
try:
import json
except ImportError:
import simplejson as json
class UTorrentClient(object):
def __init__(self, base_url, username, password):
self.base_url = base_url
self.username = username
self.password = password
self.opener = self._make_opener('uTorrent', base_url, username, password)
self.token = self._get_token()
# TODO refresh token, when necessary
def _make_opener(self, realm, base_url, username, password):
"""HTTP Basic Auth and cookie support for token verification."""
auth_handler = HTTPBasicAuthHandler()
auth_handler.add_password(realm=realm,
uri=base_url,
user=username,
passwd=password)
opener = build_opener(auth_handler)
install_opener(opener)
cookie_jar = CookieJar()
cookie_handler = HTTPCookieProcessor(cookie_jar)
handlers = [auth_handler, cookie_handler]
opener = build_opener(*handlers)
return opener
def _get_token(self):
url = urljoin(self.base_url, 'token.html')
response = self.opener.open(url)
token_re = "<div id='token' style='display:none;'>([^<>]+)</div>"
match = re.search(token_re, str(response.read()))
return match.group(1)
def list(self, **kwargs):
params = [('list', '1')]
params += kwargs.items()
return self._action(params)
def start(self, *hashes):
params = [('action', 'start')]
for cur_hash in hashes:
params.append(('hash', cur_hash))
return self._action(params)
def stop(self, *hashes):
params = [('action', 'stop')]
for cur_hash in hashes:
params.append(('hash', cur_hash))
return self._action(params)
def pause(self, *hashes):
params = [('action', 'pause')]
for cur_hash in hashes:
params.append(('hash', cur_hash))
return self._action(params)
def forcestart(self, *hashes):
params = [('action', 'forcestart')]
for cur_hash in hashes:
params.append(('hash', cur_hash))
return self._action(params)
def getfiles(self, cur_hash):
params = [('action', 'getfiles'), ('hash', cur_hash)]
return self._action(params)
def getprops(self, cur_hash):
params = [('action', 'getprops'), ('hash', cur_hash)]
return self._action(params)
def setprops(self, cur_hash, **kvpairs):
params = [('action', 'setprops'), ('hash', cur_hash)]
for k, v in iteritems(kvpairs):
params.append(('s', k))
params.append(('v', v))
return self._action(params)
def setprio(self, cur_hash, priority, *files):
params = [('action', 'setprio'), ('hash', cur_hash), ('p', str(priority))]
for file_index in files:
params.append(('f', str(file_index)))
return self._action(params)
def addfile(self, filename, filepath=None, data=None):
params = [('action', 'add-file')]
form = MultiPartForm()
if filepath is not None:
file_handler = open(filepath, 'rb')
else:
file_handler = StringIO(data)
form.add_file('torrent_file', filename.encode('utf-8'), file_handler)
return self._action(params, str(form), form.get_content_type())
def addurl(self, url):
params = [('action', 'add-url'), ('s', url)]
self._action(params)
def remove(self, *hashes):
params = [('action', 'remove')]
for cur_hash in hashes:
params.append(('hash', cur_hash))
return self._action(params)
def removedata(self, *hashes):
params = [('action', 'removedata')]
for cur_hash in hashes:
params.append(('hash', cur_hash))
return self._action(params)
def _action(self, params, body=None, content_type=None):
# about token, see https://github.com/bittorrent/webui/wiki/TokenSystem
url = self.base_url + '?token=' + self.token + '&' + urlencode(params)
request = Request(url)
if body:
request.data = body
request.add_header('Content-length', len(body))
if content_type:
request.add_header('Content-type', content_type)
response = self.opener.open(request)
return response.code, json.loads(response.read())