mirror of
https://github.com/caronc/apprise.git
synced 2024-12-03 13:33:36 +01:00
Bark Notification Support Added (#582)
This commit is contained in:
parent
d9b2ed5eee
commit
ca0c8460f1
26
.github/PULL_REQUEST_TEMPLATE.md
vendored
26
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -7,7 +7,7 @@
|
||||
<!-- This section is only applicable if you're adding a new service -->
|
||||
* [ ] apprise/plugins/Notify<!--ServiceName goes here-->.py
|
||||
* [ ] setup.py
|
||||
- add new service into the `keywords` section of the `setup()` declaration
|
||||
- add new service into the `KEYWORDS` file located in the root directory
|
||||
* [ ] README.md
|
||||
- add entry for new service to table (as a quick reference)
|
||||
* [ ] packaging/redhat/python-apprise.spec
|
||||
@ -19,3 +19,27 @@
|
||||
* [ ] There is no commented out code in this PR.
|
||||
* [ ] No lint errors (use `flake8`)
|
||||
* [ ] 100% test coverage
|
||||
|
||||
## Testing
|
||||
<!-- If this your code is testable by other users of the program
|
||||
it would be really helpful to define this here -->
|
||||
Anyone can help test this source code as follows:
|
||||
```bash
|
||||
# Create a virtual environment to work in as follows:
|
||||
python3 -m venv apprise
|
||||
|
||||
# Change into our new directory
|
||||
cd apprise
|
||||
|
||||
# Activate our virtual environment
|
||||
source bin/activate
|
||||
|
||||
# Install the branch
|
||||
pip install git+https://github.com/caronc/apprise.git@<this.branch-name>
|
||||
|
||||
# Be sure you're running your Signal API Server and query it like so
|
||||
apprise -t "Test Title" -b "Test Message" \
|
||||
<apprise url related to ticket>
|
||||
|
||||
```
|
||||
|
||||
|
81
KEYWORDS
Normal file
81
KEYWORDS
Normal file
@ -0,0 +1,81 @@
|
||||
Alerts
|
||||
API
|
||||
AWS
|
||||
Boxcar
|
||||
Chat
|
||||
CLI
|
||||
ClickSend
|
||||
DAPNET
|
||||
Dbus
|
||||
Dingtalk
|
||||
Discord
|
||||
Email
|
||||
Emby
|
||||
Faast
|
||||
FCM
|
||||
Flock
|
||||
Gitter
|
||||
Gnome
|
||||
Google
|
||||
Gotify
|
||||
Growl
|
||||
Guilded
|
||||
Home Assistant
|
||||
IFTTT
|
||||
Join
|
||||
Kavenegar
|
||||
KODI
|
||||
Kumulos
|
||||
LaMetric
|
||||
MacOS
|
||||
Mailgun
|
||||
Matrix
|
||||
Mattermost
|
||||
MessageBird
|
||||
Microsoft
|
||||
MQTT
|
||||
MSG91
|
||||
MSTeams
|
||||
Nexmo
|
||||
Nextcloud
|
||||
NextcloudTalk
|
||||
Notica
|
||||
Notifico
|
||||
Ntfy
|
||||
Office365
|
||||
OneSignal
|
||||
Opsgenie
|
||||
ParsePlatform
|
||||
PopcornNotify
|
||||
Prowl
|
||||
PushBullet
|
||||
Pushed
|
||||
Pushjet
|
||||
Push Notifications
|
||||
Pushover
|
||||
PushSafer
|
||||
Reddit
|
||||
Rocket.Chat
|
||||
Ryver
|
||||
SendGrid
|
||||
ServerChan
|
||||
SES
|
||||
Signal
|
||||
SimplePush
|
||||
Sinch
|
||||
Slack
|
||||
SMTP2Go
|
||||
SNS
|
||||
SparkPost
|
||||
Spontit
|
||||
Streamlabs
|
||||
Stride
|
||||
Syslog
|
||||
Techulus
|
||||
Telegram
|
||||
Twilio
|
||||
Twist
|
||||
Twitter
|
||||
Webex
|
||||
Windows
|
||||
XBMC
|
@ -1,4 +1,5 @@
|
||||
include LICENSE
|
||||
include KEYWORDS
|
||||
include README.md
|
||||
include requirements.txt
|
||||
include win-requirements.txt
|
||||
|
@ -36,7 +36,8 @@ The table below identifies the services this tool supports and some example serv
|
||||
| -------------------- | ---------- | ------------ | -------------- |
|
||||
| [Apprise API](https://github.com/caronc/apprise/wiki/Notify_apprise_api) | apprise:// or apprises:// | (TCP) 80 or 443 | apprise://hostname/Token
|
||||
| [AWS SES](https://github.com/caronc/apprise/wiki/Notify_ses) | ses:// | (TCP) 443 | ses://user@domain/AccessKeyID/AccessSecretKey/RegionName<br/>ses://user@domain/AccessKeyID/AccessSecretKey/RegionName/email1/email2/emailN
|
||||
| [Boxcar](https://github.com/caronc/apprise/wiki/Notify_boxcar) | boxcar:// | (TCP) 443 | boxcar://hostname<br />boxcar://hostname/@tag<br/>boxcar://hostname/device_token<br />boxcar://hostname/device_token1/device_token2/device_tokenN<br />boxcar://hostname/@tag/@tag2/device_token
|
||||
| [Bark](https://github.com/caronc/apprise/wiki/Notify_bark) | bark:// | (TCP) 80 or 443 | bark://hostname<br />bark://hostname/device_key<br />bark://hostname/device_key1/device_key2/device_keyN
|
||||
| [Boxcar](https://github.com/caronc/apprise/wiki/Notify_bark) | boxcar:// | (TCP) 443 | boxcar://hostname<br />boxcar://hostname/@tag<br/>boxcar://hostname/device_token<br />boxcar://hostname/device_token1/device_token2/device_tokenN<br />boxcar://hostname/@tag/@tag2/device_token
|
||||
| [Discord](https://github.com/caronc/apprise/wiki/Notify_discord) | discord:// | (TCP) 443 | discord://webhook_id/webhook_token<br />discord://avatar@webhook_id/webhook_token
|
||||
| [Emby](https://github.com/caronc/apprise/wiki/Notify_emby) | emby:// or embys:// | (TCP) 8096 | emby://user@hostname/<br />emby://user:password@hostname
|
||||
| [Enigma2](https://github.com/caronc/apprise/wiki/Notify_enigma2) | enigma2:// or enigma2s:// | (TCP) 80 or 443 | enigma2://hostname
|
||||
|
508
apprise/plugins/NotifyBark.py
Normal file
508
apprise/plugins/NotifyBark.py
Normal file
@ -0,0 +1,508 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2022 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.
|
||||
#
|
||||
# API: https://github.com/Finb/bark-server/blob/master/docs/API_V2.md#python
|
||||
#
|
||||
import six
|
||||
import requests
|
||||
import json
|
||||
|
||||
from .NotifyBase import NotifyBase
|
||||
from ..URLBase import PrivacyMode
|
||||
from ..common import NotifyImageSize
|
||||
from ..common import NotifyType
|
||||
from ..utils import parse_list
|
||||
from ..utils import parse_bool
|
||||
from ..AppriseLocale import gettext_lazy as _
|
||||
|
||||
|
||||
# Sounds generated off of: https://github.com/Finb/Bark/tree/master/Sounds
|
||||
BARK_SOUNDS = (
|
||||
"alarm.caf",
|
||||
"anticipate.caf",
|
||||
"bell.caf",
|
||||
"birdsong.caf",
|
||||
"bloom.caf",
|
||||
"calypso.caf",
|
||||
"chime.caf",
|
||||
"choo.caf",
|
||||
"descent.caf",
|
||||
"electronic.caf",
|
||||
"fanfare.caf",
|
||||
"glass.caf",
|
||||
"gotosleep.caf",
|
||||
"healthnotification.caf",
|
||||
"horn.caf",
|
||||
"ladder.caf",
|
||||
"mailsent.caf",
|
||||
"minuet.caf",
|
||||
"multiwayinvitation.caf",
|
||||
"newmail.caf",
|
||||
"newsflash.caf",
|
||||
"noir.caf",
|
||||
"paymentsuccess.caf",
|
||||
"shake.caf",
|
||||
"sherwoodforest.caf",
|
||||
"silence.caf",
|
||||
"spell.caf",
|
||||
"suspense.caf",
|
||||
"telegraph.caf",
|
||||
"tiptoes.caf",
|
||||
"typewriters.caf",
|
||||
"update.caf",
|
||||
)
|
||||
|
||||
|
||||
# Supported Level Entries
|
||||
class NotifyBarkLevel(object):
|
||||
"""
|
||||
Defines the Bark Level options
|
||||
"""
|
||||
ACTIVE = 'active'
|
||||
|
||||
TIME_SENSITIVE = 'timeSensitive'
|
||||
|
||||
PASSIVE = 'passive'
|
||||
|
||||
|
||||
BARK_LEVELS = (
|
||||
NotifyBarkLevel.ACTIVE,
|
||||
NotifyBarkLevel.TIME_SENSITIVE,
|
||||
NotifyBarkLevel.PASSIVE,
|
||||
)
|
||||
|
||||
|
||||
class NotifyBark(NotifyBase):
|
||||
"""
|
||||
A wrapper for Notify Bark Notifications
|
||||
"""
|
||||
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'Bark'
|
||||
|
||||
# The services URL
|
||||
service_url = 'https://github.com/Finb/Bark'
|
||||
|
||||
# The default protocol
|
||||
protocol = 'bark'
|
||||
|
||||
# The default secure protocol
|
||||
secure_protocol = 'barks'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_bark'
|
||||
|
||||
# Allows the user to specify the NotifyImageSize object; this is supported
|
||||
# through the webhook
|
||||
image_size = NotifyImageSize.XY_128
|
||||
|
||||
# Define object templates
|
||||
templates = (
|
||||
'{schema}://{host}:{port}/{targets}',
|
||||
'{schema}://{user}:{password}@{host}/{targets}',
|
||||
'{schema}://{user}:{password}@{host}:{port}/{targets}',
|
||||
'{schema}://{user}:{password}@{host}/{targets}',
|
||||
)
|
||||
|
||||
# Define our template arguments
|
||||
template_tokens = dict(NotifyBase.template_tokens, **{
|
||||
'host': {
|
||||
'name': _('Hostname'),
|
||||
'type': 'string',
|
||||
'required': True,
|
||||
},
|
||||
'port': {
|
||||
'name': _('Port'),
|
||||
'type': 'int',
|
||||
'min': 1,
|
||||
'max': 65535,
|
||||
},
|
||||
'user': {
|
||||
'name': _('Username'),
|
||||
'type': 'string',
|
||||
},
|
||||
'password': {
|
||||
'name': _('Password'),
|
||||
'type': 'string',
|
||||
'private': True,
|
||||
},
|
||||
'target_device': {
|
||||
'name': _('Target Device'),
|
||||
'type': 'string',
|
||||
'map_to': 'targets',
|
||||
},
|
||||
'targets': {
|
||||
'name': _('Targets'),
|
||||
'type': 'list:string',
|
||||
},
|
||||
})
|
||||
|
||||
# Define our template arguments
|
||||
template_args = dict(NotifyBase.template_args, **{
|
||||
'to': {
|
||||
'alias_of': 'targets',
|
||||
},
|
||||
'sound': {
|
||||
'name': _('Sound'),
|
||||
'type': 'choice:string',
|
||||
'values': BARK_SOUNDS,
|
||||
},
|
||||
'level': {
|
||||
'name': _('Level'),
|
||||
'type': 'choice:string',
|
||||
'values': BARK_LEVELS,
|
||||
},
|
||||
'click': {
|
||||
'name': _('Click'),
|
||||
'type': 'string',
|
||||
},
|
||||
'badge': {
|
||||
'name': _('Badge'),
|
||||
'type': 'int',
|
||||
'min': 0,
|
||||
},
|
||||
'category': {
|
||||
'name': _('Category'),
|
||||
'type': 'string',
|
||||
},
|
||||
'group': {
|
||||
'name': _('Group'),
|
||||
'type': 'string',
|
||||
},
|
||||
'image': {
|
||||
'name': _('Include Image'),
|
||||
'type': 'bool',
|
||||
'default': True,
|
||||
'map_to': 'include_image',
|
||||
},
|
||||
})
|
||||
|
||||
def __init__(self, targets=None, include_image=True, sound=None,
|
||||
category=None, group=None, level=None, click=None,
|
||||
badge=None, **kwargs):
|
||||
"""
|
||||
Initialize Notify Bark Object
|
||||
"""
|
||||
super(NotifyBark, self).__init__(**kwargs)
|
||||
|
||||
# Prepare our URL
|
||||
self.notify_url = '%s://%s/push' % (
|
||||
'https' if self.secure else 'http',
|
||||
self.host,
|
||||
)
|
||||
|
||||
if isinstance(self.port, int):
|
||||
self.notify_url += ':%d' % self.port
|
||||
|
||||
# Assign our category
|
||||
self.category = \
|
||||
category if isinstance(category, six.string_types) else None
|
||||
|
||||
# Assign our group
|
||||
self.group = group if isinstance(group, six.string_types) else None
|
||||
|
||||
# Initialize device list
|
||||
self.targets = parse_list(targets)
|
||||
|
||||
# Place an image inline with the message body
|
||||
self.include_image = include_image
|
||||
|
||||
# A clickthrough option for notifications
|
||||
self.click = click
|
||||
|
||||
# Badge
|
||||
try:
|
||||
# Acquire our badge count if we can:
|
||||
# - We accept both the integer form as well as a string
|
||||
# representation
|
||||
self.badge = int(badge)
|
||||
if self.badge < 0:
|
||||
raise ValueError()
|
||||
|
||||
except TypeError:
|
||||
# NoneType means use Default; this is an okay exception
|
||||
self.badge = None
|
||||
|
||||
except ValueError:
|
||||
self.badge = None
|
||||
self.logger.warning(
|
||||
'The specified Bark badge ({}) is not valid ', badge)
|
||||
|
||||
# Sound (easy-lookup)
|
||||
self.sound = None if not sound else next(
|
||||
(f for f in BARK_SOUNDS if f.startswith(sound.lower())), None)
|
||||
if sound and not self.sound:
|
||||
self.logger.warning(
|
||||
'The specified Bark sound ({}) was not found ', sound)
|
||||
|
||||
# Level
|
||||
self.level = None if not level else next(
|
||||
(f for f in BARK_LEVELS if f[0] == level[0]), None)
|
||||
if level and not self.level:
|
||||
self.logger.warning(
|
||||
'The specified Bark level ({}) is not valid ', level)
|
||||
|
||||
return
|
||||
|
||||
def send(self, body, title='', notify_type=NotifyType.INFO, **kwargs):
|
||||
"""
|
||||
Perform Bark Notification
|
||||
"""
|
||||
|
||||
# error tracking (used for function return)
|
||||
has_error = False
|
||||
|
||||
if not len(self.targets):
|
||||
# We have nothing to notify; we're done
|
||||
self.logger.warning('There are no Bark devices to notify')
|
||||
return False
|
||||
|
||||
# Prepare our headers
|
||||
headers = {
|
||||
'User-Agent': self.app_id,
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
}
|
||||
|
||||
# Prepare our payload (sample below)
|
||||
# {
|
||||
# "body": "Test Bark Server",
|
||||
# "device_key": "nysrshcqielvoxsa",
|
||||
# "title": "bleem",
|
||||
# "category": "category",
|
||||
# "sound": "minuet.caf",
|
||||
# "badge": 1,
|
||||
# "icon": "https://day.app/assets/images/avatar.jpg",
|
||||
# "group": "test",
|
||||
# "url": "https://mritd.com"
|
||||
# }
|
||||
payload = {
|
||||
'title': title if title else self.app_desc,
|
||||
'body': body,
|
||||
}
|
||||
|
||||
# Acquire our image url if configured to do so
|
||||
image_url = None if not self.include_image else \
|
||||
self.image_url(notify_type)
|
||||
|
||||
if image_url:
|
||||
payload['icon'] = image_url
|
||||
|
||||
if self.sound:
|
||||
payload['sound'] = self.sound
|
||||
|
||||
if self.click:
|
||||
payload['url'] = self.click
|
||||
|
||||
if self.badge:
|
||||
payload['badge'] = self.badge
|
||||
|
||||
if self.level:
|
||||
payload['level'] = self.level
|
||||
|
||||
if self.category:
|
||||
payload['category'] = self.category
|
||||
|
||||
if self.group:
|
||||
payload['group'] = self.group
|
||||
|
||||
auth = None
|
||||
if self.user:
|
||||
auth = (self.user, self.password)
|
||||
|
||||
# Create a copy of the targets
|
||||
targets = list(self.targets)
|
||||
|
||||
while len(targets) > 0:
|
||||
# Retrieve our device key
|
||||
target = targets.pop()
|
||||
|
||||
payload['device_key'] = target
|
||||
self.logger.debug('Bark POST URL: %s (cert_verify=%r)' % (
|
||||
self.notify_url, self.verify_certificate,
|
||||
))
|
||||
self.logger.debug('Bark Payload: %s' % str(payload))
|
||||
|
||||
# Always call throttle before any remote server i/o is made
|
||||
self.throttle()
|
||||
try:
|
||||
r = requests.post(
|
||||
self.notify_url,
|
||||
data=json.dumps(payload),
|
||||
headers=headers,
|
||||
auth=auth,
|
||||
verify=self.verify_certificate,
|
||||
timeout=self.request_timeout,
|
||||
)
|
||||
if r.status_code != requests.codes.ok:
|
||||
# We had a problem
|
||||
status_str = \
|
||||
NotifyBark.http_response_code_lookup(
|
||||
r.status_code)
|
||||
|
||||
self.logger.warning(
|
||||
'Failed to send Bark notification to {}: '
|
||||
'{}{}error={}.'.format(
|
||||
target,
|
||||
status_str,
|
||||
', ' if status_str else '',
|
||||
r.status_code))
|
||||
|
||||
self.logger.debug(
|
||||
'Response Details:\r\n{}'.format(r.content))
|
||||
|
||||
# Mark our failure
|
||||
has_error = True
|
||||
continue
|
||||
|
||||
else:
|
||||
self.logger.info(
|
||||
'Sent Bark notification to {}.'.format(target))
|
||||
|
||||
except requests.RequestException as e:
|
||||
self.logger.warning(
|
||||
'A Connection error occurred sending Bark '
|
||||
'notification to {}.'.format(target))
|
||||
self.logger.debug('Socket Exception: %s' % str(e))
|
||||
|
||||
# Mark our failure
|
||||
has_error = True
|
||||
continue
|
||||
|
||||
return not has_error
|
||||
|
||||
def url(self, privacy=False, *args, **kwargs):
|
||||
"""
|
||||
Returns the URL built dynamically based on specified arguments.
|
||||
"""
|
||||
|
||||
# Define any URL parameters
|
||||
params = {
|
||||
'image': 'yes' if self.include_image else 'no',
|
||||
}
|
||||
|
||||
if self.sound:
|
||||
params['sound'] = self.sound
|
||||
|
||||
if self.click:
|
||||
params['click'] = self.click
|
||||
|
||||
if self.badge:
|
||||
params['badge'] = str(self.badge)
|
||||
|
||||
if self.level:
|
||||
params['level'] = self.level
|
||||
|
||||
if self.category:
|
||||
params['category'] = self.category
|
||||
|
||||
if self.group:
|
||||
params['group'] = self.group
|
||||
|
||||
# Extend our parameters
|
||||
params.update(self.url_parameters(privacy=privacy, *args, **kwargs))
|
||||
|
||||
# Determine Authentication
|
||||
auth = ''
|
||||
if self.user and self.password:
|
||||
auth = '{user}:{password}@'.format(
|
||||
user=NotifyBark.quote(self.user, safe=''),
|
||||
password=self.pprint(
|
||||
self.password, privacy, mode=PrivacyMode.Secret, safe=''),
|
||||
)
|
||||
elif self.user:
|
||||
auth = '{user}@'.format(
|
||||
user=NotifyBark.quote(self.user, safe=''),
|
||||
)
|
||||
|
||||
default_port = 443 if self.secure else 80
|
||||
|
||||
return '{schema}://{auth}{hostname}{port}/{targets}?{params}'.format(
|
||||
schema=self.secure_protocol if self.secure else self.protocol,
|
||||
auth=auth,
|
||||
# never encode hostname since we're expecting it to be a valid one
|
||||
hostname=self.host,
|
||||
port='' if self.port is None or self.port == default_port
|
||||
else ':{}'.format(self.port),
|
||||
targets='/'.join(
|
||||
[NotifyBark.quote('{}'.format(x)) for x in self.targets]),
|
||||
params=NotifyBark.urlencode(params),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def parse_url(url):
|
||||
"""
|
||||
Parses the URL and returns enough arguments that can allow
|
||||
us to re-instantiate this object.
|
||||
|
||||
"""
|
||||
|
||||
results = NotifyBase.parse_url(url)
|
||||
if not results:
|
||||
# We're done early as we couldn't load the results
|
||||
return results
|
||||
|
||||
# Apply our targets
|
||||
results['targets'] = NotifyBark.split_path(results['fullpath'])
|
||||
|
||||
# Category
|
||||
if 'category' in results['qsd'] and results['qsd']['category']:
|
||||
results['category'] = NotifyBark.unquote(
|
||||
results['qsd']['category'].strip())
|
||||
|
||||
# Group
|
||||
if 'group' in results['qsd'] and results['qsd']['group']:
|
||||
results['group'] = NotifyBark.unquote(
|
||||
results['qsd']['group'].strip())
|
||||
|
||||
# Badge
|
||||
if 'badge' in results['qsd'] and results['qsd']['badge']:
|
||||
results['badge'] = NotifyBark.unquote(
|
||||
results['qsd']['badge'].strip())
|
||||
|
||||
# Level
|
||||
if 'level' in results['qsd'] and results['qsd']['level']:
|
||||
results['level'] = NotifyBark.unquote(
|
||||
results['qsd']['level'].strip())
|
||||
|
||||
# Click (URL)
|
||||
if 'click' in results['qsd'] and results['qsd']['click']:
|
||||
results['click'] = NotifyBark.unquote(
|
||||
results['qsd']['click'].strip())
|
||||
|
||||
# Sound
|
||||
if 'sound' in results['qsd'] and results['qsd']['sound']:
|
||||
results['sound'] = NotifyBark.unquote(
|
||||
results['qsd']['sound'].strip())
|
||||
|
||||
# The 'to' makes it easier to use yaml configuration
|
||||
if 'to' in results['qsd'] and len(results['qsd']['to']):
|
||||
results['targets'] += \
|
||||
NotifyBark.parse_list(results['qsd']['to'])
|
||||
|
||||
# use image= for consistency with the other plugins
|
||||
results['include_image'] = \
|
||||
parse_bool(results['qsd'].get('image', True))
|
||||
|
||||
return results
|
@ -274,7 +274,7 @@ class NotifyNtfy(NotifyBase):
|
||||
self.logger.warning('There are no ntfy topics to notify')
|
||||
return False
|
||||
|
||||
# Create a copy of the subreddits list
|
||||
# Create a copy of the topics
|
||||
topics = list(self.topics)
|
||||
while len(topics) > 0:
|
||||
# Retrieve our topic
|
||||
|
@ -47,16 +47,16 @@ Apprise is a Python package for simplifying access to all of the different
|
||||
notification services that are out there. Apprise opens the door and makes
|
||||
it easy to access:
|
||||
|
||||
Apprise API, AWS SES, AWS SNS, Boxcar, ClickSend, DAPNET, DingTalk, Discord,
|
||||
E-Mail, Emby, Faast, FCM, Flock, Gitter, Google Chat, Gotify, Growl, Guilded, Home
|
||||
Assistant, IFTTT, Join, Kavenegar, KODI, Kumulos, LaMetric, MacOSX, Mailgun,
|
||||
Mattermost, Matrix, Microsoft Windows, Microsoft Teams, MessageBird, MQTT, MSG91,
|
||||
MyAndroid, Nexmo, Nextcloud, NextcloudTalk, Notica, Notifico, ntfy, Office365,
|
||||
OneSignal, Opsgenie, ParsePlatform, PopcornNotify, Prowl, Pushalot,
|
||||
PushBullet, Pushjet, Pushover, PushSafer, Reddit, Rocket.Chat, SendGrid,
|
||||
ServerChan, Signal, SimplePush, Sinch, Slack, SMTP2Go, Spontit, SparkPost,
|
||||
Super Toasty, Streamlabs, Stride, Syslog, Techulus Push, Telegram, Twilio,
|
||||
Twitter, Twist, XBMC, XMPP, Webex Teams}
|
||||
Apprise API, AWS SES, AWS SNS, Bark, Boxcar, ClickSend, DAPNET, DingTalk,
|
||||
Discord, E-Mail, Emby, Faast, FCM, Flock, Gitter, Google Chat, Gotify, Growl,
|
||||
Guilded, Home Assistant, IFTTT, Join, Kavenegar, KODI, Kumulos, LaMetric,
|
||||
MacOSX, Mailgun, Mattermost, Matrix, Microsoft Windows, Microsoft Teams,
|
||||
MessageBird, MQTT, MSG91, MyAndroid, Nexmo, Nextcloud, NextcloudTalk, Notica,
|
||||
Notifico, ntfy, Office365, OneSignal, Opsgenie, ParsePlatform, PopcornNotify,
|
||||
Prowl, Pushalot, PushBullet, Pushjet, Pushover, PushSafer, Reddit,
|
||||
Rocket.Chat, SendGrid, ServerChan, Signal, SimplePush, Sinch, Slack, SMTP2Go,
|
||||
Spontit, SparkPost, Super Toasty, Streamlabs, Stride, Syslog, Techulus Push,
|
||||
Telegram, Twilio, Twitter, Twist, XBMC, XMPP, Webex Teams}
|
||||
|
||||
Name: python-%{pypi_name}
|
||||
Version: 0.9.8.3
|
||||
|
12
setup.py
12
setup.py
@ -24,6 +24,7 @@
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
import re
|
||||
import os
|
||||
import platform
|
||||
try:
|
||||
@ -69,16 +70,7 @@ setup(
|
||||
long_description_content_type='text/markdown',
|
||||
cmdclass=cmdclass,
|
||||
url='https://github.com/caronc/apprise',
|
||||
keywords='Push Notifications Alerts Email AWS SES SNS Boxcar ClickSend '
|
||||
'DAPNET Dingtalk Discord Dbus Emby Faast FCM Flock Gitter Gnome '
|
||||
'Google Chat Gotify Growl Guilded Home Assistant IFTTT Join Kavenegar '
|
||||
'KODI Kumulos LaMetric MacOS Mailgun Matrix Mattermost MessageBird '
|
||||
'MQTT MSG91 Nexmo Nextcloud NextcloudTalk Notica Notifico Ntfy '
|
||||
'Office365 OneSignal Opsgenie ParsePlatform PopcornNotify Prowl '
|
||||
'PushBullet Pushjet Pushed Pushover PushSafer Reddit Rocket.Chat '
|
||||
'Ryver SendGrid ServerChan Signal SimplePush Sinch Slack SMTP2Go '
|
||||
'SparkPost Spontit Streamlabs Stride Syslog Techulus Telegram Twilio '
|
||||
'Twist Twitter XBMC MSTeams Microsoft Windows Webex CLI API',
|
||||
keywords=' '.join(re.split(r'\s+', open('KEYWORDS').read())),
|
||||
author='Chris Caron',
|
||||
author_email='lead2gold@gmail.com',
|
||||
packages=find_packages(),
|
||||
|
148
test/test_plugin_bark.py
Normal file
148
test/test_plugin_bark.py
Normal file
@ -0,0 +1,148 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2022 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.
|
||||
from apprise import plugins
|
||||
from helpers import AppriseURLTester
|
||||
|
||||
# Disable logging for a cleaner testing output
|
||||
import logging
|
||||
logging.disable(logging.CRITICAL)
|
||||
|
||||
# Our Testing URLs
|
||||
apprise_url_tests = (
|
||||
('bark://', {
|
||||
# No no host
|
||||
'instance': None,
|
||||
}),
|
||||
('bark://:@/', {
|
||||
# just invalid all around
|
||||
'instance': None,
|
||||
}),
|
||||
('bark://localhost', {
|
||||
# No Device Key specified
|
||||
'instance': plugins.NotifyBark,
|
||||
# Expected notify() response False (because we won't be able
|
||||
# to actually notify anything if no device_key was specified
|
||||
'notify_response': False,
|
||||
|
||||
}),
|
||||
('bark://192.168.0.6:8081/device_key', {
|
||||
# Everything is okay
|
||||
'instance': plugins.NotifyBark,
|
||||
|
||||
# Our expected url(privacy=True) startswith() response:
|
||||
'privacy_url': 'bark://192.168.0.6:8081/',
|
||||
}),
|
||||
('bark://user@192.168.0.6:8081/device_key', {
|
||||
# Everything is okay (test with user)
|
||||
'instance': plugins.NotifyBark,
|
||||
|
||||
# Our expected url(privacy=True) startswith() response:
|
||||
'privacy_url': 'bark://user@192.168.0.6:8081/',
|
||||
}),
|
||||
('bark://192.168.0.6:8081/device_key/?sound=invalid', {
|
||||
# bad sound, but we go ahead anyway
|
||||
'instance': plugins.NotifyBark,
|
||||
}),
|
||||
('bark://192.168.0.6:8081/device_key/?sound=alarm', {
|
||||
# alarm.caf sound loaded
|
||||
'instance': plugins.NotifyBark,
|
||||
}),
|
||||
('bark://192.168.0.6:8081/device_key/?sound=NOiR.cAf', {
|
||||
# noir.caf sound loaded
|
||||
'instance': plugins.NotifyBark,
|
||||
}),
|
||||
('bark://192.168.0.6:8081/device_key/?badge=100', {
|
||||
# set badge
|
||||
'instance': plugins.NotifyBark,
|
||||
}),
|
||||
('barks://192.168.0.6:8081/device_key/?badge=invalid', {
|
||||
# set invalid badge
|
||||
'instance': plugins.NotifyBark,
|
||||
}),
|
||||
('barks://192.168.0.6:8081/device_key/?badge=-12', {
|
||||
# set invalid badge
|
||||
'instance': plugins.NotifyBark,
|
||||
}),
|
||||
('bark://192.168.0.6:8081/device_key/?category=apprise', {
|
||||
# set category
|
||||
'instance': plugins.NotifyBark,
|
||||
}),
|
||||
('bark://192.168.0.6:8081/device_key/?image=no', {
|
||||
# do not display image
|
||||
'instance': plugins.NotifyBark,
|
||||
}),
|
||||
('bark://192.168.0.6:8081/device_key/?group=apprise', {
|
||||
# set group
|
||||
'instance': plugins.NotifyBark,
|
||||
}),
|
||||
('bark://192.168.0.6:8081/device_key/?level=invalid', {
|
||||
# bad level, but we go ahead anyway
|
||||
'instance': plugins.NotifyBark,
|
||||
}),
|
||||
('bark://192.168.0.6:8081/?to=device_key', {
|
||||
# test use of to= argument
|
||||
'instance': plugins.NotifyBark,
|
||||
}),
|
||||
('bark://192.168.0.6:8081/device_key/?click=http://localhost', {
|
||||
# Our click link
|
||||
'instance': plugins.NotifyBark,
|
||||
}),
|
||||
('bark://192.168.0.6:8081/device_key/?level=active', {
|
||||
# active level
|
||||
'instance': plugins.NotifyBark,
|
||||
}),
|
||||
('bark://user:pass@192.168.0.5:8086/device_key/device_key2/', {
|
||||
# Everything is okay
|
||||
'instance': plugins.NotifyBark,
|
||||
|
||||
# Our expected url(privacy=True) startswith() response:
|
||||
'privacy_url': 'bark://user:****@192.168.0.5:8086/',
|
||||
}),
|
||||
('barks://192.168.0.7/device_key/', {
|
||||
'instance': plugins.NotifyBark,
|
||||
# throw a bizzare code forcing us to fail to look it up
|
||||
'response': False,
|
||||
'requests_response_code': 999,
|
||||
|
||||
# Our expected url(privacy=True) startswith() response:
|
||||
'privacy_url': 'barks://192.168.0.7/device_key',
|
||||
}),
|
||||
('bark://192.168.0.7/device_key', {
|
||||
'instance': plugins.NotifyBark,
|
||||
# Throws a series of connection and transfer exceptions when this flag
|
||||
# is set and tests that we gracfully handle them
|
||||
'test_requests_exceptions': True,
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
def test_plugin_bark_urls():
|
||||
"""
|
||||
NotifyBark() Apprise URLs
|
||||
|
||||
"""
|
||||
|
||||
# Run our general tests
|
||||
AppriseURLTester(tests=apprise_url_tests).run_all()
|
Loading…
Reference in New Issue
Block a user