Add scripts

This commit is contained in:
Hellowlol 2015-12-12 01:32:18 +01:00
parent ad365c7dd0
commit 9328b7e586
6 changed files with 293 additions and 145 deletions

View file

@ -48,7 +48,7 @@ from plexpy import helpers
<div class="form-group">
<label for="${item['name']}">${item['label']}</label>
<div class="row">
<div class="col-md-5">
<div class="col-md-8">
<select class="form-control" id="${item['name']}" name="${item['name']}" >
% for key, value in sorted(item['select_options'].iteritems()):
% if key == item['value']:
@ -79,6 +79,41 @@ from plexpy import helpers
<input class="form-control" type="text" id="test_body" name="test_body" value="Test notification">
<p class="help-block">Set a custom body.</p>
</div>
%if agent['name'] == 'Scripts':
<div class="form-group">
<label for="test_script">Script path</label>
<select class="form-control" id="test_script" name="test_script" >
% for key, value in sorted(data[1]['select_options'].iteritems()):
<option value="${key}">${value}</option>
% endfor
</select>
<p class="help-block">Pick your script</p>
</div>
<div class="form-group">
<label for="test_script_action">Script action</label>
<select class="form-control" id="test_script_action" name="test_script_action">
<option value=""></option>
<option value="buffer">Buffer warning</option>
<option value="watched">Watched</option>
<option value="play">Playback start</option>
<option value="pause">Playback stopp</option>
<option value="resume">Playback resume</option>
<option value="stop">Playback stop</option>
<option value="extdown">Plex Server Remote Down</option>
<option value="extup">Plex Server Remote Up</option>
<option value="intdown">Plex Server Down</option>
<option value="intup">Plex Server Up</option>
<option value="created">Recently added</option>
</select>
<p class="help-block">Pick your action</p>
</div>
<div class="form-group">
<label for="test_script_args">Script args</label>
<input class="form-control" type="text" id="test_script_args" name="test_script_args" value="">
<p class="help-block">Set a custom script args: -zomg --x.</p>
</div>
% endif
<div class="form-group">
<div class="row">
<div class="col-md-8">
@ -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');

View file

@ -758,7 +758,7 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
<li>
<div class="form-group">
<label for="notify_scripts_args_text">Script arguments</label>
<input class="form-control" type="text" id="notify_scripts_args_text" name="notify_scripts_args_text" value="${config['notify_scripts_args_text']}" data-parsley-trigger="change" required>
<input class="form-control" type="text" id="notify_scripts_args_text" name="notify_scripts_args_text" value="${config['notify_scripts_args_text']}" data-parsley-trigger="change">
<p class="help-block">Set arguments passed to the script</p>
</div>
@ -767,7 +767,6 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
</li>
</ul>
<p><input type="button" class="btn btn-bright save-button" value="Save" data-success="Changes saved successfully"></p>
</div>
<div role="tabpanel" class="tab-pane" id="tabs-10">
@ -1127,6 +1126,14 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
<td><strong>{transcode_audio_channels}</strong></td>
<td>The audio channels of the transcoded media.</td>
</tr>
<tr>
<td><strong>{streams}</strong></td>
<td>The number of concurrent streams.</td>
</tr>
<tr>
<td><strong>{action}</strong></td>
<td>The action that trigged the notification.</td>
</tr>
</tbody>
</table>
<table class="notification-params">

View file

@ -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', ''),

View file

@ -13,11 +13,13 @@
# You should have received a copy of the GNU General Public License
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
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
@ -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*<tv>[^>]+.</tv>\n*|\n*<music>[^>]+.</music>\n*', re.IGNORECASE|re.DOTALL)
pattern = re.compile('\n*<tv>[^>]+.</tv>\n*|\n*<music>[^>]+.</music>\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*<movie>[^>]+.</movie>\n*|\n*?<music>[^>]+.</music>\n*', re.IGNORECASE|re.DOTALL)
pattern = re.compile('\n*<movie>[^>]+.</movie>\n*|\n*?<music>[^>]+.</music>\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*<tv>[^>]+.</tv>\n*|\n*<movie>[^>]+.</movie>\n*', re.IGNORECASE|re.DOTALL)
pattern = re.compile('\n*<tv>[^>]+.</tv>\n*|\n*<movie>[^>]+.</movie>\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':
@ -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 = ''
# Default scripts args
script_args = []
# Regex to match {param} but not "{param}"
params_to_quote = re.compile(r'(?<!\")([\{][^}]+[\}])(?!\"\})')
script_args_text = re.sub(params_to_quote, r'"\g<0>"', script_args_text)
if script_args_text:
try:
# Add script arguments
script_args = unicode(plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT).format(**available_params)
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 notification subject. Using fallback." % e)
except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using fallback.")
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 = re.sub(params_to_quote, r'"\g<0>"', 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,12 +890,14 @@ 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

View file

@ -13,32 +13,31 @@
# You should have received a copy of the GNU General Public License
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
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.
@ -587,6 +587,7 @@ class PROWL(object):
"/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
@ -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):
@ -881,6 +885,7 @@ class PUSHBULLET(object):
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)
@ -911,6 +916,7 @@ class PUSHBULLET(object):
http_handler.request("GET", "/v2/devices",
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")
@ -983,9 +990,9 @@ class PUSHALOT(object):
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'
@ -1233,6 +1242,7 @@ class TwitterNotifier(object):
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):
@ -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):
@ -1719,12 +1733,13 @@ class Scripts(object):
# 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

View file

@ -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()
@ -675,7 +676,7 @@ class WebInterface(object):
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)
@ -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):