@@ -148,7 +183,10 @@ from plexpy import helpers
url: 'test_notifier',
data: { config_id: '${agent["id"]}',
subject: $('#test_subject').val(),
- body: $('#test_body').val() },
+ body: $('#test_body').val(),
+ notify_action: $('#test_script_action').val(),
+ script: $('#test_script').val(),
+ script_args: $('#test_script_args').val() },
cache: false,
async: true,
complete: function (xhr, status) {
@@ -164,6 +202,12 @@ from plexpy import helpers
return false;
});
+ $('#scripts_folder').on('change', function () {
+ doAjaxCall('set_notification_config', $(this), 'tabs', true);
+ reloadModal();
+ return false;
+ });
+
// Never send checkbox values directly, always substitute value in hidden input.
$('.checkboxes').click(function () {
var configToggle = $(this).data('id');
diff --git a/data/interfaces/default/settings.html b/data/interfaces/default/settings.html
index 8c31aafb..2bf3b653 100644
--- a/data/interfaces/default/settings.html
+++ b/data/interfaces/default/settings.html
@@ -758,7 +758,7 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
@@ -767,7 +767,6 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
-
@@ -1127,6 +1126,14 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
{transcode_audio_channels} |
The audio channels of the transcoded media. |
+
+ {streams} |
+ The number of concurrent streams. |
+
+
+ {action} |
+ The action that trigged the notification. |
+
diff --git a/plexpy/config.py b/plexpy/config.py
index 84af1a0b..d899f583 100644
--- a/plexpy/config.py
+++ b/plexpy/config.py
@@ -295,8 +295,8 @@ _CONFIG_DEFINITIONS = {
'SLACK_ON_INTDOWN': (int, 'Slack', 0),
'SLACK_ON_EXTUP': (int, 'Slack', 0),
'SLACK_ON_INTUP': (int, 'Slack', 0),
- 'SCRIPTS_ENABLED': (str, 'Scripts', 0),
- 'SCRIPTS_FOLDER': (str, 'Scripts', ''),
+ 'SCRIPTS_ENABLED': (int, 'Scripts', 0),
+ 'SCRIPTS_FOLDER': (unicode, 'Scripts', ''),
'SCRIPTS_ON_PLAY': (int, 'Scripts', 0),
'SCRIPTS_ON_STOP': (int, 'Scripts', 0),
'SCRIPTS_ON_PAUSE': (int, 'Scripts', 0),
@@ -308,17 +308,17 @@ _CONFIG_DEFINITIONS = {
'SCRIPTS_ON_EXTUP': (int, 'Scripts', 0),
'SCRIPTS_ON_INTDOWN': (int, 'Scripts', 0),
'SCRIPTS_ON_INTUP': (int, 'Scripts', 0),
- 'SCRIPTS_ON_PLAY_SCRIPT': (str, 'Scripts', ''),
- 'SCRIPTS_ON_STOP_SCRIPT': (str, 'Scripts', ''),
- 'SCRIPTS_ON_PAUSE_SCRIPT': (str, 'Scripts', ''),
- 'SCRIPTS_ON_RESUME_SCRIPT': (str, 'Scripts', ''),
- 'SCRIPTS_ON_BUFFER_SCRIPT': (str, 'Scripts', ''),
- 'SCRIPTS_ON_WATCHED_SCRIPT': (str, 'Scripts', ''),
- 'SCRIPTS_ON_CREATED_SCRIPT': (str, 'Scripts', ''),
- 'SCRIPTS_ON_EXTDOWN_SCRIPT': (str, 'Scripts', ''),
- 'SCRIPTS_ON_EXTUP_SCRIPT': (str, 'Scripts', ''),
- 'SCRIPTS_ON_INTDOWN_SCRIPT': (str, 'Scripts', ''),
- 'SCRIPTS_ON_INTUP_SCRIPT': (str, 'Scripts', ''),
+ 'SCRIPTS_ON_PLAY_SCRIPT': (unicode, 'Scripts', ''),
+ 'SCRIPTS_ON_STOP_SCRIPT': (unicode, 'Scripts', ''),
+ 'SCRIPTS_ON_PAUSE_SCRIPT': (unicode, 'Scripts', ''),
+ 'SCRIPTS_ON_RESUME_SCRIPT': (unicode, 'Scripts', ''),
+ 'SCRIPTS_ON_BUFFER_SCRIPT': (unicode, 'Scripts', ''),
+ 'SCRIPTS_ON_WATCHED_SCRIPT': (unicode, 'Scripts', ''),
+ 'SCRIPTS_ON_CREATED_SCRIPT': (unicode, 'Scripts', ''),
+ 'SCRIPTS_ON_EXTDOWN_SCRIPT': (unicode, 'Scripts', ''),
+ 'SCRIPTS_ON_EXTUP_SCRIPT': (unicode, 'Scripts', ''),
+ 'SCRIPTS_ON_INTDOWN_SCRIPT': (unicode, 'Scripts', ''),
+ 'SCRIPTS_ON_INTUP_SCRIPT': (unicode, 'Scripts', ''),
'TELEGRAM_BOT_TOKEN': (str, 'Telegram', ''),
'TELEGRAM_ENABLED': (int, 'Telegram', 0),
'TELEGRAM_CHAT_ID': (str, 'Telegram', ''),
diff --git a/plexpy/notification_handler.py b/plexpy/notification_handler.py
index 495d95df..f642fac6 100644
--- a/plexpy/notification_handler.py
+++ b/plexpy/notification_handler.py
@@ -13,11 +13,13 @@
# You should have received a copy of the GNU General Public License
# along with PlexPy. If not, see .
-from plexpy import logger, config, notifiers, database, helpers, plextv, pmsconnect
-import plexpy
+import re
import time
+from plexpy import logger, config, notifiers, database, helpers, plextv, pmsconnect
+import plexpy
+
def notify(stream_data=None, notify_action=None):
from plexpy import users
@@ -44,7 +46,7 @@ def notify(stream_data=None, notify_action=None):
body=notify_strings[1],
notify_action=notify_action,
script_args=notify_strings[2])
-
+
# Set the notification state in the db
set_notify_state(session=stream_data, state=notify_action, agent_info=agent)
@@ -213,7 +215,9 @@ def notify_timeline(timeline_data=None, notify_action=None):
notify_strings = build_notify_text(timeline=timeline_data, state=notify_action)
notifiers.send_notification(config_id=agent['id'],
subject=notify_strings[0],
- body=notify_strings[1])
+ body=notify_strings[1],
+ notify_action=notify_action,
+ script_args=notify_strings[2])
# Set the notification state in the db
set_notify_state(session=timeline_data, state=notify_action, agent_info=agent)
@@ -224,25 +228,33 @@ def notify_timeline(timeline_data=None, notify_action=None):
notify_strings = build_server_notify_text(state=notify_action)
notifiers.send_notification(config_id=agent['id'],
subject=notify_strings[0],
- body=notify_strings[1])
+ body=notify_strings[1],
+ notify_action=notify_action,
+ script_args=notify_strings[2])
if agent['on_intdown'] and notify_action == 'intdown':
# Build and send notification
notify_strings = build_server_notify_text(state=notify_action)
notifiers.send_notification(config_id=agent['id'],
subject=notify_strings[0],
- body=notify_strings[1])
+ body=notify_strings[1],
+ notify_action=notify_action,
+ script_args=notify_strings[2])
if agent['on_extup'] and notify_action == 'extup':
# Build and send notification
notify_strings = build_server_notify_text(state=notify_action)
notifiers.send_notification(config_id=agent['id'],
subject=notify_strings[0],
- body=notify_strings[1])
+ body=notify_strings[1],
+ notify_action=notify_action,
+ script_args=notify_strings[2])
if agent['on_intup'] and notify_action == 'intup':
# Build and send notification
notify_strings = build_server_notify_text(state=notify_action)
notifiers.send_notification(config_id=agent['id'],
subject=notify_strings[0],
- body=notify_strings[1])
+ body=notify_strings[1],
+ notify_action=notify_action,
+ script_args=notify_strings[2])
else:
logger.debug(u"PlexPy Notifier :: Notify timeline called but incomplete data received.")
@@ -269,6 +281,7 @@ def get_notify_state(session):
return notify_states
+
def get_notify_state_timeline(timeline):
monitor_db = database.MonitorDatabase()
result = monitor_db.select('SELECT on_created, agent_id '
@@ -325,7 +338,6 @@ def set_notify_state(session, state, agent_info):
def build_notify_text(session=None, timeline=None, state=None):
- import re
# Get the server name
server_name = plexpy.CONFIG.PMS_NAME
@@ -350,6 +362,8 @@ def build_notify_text(session=None, timeline=None, state=None):
pms_connect = pmsconnect.PmsConnect()
metadata_list = pms_connect.get_metadata_details(rating_key=rating_key)
+ stream_count = pms_connect.get_current_activity().get('stream_count', '')
+
if metadata_list:
metadata = metadata_list['metadata']
else:
@@ -359,13 +373,13 @@ def build_notify_text(session=None, timeline=None, state=None):
# Check for exclusion tags
if metadata['media_type'] == 'movie':
# Regex pattern to remove the text in the tags we don't want
- pattern = re.compile('\n*[^>]+.\n*|\n*[^>]+.\n*', re.IGNORECASE|re.DOTALL)
+ pattern = re.compile('\n*[^>]+.\n*|\n*[^>]+.\n*', re.IGNORECASE | re.DOTALL)
elif metadata['media_type'] == 'show' or metadata['media_type'] == 'episode':
# Regex pattern to remove the text in the tags we don't want
- pattern = re.compile('\n*[^>]+.\n*|\n*?[^>]+.\n*', re.IGNORECASE|re.DOTALL)
+ pattern = re.compile('\n*[^>]+.\n*|\n*?[^>]+.\n*', re.IGNORECASE | re.DOTALL)
elif metadata['media_type'] == 'artist' or metadata['media_type'] == 'track':
# Regex pattern to remove the text in the tags we don't want
- pattern = re.compile('\n*[^>]+.\n*|\n*[^>]+.\n*', re.IGNORECASE|re.DOTALL)
+ pattern = re.compile('\n*[^>]+.\n*|\n*[^>]+.\n*', re.IGNORECASE | re.DOTALL)
else:
pattern = None
@@ -388,6 +402,7 @@ def build_notify_text(session=None, timeline=None, state=None):
on_watched_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT))
on_created_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT))
on_created_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT))
+ script_args_text = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT))
else:
on_start_subject = plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT
on_start_body = plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT
@@ -403,6 +418,7 @@ def build_notify_text(session=None, timeline=None, state=None):
on_watched_body = plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT
on_created_subject = plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT
on_created_body = plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT
+ script_args_text = plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT
# Create a title
if metadata['media_type'] == 'episode' or metadata['media_type'] == 'track':
@@ -497,7 +513,7 @@ def build_notify_text(session=None, timeline=None, state=None):
artist_name = metadata['grandparent_title']
album_name = metadata['parent_title']
track_name = metadata['title']
-
+
available_params = {'server_name': server_name,
'server_uptime': server_uptime,
'user': user,
@@ -548,21 +564,28 @@ def build_notify_text(session=None, timeline=None, state=None):
'summary': metadata['summary'],
'tagline': metadata['tagline'],
'rating': metadata['rating'],
- 'duration': duration
+ 'duration': duration,
+ 'action': state,
+ 'streams': stream_count
}
# Default subject text
subject_text = 'PlexPy (%s)' % server_name
- # Default scripts args
- script_args = ''
- try:
- # Add script arguments
- script_args = unicode(plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback." % e)
- except:
- logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using fallback.")
+ # Default scripts args
+ script_args = []
+
+ # Regex to match {param} but not "{param}"
+ params_to_quote = re.compile(r'(?"', script_args_text)
+
+ if script_args_text:
+ try:
+ script_args = [unicode(arg).format(**available_params) for arg in script_args_text.split()]
+ except LookupError as e:
+ logger.error(u"PlexPy Notifier :: Unable to parse field %s in script argument. Using fallback." % e)
+ except Exception as e:
+ logger.error(u"PlexPy Notifier :: Unable to parse custom script arguments %s. Using fallback." % e)
if state == 'play':
# Default body text
@@ -733,6 +756,7 @@ def build_notify_text(session=None, timeline=None, state=None):
else:
return None
+
def build_server_notify_text(state=None):
# Get the server name
server_name = plexpy.CONFIG.PMS_NAME
@@ -764,6 +788,22 @@ def build_server_notify_text(state=None):
# Default text
subject_text = 'PlexPy (%s)' % server_name
+ # Default scripts args
+ script_args = []
+ script_args_text = plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT
+
+ # Regex to match {param} but not "{param}"
+ params_to_quote = re.compile(r'(?"', script_args_text)
+
+ if script_args_text:
+ try:
+ script_args = [unicode(arg).format(**available_params) for arg in script_args_text.split()]
+ except LookupError as e:
+ logger.error(u"PlexPy Notifier :: Unable to parse field %s in script argument. Using fallback." % e)
+ except Exception as e:
+ logger.error(u"PlexPy Notifier :: Unable to parse custom script arguments %s. Using fallback." % e)
+
if state == 'extdown':
# Default body text
body_text = 'The Plex Media Server remote access is down.'
@@ -783,9 +823,10 @@ def build_server_notify_text(state=None):
except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification body. Using fallback.")
- return [subject_text, body_text]
+ return [subject_text, body_text, script_args]
else:
- return [subject_text, body_text]
+ return [subject_text, body_text, script_args]
+
elif state == 'intdown':
# Default body text
body_text = 'The Plex Media Server is down.'
@@ -805,9 +846,9 @@ def build_server_notify_text(state=None):
except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification body. Using fallback.")
- return [subject_text, body_text]
+ return [subject_text, body_text, script_args]
else:
- return [subject_text, body_text]
+ return [subject_text, body_text, script_args]
if state == 'extup':
# Default body text
body_text = 'The Plex Media Server remote access is back up.'
@@ -827,9 +868,9 @@ def build_server_notify_text(state=None):
except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification body. Using fallback.")
- return [subject_text, body_text]
+ return [subject_text, body_text, script_args]
else:
- return [subject_text, body_text]
+ return [subject_text, body_text, script_args]
elif state == 'intup':
# Default body text
body_text = 'The Plex Media Server is back up.'
@@ -849,14 +890,16 @@ def build_server_notify_text(state=None):
except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification body. Using fallback.")
- return [subject_text, body_text]
+ return [subject_text, body_text, script_args]
else:
- return [subject_text, body_text]
+ return [subject_text, body_text, script_args]
+
else:
return None
+
def strip_tag(data):
import re
p = re.compile(r'<.*?>')
- return p.sub('', data)
\ No newline at end of file
+ return p.sub('', data)
diff --git a/plexpy/notifiers.py b/plexpy/notifiers.py
index b5c929ab..b00c75a7 100644
--- a/plexpy/notifiers.py
+++ b/plexpy/notifiers.py
@@ -13,32 +13,31 @@
# You should have received a copy of the GNU General Public License
# along with PlexPy. If not, see .
-from plexpy import logger, helpers, common, request
-from plexpy.helpers import checked, radio
-
-from xml.dom import minidom
-from httplib import HTTPSConnection
-from urlparse import parse_qsl
from urlparse import urlparse
-from urllib import urlencode
-from pynma import pynma
-
import base64
+import json
import cherrypy
+from email.mime.text import MIMEText
+import email.utils
+from httplib import HTTPSConnection
+import os
+import shlex
+import smtplib
+import subprocess
+
+from urllib import urlencode
import urllib
import urllib2
-import plexpy
-import os.path
-import subprocess
-import gntp.notifier
-import json
+from urlparse import parse_qsl
+from pynma import pynma
+import gntp.notifier
import oauth2 as oauth
import pythontwitter as twitter
-from email.mime.text import MIMEText
-import smtplib
-import email.utils
+import plexpy
+from plexpy import logger, helpers, request
+from plexpy.helpers import checked
AGENT_IDS = {"Growl": 0,
"Prowl": 1,
@@ -399,7 +398,7 @@ def get_notification_agent_config(config_id):
return []
-def send_notification(config_id, subject, body, notify_action=None):
+def send_notification(config_id, subject, body, **kwargs):
if str(config_id).isdigit():
config_id = int(config_id)
@@ -450,7 +449,7 @@ def send_notification(config_id, subject, body, notify_action=None):
slackClient.notify(message=body, event=subject)
elif config_id == 15:
scripts = Scripts()
- scripts.notify(message=body, subject=subject, notify_action=notify_action, script_args=script_args)
+ scripts.notify(message=body, subject=subject, **kwargs)
else:
logger.debug(u"PlexPy Notifier :: Unknown agent id received.")
else:
@@ -531,7 +530,7 @@ class GROWL(object):
logger.info(u"Growl notifications sent.")
def updateLibrary(self):
- #For uniformity reasons not removed
+ # For uniformity reasons not removed
return
def test(self, host, password):
@@ -558,6 +557,7 @@ class GROWL(object):
return config_option
+
class PROWL(object):
"""
Prowl notifications.
@@ -584,9 +584,10 @@ class PROWL(object):
'priority': plexpy.CONFIG.PROWL_PRIORITY}
http_handler.request("POST",
- "/publicapi/add",
- headers={'Content-type': "application/x-www-form-urlencoded"},
- body=urlencode(data))
+ "/publicapi/add",
+ headers={'Content-type': "application/x-www-form-urlencoded"},
+ body=urlencode(data))
+
response = http_handler.getresponse()
request_status = response.status
@@ -601,7 +602,7 @@ class PROWL(object):
return False
def updateLibrary(self):
- #For uniformity reasons not removed
+ # For uniformity reasons not removed
return
def test(self, keys, priority):
@@ -629,6 +630,7 @@ class PROWL(object):
return config_option
+
class XBMC(object):
"""
XBMC notifications
@@ -754,7 +756,7 @@ class Plex(object):
header = subject
message = message
- time = "3000" # in ms
+ time = "3000" # in ms
for host in hosts:
logger.info('Sending notification command to Plex Media Server @ ' + host)
@@ -792,6 +794,7 @@ class Plex(object):
return config_option
+
class NMA(object):
def __init__(self):
@@ -850,6 +853,7 @@ class NMA(object):
return config_option
+
class PUSHBULLET(object):
def __init__(self):
@@ -877,10 +881,11 @@ class PUSHBULLET(object):
data['channel_tag'] = self.channel_tag
http_handler.request("POST",
- "/v2/pushes",
- headers={'Content-type': "application/json",
- 'Authorization': 'Basic %s' % base64.b64encode(plexpy.CONFIG.PUSHBULLET_APIKEY + ":")},
- body=json.dumps(data))
+ "/v2/pushes",
+ headers={'Content-type': "application/json",
+ 'Authorization': 'Basic %s' % base64.b64encode(plexpy.CONFIG.PUSHBULLET_APIKEY + ":")},
+ body=json.dumps(data))
+
response = http_handler.getresponse()
request_status = response.status
# logger.debug(u"PushBullet response status: %r" % request_status)
@@ -909,8 +914,9 @@ class PUSHBULLET(object):
if plexpy.CONFIG.PUSHBULLET_APIKEY:
http_handler = HTTPSConnection("api.pushbullet.com")
http_handler.request("GET", "/v2/devices",
- headers={'Content-type': "application/json",
- 'Authorization': 'Basic %s' % base64.b64encode(plexpy.CONFIG.PUSHBULLET_APIKEY + ":")})
+ headers={'Content-type': "application/json",
+ 'Authorization': 'Basic %s' % base64.b64encode(plexpy.CONFIG.PUSHBULLET_APIKEY + ":")})
+
response = http_handler.getresponse()
request_status = response.status
@@ -955,6 +961,7 @@ class PUSHBULLET(object):
return config_option
+
class PUSHALOT(object):
def __init__(self):
@@ -966,9 +973,9 @@ class PUSHALOT(object):
pushalot_authorizationtoken = plexpy.CONFIG.PUSHALOT_APIKEY
- #logger.debug(u"Pushalot event: " + event)
- #logger.debug(u"Pushalot message: " + message)
- #logger.debug(u"Pushalot api: " + pushalot_authorizationtoken)
+ # logger.debug(u"Pushalot event: " + event)
+ # logger.debug(u"Pushalot message: " + message)
+ # logger.debug(u"Pushalot api: " + pushalot_authorizationtoken)
http_handler = HTTPSConnection("pushalot.com")
@@ -977,15 +984,15 @@ class PUSHALOT(object):
'Body': message.encode("utf-8")}
http_handler.request("POST",
- "/api/sendmessage",
- headers={'Content-type': "application/x-www-form-urlencoded"},
- body=urlencode(data))
+ "/api/sendmessage",
+ headers={'Content-type': "application/x-www-form-urlencoded"},
+ body=urlencode(data))
response = http_handler.getresponse()
request_status = response.status
- #logger.debug(u"Pushalot response status: %r" % request_status)
- #logger.debug(u"Pushalot response headers: %r" % response.getheaders())
- #logger.debug(u"Pushalot response body: %r" % response.read())
+ # logger.debug(u"Pushalot response status: %r" % request_status)
+ # logger.debug(u"Pushalot response headers: %r" % response.getheaders())
+ # logger.debug(u"Pushalot response body: %r" % response.read())
if request_status == 200:
logger.info(u"Pushalot notifications sent.")
@@ -1008,6 +1015,7 @@ class PUSHALOT(object):
return config_option
+
class PUSHOVER(object):
def __init__(self):
@@ -1054,7 +1062,7 @@ class PUSHOVER(object):
return False
def updateLibrary(self):
- #For uniformity reasons not removed
+ # For uniformity reasons not removed
return
def test(self, keys, priority, sound):
@@ -1118,6 +1126,7 @@ class PUSHOVER(object):
return config_option
+
class TwitterNotifier(object):
REQUEST_TOKEN_URL = 'https://api.twitter.com/oauth/request_token'
@@ -1215,24 +1224,25 @@ class TwitterNotifier(object):
'description': 'Step 1: Click Request button above. (Ensure you allow the browser pop-up).',
'input_type': 'button'
},
- {'label': 'Authorisation Key',
- 'value': '',
- 'name': 'twitter_key',
- 'description': 'Step 2: Input the authorisation key you received from Step 1.',
- 'input_type': 'text'
+ {'label': 'Authorisation Key',
+ 'value': '',
+ 'name': 'twitter_key',
+ 'description': 'Step 2: Input the authorisation key you received from Step 1.',
+ 'input_type': 'text'
},
- {'label': 'Verify Key',
- 'value': 'Verify Key',
- 'name': 'twitterStep2',
- 'description': 'Step 3: Verify the key.',
- 'input_type': 'button'
+ {'label': 'Verify Key',
+ 'value': 'Verify Key',
+ 'name': 'twitterStep2',
+ 'description': 'Step 3: Verify the key.',
+ 'input_type': 'button'
},
- {'input_type': 'nosave'
+ {'input_type': 'nosave'
}
]
return config_option
+
class OSX_NOTIFY(object):
def __init__(self):
@@ -1240,7 +1250,7 @@ class OSX_NOTIFY(object):
self.objc = __import__("objc")
self.AppKit = __import__("AppKit")
except:
- #logger.error(u"PlexPy Notifier :: Cannot load OSX Notifications agent.")
+ # logger.error(u"PlexPy Notifier :: Cannot load OSX Notifications agent.")
pass
def validate(self):
@@ -1257,7 +1267,7 @@ class OSX_NOTIFY(object):
def wrapper(self, *args, **kwargs):
return func(self, old_IMP, *args, **kwargs)
new_IMP = self.objc.selector(wrapper, selector=old_IMP.selector,
- signature=old_IMP.signature)
+ signature=old_IMP.signature)
self.objc.classAddMethod(cls, SEL, new_IMP)
def notify(self, title, subtitle=None, text=None, sound=True, image=None):
@@ -1287,7 +1297,7 @@ class OSX_NOTIFY(object):
if image:
source_img = self.AppKit.NSImage.alloc().initByReferencingFile_(image)
notification.setContentImage_(source_img)
- #notification.set_identityImage_(source_img)
+ # notification.set_identityImage_(source_img)
notification.setHasActionButton_(False)
notification_center = NSUserNotificationCenter.defaultUserNotificationCenter()
@@ -1316,6 +1326,7 @@ class OSX_NOTIFY(object):
return config_option
+
class BOXCAR(object):
def __init__(self):
@@ -1376,7 +1387,7 @@ class BOXCAR(object):
'flourish': 'Flourish',
'harp': 'Harp',
'light': 'Light',
- 'magic-chime':'Magic Chime',
+ 'magic-chime': 'Magic Chime',
'magic-coin': 'Magic Coin',
'no-sound': 'No Sound',
'notifier-1': 'Notifier (1)',
@@ -1392,6 +1403,7 @@ class BOXCAR(object):
return config_option
+
class Email(object):
def __init__(self):
@@ -1552,10 +1564,12 @@ class IFTTT(object):
' as value1 and value2 respectively.',
'input_type': 'text'
}
+
]
return config_option
+
class TELEGRAM(object):
def __init__(self):
@@ -1594,7 +1608,7 @@ class TELEGRAM(object):
return False
def updateLibrary(self):
- #For uniformity reasons not removed
+ # For uniformity reasons not removed
return
def test(self, bot_token, chat_id):
@@ -1713,18 +1727,19 @@ class Scripts(object):
pass
def conf(self, options):
- return cherrypy.config['config'].get('Scripts', options)
+ return cherrypy.config['config'].get('Scripts', options)
def updateLibrary(self):
# For uniformity reasons not removed
return
- def test(self, subject, message, action):
- self.notify(subject, message, action)
+ def test(self, subject, message, *args, **kwargs):
+ self.notify(subject, message, *args, **kwargs)
+ return
def list_scripts(self):
scriptdir = plexpy.CONFIG.SCRIPTS_FOLDER
- scripts = {}
+ scripts = {'': ''}
if scriptdir and not os.path.exists(scriptdir):
os.makedirs(scriptdir)
@@ -1732,18 +1747,26 @@ class Scripts(object):
for root, dirs, files in os.walk(scriptdir):
for f in files:
name, ext = os.path.splitext(f)
- ext = ext[1:]
- if ext in ('rb', 'pl', 'bat', 'py', 'sh', 'cmd', 'php'):
- fp = os.path.join(scriptdir, f)
- scripts[fp] = fp
+ if ext in ('.rb', '.pl', '.bat', '.py', '.sh', '.cmd', '.php'):
+ rfp = os.path.join(os.path.relpath(root, scriptdir), f)
+ fp = os.path.join(root, f)
+ scripts[fp] = rfp
return scripts
- def notify(self, subject, message, notify_action=None, script_args=''):
- logger.debug('Ran notify script subject: %s message: %s, action: %s script_args: %s' % (subject, message, notify_action, script_args))
+ def notify(self, subject='', message='', notify_action='', script_args='', *args, **kwargs):
+ """
+ Args:
+ subject(string, optional): Head text,
+ message(string, optional): Body text,
+ notify_action(string): 'play'
+ script_args(list): ["python2", '-p', '-zomg']
+ """
+ logger.debug(u'Trying to run notify script subject: %s message: %s, action: %s script_args: %s' %
+ (subject, message, notify_action, script_args))
prefix = ''
- script = ''
+ script = kwargs.get('script', '') # for manual scripts
if not plexpy.CONFIG.SCRIPTS_FOLDER:
return
@@ -1779,6 +1802,15 @@ class Scripts(object):
elif notify_action == 'created':
script = plexpy.CONFIG.SCRIPTS_ON_CREATED_SCRIPT
+ elif notify_action == 'watched':
+ script = plexpy.CONFIG.SCRIPTS_ON_WATCHED_SCRIPT
+
+ # Dont try to run the script
+ # if the action does not have one
+ if not script:
+ logger.debug(u'%s has no script, exiting..' % notify_action)
+ return
+
name, ext = os.path.splitext(script)
if ext == '.py':
@@ -1790,17 +1822,38 @@ class Scripts(object):
elif ext == '.rb':
prefix = 'ruby'
- script = script.split()
+ if os.name == 'nt':
+ script = script.encode(plexpy.SYS_ENCODING, 'ignore')
+ script = [script]
if prefix:
script.insert(0, prefix)
- if script_args:
- script = script + script_args.split()
+ # for manual notifications
+ if script_args and isinstance(script_args, basestring):
+ # attemps for format it for the user
+ script_args = shlex.split(script_args)
+
+ # Windows handles unicode very badly.
+ # https://bugs.python.org/issue19264
+ if script_args and os.name == 'nt':
+ script_args = [s.encode(plexpy.SYS_ENCODING, 'ignore') for s in script_args]
+
+ # Allow overrides for shitty systems
+ if prefix and script_args:
+ if script_args[0] in ['python2', 'python', 'php', 'ruby', 'perl']:
+ script[0] = script_args[0]
+ del script_args[0]
+
+ script.extend(script_args)
+
+ logger.debug(u'Full script is %s' % script)
try:
- p = subprocess.Popen(script, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT, cwd=plexpy.CONFIG.SCRIPTS_FOLDER)
+ p = subprocess.Popen(script, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ cwd=plexpy.CONFIG.SCRIPTS_FOLDER)
out, error = p.communicate()
status = p.returncode
@@ -1823,83 +1876,83 @@ class Scripts(object):
'description': 'Add your script folder.',
'input_type': 'text',
},
- {'label': 'Playback start',
+ {'label': 'Playback Start',
'value': plexpy.CONFIG.SCRIPTS_ON_PLAY_SCRIPT,
'name': 'scripts_on_play_script',
'description': 'Pick the script for on play.',
'input_type': 'select',
'select_options': self.list_scripts()
},
- {'label': 'Playback stop',
+ {'label': 'Playback Stop',
'value': plexpy.CONFIG.SCRIPTS_ON_STOP_SCRIPT,
'name': 'scripts_on_stop_script',
'description': 'Pick the script for on stop.',
'input_type': 'select',
'select_options': self.list_scripts()
},
- {'label': 'Playback pause',
+ {'label': 'Playback Pause',
'value': plexpy.CONFIG.SCRIPTS_ON_PAUSE_SCRIPT,
'name': 'scripts_on_pause_script',
'description': 'Pick the script for on pause.',
'input_type': 'select',
'select_options': self.list_scripts()
},
- {'label': 'Playback resume',
+ {'label': 'Playback Resume',
'value': plexpy.CONFIG.SCRIPTS_ON_RESUME_SCRIPT,
'name': 'scripts_on_resume_script',
'description': 'Pick the script for on resume.',
'input_type': 'select',
'select_options': self.list_scripts()
},
- {'label': 'On watched',
+ {'label': 'Watched',
'value': plexpy.CONFIG.SCRIPTS_ON_WATCHED_SCRIPT,
'name': 'scripts_on_watched_script',
'description': 'Pick the script for on watched.',
'input_type': 'select',
'select_options': self.list_scripts()
},
- {'label': 'On buffer warning',
+ {'label': 'Buffer Warnings',
'value': plexpy.CONFIG.SCRIPTS_ON_BUFFER_SCRIPT,
'name': 'scripts_on_buffer_script',
- 'description': 'Pick the script for on buffer.',
+ 'description': 'Pick the script for buffer warnings.',
'input_type': 'select',
'select_options': self.list_scripts()
},
- {'label': 'On recently added',
+ {'label': 'Recently Added',
'value': plexpy.CONFIG.SCRIPTS_ON_CREATED_SCRIPT,
'name': 'scripts_on_created_script',
'description': 'Pick the script for recently added.',
'input_type': 'select',
'select_options': self.list_scripts()
},
- {'label': 'On external connection down',
+ {'label': 'Plex Remote Access Down',
'value': plexpy.CONFIG.SCRIPTS_ON_EXTDOWN_SCRIPT,
'name': 'scripts_on_extdown_script',
'description': 'Pick the script for external connection down.',
'input_type': 'select',
'select_options': self.list_scripts()
},
- {'label': 'On external connection down',
+ {'label': 'Plex Remote Access Up',
'value': plexpy.CONFIG.SCRIPTS_ON_EXTUP_SCRIPT,
'name': 'scripts_on_extup_script',
'description': 'Pick the script for external connection up.',
'input_type': 'select',
'select_options': self.list_scripts()
},
- {'label': 'On plex down',
+ {'label': 'Plex Server Down',
'value': plexpy.CONFIG.SCRIPTS_ON_INTDOWN_SCRIPT,
'name': 'scripts_on_intdown_script',
'description': 'Pick the script for pms down',
'input_type': 'select',
'select_options': self.list_scripts()
},
- {'label': 'On plex up',
+ {'label': 'Plex Server Up',
'value': plexpy.CONFIG.SCRIPTS_ON_INTUP_SCRIPT,
'name': 'scripts_on_intup_script',
- 'description': 'Pick the script for pms down',
+ 'description': 'Pick the script for pms up',
'input_type': 'select',
'select_options': self.list_scripts()
}
-]
+ ]
- return config_option
\ No newline at end of file
+ return config_option
diff --git a/plexpy/webserve.py b/plexpy/webserve.py
index c23f9d7f..b021862c 100644
--- a/plexpy/webserve.py
+++ b/plexpy/webserve.py
@@ -555,7 +555,7 @@ class WebInterface(object):
# Get new server URLs for SSL communications.
plextv.get_real_pms_url()
-
+
# Get new server friendly name
pmsconnect.get_server_friendly_name()
@@ -663,6 +663,7 @@ class WebInterface(object):
@cherrypy.expose
def test_notifier(self, config_id=None, subject='PlexPy', body='Test notification', **kwargs):
cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store"
+ print kwargs
if config_id.isdigit():
agents = notifiers.available_notification_agents()
@@ -672,10 +673,10 @@ class WebInterface(object):
break
else:
this_agent = None
-
+
if this_agent:
logger.debug("Sending test %s notification." % this_agent['name'])
- notifiers.send_notification(this_agent['id'], subject, body)
+ notifiers.send_notification(this_agent['id'], subject, body, **kwargs)
return "Notification sent."
else:
logger.debug("Unable to send test notification, invalid notification agent ID %s." % config_id)
@@ -683,7 +684,7 @@ class WebInterface(object):
else:
logger.debug("Unable to send test notification, no notification agent ID received.")
return "No notification agent ID received."
-
+
@cherrypy.expose
def twitterStep1(self):
cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store"
@@ -1340,12 +1341,12 @@ class WebInterface(object):
plexpy.CONFIG.__setattr__('PMS_SSL', ssl)
plexpy.CONFIG.__setattr__('PMS_IS_REMOTE', remote)
plexpy.CONFIG.write()
-
+
plextv.get_real_pms_url()
-
+
pms_connect = pmsconnect.PmsConnect()
request = pms_connect.get_local_server_identity()
-
+
if request:
cherrypy.response.headers['Content-type'] = 'application/xml'
return request
@@ -1425,7 +1426,7 @@ class WebInterface(object):
def testScripts(self, *args, **kwargs):
''' Used for manual testing for now cba with adding buttion '''
script = notifiers.Scripts()
- return script.test(*args)
+ return script.test(*args, **kwargs)
@cherrypy.expose
def delete_history_rows(self, row_id, **kwargs):