import os
import sys
from loguru import logger
from flexget import plugin
from flexget.event import event
from flexget.plugin import DependencyError, PluginWarning
plugin_name = 'toast'
logger = logger.bind(name=plugin_name)
[docs]
class NotifyToast:
"""Send messages via local notification system.
You must have a notification system like dbus for Linux.
Preliminary support for Windows notifications. Not heavily tested yet.
Examples::
notify:
entries:
via:
- toast: yes
notify:
entries:
via:
- toast:
timeout: 5
"""
schema = {
'anyOf': [
{'type': 'boolean', 'enum': [True]},
{
'type': 'object',
'properties': {'timeout': {'type': 'integer'}, 'url': {'type': 'string'}},
'additionalProperties': False,
},
]
}
def __init__(self):
self.windows_classAtom = None
[docs]
def prepare_config(self, config):
if not isinstance(config, dict):
config = {}
config.setdefault('timeout', 4)
config.setdefault('url', '')
return config
[docs]
def mac_notify(self, title, message, config):
config = self.prepare_config(config)
try:
from pync import Notifier
except ImportError as e:
logger.debug('Error importing pync: {}', e)
raise DependencyError(plugin_name, 'pync', f'pync module required. ImportError: {e}')
icon_path = None
try:
import flexget.ui
icon_path = os.path.join(flexget.ui.__path__[0], 'v1', 'app', 'favicon.ico')
except Exception as e:
logger.debug('Error trying to get flexget icon from webui folder: {}', e)
notify_kwargs = {
'subtitle': title,
'title': 'FlexGet Notification',
'appIcon': icon_path,
'timeout': config['timeout'],
}
if config.get('url'):
notify_kwargs['open'] = config.get('url')
try:
Notifier.notify(message, **notify_kwargs)
except Exception as e:
raise PluginWarning(f'Cannot send a notification: {e}')
[docs]
def linux_notify(self, title, message, config):
config = self.prepare_config(config)
try:
from gi.repository import Notify
except ImportError as e:
logger.debug('Error importing Notify: {}', e)
raise DependencyError(
plugin_name, 'gi.repository', f'Notify module required. ImportError: {e}'
)
if not Notify.init('Flexget'):
raise PluginWarning('Unable to init libnotify.')
n = Notify.Notification.new(title, message, None)
timeout = config['timeout'] * 1000
n.set_timeout(timeout)
if not n.show():
raise PluginWarning(f'Unable to send notification for {title}')
[docs]
def windows_notify(self, title, message, config):
config = self.prepare_config(config)
try:
from win32api import GetModuleHandle
from win32con import (
CW_USEDEFAULT,
IDI_APPLICATION,
IMAGE_ICON,
LR_DEFAULTSIZE,
LR_LOADFROMFILE,
WM_USER,
WS_OVERLAPPED,
WS_SYSMENU,
)
from win32gui import (
NIF_ICON,
NIF_INFO,
NIF_MESSAGE,
NIF_TIP,
NIM_ADD,
WNDCLASS,
CreateWindow,
LoadIcon,
LoadImage,
RegisterClass,
Shell_NotifyIcon,
UpdateWindow,
)
except ImportError:
raise DependencyError(
plugin_name,
'pypiwin32',
'pywin32 module is required for desktop notifications on '
'windows. You can install it with `pip install pypiwin32`',
)
# Register the window class.
wc = WNDCLASS()
hinst = wc.hInstance = GetModuleHandle(None)
wc.lpszClassName = 'FlexGetTaskbar'
if not self.windows_classAtom:
self.windows_classAtom = RegisterClass(wc)
style = WS_OVERLAPPED | WS_SYSMENU
hwnd = CreateWindow(
self.windows_classAtom,
'Taskbar',
style,
0,
0,
CW_USEDEFAULT,
CW_USEDEFAULT,
0,
0,
hinst,
None,
)
UpdateWindow(hwnd)
hicon = LoadIcon(0, IDI_APPLICATION)
# Hackily grab the icon from the webui if possible
icon_flags = LR_LOADFROMFILE | LR_DEFAULTSIZE
try:
import flexget.ui
icon_path = os.path.join(flexget.ui.__path__[0], 'v1', 'app', 'favicon.ico')
hicon = LoadImage(hinst, icon_path, IMAGE_ICON, 0, 0, icon_flags)
except Exception as e:
logger.debug('Error trying to get flexget icon from webui folder: {}', e)
# Taskbar icon
flags = NIF_ICON | NIF_MESSAGE | NIF_TIP | NIF_INFO
nid = (
hwnd,
0,
flags,
WM_USER + 20,
hicon,
'FlexGet Notification',
message,
config['timeout'] * 1000,
title,
)
Shell_NotifyIcon(NIM_ADD, nid)
if sys.platform.startswith('win'):
notify = windows_notify
elif sys.platform == 'darwin':
notify = mac_notify
else:
notify = linux_notify
[docs]
@event('plugin.register')
def register_plugin():
plugin.register(NotifyToast, plugin_name, api_ver=2, interfaces=['notifiers'])