From d9f702e7f270d1eff9e7a46dccb33f0e24040a04 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Mon, 24 May 2021 12:53:41 -0700 Subject: [PATCH] Add ability to evaluate math in notification text --- plexpy/config.py | 1 + plexpy/notification_handler.py | 35 ++++++++++++++++++++++++++++++---- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/plexpy/config.py b/plexpy/config.py index ebc996de..f17a9829 100644 --- a/plexpy/config.py +++ b/plexpy/config.py @@ -175,6 +175,7 @@ _CONFIG_DEFINITIONS = { 'NOTIFY_SERVER_CONNECTION_THRESHOLD': (int, 'Monitoring', 60), 'NOTIFY_SERVER_UPDATE_REPEAT': (int, 'Monitoring', 0), 'NOTIFY_PLEXPY_UPDATE_REPEAT': (int, 'Monitoring', 0), + 'NOTIFY_TEXT_EVAL': (int, 'Advanced', 0), 'PLEXPY_AUTO_UPDATE': (int, 'General', 0), 'REFRESH_LIBRARIES_INTERVAL': (int, 'Monitoring', 12), 'REFRESH_LIBRARIES_ON_STARTUP': (int, 'Monitoring', 1), diff --git a/plexpy/notification_handler.py b/plexpy/notification_handler.py index 4d3fde55..a22b5d2c 100644 --- a/plexpy/notification_handler.py +++ b/plexpy/notification_handler.py @@ -1814,6 +1814,24 @@ def str_format(s, parameters): return s +def str_eval(field_name, kwargs): + field_name = field_name.strip('`') + allowed_names = { + 'bool': bool, + 'divmod': divmod, + 'float': float, + 'int': int, + 'round': round, + 'str': str + } + allowed_names.update(kwargs) + code = compile(field_name, '', 'eval') + for name in code.co_names: + if name not in allowed_names: + raise NameError('Use of {name} not allowed'.format(name=name)) + return eval(code, {'__builtins__': {}}, allowed_names) + + class CustomFormatter(Formatter): def __init__(self, default='{{{0}}}'): self.default = default @@ -1926,10 +1944,19 @@ class CustomFormatter(Formatter): # used later on, then an exception will be raised auto_arg_index = False - # given the field_name, find the object it references - # and the argument it came from - obj, arg_used = self.get_field(field_name, args, kwargs) - used_args.add(arg_used) + if plexpy.CONFIG.NOTIFY_TEXT_EVAL and field_name.startswith('`') and field_name.endswith('`'): + try: + obj = str_eval(field_name, kwargs) + used_args.add(field_name) + except (SyntaxError, NameError, ValueError, TypeError) as e: + logger.error("Tautulli NotificationHandler :: Failed to evaluate notification text %s: %s.", + field_name, e) + obj = field_name + else: + # given the field_name, find the object it references + # and the argument it came from + obj, arg_used = self.get_field(field_name, args, kwargs) + used_args.add(arg_used) # do any conversion on the resulting object obj = self.convert_field(obj, conversion)