Skip to content

Instantly share code, notes, and snippets.

@Feuermurmel
Last active August 29, 2015 14:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Feuermurmel/c53decd96d7ca55d65e6 to your computer and use it in GitHub Desktop.
Save Feuermurmel/c53decd96d7ca55d65e6 to your computer and use it in GitHub Desktop.
prowl.py
#! /usr/bin/env python3
import os, sys, argparse, subprocess, json, re, getpass, socket, requests
script_dir = os.path.dirname(os.path.realpath(__file__))
terminal_notifier = os.path.join(script_dir, 'terminal-notifier.app/Contents/MacOS/terminal-notifier')
def log(msg, *args):
print(msg.format(*args), file = sys.stderr)
def read_file(path):
with open(path, 'rb') as file:
return file.read()
def write_file(path, data):
temp_path = path + '~'
os.makedirs(os.path.dirname(path), exist_ok = True)
with open(temp_path, 'wb') as file:
file.write(data)
os.rename(temp_path, path)
class UserError(Exception):
def __init__(self, msg, *args):
self.message = msg.format(*args)
class Settings:
def __init__(self, path):
self._path = path
self._values = None
def _load_values(self):
if self._values is None:
if os.path.exists(self._path):
self._values = json.loads(read_file(self._path).decode())
else:
self._values = { }
def _save_values(self):
if self._values is not None:
write_file(self._path, json.dumps(self._values).encode())
def get(self, key, default = None):
self._load_values()
return self._values.get(key, default)
def set(self, key, value):
self._load_values()
self._values[key] = value
self._save_values()
def api_key_type(value):
if not re.match('[0-9a-f]{40}$', value):
raise UserError('Invalid API key specified.')
return value
def api_argument_type(value):
"""A workaround for the Prowl API not accepting the string "0" as a valid argument."""
if value == '0':
value += ' '
return value
def parse_args():
usage = '\n'.join([
'prowl --help',
' prowl --set-api-key=<api-key>',
' prowl [<options>] [<event>] <description>'])
parser = argparse.ArgumentParser(description = 'Deliver a notification using Prowl for iOS.', usage = usage)
parser.add_argument('event', type = api_argument_type, nargs = '?', help = 'The event part of the notification.')
parser.add_argument('description', type = api_argument_type, nargs = '?', help = 'The description part of the notification.')
parser.add_argument('-a', '--application', type = api_argument_type, help = 'The application part of the notification. Defaults current user\'s name and the host\'s name in the form of <username>@<hostname>.')
parser.add_argument('-u', '--url', help = 'URL that should be opened when the notification is activated.')
parser.add_argument('-p', '--priority', type = int, default = 0, help = 'The priority of the notification. Specify a number from -2 to 2. Defaults to 0.')
parser.add_argument('-k', '--api-key', type = api_key_type, help = 'API key to use for the notification.')
parser.add_argument('--set-api-key', type = api_key_type, help = 'Set the default API key used for calls where -k is not specified.')
args = parser.parse_args()
if args.set_api_key is None:
# If no event is given, the description is actually stored in event.
if args.event is None:
raise UserError('Required argument `description\' missing.')
if args.description is None:
args.description = args.event
args.event = None
if not (-2 <= args.priority <= 2):
raise UserError('Invalid value for --priority: {}', args.priority)
else:
if any(i is not None for i in [args.event, args.application, args.url, args.priority, args.api_key]):
raise UserError('Cannot use --set-api-key with any other arguments or options.')
return args
def main():
settings = Settings(os.path.join(os.path.expanduser('~'), 'opt/etc/prowl.json'))
args = parse_args()
if args.set_api_key is None:
api_key = args.api_key
application = args.application
if api_key is None:
api_key = settings.get('default-api-key')
if api_key is None:
raise UserError('--api-key is mandatory if because default API key has been set.')
if application is None:
application = '{}@{}'.format(getpass.getuser(), socket.gethostname())
def iter_arguments():
yield 'apikey', api_key
yield 'application', application
if args.url is not None:
yield 'url', args.url
if args.event is not None:
yield 'event', args.event
if args.description:
yield 'description', args.description
if args.priority:
yield 'priority', args.priority
response = requests.post('https://api.prowlapp.com/publicapi/add', dict(iter_arguments()))
if not response.ok:
raise UserError('Error received from server: {}', response.content)
else:
settings.set('default-api-key', args.set_api_key)
try:
main()
except UserError as e:
log('Error: {}', e.message)
except KeyboardInterrupt:
log('Operation interrupted.')
usage: prowl --help
prowl --set-api-key=<api-key>
prowl [<options>] [<event>] <description>
Deliver a notification using Prowl for iOS.
positional arguments:
event The event part of the notification.
description The description part of the notification.
optional arguments:
-h, --help show this help message and exit
-a APPLICATION, --application APPLICATION
The application part of the notification. Defaults
current user's name and the host's name in the form of
<username>@<hostname>.
-u URL, --url URL URL that should be opened when the notification is
activated.
-p PRIORITY, --priority PRIORITY
The priority of the notification. Specify a number
from -2 to 2. Defaults to 0.
-k API_KEY, --api-key API_KEY
API key to use for the notification.
--set-api-key SET_API_KEY
Set the default API key used for calls where -k is not
specified.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment