From 454db6fe6acb71c7a99407b9e47482a7209320c9 Mon Sep 17 00:00:00 2001 From: clinton-hall Date: Tue, 10 Jan 2017 08:25:55 +1030 Subject: [PATCH] update utorrent client. Fixes #1138 --- core/utorrent/client.py | 105 +++++++++++++++++++++------------------- core/utorrent/upload.py | 43 ++++++++-------- 2 files changed, 77 insertions(+), 71 deletions(-) diff --git a/core/utorrent/client.py b/core/utorrent/client.py index 02c29583..2d5a5741 100644 --- a/core/utorrent/client.py +++ b/core/utorrent/client.py @@ -1,50 +1,47 @@ # coding=utf8 - -import json +import urllib +import urllib2 +import urlparse +import cookielib import re +import StringIO +try: + import json +except ImportError: + import simplejson as json -from six import StringIO -from six.moves.http_cookiejar import CookieJar -from six.moves.urllib_error import HTTPError -from six.moves.urllib_parse import urljoin, urlencode -from six.moves.urllib_request import ( - build_opener, install_opener, - HTTPBasicAuthHandler, HTTPCookieProcessor, - Request, -) - -from core.utorrent.upload import MultiPartForm - +from upload import MultiPartForm 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 + #TODO refresh token, when necessary def _make_opener(self, realm, base_url, username, password): - """uTorrent API need HTTP Basic Auth and cookie support for token verify.""" + '''uTorrent API need HTTP Basic Auth and cookie support for token verify.''' - auth_handler = HTTPBasicAuthHandler() + auth_handler = urllib2.HTTPBasicAuthHandler() auth_handler.add_password(realm=realm, uri=base_url, user=username, passwd=password) - opener = build_opener(auth_handler) - install_opener(opener) + opener = urllib2.build_opener(auth_handler) + urllib2.install_opener(opener) - cookie_jar = CookieJar() - cookie_handler = HTTPCookieProcessor(cookie_jar) + cookie_jar = cookielib.CookieJar() + cookie_handler = urllib2.HTTPCookieProcessor(cookie_jar) handlers = [auth_handler, cookie_handler] - opener = build_opener(*handlers) + opener = urllib2.build_opener(*handlers) return opener def _get_token(self): - url = urljoin(self.base_url, 'token.html') + url = urlparse.urljoin(self.base_url, 'token.html') response = self.opener.open(url) token_re = "" match = re.search(token_re, response.read()) @@ -56,43 +53,25 @@ class UTorrentClient(object): return self._action(params) def start(self, *hashes): - params = [('action', 'start'), ] + params = [('action', 'start'),] for hash in hashes: params.append(('hash', hash)) return self._action(params) def stop(self, *hashes): - params = [('action', 'stop'), ] + params = [('action', 'stop'),] for hash in hashes: params.append(('hash', hash)) return self._action(params) def pause(self, *hashes): - params = [('action', 'pause'), ] + params = [('action', 'pause'),] for hash in hashes: params.append(('hash', hash)) return self._action(params) def forcestart(self, *hashes): - params = [('action', 'forcestart'), ] - for hash in hashes: - params.append(('hash', hash)) - return self._action(params) - - def remove(self, *hashes): - params = [('action', 'remove'), ] - for hash in hashes: - params.append(('hash', hash)) - return self._action(params) - - def removedata(self, *hashes): - params = [('action', 'removedata'), ] - for hash in hashes: - params.append(('hash', hash)) - return self._action(params) - - def recheck(self, *hashes): - params = [('action', 'recheck'), ] + params = [('action', 'forcestart'),] for hash in hashes: params.append(('hash', hash)) return self._action(params) @@ -105,6 +84,14 @@ class UTorrentClient(object): params = [('action', 'getprops'), ('hash', hash)] return self._action(params) + def setprops(self, hash, **kvpairs): + params = [('action', 'setprops'), ('hash', hash)] + for k, v in kvpairs.iteritems(): + params.append( ("s", k) ) + params.append( ("v", v) ) + + return self._action(params) + def setprio(self, hash, priority, *files): params = [('action', 'setprio'), ('hash', hash), ('p', str(priority))] for file_index in files: @@ -117,7 +104,7 @@ class UTorrentClient(object): form = MultiPartForm() if filepath is not None: - file_handler = open(filepath) + file_handler = open(filepath,'rb') else: file_handler = StringIO.StringIO(bytes) @@ -125,10 +112,26 @@ class UTorrentClient(object): 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 hash in hashes: + params.append(('hash', hash)) + return self._action(params) + + def removedata(self, *hashes): + params = [('action', 'removedata'),] + for hash in hashes: + params.append(('hash', 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 = '{url}?token={token}&{params}'.format(url=self.url, token=self.token, params=urlencode(params)) - request = Request(url) + #about token, see https://github.com/bittorrent/webui/wiki/TokenSystem + url = self.base_url + '?token=' + self.token + '&' + urllib.urlencode(params) + request = urllib2.Request(url) if body: request.add_data(body) @@ -139,5 +142,5 @@ class UTorrentClient(object): try: response = self.opener.open(request) return response.code, json.loads(response.read()) - except HTTPError: - raise + except urllib2.HTTPError,e: + raise \ No newline at end of file diff --git a/core/utorrent/upload.py b/core/utorrent/upload.py index 948e5491..8b502532 100644 --- a/core/utorrent/upload.py +++ b/core/utorrent/upload.py @@ -1,10 +1,12 @@ # coding=utf-8 # code copied from http://www.doughellmann.com/PyMOTW/urllib2/ -from email.generator import _make_boundary as make_boundary import itertools +import mimetools import mimetypes - +from cStringIO import StringIO +import urllib +import urllib2 class MultiPartForm(object): """Accumulate the data to be used when posting a form.""" @@ -12,11 +14,11 @@ class MultiPartForm(object): def __init__(self): self.form_fields = [] self.files = [] - self.boundary = make_boundary() + self.boundary = mimetools.choose_boundary() return def get_content_type(self): - return 'multipart/form-data; boundary={0}'.format(self.boundary) + return 'multipart/form-data; boundary=%s' % self.boundary def add_field(self, name, value): """Add a simple field to the form data.""" @@ -38,32 +40,33 @@ class MultiPartForm(object): # Once the list is built, return a string where each # line is separated by '\r\n'. parts = [] - part_boundary = '--{boundary}'.format(boundary=self.boundary) + part_boundary = '--' + self.boundary # Add the form fields parts.extend( - [part_boundary, - 'Content-Disposition: form-data; name="{0}"'.format(name), - '', - value, - ] + [ part_boundary, + 'Content-Disposition: form-data; name="%s"' % name, + '', + value, + ] for name, value in self.form_fields - ) + ) # Add the files to upload parts.extend( - [part_boundary, - 'Content-Disposition: file; name="{0}"; filename="{1}"'.format(field_name, filename), - 'Content-Type: {0}'.format(content_type), - '', - body, - ] + [ part_boundary, + 'Content-Disposition: file; name="%s"; filename="%s"' % \ + (field_name, filename), + 'Content-Type: %s' % content_type, + '', + body, + ] for field_name, filename, content_type, body in self.files - ) + ) # Flatten the list and add closing boundary marker, # then return CR+LF separated data flattened = list(itertools.chain(*parts)) - flattened.append('--{boundary}--'.format(boundary=self.boundary)) + flattened.append('--' + self.boundary + '--') flattened.append('') - return '\r\n'.join(flattened) + return '\r\n'.join(flattened) \ No newline at end of file