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 12aba510..8e21e7fc 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 from scandir import scandir @@ -52,7 +53,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( @@ -169,6 +175,21 @@ class rTorrent(Downloader): log.error('Failed to send torrent to rTorrent: %s', err) return False + def getTorrentStatus(self, torrent): + if torrent.hashing or torrent.hash_checking or torrent.message: + return 'busy' + + if not torrent.complete: + return 'busy' + + if not torrent.open: + return 'completed' + + if torrent.state and torrent.active: + return 'seeding' + + return 'busy' + def getAllDownloadStatus(self, ids): log.debug('Checking rTorrent download status.') @@ -193,17 +214,10 @@ class rTorrent(Downloader): torrent_files.append(sp(file_path)) - status = 'busy' - if torrent.complete: - if torrent.active: - status = 'seeding' - else: - status = 'completed' - release_downloads.append({ 'id': torrent.info_hash, 'name': torrent.name, - 'status': status, + 'status': self.getTorrentStatus(torrent), 'seed_ratio': torrent.ratio, 'original_status': torrent.state, 'timeleft': str(timedelta(seconds = float(torrent.left_bytes) / torrent.down_rate)) if torrent.down_rate > 0 else -1, diff --git a/couchpotato/core/notifications/pushbullet/main.py b/couchpotato/core/notifications/pushbullet/main.py index 15120f0b..487fb3aa 100644 --- a/couchpotato/core/notifications/pushbullet/main.py +++ b/couchpotato/core/notifications/pushbullet/main.py @@ -1,5 +1,5 @@ from couchpotato.core.helpers.encoding import toUnicode -from couchpotato.core.helpers.variable import tryInt +from couchpotato.core.helpers.variable import splitString from couchpotato.core.logger import CPLog from couchpotato.core.notifications.base import Notification import base64 @@ -32,7 +32,7 @@ class Pushbullet(Notification): response = self.request( 'pushes', cache = False, - device_id = device, + device_iden = device, type = 'note', title = self.default_title, body = toUnicode(message) @@ -46,24 +46,7 @@ class Pushbullet(Notification): return successful == len(devices) def getDevices(self): - devices = [d.strip() for d in self.conf('devices').split(',')] - - # Remove empty items - devices = [d for d in devices if len(d)] - - # Break on any ids that aren't integers - valid_devices = [] - - for device_id in devices: - d = tryInt(device_id, None) - - if not d: - log.error('Device ID "%s" is not valid', device_id) - return None - - valid_devices.append(d) - - return valid_devices + return splitString(self.conf('devices')) def request(self, method, cache = True, **kwargs): try: diff --git a/couchpotato/core/providers/torrent/passthepopcorn/main.py b/couchpotato/core/providers/torrent/passthepopcorn/main.py index 21bfa72e..bc6136fc 100644 --- a/couchpotato/core/providers/torrent/passthepopcorn/main.py +++ b/couchpotato/core/providers/torrent/passthepopcorn/main.py @@ -89,11 +89,11 @@ class PassThePopcorn(TorrentProvider): if 'GoldenPopcorn' in torrent and torrent['GoldenPopcorn']: torrentdesc += ' HQ' if self.conf('prefer_golden'): - torrentscore += 200 + torrentscore += 5000 if 'Scene' in torrent and torrent['Scene']: torrentdesc += ' Scene' if self.conf('prefer_scene'): - torrentscore += 50 + torrentscore += 2000 if 'RemasterTitle' in torrent and torrent['RemasterTitle']: torrentdesc += self.htmlToASCII(' %s' % torrent['RemasterTitle']) diff --git a/couchpotato/core/providers/torrent/sceneaccess/main.py b/couchpotato/core/providers/torrent/sceneaccess/main.py index dcf0b351..8db1b4ef 100644 --- a/couchpotato/core/providers/torrent/sceneaccess/main.py +++ b/couchpotato/core/providers/torrent/sceneaccess/main.py @@ -40,7 +40,7 @@ class SceneAccess(TorrentProvider): arguments = tryUrlencode({ 'search': movie['identifier'], - 'method': 1, + 'method': 3, }) url = "%s&%s" % (url, arguments) diff --git a/couchpotato/core/providers/torrent/yify/main.py b/couchpotato/core/providers/torrent/yify/main.py index 00d67eb0..080e6e36 100644 --- a/couchpotato/core/providers/torrent/yify/main.py +++ b/couchpotato/core/providers/torrent/yify/main.py @@ -18,9 +18,9 @@ class Yify(TorrentMagnetProvider): proxy_list = [ 'http://yify.unlocktorrent.com', - 'http://yify.ftwnet.co.uk', 'http://yify-torrents.com.come.in', 'http://yts.re', + 'http://yts.im' 'https://yify-torrents.im', ] 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)