From 651119b7dd7c312b584a07834bff1cd09b2a38f0 Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Fri, 28 Feb 2014 17:35:08 +0000 Subject: [PATCH 01/14] replaced a duplicate URL replaced a duplicate URL. --- couchpotato/core/providers/torrent/thepiratebay/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/providers/torrent/thepiratebay/main.py b/couchpotato/core/providers/torrent/thepiratebay/main.py index c366c51..6ef5123 100644 --- a/couchpotato/core/providers/torrent/thepiratebay/main.py +++ b/couchpotato/core/providers/torrent/thepiratebay/main.py @@ -37,7 +37,7 @@ class ThePirateBay(TorrentMagnetProvider): 'http://nl.tpb.li', 'http://proxybay.eu', 'https://www.getpirate.com', - 'http://pirateproxy.ca', + 'http://piratebay.io', ] def _searchOnTitle(self, title, movie, quality, results): From 22e922e8602411a016aee6b195707e6b6b47ee13 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 3 Mar 2014 23:34:49 +0100 Subject: [PATCH 02/14] Split socket error to nr --- CouchPotato.py | 1 + 1 file changed, 1 insertion(+) diff --git a/CouchPotato.py b/CouchPotato.py index e73ed9a..375a1d4 100755 --- a/CouchPotato.py +++ b/CouchPotato.py @@ -136,6 +136,7 @@ if __name__ == '__main__': except socket.error as e: # log when socket receives SIGINT, but continue. # previous code would have skipped over other types of IO errors too. + nr, msg = e if nr != 4: try: l.log.critical(traceback.format_exc()) From 5b279a48cbf79603534aa17fcba9de6a6c169244 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 7 Mar 2014 17:38:40 +0100 Subject: [PATCH 03/14] Make sure q is first for nzbclub --- couchpotato/core/providers/nzb/nzbclub/main.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/providers/nzb/nzbclub/main.py b/couchpotato/core/providers/nzb/nzbclub/main.py index 643f247..ce853cd 100644 --- a/couchpotato/core/providers/nzb/nzbclub/main.py +++ b/couchpotato/core/providers/nzb/nzbclub/main.py @@ -22,8 +22,11 @@ class NZBClub(NZBProvider, RSS): q = '"%s %s"' % (title, movie['library']['year']) - params = tryUrlencode({ + q_param = tryUrlencode({ 'q': q, + }) + + params = tryUrlencode({ 'ig': 1, 'rpp': 200, 'st': 5, @@ -31,7 +34,7 @@ class NZBClub(NZBProvider, RSS): 'ns': 1, }) - nzbs = self.getRSSData(self.urls['search'] % params) + nzbs = self.getRSSData(self.urls['search'] % ('%s&%s' % (q_param, params))) for nzb in nzbs: From 7af1d00ea261ee4921220648d56bf9442611c838 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 7 Mar 2014 18:10:17 +0100 Subject: [PATCH 04/14] Allow passwords inside nzb name --- couchpotato/core/helpers/variable.py | 11 +++++++++++ couchpotato/core/plugins/base.py | 13 +++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/helpers/variable.py b/couchpotato/core/helpers/variable.py index a586cef..64cdce2 100644 --- a/couchpotato/core/helpers/variable.py +++ b/couchpotato/core/helpers/variable.py @@ -295,3 +295,14 @@ def dictIsSubset(a, b): def isSubFolder(sub_folder, base_folder): # Returns True if sub_folder is the same as or inside base_folder return base_folder and sub_folder and ss(os.path.normpath(base_folder).rstrip(os.path.sep) + os.path.sep) in ss(os.path.normpath(sub_folder).rstrip(os.path.sep) + os.path.sep) + +# From SABNZBD +re_password = [re.compile(r'([^/\\]+)[/\\](.+)'), re.compile(r'(.+){{([^{}]+)}}$'), re.compile(r'(.+)\s+password\s*=\s*(.+)$', re.I)] +def scanForPassword(name): + m = None + for reg in re_password: + m = reg.search(name) + if m: break + + if m: + return m.group(1).strip('. '), m.group(2).strip() diff --git a/couchpotato/core/plugins/base.py b/couchpotato/core/plugins/base.py index 378ed50..891e6b4 100644 --- a/couchpotato/core/plugins/base.py +++ b/couchpotato/core/plugins/base.py @@ -1,7 +1,7 @@ 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 +from couchpotato.core.helpers.variable import getExt, md5, isLocalIP, scanForPassword from couchpotato.core.logger import CPLog from couchpotato.environment import Env import requests @@ -283,8 +283,17 @@ class Plugin(object): return value def createNzbName(self, data, media): + release_name = data.get('name') tag = self.cpTag(media) - return '%s%s' % (toSafeString(toUnicode(data.get('name'))[:127 - len(tag)]), tag) + + # Check if password is filename + name_password = scanForPassword(data.get('name')) + if name_password: + release_name, password = name_password + tag += '{{%s}}' % password + + 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 = sp(os.path.join(self.createNzbName(data, media))) From 2066625bf001ab0e82b501029c273717bd9909ee Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 7 Mar 2014 18:58:27 +0100 Subject: [PATCH 05/14] Don't use ctime on unix system. Cleanup check a bit. close #2904 --- couchpotato/core/plugins/base.py | 38 +++++++++++++++++++++++++++++++- couchpotato/core/plugins/renamer/main.py | 24 ++------------------ couchpotato/core/plugins/scanner/main.py | 36 +++++++----------------------- 3 files changed, 47 insertions(+), 51 deletions(-) diff --git a/couchpotato/core/plugins/base.py b/couchpotato/core/plugins/base.py index 891e6b4..b852d62 100644 --- a/couchpotato/core/plugins/base.py +++ b/couchpotato/core/plugins/base.py @@ -1,7 +1,7 @@ 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 +from couchpotato.core.helpers.variable import getExt, md5, isLocalIP, scanForPassword, tryInt from couchpotato.core.logger import CPLog from couchpotato.environment import Env import requests @@ -307,6 +307,42 @@ class Plugin(object): return '' + def checkFilesChanged(self, files, unchanged_for = 60): + now = time.time() + + for cur_file in files: + + # File got removed while checking + if not os.path.isfile(cur_file): + file_too_new = now + break + + # File has changed in last 60 seconds + file_time = self.self.getFileTimes(cur_file) + for t in file_time: + if t > now - unchanged_for: + file_too_new = tryInt(time.time() - t) + break + + if file_too_new: + break + + if file_too_new: + try: + time_string = time.ctime(file_time[0]) + except: + try: + time_string = time.ctime(file_time[1]) + except: + time_string = 'unknown' + + return file_too_new, time_string + + return False, None + + def getFileTimes(self, file_path): + return [os.path.getmtime(file_path), os.path.getctime(file_path) if os.name != 'posix' else 0] + def isDisabled(self): return not self.isEnabled() diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index 1bf4ec9..fe698d2 100755 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -1127,29 +1127,9 @@ Remove it if you want it to be renamed (again, or at least let it try again) # Check if archive is fresh and maybe still copying/moving/downloading, ignore files newer than 1 minute if check_file_date: - file_too_new = False - for cur_file in archive['files']: - if not os.path.isfile(cur_file): - file_too_new = time.time() - break - file_time = [os.path.getmtime(cur_file), os.path.getctime(cur_file)] - for t in file_time: - if t > time.time() - 60: - file_too_new = tryInt(time.time() - t) - break - - if file_too_new: - break - - if file_too_new: - try: - time_string = time.ctime(file_time[0]) - except: - try: - time_string = time.ctime(file_time[1]) - except: - time_string = 'unknown' + files_too_new, time_string = self.checkFilesChanged(archive['files']) + if files_too_new: log.info('Archive seems to be still copying/moving/downloading or just copied/moved/downloaded (created on %s), ignoring for now: %s', (time_string, os.path.basename(archive['file']))) continue diff --git a/couchpotato/core/plugins/scanner/main.py b/couchpotato/core/plugins/scanner/main.py index daff091..3031236 100644 --- a/couchpotato/core/plugins/scanner/main.py +++ b/couchpotato/core/plugins/scanner/main.py @@ -291,41 +291,21 @@ class Scanner(Plugin): break # Check if movie is fresh and maybe still unpacking, ignore files newer than 1 minute - file_too_new = False - for cur_file in group['unsorted_files']: - if not os.path.isfile(cur_file): - file_too_new = time.time() - break - file_time = [os.path.getmtime(cur_file), os.path.getctime(cur_file)] - for t in file_time: - if t > time.time() - 60: - file_too_new = tryInt(time.time() - t) - break - - if file_too_new: - break - - if check_file_date and file_too_new: - try: - time_string = time.ctime(file_time[0]) - except: - try: - time_string = time.ctime(file_time[1]) - except: - time_string = 'unknown' - - log.info('Files seem to be still unpacking or just unpacked (created on %s), ignoring for now: %s', (time_string, identifier)) + if check_file_date: + files_too_new, time_string = self.checkFilesChanged(group['unsorted_files']) + if files_too_new: + log.info('Files seem to be still unpacking or just unpacked (created on %s), ignoring for now: %s', (time_string, identifier)) - # Delete the unsorted list - del group['unsorted_files'] + # Delete the unsorted list + del group['unsorted_files'] - continue + continue # Only process movies newer than x if newer_than and newer_than > 0: has_new_files = False for cur_file in group['unsorted_files']: - file_time = [os.path.getmtime(cur_file), os.path.getctime(cur_file)] + file_time = self.getFileTimes(cur_file) if file_time[0] > newer_than or file_time[1] > newer_than: has_new_files = True break From b69898d624520af8446ebeba8e839cc6fa6a7e03 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 8 Mar 2014 09:37:39 +0100 Subject: [PATCH 06/14] Remove double self in filetime check. fixes #2952 --- 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 b852d62..81ffcec 100644 --- a/couchpotato/core/plugins/base.py +++ b/couchpotato/core/plugins/base.py @@ -318,7 +318,7 @@ class Plugin(object): break # File has changed in last 60 seconds - file_time = self.self.getFileTimes(cur_file) + file_time = self.getFileTimes(cur_file) for t in file_time: if t > now - unchanged_for: file_too_new = tryInt(time.time() - t) From b50cf1cf4c82912f14d1d334a6e982e18db071a0 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 8 Mar 2014 10:50:11 +0100 Subject: [PATCH 07/14] Only allow next year for couldbereleased check --- couchpotato/core/media/movie/searcher/main.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/couchpotato/core/media/movie/searcher/main.py b/couchpotato/core/media/movie/searcher/main.py index 7ae76a4..1c22e18 100644 --- a/couchpotato/core/media/movie/searcher/main.py +++ b/couchpotato/core/media/movie/searcher/main.py @@ -282,13 +282,15 @@ class MovieSearcher(SearcherBase, MovieTypeBase): now = int(time.time()) now_year = date.today().year + now_month = date.today().month if (year is None or year < now_year - 1) and (not dates or (dates.get('theater', 0) == 0 and dates.get('dvd', 0) == 0)): return True else: # Don't allow movies with years to far in the future - if year is not None and year > now_year + 1: + add_year = 1 if now_month > 10 else 0 # Only allow +1 year if end of the year + if year is not None and year > (now_year + add_year): return False # For movies before 1972 From dc0ea5b3f61a6f6d1492a72b32106af4ad487c12 Mon Sep 17 00:00:00 2001 From: Ruud Date: Thu, 6 Mar 2014 21:30:59 +0100 Subject: [PATCH 08/14] Use proper sorting --- couchpotato/core/event.py | 9 ++------- couchpotato/core/helpers/variable.py | 13 +++---------- libs/axl/axel.py | 7 +++++-- 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/couchpotato/core/event.py b/couchpotato/core/event.py index a36c430..8af2967 100644 --- a/couchpotato/core/event.py +++ b/couchpotato/core/event.py @@ -1,5 +1,5 @@ from axl.axel import Event -from couchpotato.core.helpers.variable import mergeDicts, natcmp +from couchpotato.core.helpers.variable import mergeDicts, natsortKey from couchpotato.core.logger import CPLog import threading import traceback @@ -51,11 +51,6 @@ def addEvent(name, handler, priority = 100): }) -def removeEvent(name, handler): - e = events[name] - e -= handler - - def fireEvent(name, *args, **kwargs): if name not in events: return @@ -106,7 +101,7 @@ def fireEvent(name, *args, **kwargs): result = e(*args, **kwargs) result_keys = result.keys() - result_keys.sort(natcmp) + result_keys.sort(key = natsortKey) if options['single'] and not options['merge']: results = None diff --git a/couchpotato/core/helpers/variable.py b/couchpotato/core/helpers/variable.py index 64cdce2..8be6f29 100644 --- a/couchpotato/core/helpers/variable.py +++ b/couchpotato/core/helpers/variable.py @@ -214,16 +214,9 @@ def tryFloat(s): return float(s) except: return 0 - -def natsortKey(s): - return map(tryInt, re.findall(r'(\d+|\D+)', s)) - - -def natcmp(a, b): - a2 = natsortKey(a) - b2 = natsortKey(b) - - return (a2 > b2) - (a2 < b2) +def natsortKey(string_): + """See http://www.codinghorror.com/blog/archives/001018.html""" + return [int(s) if s.isdigit() else s for s in re.split(r'(\d+)', string_)] def toIterable(value): diff --git a/libs/axl/axel.py b/libs/axl/axel.py index 46940da..d0f069a 100644 --- a/libs/axl/axel.py +++ b/libs/axl/axel.py @@ -11,7 +11,7 @@ # Source: http://pypi.python.org/pypi/axel # Docs: http://packages.python.org/axel -from couchpotato.core.helpers.variable import natcmp +from couchpotato.core.helpers.variable import natsortKey import Queue import hashlib import sys @@ -158,7 +158,10 @@ class Event(object): t.daemon = True t.start() - for handler in sorted(self.handlers.iterkeys(), cmp = natcmp): + handler_keys = self.handlers.keys() + handler_keys.sort(key = natsortKey) + + for handler in handler_keys: self.queue.put(handler) if self.asynchronous: From c58315e2ee0261886e0ce7d42fde18dc885e0184 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 8 Mar 2014 11:59:12 +0100 Subject: [PATCH 09/14] Use natural sorting --- couchpotato/core/helpers/request.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/helpers/request.py b/couchpotato/core/helpers/request.py index b62ab68..a0baa85 100644 --- a/couchpotato/core/helpers/request.py +++ b/couchpotato/core/helpers/request.py @@ -1,5 +1,5 @@ from couchpotato.core.helpers.encoding import toUnicode -from couchpotato.core.helpers.variable import natcmp +from couchpotato.core.helpers.variable import natsortKey from urllib import unquote import re @@ -8,8 +8,13 @@ def getParams(params): reg = re.compile('^[a-z0-9_\.]+$') + # Sort keys + param_keys = params.keys() + param_keys.sort(key = natsortKey) + temp = {} - for param, value in sorted(params.items()): + for param in param_keys: + value = params[param] nest = re.split("([\[\]]+)", param) if len(nest) > 1: From 3172a4d030e5a7064c403256ac2f5da51a176c2c Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 8 Mar 2014 12:27:06 +0100 Subject: [PATCH 10/14] Check for year in coming soon --- couchpotato/core/plugins/dashboard/main.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/plugins/dashboard/main.py b/couchpotato/core/plugins/dashboard/main.py index 949d8f5..3367ffb 100644 --- a/couchpotato/core/plugins/dashboard/main.py +++ b/couchpotato/core/plugins/dashboard/main.py @@ -1,3 +1,4 @@ +from datetime import date from couchpotato import get_session from couchpotato.api import addApiView from couchpotato.core.event import fireEvent @@ -65,6 +66,7 @@ class Dashboard(Plugin): active = q.all() movies = [] + now_year = date.today().year if len(active) > 0: @@ -91,8 +93,8 @@ class Dashboard(Plugin): if coming_soon: # Don't list older movies - if ((not late and (not eta.get('dvd') and not eta.get('theater') or eta.get('dvd') and eta.get('dvd') > (now - 2419200))) or - (late and (eta.get('dvd', 0) > 0 or eta.get('theater')) and eta.get('dvd') < (now - 2419200))): + if ((not late and (year >= now_year-1) and (not eta.get('dvd') and not eta.get('theater') or eta.get('dvd') and eta.get('dvd') > (now - 2419200))) or + (late and ((year < now_year-1) or ((eta.get('dvd', 0) > 0 or eta.get('theater')) and eta.get('dvd') < (now - 2419200))))): movie_ids.append(movie_id) if len(movie_ids) >= limit: From 9e471ac38933bcf6d870d503f408cba5f6eb6e87 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 8 Mar 2014 14:05:49 +0100 Subject: [PATCH 11/14] Add "I Just Watched" Reddit to userscripts. fix #2621 --- .../core/providers/userscript/reddit/__init__.py | 7 +++++++ couchpotato/core/providers/userscript/reddit/main.py | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 couchpotato/core/providers/userscript/reddit/__init__.py create mode 100644 couchpotato/core/providers/userscript/reddit/main.py diff --git a/couchpotato/core/providers/userscript/reddit/__init__.py b/couchpotato/core/providers/userscript/reddit/__init__.py new file mode 100644 index 0000000..a74bbf0 --- /dev/null +++ b/couchpotato/core/providers/userscript/reddit/__init__.py @@ -0,0 +1,7 @@ +from .main import Reddit + + +def start(): + return Reddit() + +config = [] diff --git a/couchpotato/core/providers/userscript/reddit/main.py b/couchpotato/core/providers/userscript/reddit/main.py new file mode 100644 index 0000000..9790f6e --- /dev/null +++ b/couchpotato/core/providers/userscript/reddit/main.py @@ -0,0 +1,17 @@ +from couchpotato import fireEvent +from couchpotato.core.helpers.variable import splitString +from couchpotato.core.providers.userscript.base import UserscriptBase + + +class Reddit(UserscriptBase): + + includes = ['*://www.reddit.com/r/Ijustwatched/comments/*'] + + def getMovie(self, url): + name = splitString(url, '/')[-1] + if name.startswith('ijw_'): + name = name[4:] + + year_name = fireEvent('scanner.name_year', name, single = True) + + return self.search(year_name.get('name'), year_name.get('year')) From d60a8a71b708f2c1fab16c8ffa996e3db72f8268 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 8 Mar 2014 18:18:06 +0100 Subject: [PATCH 12/14] Check if file has moved, ignore copystat errors. close #2936 --- couchpotato/core/plugins/renamer/main.py | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index fe698d2..436107f 100755 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -736,8 +736,15 @@ Remove it if you want it to be renamed (again, or at least let it try again) def moveFile(self, old, dest, forcemove = False): dest = ss(dest) try: - if forcemove: - shutil.move(old, dest) + if forcemove or self.conf('file_action') not in ['copy', 'link']: + try: + shutil.move(old, dest) + except: + if os.path.exists(dest): + log.error('Successfully moved file "%s", but something went wrong: %s', (dest, traceback.format_exc())) + os.unlink(old) + else: + raise elif self.conf('file_action') == 'copy': shutil.copy(old, dest) elif self.conf('file_action') == 'link': @@ -755,8 +762,6 @@ Remove it if you want it to be renamed (again, or at least let it try again) os.rename(old + '.link', old) except: log.error('Couldn\'t symlink file "%s" to "%s". Copied instead. Error: %s. ', (old, dest, traceback.format_exc())) - else: - shutil.move(old, dest) try: os.chmod(dest, Env.getPermission('file')) @@ -764,15 +769,6 @@ Remove it if you want it to be renamed (again, or at least let it try again) os.popen('icacls "' + dest + '"* /reset /T') except: log.error('Failed setting permissions for file: %s, %s', (dest, traceback.format_exc(1))) - - except OSError as err: - # Copying from a filesystem with octal permission to an NTFS file system causes a permission error. In this case ignore it. - if not hasattr(os, 'chmod') or err.errno != errno.EPERM: - raise - else: - if os.path.exists(dest): - os.unlink(old) - except: log.error('Couldn\'t move file "%s" to "%s": %s', (old, dest, traceback.format_exc())) raise From 75f22f44a1ad1ea47e44091a5000b2df9cef05e7 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 8 Mar 2014 18:55:38 +0100 Subject: [PATCH 13/14] Reference before assigned --- couchpotato/core/plugins/base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/couchpotato/core/plugins/base.py b/couchpotato/core/plugins/base.py index 81ffcec..d7487a1 100644 --- a/couchpotato/core/plugins/base.py +++ b/couchpotato/core/plugins/base.py @@ -309,6 +309,7 @@ class Plugin(object): def checkFilesChanged(self, files, unchanged_for = 60): now = time.time() + file_too_new = False for cur_file in files: From ffe6b7dd70462c3af87592027258682a08c388d8 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 10 Mar 2014 15:42:40 +0100 Subject: [PATCH 14/14] Add boxcar 2 support. closes #2886 --- couchpotato/core/notifications/boxcar2/__init__.py | 34 +++++++++++++++++++ couchpotato/core/notifications/boxcar2/main.py | 39 ++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 couchpotato/core/notifications/boxcar2/__init__.py create mode 100644 couchpotato/core/notifications/boxcar2/main.py diff --git a/couchpotato/core/notifications/boxcar2/__init__.py b/couchpotato/core/notifications/boxcar2/__init__.py new file mode 100644 index 0000000..da7f99c --- /dev/null +++ b/couchpotato/core/notifications/boxcar2/__init__.py @@ -0,0 +1,34 @@ +from .main import Boxcar2 + + +def start(): + return Boxcar2() + +config = [{ + 'name': 'boxcar2', + 'groups': [ + { + 'tab': 'notifications', + 'list': 'notification_providers', + 'name': 'boxcar2', + 'options': [ + { + 'name': 'enabled', + 'default': 0, + 'type': 'enabler', + }, + { + 'name': 'token', + 'description': ('Your Boxcar access token.', 'Can be found in the app under settings') + }, + { + 'name': 'on_snatch', + 'default': 0, + 'type': 'bool', + 'advanced': True, + 'description': 'Also send message when movie is snatched.', + }, + ], + } + ], +}] diff --git a/couchpotato/core/notifications/boxcar2/main.py b/couchpotato/core/notifications/boxcar2/main.py new file mode 100644 index 0000000..6633ca7 --- /dev/null +++ b/couchpotato/core/notifications/boxcar2/main.py @@ -0,0 +1,39 @@ +from couchpotato.core.helpers.encoding import toUnicode +from couchpotato.core.logger import CPLog +from couchpotato.core.notifications.base import Notification + +log = CPLog(__name__) + + +class Boxcar2(Notification): + + url = 'https://new.boxcar.io/api/notifications' + + def notify(self, message = '', data = None, listener = None): + if not data: data = {} + + try: + message = message.strip() + + long_message = '' + if listener == 'test': + long_message = 'This is a test message' + elif data.get('identifier'): + long_message = 'More movie info on IMDB' % data['identifier'] + + data = { + 'user_credentials': self.conf('token'), + 'notification[title]': toUnicode(message), + 'notification[long_message]': toUnicode(long_message), + } + + self.urlopen(self.url, data = data) + except: + log.error('Make sure the token provided is for the correct device') + return False + + log.info('Boxcar notification successful.') + return True + + def isEnabled(self): + return super(Boxcar2, self).isEnabled() and self.conf('token')