diff --git a/couchpotato/core/downloaders/rtorrent/__init__.py b/couchpotato/core/downloaders/rtorrent/__init__.py
index 4a593fd2..f793cad1 100755
--- a/couchpotato/core/downloaders/rtorrent/__init__.py
+++ b/couchpotato/core/downloaders/rtorrent/__init__.py
@@ -31,8 +31,8 @@ config = [{
{
'name': 'host',
'default': 'localhost:80',
- 'description': 'Hostname with port or XML-RPC Endpoint URI. Usually scgi://localhost:5000 '
- 'or localhost:80'
+ 'description': 'RPC Communication URI. Usually scgi://localhost:5000, '
+ 'httprpc://localhost/rutorrent or localhost:80'
},
{
'name': 'ssl',
@@ -46,7 +46,7 @@ config = [{
'type': 'string',
'default': 'RPC2',
'advanced': True,
- 'description': 'Change if you don\'t run rTorrent RPC at the default url.',
+ 'description': 'Change if your RPC mount is at a different path.',
},
{
'name': 'username',
diff --git a/couchpotato/core/downloaders/rtorrent/main.py b/couchpotato/core/downloaders/rtorrent/main.py
index 1fbae354..b7b18b86 100755
--- a/couchpotato/core/downloaders/rtorrent/main.py
+++ b/couchpotato/core/downloaders/rtorrent/main.py
@@ -1,14 +1,15 @@
-from base64 import b16encode, b32decode
-from bencode import bencode, bdecode
from couchpotato.core.downloaders.base import Downloader, ReleaseDownloadList
from couchpotato.core.event import fireEvent, addEvent
from couchpotato.core.helpers.encoding import sp
from couchpotato.core.helpers.variable import cleanHost, splitString
from couchpotato.core.logger import CPLog
+from base64 import b16encode, b32decode
+from bencode import bencode, bdecode
from datetime import timedelta
from hashlib import sha1
from rtorrent import RTorrent
from rtorrent.err import MethodError
+from urlparse import urlparse
import os
log = CPLog(__name__)
@@ -51,7 +52,12 @@ class rTorrent(Downloader):
if self.rt is not None:
return self.rt
- url = cleanHost(self.conf('host'), protocol = True, ssl = self.conf('ssl')) + self.conf('rpc_url')
+ url = cleanHost(self.conf('host'), protocol = True, ssl = self.conf('ssl'))
+ parsed = urlparse(url)
+
+ # rpc_url is only used on http/https scgi pass-through
+ if parsed.scheme in ['http', 'https']:
+ url += self.conf('rpc_url')
if self.conf('username') and self.conf('password'):
self.rt = RTorrent(
diff --git a/libs/rtorrent/__init__.py b/libs/rtorrent/__init__.py
index 2c0f3fa9..4aec991e 100755
--- a/libs/rtorrent/__init__.py
+++ b/libs/rtorrent/__init__.py
@@ -22,8 +22,8 @@ import os.path
import time
import xmlrpclib
-from rtorrent.common import find_torrent, \
- is_valid_port, convert_version_tuple_to_str
+from rtorrent.common import find_torrent, join_uri, \
+ update_uri, is_valid_port, convert_version_tuple_to_str
from rtorrent.lib.torrentparser import TorrentParser
from rtorrent.lib.xmlrpc.http import HTTPServerProxy
from rtorrent.lib.xmlrpc.scgi import SCGIServerProxy
@@ -48,18 +48,18 @@ class RTorrent:
def __init__(self, uri, username=None, password=None,
verify=False, sp=None, sp_kwargs=None):
- self.uri = uri # : From X{__init__(self, url)}
+ self.uri = self._transform_uri(uri) # : From X{__init__(self, url)}
self.username = username
self.password = password
- self.schema = urllib.splittype(uri)[0]
+ self.scheme = urllib.splittype(self.uri)[0]
if sp:
self.sp = sp
- elif self.schema in ['http', 'https']:
+ elif self.scheme in ['http', 'https']:
self.sp = HTTPServerProxy
- elif self.schema == 'scgi':
+ elif self.scheme == 'scgi':
self.sp = SCGIServerProxy
else:
raise NotImplementedError()
@@ -74,10 +74,23 @@ class RTorrent:
if verify is True:
self._verify_conn()
+ def _transform_uri(self, uri):
+ scheme = urllib.splittype(uri)[0]
+
+ if scheme == 'httprpc' or scheme.startswith('httprpc+'):
+ # Try find HTTPRPC transport (token after '+' in 'httprpc+https'), otherwise assume HTTP
+ transport = scheme[scheme.index('+') + 1:] if '+' in scheme else 'http'
+
+ # Transform URI with new path and scheme
+ uri = join_uri(uri, 'plugins/httprpc/action.php', construct=False)
+ return update_uri(uri, scheme=transport)
+
+ return uri
+
def _get_conn(self):
"""Get ServerProxy instance"""
if self.username is not None and self.password is not None:
- if self.schema == 'scgi':
+ if self.scheme == 'scgi':
raise NotImplementedError()
return self.sp(
diff --git a/libs/rtorrent/common.py b/libs/rtorrent/common.py
index 371c71c3..668865b0 100755
--- a/libs/rtorrent/common.py
+++ b/libs/rtorrent/common.py
@@ -17,7 +17,8 @@
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
+import urlparse
+import os
from rtorrent.compat import is_py3
@@ -84,3 +85,67 @@ def safe_repr(fmt, *args, **kwargs):
return out.encode("utf-8")
else:
return fmt.format(*args, **kwargs)
+
+
+def split_path(path):
+ fragments = path.split('/')
+
+ if len(fragments) == 1:
+ return fragments
+
+ if not fragments[-1]:
+ return fragments[:-1]
+
+ return fragments
+
+
+def join_path(base, path):
+ # Return if we have a new absolute path
+ if os.path.isabs(path):
+ return path
+
+ # non-absolute base encountered
+ if base and not os.path.isabs(base):
+ raise NotImplementedError()
+
+ return '/'.join(split_path(base) + split_path(path))
+
+
+def join_uri(base, uri, construct=True):
+ p_uri = urlparse.urlparse(uri)
+
+ # Return if there is nothing to join
+ if not p_uri.path:
+ return base
+
+ scheme, netloc, path, params, query, fragment = urlparse.urlparse(base)
+
+ # Switch to 'uri' parts
+ _, _, _, params, query, fragment = p_uri
+
+ path = join_path(path, p_uri.path)
+
+ result = urlparse.ParseResult(scheme, netloc, path, params, query, fragment)
+
+ if not construct:
+ return result
+
+ # Construct from parts
+ return urlparse.urlunparse(result)
+
+
+def update_uri(uri, construct=True, **kwargs):
+ if isinstance(uri, urlparse.ParseResult):
+ uri = dict(uri._asdict())
+
+ if type(uri) is not dict:
+ raise ValueError("Unknown URI type")
+
+ uri.update(kwargs)
+
+ result = urlparse.ParseResult(**uri)
+
+ if not construct:
+ return result
+
+ return urlparse.urlunparse(result)