From faefd7a5b5cd6cb760eacc9a5595ccab91bb64de Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 23 Sep 2014 16:54:24 +0200 Subject: [PATCH 1/6] Traks notifier always enabled --- couchpotato/core/notifications/trakt.py | 1 + 1 file changed, 1 insertion(+) diff --git a/couchpotato/core/notifications/trakt.py b/couchpotato/core/notifications/trakt.py index fe170be8..91c6ae16 100644 --- a/couchpotato/core/notifications/trakt.py +++ b/couchpotato/core/notifications/trakt.py @@ -17,6 +17,7 @@ class Trakt(Notification): } listen_to = ['movie.snatched'] + enabled_option = 'notification_enabled' def notify(self, message = '', data = None, listener = None): if not data: data = {} From f6d4ddbe80601aee894a7fc0e195fc581ee2e4f6 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 23 Sep 2014 17:40:21 +0200 Subject: [PATCH 2/6] NZBVortex, create unique ID --- couchpotato/core/downloaders/nzbvortex.py | 27 ++++++++++++++--------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/couchpotato/core/downloaders/nzbvortex.py b/couchpotato/core/downloaders/nzbvortex.py index 9094055f..af95628d 100644 --- a/couchpotato/core/downloaders/nzbvortex.py +++ b/couchpotato/core/downloaders/nzbvortex.py @@ -1,4 +1,5 @@ from base64 import b64encode +import re from urllib2 import URLError from uuid import uuid4 import hashlib @@ -14,7 +15,7 @@ import urllib2 from couchpotato.core._base.downloader.main import DownloaderBase, ReleaseDownloadList from couchpotato.core.helpers.encoding import tryUrlencode, sp -from couchpotato.core.helpers.variable import cleanHost +from couchpotato.core.helpers.variable import cleanHost, randomString from couchpotato.core.logger import CPLog @@ -35,13 +36,17 @@ class NZBVortex(DownloaderBase): # Send the nzb try: + nzb_id = '%s-%s' % (self.cpTag(media), randomString()) nzb_filename = self.createFileName(data, filedata, media) - self.call('nzb/add', files = {'file': (nzb_filename, filedata)}) + nzb_filename = re.sub('(.cp\(tt[0-9{7}]+\))', '', nzb_filename) + nzb_filename = '%s%s.nzb' % (nzb_filename[0:-4], nzb_id) + response = self.call('nzb/add', files = {'file': (nzb_filename, filedata, 'application/octet-stream')}) - time.sleep(10) - raw_statuses = self.call('nzb') - nzb_id = [nzb['id'] for nzb in raw_statuses.get('nzbs', []) if os.path.basename(nzb['nzbFileName']) == nzb_filename][0] - return self.downloadReturnId(nzb_id) + if response and response.get('result', '').lower() == 'ok': + return self.downloadReturnId(nzb_id) + + log.error('Something went wrong sending the NZB file. Response: %s', response) + return False except: log.error('Something went wrong sending the NZB file: %s', traceback.format_exc()) return False @@ -114,7 +119,7 @@ class NZBVortex(DownloaderBase): log.error('Login failed, please check you api-key') return False - def call(self, call, parameters = None, repeat = False, auth = True, *args, **kwargs): + def call(self, call, parameters = None, is_repeat = False, auth = True, *args, **kwargs): # Login first if not parameters: parameters = {} @@ -130,16 +135,16 @@ class NZBVortex(DownloaderBase): url = cleanHost(self.conf('host'), ssl = self.conf('ssl')) + 'api/' + call try: - data = self.urlopen('%s?%s' % (url, params), *args, **kwargs) + data = self.getJsonData('%s?%s' % (url, params), *args, **kwargs) if data: - return json.loads(data) + return data except URLError as e: if hasattr(e, 'code') and e.code == 403: # Try login and do again - if not repeat: + if not is_repeat: self.login() - return self.call(call, parameters = parameters, repeat = True, **kwargs) + return self.call(call, parameters = parameters, is_repeat = True, **kwargs) log.error('Failed to parsing %s: %s', (self.getName(), traceback.format_exc())) except: From 7cb214d8a2dcf31bef04f6c47bcf5c659c8e6c5e Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 23 Sep 2014 20:33:26 +0200 Subject: [PATCH 3/6] Don't force send host with every request --- couchpotato/core/plugins/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/base.py b/couchpotato/core/plugins/base.py index 5054b325..3c655bc0 100644 --- a/couchpotato/core/plugins/base.py +++ b/couchpotato/core/plugins/base.py @@ -192,7 +192,7 @@ class Plugin(object): host = '%s%s' % (parsed_url.hostname, (':' + str(parsed_url.port) if parsed_url.port else '')) headers['Referer'] = headers.get('Referer', '%s://%s' % (parsed_url.scheme, host)) - headers['Host'] = headers.get('Host', host) + headers['Host'] = headers.get('Host', None) headers['User-Agent'] = headers.get('User-Agent', self.user_agent) headers['Accept-encoding'] = headers.get('Accept-encoding', 'gzip') headers['Connection'] = headers.get('Connection', 'keep-alive') From b9dbadda0b1bdcceb3f25f2cf4f79d25f4d4268f Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 23 Sep 2014 22:00:27 +0200 Subject: [PATCH 4/6] Add randomstring support to cptag --- couchpotato/core/plugins/base.py | 27 +++++++++++++++++---------- couchpotato/core/plugins/scanner.py | 4 ++-- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/couchpotato/core/plugins/base.py b/couchpotato/core/plugins/base.py index 3c655bc0..2e993715 100644 --- a/couchpotato/core/plugins/base.py +++ b/couchpotato/core/plugins/base.py @@ -11,7 +11,8 @@ import traceback from couchpotato.core.event import fireEvent, addEvent from couchpotato.core.helpers.encoding import ss, toSafeString, \ toUnicode, sp -from couchpotato.core.helpers.variable import getExt, md5, isLocalIP, scanForPassword, tryInt, getIdentifier +from couchpotato.core.helpers.variable import getExt, md5, isLocalIP, scanForPassword, tryInt, getIdentifier, \ + randomString from couchpotato.core.logger import CPLog from couchpotato.environment import Env import requests @@ -346,9 +347,9 @@ class Plugin(object): Env.get('cache').set(cache_key_md5, value, timeout) return value - def createNzbName(self, data, media): + def createNzbName(self, data, media, unique_tag = False): release_name = data.get('name') - tag = self.cpTag(media) + tag = self.cpTag(media, unique_tag = unique_tag) # Check if password is filename name_password = scanForPassword(data.get('name')) @@ -361,18 +362,24 @@ class Plugin(object): max_length = 127 - len(tag) # Some filesystems don't support 128+ long filenames return '%s%s' % (toSafeString(toUnicode(release_name)[:max_length]), tag) - def createFileName(self, data, filedata, media): - name = self.createNzbName(data, media) + def createFileName(self, data, filedata, media, unique_tag = False): + name = self.createNzbName(data, media, unique_tag = unique_tag) if data.get('protocol') == 'nzb' and 'DOCTYPE nzb' not in filedata and '' not in filedata: return '%s.%s' % (name, 'rar') return '%s.%s' % (name, data.get('protocol')) - def cpTag(self, media): - if Env.setting('enabled', 'renamer'): - identifier = getIdentifier(media) - return '.cp(' + identifier + ')' if identifier else '' + def cpTag(self, media, unique_tag = False): - return '' + identifier = getIdentifier(media) or '' + unique_tag = ', ' + randomString() if unique_tag else '' + + tag = '.cp(' + tag += identifier + tag += ', ' if unique_tag and identifier else '' + tag += randomString() if unique_tag else '' + tag += ')' + + return tag if len(tag) > 7 else '' def checkFilesChanged(self, files, unchanged_for = 60): now = time.time() diff --git a/couchpotato/core/plugins/scanner.py b/couchpotato/core/plugins/scanner.py index a1b5cf88..a7a5e88e 100644 --- a/couchpotato/core/plugins/scanner.py +++ b/couchpotato/core/plugins/scanner.py @@ -120,7 +120,7 @@ class Scanner(Plugin): '()([ab])(\.....?)$' #*a.mkv ] - cp_imdb = '(.cp.(?Ptt[0-9{7}]+).)' + cp_imdb = '\.cp\((?Ptt[0-9]+),?\s?(?P[A-Za-z0-9]+)?\)' def __init__(self): @@ -492,7 +492,7 @@ class Scanner(Plugin): data['quality_type'] = 'HD' if data.get('resolution_width', 0) >= 1280 or data['quality'].get('hd') else 'SD' - filename = re.sub('(.cp\(tt[0-9{7}]+\))', '', files[0]) + filename = re.sub(self.cp_imdb, '', files[0]) data['group'] = self.getGroup(filename[len(folder):]) data['source'] = self.getSourceMedia(filename) if data['quality'].get('is_3d', 0): From 543226450c40e33db30d0efcf2eb4d336fdc6409 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 23 Sep 2014 22:22:27 +0200 Subject: [PATCH 5/6] NZBVortex status checking --- couchpotato/core/downloaders/nzbvortex.py | 84 +++++++---------------- 1 file changed, 23 insertions(+), 61 deletions(-) diff --git a/couchpotato/core/downloaders/nzbvortex.py b/couchpotato/core/downloaders/nzbvortex.py index af95628d..aa2ac1ef 100644 --- a/couchpotato/core/downloaders/nzbvortex.py +++ b/couchpotato/core/downloaders/nzbvortex.py @@ -1,21 +1,14 @@ from base64 import b64encode -import re -from urllib2 import URLError +import os from uuid import uuid4 import hashlib -import httplib -import json -import os -import socket -import ssl -import sys -import time import traceback -import urllib2 + +from requests import HTTPError from couchpotato.core._base.downloader.main import DownloaderBase, ReleaseDownloadList from couchpotato.core.helpers.encoding import tryUrlencode, sp -from couchpotato.core.helpers.variable import cleanHost, randomString +from couchpotato.core.helpers.variable import cleanHost from couchpotato.core.logger import CPLog @@ -36,14 +29,11 @@ class NZBVortex(DownloaderBase): # Send the nzb try: - nzb_id = '%s-%s' % (self.cpTag(media), randomString()) - nzb_filename = self.createFileName(data, filedata, media) - nzb_filename = re.sub('(.cp\(tt[0-9{7}]+\))', '', nzb_filename) - nzb_filename = '%s%s.nzb' % (nzb_filename[0:-4], nzb_id) + nzb_filename = self.createFileName(data, filedata, media, unique_tag = True) response = self.call('nzb/add', files = {'file': (nzb_filename, filedata, 'application/octet-stream')}) if response and response.get('result', '').lower() == 'ok': - return self.downloadReturnId(nzb_id) + return self.downloadReturnId(nzb_filename) log.error('Something went wrong sending the NZB file. Response: %s', response) return False @@ -65,7 +55,8 @@ class NZBVortex(DownloaderBase): release_downloads = ReleaseDownloadList(self) for nzb in raw_statuses.get('nzbs', []): - if nzb['id'] in ids: + nzb_id = os.path.basename(nzb['nzbFileName']) + if nzb_id in ids: # Check status status = 'busy' @@ -75,7 +66,8 @@ class NZBVortex(DownloaderBase): status = 'failed' release_downloads.append({ - 'id': nzb['id'], + 'temp_id': nzb['id'], + 'id': nzb_id, 'name': nzb['uiTitle'], 'status': status, 'original_status': nzb['state'], @@ -90,7 +82,7 @@ class NZBVortex(DownloaderBase): log.info('%s failed downloading, deleting...', release_download['name']) try: - self.call('nzb/%s/cancel' % release_download['id']) + self.call('nzb/%s/cancel' % release_download['temp_id']) except: log.error('Failed deleting: %s', traceback.format_exc(0)) return False @@ -132,15 +124,16 @@ class NZBVortex(DownloaderBase): params = tryUrlencode(parameters) - url = cleanHost(self.conf('host'), ssl = self.conf('ssl')) + 'api/' + call + url = cleanHost(self.conf('host')) + 'api/' + call try: - data = self.getJsonData('%s?%s' % (url, params), *args, **kwargs) + data = self.getJsonData('%s%s' % (url, '?' + params if params else ''), *args, cache_timeout = 0, show_error = False, **kwargs) if data: return data - except URLError as e: - if hasattr(e, 'code') and e.code == 403: + except HTTPError as e: + sc = e.response.status_code + if sc == 403: # Try login and do again if not is_repeat: self.login() @@ -156,13 +149,12 @@ class NZBVortex(DownloaderBase): if not self.api_level: - url = cleanHost(self.conf('host')) + 'api/app/apilevel' - try: - data = self.urlopen(url, show_error = False) - self.api_level = float(json.loads(data).get('apilevel')) - except URLError as e: - if hasattr(e, 'code') and e.code == 403: + data = self.call('app/apilevel', auth = False) + self.api_level = float(data.get('apilevel')) + except HTTPError as e: + sc = e.response.status_code + if sc == 403: log.error('This version of NZBVortex isn\'t supported. Please update to 2.8.6 or higher') else: log.error('NZBVortex doesn\'t seem to be running or maybe the remote option isn\'t enabled yet: %s', traceback.format_exc(1)) @@ -174,29 +166,6 @@ class NZBVortex(DownloaderBase): return super(NZBVortex, self).isEnabled(manual, data) and self.getApiLevel() -class HTTPSConnection(httplib.HTTPSConnection): - def __init__(self, *args, **kwargs): - httplib.HTTPSConnection.__init__(self, *args, **kwargs) - - def connect(self): - sock = socket.create_connection((self.host, self.port), self.timeout) - if sys.version_info < (2, 6, 7): - if hasattr(self, '_tunnel_host'): - self.sock = sock - self._tunnel() - else: - if self._tunnel_host: - self.sock = sock - self._tunnel() - - self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version = ssl.PROTOCOL_TLSv1) - - -class HTTPSHandler(urllib2.HTTPSHandler): - def https_open(self, req): - return self.do_open(HTTPSConnection, req) - - config = [{ 'name': 'nzbvortex', 'groups': [ @@ -216,15 +185,8 @@ config = [{ }, { 'name': 'host', - 'default': 'localhost:4321', - 'description': 'Hostname with port. Usually localhost:4321', - }, - { - 'name': 'ssl', - 'default': 1, - 'type': 'bool', - 'advanced': True, - 'description': 'Use HyperText Transfer Protocol Secure, or https', + 'default': 'https://localhost:4321', + 'description': 'Hostname with port. Usually https://localhost:4321', }, { 'name': 'api_key', From 4b66b0ea0761707e8f8e1a36d44fa1649230c9a9 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 23 Sep 2014 22:36:01 +0200 Subject: [PATCH 6/6] Add NZBVortex group support fix #1279 --- couchpotato/core/downloaders/nzbvortex.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/couchpotato/core/downloaders/nzbvortex.py b/couchpotato/core/downloaders/nzbvortex.py index aa2ac1ef..4f28ed45 100644 --- a/couchpotato/core/downloaders/nzbvortex.py +++ b/couchpotato/core/downloaders/nzbvortex.py @@ -30,7 +30,10 @@ class NZBVortex(DownloaderBase): # Send the nzb try: nzb_filename = self.createFileName(data, filedata, media, unique_tag = True) - response = self.call('nzb/add', files = {'file': (nzb_filename, filedata, 'application/octet-stream')}) + response = self.call('nzb/add', files = {'file': (nzb_filename, filedata, 'application/octet-stream')}, parameters = { + 'name': nzb_filename, + 'groupname': self.conf('group') + }) if response and response.get('result', '').lower() == 'ok': return self.downloadReturnId(nzb_filename) @@ -192,6 +195,11 @@ config = [{ 'name': 'api_key', 'label': 'Api Key', }, + { + 'name': 'group', + 'label': 'Group', + 'description': 'The group CP places the nzb in. Make sure to create it in NZBVortex.', + }, { 'name': 'manual', 'default': False,