bazarr/libs/apprise/AppriseAsset.py

311 lines
9.8 KiB
Python

# -*- coding: utf-8 -*-
#
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
# All rights reserved.
#
# This code is licensed under the MIT License.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files(the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions :
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import re
from uuid import uuid4
from os.path import join
from os.path import dirname
from os.path import isfile
from os.path import abspath
from .common import NotifyType
class AppriseAsset(object):
"""
Provides a supplimentary class that can be used to provide extra
information and details that can be used by Apprise such as providing
an alternate location to where images/icons can be found and the
URL masks.
"""
# Application Identifier
app_id = 'Apprise'
# Application Description
app_desc = 'Apprise Notifications'
# Provider URL
app_url = 'https://github.com/caronc/apprise'
# A Simple Mapping of Colors; For every NOTIFY_TYPE identified,
# there should be a mapping to it's color here:
html_notify_map = {
NotifyType.INFO: '#3AA3E3',
NotifyType.SUCCESS: '#3AA337',
NotifyType.FAILURE: '#A32037',
NotifyType.WARNING: '#CACF29',
}
# The default color to return if a mapping isn't found in our table above
default_html_color = '#888888'
# The default image extension to use
default_extension = '.png'
# The default theme
theme = 'default'
# Image URL Mask
image_url_mask = \
'https://github.com/caronc/apprise/raw/master/apprise/assets/' \
'themes/{THEME}/apprise-{TYPE}-{XY}{EXTENSION}'
# Application Logo
image_url_logo = \
'https://github.com/caronc/apprise/raw/master/apprise/assets/' \
'themes/{THEME}/apprise-logo.png'
# Image Path Mask
image_path_mask = abspath(join(
dirname(__file__),
'assets',
'themes',
'{THEME}',
'apprise-{TYPE}-{XY}{EXTENSION}',
))
# This value can also be set on calls to Apprise.notify(). This allows
# you to let Apprise upfront the type of data being passed in. This
# must be of type NotifyFormat. Possible values could be:
# - NotifyFormat.TEXT
# - NotifyFormat.MARKDOWN
# - NotifyFormat.HTML
# - None
#
# If no format is specified (hence None), then no special pre-formating
# actions will take place during a notificaton. This has been and always
# will be the default.
body_format = None
# Always attempt to send notifications asynchronous (as the same time
# if possible)
# This is a Python 3 supported option only. If set to False, then
# notifications are sent sequentially (one after another)
async_mode = True
# Whether or not to interpret escapes found within the input text prior
# to passing it upstream. Such as converting \t to an actual tab and \n
# to a new line.
interpret_escapes = False
# For more detail see CWE-312 @
# https://cwe.mitre.org/data/definitions/312.html
#
# By enabling this, the logging output has additional overhead applied to
# it preventing secure password and secret information from being
# displayed in the logging. Since there is overhead involved in performing
# this cleanup; system owners who run in a very isolated environment may
# choose to disable this for a slight performance bump. It is recommended
# that you leave this option as is otherwise.
secure_logging = True
# All internal/system flags are prefixed with an underscore (_)
# These can only be initialized using Python libraries and are not picked
# up from (yaml) configuration files (if set)
# An internal counter that is used by AppriseAPI
# (https://github.com/caronc/apprise-api). The idea is to allow one
# instance of AppriseAPI to call another, but to track how many times
# this occurs. It's intent is to prevent a loop where an AppriseAPI
# Server calls itself (or loops indefinitely)
_recursion = 0
# A unique identifer we can use to associate our calling source
_uid = str(uuid4())
def __init__(self, **kwargs):
"""
Asset Initialization
"""
# Assign default arguments if specified
for key, value in kwargs.items():
if not hasattr(AppriseAsset, key):
raise AttributeError(
'AppriseAsset init(): '
'An invalid key {} was specified.'.format(key))
setattr(self, key, value)
def color(self, notify_type, color_type=None):
"""
Returns an HTML mapped color based on passed in notify type
if color_type is:
None then a standard hex string is returned as
a string format ('#000000').
int then the integer representation is returned
tuple then the the red, green, blue is returned in a tuple
"""
# Attempt to get the type, otherwise return a default grey
# if we couldn't look up the entry
color = self.html_notify_map.get(notify_type, self.default_html_color)
if color_type is None:
# This is the default return type
return color
elif color_type is int:
# Convert the color to integer
return AppriseAsset.hex_to_int(color)
# The only other type is tuple
elif color_type is tuple:
return AppriseAsset.hex_to_rgb(color)
# Unsupported type
raise ValueError(
'AppriseAsset html_color(): An invalid color_type was specified.')
def image_url(self, notify_type, image_size, logo=False, extension=None):
"""
Apply our mask to our image URL
if logo is set to True, then the logo_url is used instead
"""
url_mask = self.image_url_logo if logo else self.image_url_mask
if not url_mask:
# No image to return
return None
if extension is None:
extension = self.default_extension
re_map = {
'{THEME}': self.theme if self.theme else '',
'{TYPE}': notify_type,
'{XY}': image_size,
'{EXTENSION}': extension,
}
# Iterate over above list and store content accordingly
re_table = re.compile(
r'(' + '|'.join(re_map.keys()) + r')',
re.IGNORECASE,
)
return re_table.sub(lambda x: re_map[x.group()], url_mask)
def image_path(self, notify_type, image_size, must_exist=True,
extension=None):
"""
Apply our mask to our image file path
"""
if not self.image_path_mask:
# No image to return
return None
if extension is None:
extension = self.default_extension
re_map = {
'{THEME}': self.theme if self.theme else '',
'{TYPE}': notify_type,
'{XY}': image_size,
'{EXTENSION}': extension,
}
# Iterate over above list and store content accordingly
re_table = re.compile(
r'(' + '|'.join(re_map.keys()) + r')',
re.IGNORECASE,
)
# Acquire our path
path = re_table.sub(lambda x: re_map[x.group()], self.image_path_mask)
if must_exist and not isfile(path):
return None
# Return what we parsed
return path
def image_raw(self, notify_type, image_size, extension=None):
"""
Returns the raw image if it can (otherwise the function returns None)
"""
path = self.image_path(
notify_type=notify_type,
image_size=image_size,
extension=extension,
)
if path:
try:
with open(path, 'rb') as fd:
return fd.read()
except (OSError, IOError):
# We can't access the file
return None
return None
def details(self):
"""
Returns the details associated with the AppriseAsset object
"""
return {
'app_id': self.app_id,
'app_desc': self.app_desc,
'default_extension': self.default_extension,
'theme': self.theme,
'image_path_mask': self.image_path_mask,
'image_url_mask': self.image_url_mask,
'image_url_logo': self.image_url_logo,
}
@staticmethod
def hex_to_rgb(value):
"""
Takes a hex string (such as #00ff00) and returns a tuple in the form
of (red, green, blue)
eg: #00ff00 becomes : (0, 65535, 0)
"""
value = value.lstrip('#')
lv = len(value)
return tuple(int(value[i:i + lv // 3], 16)
for i in range(0, lv, lv // 3))
@staticmethod
def hex_to_int(value):
"""
Takes a hex string (such as #00ff00) and returns its integer
equivalent
eg: #00000f becomes : 15
"""
return int(value.lstrip('#'), 16)