diff --git a/couchpotato/core/notifications/base.py b/couchpotato/core/notifications/base.py index 9e80aea..8d1608a 100644 --- a/couchpotato/core/notifications/base.py +++ b/couchpotato/core/notifications/base.py @@ -18,6 +18,7 @@ class Notification(Provider): listen_to = [ 'renamer.after', 'movie.snatched', 'updater.available', 'updater.updated', + 'core.message', ] dont_listen_to = [] diff --git a/couchpotato/core/notifications/core/main.py b/couchpotato/core/notifications/core/main.py index bc8bd86..a28ccb9 100644 --- a/couchpotato/core/notifications/core/main.py +++ b/couchpotato/core/notifications/core/main.py @@ -1,12 +1,13 @@ from couchpotato import get_session from couchpotato.api import addApiView, addNonBlockApiView -from couchpotato.core.event import addEvent +from couchpotato.core.event import addEvent, fireEvent from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.helpers.request import jsonified, getParam from couchpotato.core.helpers.variable import tryInt, splitString from couchpotato.core.logger import CPLog from couchpotato.core.notifications.base import Notification from couchpotato.core.settings.model import Notification as Notif +from couchpotato.environment import Env from sqlalchemy.sql.expression import or_ import threading import time @@ -21,11 +22,6 @@ class CoreNotifier(Notification): messages = [] listeners = [] - listen_to = [ - 'renamer.after', 'movie.snatched', - 'updater.available', 'updater.updated', - ] - def __init__(self): super(CoreNotifier, self).__init__() @@ -54,7 +50,10 @@ class CoreNotifier(Notification): addNonBlockApiView('notification.listener', (self.addListener, self.removeListener)) addApiView('notification.listener', self.listener) + fireEvent('schedule.interval', 'core.check_messages', self.checkMessages, hours = 12, single = True) + addEvent('app.load', self.clean) + addEvent('app.load', self.checkMessages) def clean(self): @@ -112,6 +111,23 @@ class CoreNotifier(Notification): 'notifications': notifications }) + def checkMessages(self): + + prop_name = 'messages.last_check' + last_check = tryInt(Env.prop(prop_name, default = 0)) + + messages = fireEvent('cp.messages', last_check = last_check, single = True) + + last_time = 0 + for message in messages: + if message.get('time') > last_check: + fireEvent('core.message', message = message.get('message'), data = message) + + if last_time < message.get('time'): + last_time = message.get('time') + + Env.prop(prop_name, value = last_time) + def notify(self, message = '', data = {}, listener = None): db = get_session() diff --git a/couchpotato/core/notifications/core/static/notification.js b/couchpotato/core/notifications/core/static/notification.js index 3843df1..243d561 100644 --- a/couchpotato/core/notifications/core/static/notification.js +++ b/couchpotato/core/notifications/core/static/notification.js @@ -44,14 +44,19 @@ var NotificationBase = new Class({ result.el = App.getBlock('notification').addLink( new Element('span.'+(result.read ? 'read' : '' )).adopt( - new Element('span.message', {'text': result.message}), + new Element('span.message', {'html': result.message}), new Element('span.added', {'text': added.timeDiffInWords(), 'title': added}) ) , 'top'); self.notifications.include(result); - if(!result.read) + if(result.data.important !== undefined && !result.read){ + var sticky = true + App.fireEvent('message', [result.message, sticky, result]) + } + else if(!result.read){ self.setBadge(self.notifications.filter(function(n){ return !n.read}).length) + } }, @@ -61,20 +66,26 @@ var NotificationBase = new Class({ self.badge[value ? 'show' : 'hide']() }, - markAsRead: function(){ - var self = this; + markAsRead: function(force_ids){ + var self = this, + ids = force_ids; - var rn = self.notifications.filter(function(n){ - return !n.read - }) + if(!force_ids) { + var rn = self.notifications.filter(function(n){ + return !n.read && n.data.important === undefined + }) - var ids = [] - rn.each(function(n){ - ids.include(n.id) - }) + var ids = [] + rn.each(function(n){ + ids.include(n.id) + }) + } if(ids.length > 0) Api.request('notification.markread', { + 'data': { + 'ids': ids.join(',') + }, 'onSuccess': function(){ self.setBadge('') } @@ -140,26 +151,41 @@ var NotificationBase = new Class({ self.startPoll() }, - showMessage: function(message){ + showMessage: function(message, sticky, data){ var self = this; if(!self.message_container) self.message_container = new Element('div.messages').inject(document.body); - var new_message = new Element('div.message', { - 'text': message - }).inject(self.message_container); + var new_message = new Element('div', { + 'class': 'message' + (sticky ? ' sticky' : ''), + 'html': message + }).inject(self.message_container, 'top'); setTimeout(function(){ new_message.addClass('show') }, 10); - setTimeout(function(){ + var hide_message = function(){ new_message.addClass('hide') setTimeout(function(){ new_message.destroy(); }, 1000); - }, 4000); + } + + if(sticky) + new_message.grab( + new Element('a.close.icon2', { + 'events': { + 'click': function(){ + self.markAsRead([data.id]); + hide_message(); + } + } + }) + ); + else + setTimeout(hide_message, 4000); }, diff --git a/couchpotato/core/providers/movie/couchpotatoapi/main.py b/couchpotato/core/providers/movie/couchpotatoapi/main.py index d942da1..2beb7e2 100644 --- a/couchpotato/core/providers/movie/couchpotatoapi/main.py +++ b/couchpotato/core/providers/movie/couchpotatoapi/main.py @@ -2,6 +2,7 @@ from couchpotato import get_session from couchpotato.core.event import addEvent, fireEvent from couchpotato.core.helpers.encoding import tryUrlencode from couchpotato.core.helpers.request import jsonified, getParams +from couchpotato.core.helpers.variable import tryInt from couchpotato.core.logger import CPLog from couchpotato.core.providers.movie.base import MovieProvider from couchpotato.core.settings.model import Movie @@ -20,6 +21,7 @@ class CouchPotatoApi(MovieProvider): 'eta': 'https://couchpota.to/api/eta/%s/', 'suggest': 'https://couchpota.to/api/suggest/', 'updater': 'https://couchpota.to/api/updater/?%s', + 'messages': 'https://couchpota.to/api/messages/?%s', } http_time_between_calls = 0 api_version = 1 @@ -32,6 +34,15 @@ class CouchPotatoApi(MovieProvider): addEvent('movie.is_movie', self.isMovie) addEvent('cp.source_url', self.getSourceUrl) + addEvent('cp.messages', self.getMessages) + + def getMessages(self, last_check = 0): + + data = self.getJsonData(self.urls['messages'] % tryUrlencode({ + 'last_check': last_check, + }), headers = self.getRequestHeaders(), cache_timeout = 10) + + return data def getSourceUrl(self, repo = None, repo_name = None, branch = None): return self.getJsonData(self.urls['updater'] % tryUrlencode({ diff --git a/couchpotato/static/style/main.css b/couchpotato/static/style/main.css index e933517..02dda3d 100644 --- a/couchpotato/static/style/main.css +++ b/couchpotato/static/style/main.css @@ -160,6 +160,7 @@ body > .spinner, .mask{ .icon2.eye-open:before { content: "\e09d"; } .icon2.search:before { content: "\e03e"; } .icon2.return-key:before { content: "\e111"; } +.icon2.close:before { content: "\e04e"; } .icon2.menu:before { content: "\e076 \e076 \e076"; line-height: 6px; @@ -715,43 +716,51 @@ body > .spinner, .mask{ position: fixed; right: 0; bottom: 0; - padding: 2px; - width: 240px; + width: 320px; z-index: 20; overflow: hidden; font-size: 14px; font-weight: bold; } + @media all and (max-width: 480px) { + .messages { + width: 100%; + } + } .messages .message { - text-align: center; - border-radius: 2px; - margin: 2px 0 0 0; - height: 0; overflow: hidden; transition: all .6s cubic-bezier(0.9,0,0.1,1); - box-shadow: 0 1px 1px rgba(0,0,0,0.35), inset 0 1px 0px rgba(255,255,255,0.20); - background-image: linear-gradient( - 180deg, - #5b9bd1 0%, - #406db8 100% - ); + background: #5b9bd1; width: 100%; - padding: 0 5px; - visibility: hidden; + position: relative; + margin: 1px 0 0; max-height: 0; + padding: 0 30px 0 20px; + font-size: 1.1em; + font-weight: normal; + transform: scale(0); } + .messages .message.sticky { + background-color: #c84040; + } .messages .message.show { - visibility: visible; - height: auto; - padding-top: 3px; - padding-bottom: 3px; - min-height: 1px; - max-height: 400px; + max-height: 100px; + padding: 15px 30px 15px 20px; + transform: scale(1); } .messages .message.hide { - margin-left: 240px; - opacity: 0; + max-height: 0; + padding: 0 20px; + margin: 0; + transform: scale(0); + } + .messages .close { + position: absolute; + padding: 10px 8px; + top: 0; + right: 0; + color: #FFF; } /* Fonts */