1from loguru import logger
2from requests.exceptions import RequestException
3
4from flexget import plugin
5from flexget.event import event
6from flexget.plugin import PluginWarning
7from flexget.utils.requests import Session as RequestSession
8
9requests = RequestSession(max_retries=3)
10
11plugin_name = 'slack'
12
13logger = logger.bind(name=plugin_name)
14
15
16class SlackNotifier:
17    """
18    Example:
19
20      notify:
21        entries:
22          via:
23            - slack:
24                web_hook_url: <string>
25                [channel: <string>] (override channel, use "@username" or "#channel")
26                [username: <string>] (override username)
27                [icon_emoji: <string>] (override emoji icon)
28                [icon_url: <string>] (override emoji icon)
29                [attachments: <array>[<object>]] (override attachments)
30
31    """
32
33    schema = {
34        'type': 'object',
35        'properties': {
36            'web_hook_url': {'type': 'string', 'format': 'uri'},
37            'username': {'type': 'string', 'default': 'Flexget'},
38            'icon_url': {'type': 'string', 'format': 'uri'},
39            'icon_emoji': {'type': 'string'},
40            'channel': {'type': 'string'},
41            'unfurl_links': {'type': 'boolean'},
42            'message': {'type': 'string'},
43            'attachments': {
44                'type': 'array',
45                'items': {
46                    'type': 'object',
47                    'properties': {
48                        'title': {'type': 'string'},
49                        'author_name': {'type': 'string'},
50                        'author_link': {'type': 'string'},
51                        'author_icon': {'type': 'string'},
52                        'title_link': {'type': 'string'},
53                        'image_url': {'type': 'string'},
54                        'thumb_url': {'type': 'string'},
55                        'footer': {'type': 'string'},
56                        'footer_icon': {'type': 'string'},
57                        'ts': {'type': 'number'},
58                        'fallback': {'type': 'string'},
59                        'text': {'type': 'string'},
60                        'pretext': {'type': 'string'},
61                        'color': {'type': 'string'},
62                        'fields': {
63                            'type': 'array',
64                            'minItems': 1,
65                            'items': {
66                                'type': 'object',
67                                'properties': {
68                                    'title': {'type': 'string'},
69                                    'value': {'type': 'string'},
70                                    'short': {'type': 'boolean'},
71                                },
72                                'required': ['title'],
73                                'additionalProperties': False,
74                            },
75                        },
76                        'actions': {
77                            'type': 'array',
78                            'minItems': 1,
79                            'items': {
80                                'type': 'object',
81                                'properties': {
82                                    'name': {'type': 'string'},
83                                    'text': {'type': 'string'},
84                                    'type': {'type': 'string'},
85                                    'value': {'type': 'string'},
86                                },
87                                'required': ['name', 'text', 'type', 'value'],
88                                'additionalProperties': False,
89                            },
90                        },
91                        'callback_id': {'type': 'string'},
92                    },
93                    'required': ['fallback'],
94                    'dependencies': {'actions': ['callback_id']},
95                    'additionalProperties': False,
96                },
97            },
98        },
99        'not': {'required': ['icon_emoji', 'icon_url']},
100        'error_not': 'Can only use one of \'icon_emoji\' or \'icon_url\'',
101        'required': ['web_hook_url'],
102        'additionalProperties': False,
103    }
104
105    def notify(self, title, message, config):
106        """
107        Send a Slack notification
108        """
109        notification = {
110            'text': message,
111            'username': config.get('username'),
112            'channel': config.get('channel'),
113            'attachments': config.get('attachments'),
114        }
115        if config.get('icon_emoji'):
116            notification['icon_emoji'] = ':%s:' % config['icon_emoji'].strip(':')
117        if config.get('icon_url'):
118            notification['icon_url'] = config['icon_url']
119
120        try:
121            requests.post(config['web_hook_url'], json=notification)
122        except RequestException as e:
123            raise PluginWarning(e.args[0])
124
125
126@event('plugin.register')
127def register_plugin():
128    plugin.register(SlackNotifier, plugin_name, api_ver=2, interfaces=['notifiers'])
129