diff --git a/couchpotato/core/_base/updater/main.py b/couchpotato/core/_base/updater/main.py index 0ad60c0..ae9f037 100644 --- a/couchpotato/core/_base/updater/main.py +++ b/couchpotato/core/_base/updater/main.py @@ -98,7 +98,7 @@ class Updater(Plugin): if self.conf('notification'): info = self.updater.info() version_date = datetime.fromtimestamp(info['update_version']['date']) - fireEvent('updater.updated', 'Updated to a new version with hash "%s", this version is from %s' % (info['update_version']['hash'], version_date), data = info) + fireEvent('updater.updated', 'CouchPotato: Updated to a new version with hash "%s", this version is from %s' % (info['update_version']['hash'], version_date), data = info) except: log.error('Failed notifying for update: %s', traceback.format_exc()) diff --git a/couchpotato/core/downloaders/hadouken.py b/couchpotato/core/downloaders/hadouken.py index b2057d5..f96a374 100644 --- a/couchpotato/core/downloaders/hadouken.py +++ b/couchpotato/core/downloaders/hadouken.py @@ -371,29 +371,29 @@ class TorrentItemv5(TorrentItem): self.obj = obj def info_hash(self): - return self.obj['infoHash'] + return self.obj[0] def save_path(self): - return self.obj['savePath'] + return self.obj[26] def name(self): - return self.obj['name'] + return self.obj[2] def state(self): - return self.obj['state'] + return self.obj[1] def get_status(self): - if self.obj['isSeeding'] and self.obj['isFinished'] and self.obj['isPaused']: + if self.obj[1] == 32: return 'completed' - if self.obj['isSeeding']: + if self.obj[1] == 1: return 'seeding' return 'busy' def get_seed_ratio(self): - up = self.obj['uploadedBytesTotal'] - down = self.obj['downloadedBytesTotal'] + up = self.obj[6] + down = self.obj[5] if up > 0 and down > 0: return up / down @@ -402,28 +402,29 @@ class TorrentItemv5(TorrentItem): class HadoukenAPIv5(HadoukenAPI): + def add_file(self, data, params): - return self.rpc.invoke('session.addTorrentFile', [b64encode(data), params]) + return self.rpc.invoke('webui.addTorrent', ['file', b64encode(data), params]) def add_magnet_link(self, link, params): - return self.rpc.invoke('session.addTorrentUri', [link, params]) + return self.rpc.invoke('webui.addTorrent', ['url', link, params]) def get_by_hash_list(self, infoHashList): - torrents = self.rpc.invoke('session.getTorrents') + torrents = self.rpc.invoke('webui.list', None) result = [] - for torrent in torrents.values(): - if torrent['infoHash'] in infoHashList: + for torrent in torrents['torrents']: + if torrent[0] in infoHashList: result.append(TorrentItemv5(torrent)) return result def get_files_by_hash(self, infoHash): - files = self.rpc.invoke('torrent.getFiles', [infoHash]) + files = self.rpc.invoke('webui.getFiles', [infoHash]) result = [] - for file in files: - result.append(file['path']) + for file in files['files'][1]: + result.append(file[0]) return result @@ -437,12 +438,15 @@ class HadoukenAPIv5(HadoukenAPI): def pause(self, infoHash, pause): if pause: - return self.rpc.invoke('torrent.pause', [infoHash]) + return self.rpc.invoke('webui.perform', ['pause', infoHash]) - return self.rpc.invoke('torrent.resume', [infoHash]) + return self.rpc.invoke('webui.perform', ['resume', infoHash]) - def remove(self, infoHash, remove_data = False): - return self.rpc.invoke('session.removeTorrent', [infoHash, remove_data]) + def remove(self, infoHash, remove_data=False): + if remove_data: + return self.rpc.invoke('webui.perform', ['removedata', infoHash]) + + return self.rpc.invoke('webui.perform', ['remove', infoHash]) class TorrentItemv4(TorrentItem): diff --git a/couchpotato/core/downloaders/rtorrent_.py b/couchpotato/core/downloaders/rtorrent_.py index a9e8e6a..4902cff 100644 --- a/couchpotato/core/downloaders/rtorrent_.py +++ b/couchpotato/core/downloaders/rtorrent_.py @@ -3,6 +3,7 @@ from datetime import timedelta from hashlib import sha1 from urlparse import urlparse import os +import re from couchpotato.core._base.downloader.main import DownloaderBase, ReleaseDownloadList from couchpotato.core.event import addEvent @@ -146,6 +147,7 @@ class rTorrent(DownloaderBase): if not self.connect(): return False + torrent_hash = 0 torrent_params = {} if self.conf('label'): torrent_params['label'] = self.conf('label') @@ -156,29 +158,42 @@ class rTorrent(DownloaderBase): # Try download magnet torrents if data.get('protocol') == 'torrent_magnet': - filedata = self.magnetToTorrent(data.get('url')) - - if filedata is False: + # Send magnet to rTorrent + torrent_hash = re.findall('urn:btih:([\w]{32,40})', data.get('url'))[0].upper() + # Send request to rTorrent + try: + torrent = self.rt.load_magnet(data.get('url'), torrent_hash) + + if not torrent: + log.error('Unable to find the torrent, did it fail to load?') + return False + + except Exception as err: + log.error('Failed to send magnet to rTorrent: %s', err) return False - data['protocol'] = 'torrent' + if data.get('protocol') == 'torrent': + info = bdecode(filedata)["info"] + torrent_hash = sha1(bencode(info)).hexdigest().upper() - info = bdecode(filedata)["info"] - torrent_hash = sha1(bencode(info)).hexdigest().upper() + # Convert base 32 to hex + if len(torrent_hash) == 32: + torrent_hash = b16encode(b32decode(torrent_hash)) - # Convert base 32 to hex - if len(torrent_hash) == 32: - torrent_hash = b16encode(b32decode(torrent_hash)) + # Send request to rTorrent + try: + # Send torrent to rTorrent + torrent = self.rt.load_torrent(filedata, verify_retries=10) - # Send request to rTorrent - try: - # Send torrent to rTorrent - torrent = self.rt.load_torrent(filedata, verify_retries=10) + if not torrent: + log.error('Unable to find the torrent, did it fail to load?') + return False - if not torrent: - log.error('Unable to find the torrent, did it fail to load?') + except Exception as err: + log.error('Failed to send torrent to rTorrent: %s', err) return False + try: # Set label if self.conf('label'): torrent.set_custom(1, self.conf('label')) @@ -191,10 +206,12 @@ class rTorrent(DownloaderBase): torrent.start() return self.downloadReturnId(torrent_hash) + except Exception as err: log.error('Failed to send torrent to rTorrent: %s', err) return False + def getTorrentStatus(self, torrent): if not torrent.complete: return 'busy' diff --git a/couchpotato/core/downloaders/sabnzbd.py b/couchpotato/core/downloaders/sabnzbd.py index c9bb7cc..0f82618 100644 --- a/couchpotato/core/downloaders/sabnzbd.py +++ b/couchpotato/core/downloaders/sabnzbd.py @@ -95,7 +95,7 @@ class Sabnzbd(DownloaderBase): 'mode': 'version', }) v = sab_data.split('.') - if int(v[0]) == 0 and int(v[1]) < 7: + if sab_data != 'develop' and int(v[0]) == 0 and int(v[1]) < 7: return False, 'Your Sabnzbd client is too old, please update to newest version.' # the version check will work even with wrong api key, so we need the next check as well diff --git a/couchpotato/core/downloaders/transmission.py b/couchpotato/core/downloaders/transmission.py index 78f8fd7..f40b955 100644 --- a/couchpotato/core/downloaders/transmission.py +++ b/couchpotato/core/downloaders/transmission.py @@ -67,7 +67,8 @@ class Transmission(DownloaderBase): } if self.conf('directory'): - if os.path.isdir(self.conf('directory')): + host = cleanHost(self.conf('host')).rstrip('/').rsplit(':', 1) + if os.path.isdir(self.conf('directory')) or not (host[0] == '127.0.0.1' or host[0] == 'localhost'): params['download-dir'] = self.conf('directory').rstrip(os.path.sep) else: log.error('Download directory from Transmission settings: %s doesn\'t exist', self.conf('directory')) diff --git a/couchpotato/core/media/_base/providers/nzb/omgwtfnzbs.py b/couchpotato/core/media/_base/providers/nzb/omgwtfnzbs.py index e87d783..6d4d0a2 100644 --- a/couchpotato/core/media/_base/providers/nzb/omgwtfnzbs.py +++ b/couchpotato/core/media/_base/providers/nzb/omgwtfnzbs.py @@ -12,7 +12,7 @@ log = CPLog(__name__) class Base(NZBProvider, RSS): urls = { - 'search': 'https://api.omgwtfnzbs.org/json/?%s', + 'search': 'https://api.omgwtfnzbs.me/json/?%s', } http_time_between_calls = 1 # Seconds @@ -61,7 +61,7 @@ config = [{ 'tab': 'searcher', 'list': 'nzb_providers', 'name': 'OMGWTFNZBs', - 'description': 'See OMGWTFNZBs', + 'description': 'See OMGWTFNZBs', 'wizard': True, 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQEAIAAADAAbR1AAADbElEQVR4AZ2UW0ybZRiAy/OvdHaLYvB0YTRIFi7GkM44zRLmIfNixkWdiRMyYoxRE8/TC7MYvXCGEBmr3mxLwVMwY0wYA7e6Wso4lB6h/U9taSlMGIfBXLYlJMyo0S///2dJI5lxN8/F2/f9nu9737e/jYmXr6KTbN9BGG9HE/NotQ76UWziNzrXFiETk/5ARUNH+7+0kW7fSgTl0VKGOLZzidOkmuuIo7q2oTArNLPIzhdIkqXkerFOm2CaD/5bcKrjIL2c3fkhPxOq93Kcb91v46fV9TQKF4TgV/TbUsQtzfCaK6jMOd5DJrguSIIhexmqqVxN0FXbRR8/ND/LYTTj6J7nl2gnL47OkDW4KJhnQHCa6JpKVNJGA3OC58nwBJoZ//ebbIyKpBxjrr0o1q1FMRkrKXZnHWF85VvxMrJxibwhGyd0f5bLnKzqJs1k0Sfo+EU8hdAUvkbcwKEgs2D0OiV4jmmD1zb+Tp6er0JMMvDxPo5xev9zTBF683NS+N56n1YiB95B5crr93KRuKhKI0tb0Kw2mgLLqTjLEWO8424i9IvURaYeOckwf3+/yCC9e3bQQ/MuD+Monk0k+XFXMUfx7z5EEP+XlXi5tLlMxH8zLppw7idJrugcus30kC86gc7UrQqjLIukM8zWHOACeU+TiMxXN6ExVOkgz4lvPEzice1GIVhxhG4CrZvpl6TH55giKWqXGLy9hZh5aUtgDSew/msSyCKpl+DDNfxJc8NBIsxUxUnz14O/oONu+IIIvso9TLBQ1SY5rUhuSzUhAqJ2mRXBLDOCeUtgUZXsaObT8BffhUJPqWgiV+3zKKzYH0ClvTRLhD77HIqVkyh5jThnivehoG+qJctIRSPn6bxvO4FCgTl9c1DmbpjLajbQFE8aW5SU3rg+zOPGUjTUF9NFpLEbH2c/KmGYlY69/GQJVtGMSUcEp9eCbB1nctbxHTLRdTUkGDf+B02uGWRG3OvpJ/zSMwzif+oxVBID3cQKBavLCiPmB2PM2UuSCUPgrX4VDb97AwEG67bh4+KTOlncvu3M31BwA5rLHbCfEjwkNDky9e/SSbSxnD46Pg0RJtpXRvhmBSZHpRjWtKwFybjuQeXaKxto4WjLZZZvVmC17pZLJFkwxm5++PS2Mrwc7nyIMYZe/IzoP5d6QgEybqTXAAAAAElFTkSuQmCC', 'options': [ diff --git a/couchpotato/core/media/_base/providers/torrent/iptorrents.py b/couchpotato/core/media/_base/providers/torrent/iptorrents.py index b25e29b..1197838 100644 --- a/couchpotato/core/media/_base/providers/torrent/iptorrents.py +++ b/couchpotato/core/media/_base/providers/torrent/iptorrents.py @@ -16,9 +16,9 @@ class Base(TorrentProvider): urls = { 'test': 'https://iptorrents.eu/', 'base_url': 'https://iptorrents.eu', - 'login': 'https://iptorrents.eu/', + 'login': 'https://iptorrents.eu/take_login.php', 'login_check': 'https://iptorrents.eu/oldinbox.php', - 'search': 'https://iptorrents.eu/t?%s%%s&q=%s&qf=#torrents&p=%%d', + 'search': 'https://iptorrents.eu/t?%s%%s&q=%s&qf=ti#torrents&p=%%d', } http_time_between_calls = 1 # Seconds @@ -36,7 +36,7 @@ class Base(TorrentProvider): log.warning('Unable to find category ids for identifier "%s"', quality.get('identifier')) return None - return self.urls['search'] % ("&".join(("l%d=" % x) for x in cat_ids), tryUrlencode(query).replace('%', '%%')) + return self.urls['search'] % ("&".join(("%d=" % x) for x in cat_ids), tryUrlencode(query).replace('%', '%%')) def _searchOnTitle(self, title, media, quality, results): diff --git a/couchpotato/core/media/_base/providers/torrent/passthepopcorn.py b/couchpotato/core/media/_base/providers/torrent/passthepopcorn.py index ee01836..d4db814 100644 --- a/couchpotato/core/media/_base/providers/torrent/passthepopcorn.py +++ b/couchpotato/core/media/_base/providers/torrent/passthepopcorn.py @@ -204,7 +204,7 @@ config = [{ 'tab': 'searcher', 'list': 'torrent_providers', 'name': 'PassThePopcorn', - 'description': 'PassThePopcorn.me', + 'description': 'PassThePopcorn.me', 'wizard': True, 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAARklEQVQoz2NgIAP8BwMiGWRpIN1JNWn/t6T9f5' '32+W8GkNt7vzz9UkfarZVpb68BuWlbnqW1nU7L2DMx7eCoBlpqGOppCQB83zIgIg+wWQAAAABJRU5ErkJggg==', diff --git a/couchpotato/core/media/movie/providers/torrent/iptorrents.py b/couchpotato/core/media/movie/providers/torrent/iptorrents.py index 84a52f5..68365b8 100644 --- a/couchpotato/core/media/movie/providers/torrent/iptorrents.py +++ b/couchpotato/core/media/movie/providers/torrent/iptorrents.py @@ -11,10 +11,12 @@ class IPTorrents(MovieProvider, Base): cat_ids = [ ([87], ['3d']), - ([48], ['720p', '1080p', 'bd50']), - ([72], ['cam', 'ts', 'tc', 'r5', 'scr']), - ([7, 48, 20], ['dvdrip', 'brrip']), - ([6], ['dvdr']), + ([48], ['720p', '1080p']), + ([89], ['bd50']), + ([96], ['cam', 'ts', 'tc', 'r5', 'scr']), + ([48, 20, 90], ['brrip']), + ([7, 77], ['dvdrip']), + ([6], ['dvdr']) ] def buildUrl(self, title, media, quality): diff --git a/couchpotato/core/notifications/boxcar2.py b/couchpotato/core/notifications/boxcar2.py index 04ce4f3..c6f49e6 100644 --- a/couchpotato/core/notifications/boxcar2.py +++ b/couchpotato/core/notifications/boxcar2.py @@ -10,6 +10,7 @@ autoload = 'Boxcar2' class Boxcar2(Notification): url = 'https://new.boxcar.io/api/notifications' + LOGO_URL = 'https://raw.githubusercontent.com/CouchPotato/CouchPotatoServer/master/couchpotato/static/images/notify.couch.small.png' def notify(self, message = '', data = None, listener = None): if not data: data = {} @@ -27,6 +28,8 @@ class Boxcar2(Notification): 'user_credentials': self.conf('token'), 'notification[title]': toUnicode('%s - %s' % (self.default_title, message)), 'notification[long_message]': toUnicode(long_message), + 'notification[icon_url]': self.LOGO_URL, + 'notification[source_name]': 'CouchPotato', } self.urlopen(self.url, data = data) diff --git a/couchpotato/core/plugins/quality/main.py b/couchpotato/core/plugins/quality/main.py index 8bdd383..f2cd100 100644 --- a/couchpotato/core/plugins/quality/main.py +++ b/couchpotato/core/plugins/quality/main.py @@ -27,7 +27,7 @@ class QualityPlugin(Plugin): {'identifier': 'bd50', 'hd': True, 'allow_3d': True, 'size': (20000, 60000), 'median_size': 40000, 'label': 'BR-Disk', 'alternative': ['bd25', ('br', 'disk')], 'allow': ['1080p'], 'ext':['iso', 'img'], 'tags': ['bdmv', 'certificate', ('complete', 'bluray'), 'avc', 'mvc']}, {'identifier': '1080p', 'hd': True, 'allow_3d': True, 'size': (4000, 20000), 'median_size': 10000, 'label': '1080p', 'width': 1920, 'height': 1080, 'alternative': [], 'allow': [], 'ext':['mkv', 'm2ts', 'ts'], 'tags': ['m2ts', 'x264', 'h264', '1080']}, {'identifier': '720p', 'hd': True, 'allow_3d': True, 'size': (3000, 10000), 'median_size': 5500, 'label': '720p', 'width': 1280, 'height': 720, 'alternative': [], 'allow': [], 'ext':['mkv', 'ts'], 'tags': ['x264', 'h264', '720']}, - {'identifier': 'brrip', 'hd': True, 'allow_3d': True, 'size': (700, 7000), 'median_size': 2000, 'label': 'BR-Rip', 'alternative': ['bdrip', ('br', 'rip'), 'hdtv', 'hdrip'], 'allow': ['720p', '1080p'], 'ext':['mp4', 'avi'], 'tags': ['webdl', ('web', 'dl')]}, + {'identifier': 'brrip', 'hd': True, 'allow_3d': True, 'size': (700, 7000), 'median_size': 2000, 'label': 'BR-Rip', 'alternative': ['bdrip', ('br', 'rip'), 'hdtv', 'hdrip'], 'allow': ['720p', '1080p', '2160p'], 'ext':['mp4', 'avi'], 'tags': ['webdl', ('web', 'dl')]}, {'identifier': 'dvdr', 'size': (3000, 10000), 'median_size': 4500, 'label': 'DVD-R', 'alternative': ['br2dvd', ('dvd', 'r')], 'allow': [], 'ext':['iso', 'img', 'vob'], 'tags': ['pal', 'ntsc', 'video_ts', 'audio_ts', ('dvd', 'r'), 'dvd9']}, {'identifier': 'dvdrip', 'size': (600, 2400), 'median_size': 1500, 'label': 'DVD-Rip', 'width': 720, 'alternative': [('dvd', 'rip')], 'allow': [], 'ext':['avi'], 'tags': [('dvd', 'rip'), ('dvd', 'xvid'), ('dvd', 'divx')]}, {'identifier': 'scr', 'size': (600, 1600), 'median_size': 700, 'label': 'Screener', 'alternative': ['screener', 'dvdscr', 'ppvrip', 'dvdscreener', 'hdscr', 'webrip', ('web', 'rip')], 'allow': ['dvdr', 'dvdrip', '720p', '1080p'], 'ext':[], 'tags': []}, diff --git a/libs/rtorrent/__init__.py b/libs/rtorrent/__init__.py old mode 100755 new mode 100644 index f283d92..0d64e81 --- a/libs/rtorrent/__init__.py +++ b/libs/rtorrent/__init__.py @@ -129,6 +129,42 @@ class RTorrent: return(func_name) + def load_magnet(self, magneturl, info_hash, start=False, verbose=False, verify_load=True, verify_retries=3): + + p = self._get_conn() + + info_hash = info_hash.upper() + + func_name = self._get_load_function("url", start, verbose) + + # load magnet + getattr(p, func_name)(magneturl) + + if verify_load: + i = 0 + while i < verify_retries: + for torrent in self.get_torrents(): + if torrent.info_hash != info_hash: + continue + time.sleep(1) + i += 1 + + # Resolve magnet to torrent + torrent.start() + + assert info_hash in [t.info_hash for t in self.torrents],\ + "Adding magnet was unsuccessful." + + i = 0 + while i < verify_retries: + for torrent in self.get_torrents(): + if torrent.info_hash == info_hash: + if str(info_hash) not in str(torrent.name): + time.sleep(1) + i += 1 + + return(torrent) + def load_torrent(self, torrent, start=False, verbose=False, verify_load=True, verify_retries=3): """ Loads torrent into rTorrent (with various enhancements)