We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Can’t send email notification with full statistics including rejected and undecided entries (not only accepted/failed ones)
### Expected behaviour:
notification with accepted|rejected|undecided|failed entries is sent

### Actual behaviour:
notification with only accepted and failed entries is sent

### Steps to reproduce:
- Step 1: add to tasks "digest" plugin with "accepted|rejected|undecided|failed" options
- Step 2: add "emailreport" task with "notify" and "from_digest" plugins and "restore_state: yes" option
- Step 3: execute tasks from step 1

#### Config example:
```
schedules:
  - tasks: 'task1'
    interval:
      hours: 2
  - tasks: 'task2'
    interval:
      hours: 4
  - tasks: 'emailreport'
    schedule:
      hour: 21
...
templates:
  ...
  video:
    digest:
        list: email_list
        state:
          - accepted
          - rejected
          - undecided
          - failed
...
tasks:
  task1:
    template:
      - video
...
  task2:
    template:
      - video
...
  emailreport:
    no_entries_ok: yes
    from_digest:
      list: email_list
      restore_state: yes
    seen: local

    notify:
      task:
        title: "[FLEXGET] Daily report"
        template: custom_html.template
        via:
          - email:
              from: '{? email.email_from ?}'
              to:
                - '{? email.email_to1 ?}'
                - '{? email.email_to2 ?}'
              smtp_host: smtp.gmail.com
              smtp_port: 587
              smtp_username: '{? email.smtp_username ?}'
              smtp_password: '{? email.smtp_password ?}'
              smtp_tls: yes
              html: yes
```
  
#### Log:
```
2017-01-26 21:00 VERBOSE  details       emailreport     Produced 586 entries.
2017-01-26 21:00 VERBOSE  manipulate    emailreport     Modified 0 entries.
2017-01-26 21:00 VERBOSE  details       emailreport     Summary - Accepted: 0 (Rejected: 1070 Undecided: 586 Failed: 0)
2017-01-26 21:00 WARNING  task          emailreport     Task doesn't have any output plugins, you should add (at least) one!
2017-01-26 21:00 VERBOSE  notify_entry  emailreport     No accepted or failed entries, not sending a notification.
```

### Additional information:

- Flexget Version: 2.9.8
- Python Version: 2.7.12
- Installation method: pip
- OS and version: Ubuntu 16.04

P.S.
As @liiight proposed maybe "always_send" should be added to the "notify" plugin

Related issue and FR in forum:
https://discuss.flexget.com/t/cant-send-email-notification-with-full-statistics-including-rejected-and-undecided-entries-not-only-accepted-failed-ones/3129
https://discuss.flexget.com/t/add-always-send-option-to-notify-plugin/3130?source_topic_id=3129


Can’t send email notification with full statistics including rejected and undecided entries (not only accepted/failed ones)
### Expected behaviour:
notification with accepted|rejected|undecided|failed entries is sent

### Actual behaviour:
notification with only accepted and failed entries is sent

### Steps to reproduce:
- Step 1: add to tasks "digest" plugin with "accepted|rejected|undecided|failed" options
- Step 2: add "emailreport" task with "notify" and "from_digest" plugins and "restore_state: yes" option
- Step 3: execute tasks from step 1

#### Config example:
```
schedules:
  - tasks: 'task1'
    interval:
      hours: 2
  - tasks: 'task2'
    interval:
      hours: 4
  - tasks: 'emailreport'
    schedule:
      hour: 21
...
templates:
  ...
  video:
    digest:
        list: email_list
        state:
          - accepted
          - rejected
          - undecided
          - failed
...
tasks:
  task1:
    template:
      - video
...
  task2:
    template:
      - video
...
  emailreport:
    no_entries_ok: yes
    from_digest:
      list: email_list
      restore_state: yes
    seen: local

    notify:
      task:
        title: "[FLEXGET] Daily report"
        template: custom_html.template
        via:
          - email:
              from: '{? email.email_from ?}'
              to:
                - '{? email.email_to1 ?}'
                - '{? email.email_to2 ?}'
              smtp_host: smtp.gmail.com
              smtp_port: 587
              smtp_username: '{? email.smtp_username ?}'
              smtp_password: '{? email.smtp_password ?}'
              smtp_tls: yes
              html: yes
```
  
#### Log:
```
2017-01-26 21:00 VERBOSE  details       emailreport     Produced 586 entries.
2017-01-26 21:00 VERBOSE  manipulate    emailreport     Modified 0 entries.
2017-01-26 21:00 VERBOSE  details       emailreport     Summary - Accepted: 0 (Rejected: 1070 Undecided: 586 Failed: 0)
2017-01-26 21:00 WARNING  task          emailreport     Task doesn't have any output plugins, you should add (at least) one!
2017-01-26 21:00 VERBOSE  notify_entry  emailreport     No accepted or failed entries, not sending a notification.
```

### Additional information:

- Flexget Version: 2.9.8
- Python Version: 2.7.12
- Installation method: pip
- OS and version: Ubuntu 16.04

P.S.
As @liiight proposed maybe "always_send" should be added to the "notify" plugin

Related issue and FR in forum:
https://discuss.flexget.com/t/cant-send-email-notification-with-full-statistics-including-rejected-and-undecided-entries-not-only-accepted-failed-ones/3129
https://discuss.flexget.com/t/add-always-send-option-to-notify-plugin/3130?source_topic_id=3129



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `flexget/plugins/notifiers/notify.py`
Content:
```
1 from __future__ import unicode_literals, division, absolute_import
2 from builtins import *  # noqa pylint: disable=unused-import, redefined-builtin
3 
4 import logging
5 
6 import itertools
7 from flexget import plugin
8 from flexget.config_schema import one_or_more
9 from flexget.event import event
10 from flexget.utils.template import get_template
11 
12 log = logging.getLogger('notify_entry')
13 
14 ENTRY_CONTAINERS = ['entries', 'accepted', 'rejected', 'failed', 'undecided']
15 
16 VIA_SCHEMA = {
17     'type': 'array',
18     'items': {
19         'allOf': [
20             {'$ref': '/schema/plugins?interface=notifiers'},
21             {
22                 'maxProperties': 1,
23                 'error_maxProperties': 'Plugin options indented 2 more spaces than '
24                                        'the first letter of the plugin name.',
25                 'minProperties': 1
26             }
27         ]
28     }
29 }
30 
31 
32 class Notify(object):
33     schema = {
34         'type': 'object',
35         'properties': {
36             'entries': {
37                 'type': 'object',
38                 'properties': {
39                     'title': {'type': 'string', 'default': '{{ title }}'},
40                     'message': {
41                         'type': 'string',
42                         'default': '{% if series_name is defined %}'
43                                    '{{ tvdb_series_name|d(series_name) }} '
44                                    '{{series_id}} {{tvdb_ep_name|d('')}}'
45                                    '{% elif imdb_name is defined %}'
46                                    '{{imdb_name}} {{imdb_year}}'
47                                    '{% elif title is defined %}'
48                                    '{{ title }}'
49                                    '{% endif %}'
50                     },
51                     'template': {'type': 'string'},
52                     'what': one_or_more({'type': 'string', 'enum': ENTRY_CONTAINERS}),
53                     'via': VIA_SCHEMA
54                 },
55                 'required': ['via'],
56                 'additionalProperties': False
57             },
58             'task': {
59                 'type': 'object',
60                 'properties': {
61                     'title': {
62                         'type': 'string',
63                         'default': '[FlexGet] {{task.name}}:'
64                                    '{%if task.failed %} {{task.failed|length}} failed entries.{% endif %}'
65                                    '{% if task.accepted %} {{task.accepted|length}} new entries downloaded.{% endif %}'},
66                     'template': {'type': 'string', 'default': 'default.template'},
67                     'via': VIA_SCHEMA
68                 },
69                 'required': ['via'],
70                 'additionalProperties': False
71             },
72             'abort': {
73                 'type': 'object',
74                 'properties': {
75                     'title': {'type': 'string', 'default': 'Task {{ task.name }} has aborted!'},
76                     'message': {'type': 'string', 'default': 'Reason: {{ task.abort_reason }}'},
77                     'via': VIA_SCHEMA
78                 },
79                 'required': ['via']
80             }
81         },
82         'additionalProperties': False,
83         'minProperties': 1,
84         'error_minProperties': 'You must specify at least one of `entries` or `task` in your notify config.'
85     }
86 
87     def prepare_config(self, config):
88         if 'entries' in config:
89             config['entries'].setdefault('what', ['accepted'])
90             if not isinstance(config['entries']['what'], list):
91                 config['entries']['what'] = [config['entries']['what']]
92         return config
93 
94     def send_notification(self, *args, **kwargs):
95         send_notification = plugin.get_plugin_by_name('notification_framework').instance.send_notification
96         try:
97             send_notification(*args, **kwargs)
98         except plugin.PluginError as e:
99             log.error(e)
100         except plugin.PluginWarning as e:
101             log.warning(e)
102         except Exception as e:
103             log.exception(e)
104 
105     @plugin.priority(0)
106     def on_task_output(self, task, config):
107         config = self.prepare_config(config)
108         if 'entries' in config:
109             entries = list(itertools.chain(*(getattr(task, what) for what in config['entries']['what'])))
110             if not entries:
111                 log.debug('No entries to notify about.')
112                 return
113             # If a file template is defined, it overrides message
114             if config['entries'].get('template'):
115                 try:
116                     message = get_template(config['entries']['template'], scope='entry')
117                 except ValueError:
118                     raise plugin.PluginError('Cannot locate template on disk: %s' % config['entries']['template'])
119             else:
120                 message = config['entries']['message']
121             for entry in entries:
122                 self.send_notification(config['entries']['title'], message, config['entries']['via'],
123                                        template_renderer=entry.render)
124         if 'task' in config:
125             if not (task.accepted or task.failed):
126                 log.verbose('No accepted or failed entries, not sending a notification.')
127                 return
128             try:
129                 template = get_template(config['task']['template'], scope='task')
130             except ValueError:
131                 raise plugin.PluginError('Cannot locate template on disk: %s' % config['task']['template'])
132             self.send_notification(config['task']['title'], template, config['task']['via'],
133                                    template_renderer=task.render)
134 
135     def on_task_abort(self, task, config):
136         if 'abort' in config:
137             if task.silent_abort:
138                 return
139             log.debug('sending abort notification')
140             self.send_notification(config['abort']['title'], config['abort']['message'], config['abort']['via'],
141                                    template_renderer=task.render)
142 
143 
144 @event('plugin.register')
145 def register_plugin():
146     plugin.register(Notify, 'notify', api_ver=2)
147
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/flexget/plugins/notifiers/notify.py b/flexget/plugins/notifiers/notify.py
--- a/flexget/plugins/notifiers/notify.py
+++ b/flexget/plugins/notifiers/notify.py
@@ -60,10 +60,15 @@
                 'properties': {
                     'title': {
                         'type': 'string',
-                        'default': '[FlexGet] {{task.name}}:'
-                                   '{%if task.failed %} {{task.failed|length}} failed entries.{% endif %}'
-                                   '{% if task.accepted %} {{task.accepted|length}} new entries downloaded.{% endif %}'},
+                        'default': '{% if not task.failed or not task.accepted %} Task {{task.name}} did not'
+                                   ' produce any entries.'
+                                   '{% else %} [FlexGet] {{task.name}}:'
+                                   '{% if task.failed %} {{task.failed|length}} failed entries.{% endif %}'
+                                   '{% if task.accepted %} {{task.accepted|length}} new entries downloaded.{% endif %}'
+                                   '{% endif %}'
+                    },
                     'template': {'type': 'string', 'default': 'default.template'},
+                    'always_send': {'type': 'boolean', 'default': False},
                     'via': VIA_SCHEMA
                 },
                 'required': ['via'],
@@ -122,7 +127,7 @@
                 self.send_notification(config['entries']['title'], message, config['entries']['via'],
                                        template_renderer=entry.render)
         if 'task' in config:
-            if not (task.accepted or task.failed):
+            if not (task.accepted or task.failed) and not config['task']['always_send']:
                 log.verbose('No accepted or failed entries, not sending a notification.')
                 return
             try:

{"golden_diff": "diff --git a/flexget/plugins/notifiers/notify.py b/flexget/plugins/notifiers/notify.py\n--- a/flexget/plugins/notifiers/notify.py\n+++ b/flexget/plugins/notifiers/notify.py\n@@ -60,10 +60,15 @@\n                 'properties': {\n                     'title': {\n                         'type': 'string',\n-                        'default': '[FlexGet] {{task.name}}:'\n-                                   '{%if task.failed %} {{task.failed|length}} failed entries.{% endif %}'\n-                                   '{% if task.accepted %} {{task.accepted|length}} new entries downloaded.{% endif %}'},\n+                        'default': '{% if not task.failed or not task.accepted %} Task {{task.name}} did not'\n+                                   ' produce any entries.'\n+                                   '{% else %} [FlexGet] {{task.name}}:'\n+                                   '{% if task.failed %} {{task.failed|length}} failed entries.{% endif %}'\n+                                   '{% if task.accepted %} {{task.accepted|length}} new entries downloaded.{% endif %}'\n+                                   '{% endif %}'\n+                    },\n                     'template': {'type': 'string', 'default': 'default.template'},\n+                    'always_send': {'type': 'boolean', 'default': False},\n                     'via': VIA_SCHEMA\n                 },\n                 'required': ['via'],\n@@ -122,7 +127,7 @@\n                 self.send_notification(config['entries']['title'], message, config['entries']['via'],\n                                        template_renderer=entry.render)\n         if 'task' in config:\n-            if not (task.accepted or task.failed):\n+            if not (task.accepted or task.failed) and not config['task']['always_send']:\n                 log.verbose('No accepted or failed entries, not sending a notification.')\n                 return\n             try:\n", "issue": "Can\u2019t send email notification with full statistics including rejected and undecided entries (not only accepted/failed ones)\n### Expected behaviour:\r\nnotification with accepted|rejected|undecided|failed entries is sent\r\n\r\n### Actual behaviour:\r\nnotification with only accepted and failed entries is sent\r\n\r\n### Steps to reproduce:\r\n- Step 1: add to tasks \"digest\" plugin with \"accepted|rejected|undecided|failed\" options\r\n- Step 2: add \"emailreport\" task with \"notify\" and \"from_digest\" plugins and \"restore_state: yes\" option\r\n- Step 3: execute tasks from step 1\r\n\r\n#### Config example:\r\n```\r\nschedules:\r\n  - tasks: 'task1'\r\n    interval:\r\n      hours: 2\r\n  - tasks: 'task2'\r\n    interval:\r\n      hours: 4\r\n  - tasks: 'emailreport'\r\n    schedule:\r\n      hour: 21\r\n...\r\ntemplates:\r\n  ...\r\n  video:\r\n    digest:\r\n        list: email_list\r\n        state:\r\n          - accepted\r\n          - rejected\r\n          - undecided\r\n          - failed\r\n...\r\ntasks:\r\n  task1:\r\n    template:\r\n      - video\r\n...\r\n  task2:\r\n    template:\r\n      - video\r\n...\r\n  emailreport:\r\n    no_entries_ok: yes\r\n    from_digest:\r\n      list: email_list\r\n      restore_state: yes\r\n    seen: local\r\n\r\n    notify:\r\n      task:\r\n        title: \"[FLEXGET] Daily report\"\r\n        template: custom_html.template\r\n        via:\r\n          - email:\r\n              from: '{? email.email_from ?}'\r\n              to:\r\n                - '{? email.email_to1 ?}'\r\n                - '{? email.email_to2 ?}'\r\n              smtp_host: smtp.gmail.com\r\n              smtp_port: 587\r\n              smtp_username: '{? email.smtp_username ?}'\r\n              smtp_password: '{? email.smtp_password ?}'\r\n              smtp_tls: yes\r\n              html: yes\r\n```\r\n  \r\n#### Log:\r\n```\r\n2017-01-26 21:00 VERBOSE  details       emailreport     Produced 586 entries.\r\n2017-01-26 21:00 VERBOSE  manipulate    emailreport     Modified 0 entries.\r\n2017-01-26 21:00 VERBOSE  details       emailreport     Summary - Accepted: 0 (Rejected: 1070 Undecided: 586 Failed: 0)\r\n2017-01-26 21:00 WARNING  task          emailreport     Task doesn't have any output plugins, you should add (at least) one!\r\n2017-01-26 21:00 VERBOSE  notify_entry  emailreport     No accepted or failed entries, not sending a notification.\r\n```\r\n\r\n### Additional information:\r\n\r\n- Flexget Version: 2.9.8\r\n- Python Version: 2.7.12\r\n- Installation method: pip\r\n- OS and version: Ubuntu 16.04\r\n\r\nP.S.\r\nAs @liiight proposed maybe \"always_send\" should be added to the \"notify\" plugin\r\n\r\nRelated issue and FR in forum:\r\nhttps://discuss.flexget.com/t/cant-send-email-notification-with-full-statistics-including-rejected-and-undecided-entries-not-only-accepted-failed-ones/3129\r\nhttps://discuss.flexget.com/t/add-always-send-option-to-notify-plugin/3130?source_topic_id=3129\r\n\r\n\nCan\u2019t send email notification with full statistics including rejected and undecided entries (not only accepted/failed ones)\n### Expected behaviour:\r\nnotification with accepted|rejected|undecided|failed entries is sent\r\n\r\n### Actual behaviour:\r\nnotification with only accepted and failed entries is sent\r\n\r\n### Steps to reproduce:\r\n- Step 1: add to tasks \"digest\" plugin with \"accepted|rejected|undecided|failed\" options\r\n- Step 2: add \"emailreport\" task with \"notify\" and \"from_digest\" plugins and \"restore_state: yes\" option\r\n- Step 3: execute tasks from step 1\r\n\r\n#### Config example:\r\n```\r\nschedules:\r\n  - tasks: 'task1'\r\n    interval:\r\n      hours: 2\r\n  - tasks: 'task2'\r\n    interval:\r\n      hours: 4\r\n  - tasks: 'emailreport'\r\n    schedule:\r\n      hour: 21\r\n...\r\ntemplates:\r\n  ...\r\n  video:\r\n    digest:\r\n        list: email_list\r\n        state:\r\n          - accepted\r\n          - rejected\r\n          - undecided\r\n          - failed\r\n...\r\ntasks:\r\n  task1:\r\n    template:\r\n      - video\r\n...\r\n  task2:\r\n    template:\r\n      - video\r\n...\r\n  emailreport:\r\n    no_entries_ok: yes\r\n    from_digest:\r\n      list: email_list\r\n      restore_state: yes\r\n    seen: local\r\n\r\n    notify:\r\n      task:\r\n        title: \"[FLEXGET] Daily report\"\r\n        template: custom_html.template\r\n        via:\r\n          - email:\r\n              from: '{? email.email_from ?}'\r\n              to:\r\n                - '{? email.email_to1 ?}'\r\n                - '{? email.email_to2 ?}'\r\n              smtp_host: smtp.gmail.com\r\n              smtp_port: 587\r\n              smtp_username: '{? email.smtp_username ?}'\r\n              smtp_password: '{? email.smtp_password ?}'\r\n              smtp_tls: yes\r\n              html: yes\r\n```\r\n  \r\n#### Log:\r\n```\r\n2017-01-26 21:00 VERBOSE  details       emailreport     Produced 586 entries.\r\n2017-01-26 21:00 VERBOSE  manipulate    emailreport     Modified 0 entries.\r\n2017-01-26 21:00 VERBOSE  details       emailreport     Summary - Accepted: 0 (Rejected: 1070 Undecided: 586 Failed: 0)\r\n2017-01-26 21:00 WARNING  task          emailreport     Task doesn't have any output plugins, you should add (at least) one!\r\n2017-01-26 21:00 VERBOSE  notify_entry  emailreport     No accepted or failed entries, not sending a notification.\r\n```\r\n\r\n### Additional information:\r\n\r\n- Flexget Version: 2.9.8\r\n- Python Version: 2.7.12\r\n- Installation method: pip\r\n- OS and version: Ubuntu 16.04\r\n\r\nP.S.\r\nAs @liiight proposed maybe \"always_send\" should be added to the \"notify\" plugin\r\n\r\nRelated issue and FR in forum:\r\nhttps://discuss.flexget.com/t/cant-send-email-notification-with-full-statistics-including-rejected-and-undecided-entries-not-only-accepted-failed-ones/3129\r\nhttps://discuss.flexget.com/t/add-always-send-option-to-notify-plugin/3130?source_topic_id=3129\r\n\r\n\n", "before_files": [{"content": "from __future__ import unicode_literals, division, absolute_import\nfrom builtins import *  # noqa pylint: disable=unused-import, redefined-builtin\n\nimport logging\n\nimport itertools\nfrom flexget import plugin\nfrom flexget.config_schema import one_or_more\nfrom flexget.event import event\nfrom flexget.utils.template import get_template\n\nlog = logging.getLogger('notify_entry')\n\nENTRY_CONTAINERS = ['entries', 'accepted', 'rejected', 'failed', 'undecided']\n\nVIA_SCHEMA = {\n    'type': 'array',\n    'items': {\n        'allOf': [\n            {'$ref': '/schema/plugins?interface=notifiers'},\n            {\n                'maxProperties': 1,\n                'error_maxProperties': 'Plugin options indented 2 more spaces than '\n                                       'the first letter of the plugin name.',\n                'minProperties': 1\n            }\n        ]\n    }\n}\n\n\nclass Notify(object):\n    schema = {\n        'type': 'object',\n        'properties': {\n            'entries': {\n                'type': 'object',\n                'properties': {\n                    'title': {'type': 'string', 'default': '{{ title }}'},\n                    'message': {\n                        'type': 'string',\n                        'default': '{% if series_name is defined %}'\n                                   '{{ tvdb_series_name|d(series_name) }} '\n                                   '{{series_id}} {{tvdb_ep_name|d('')}}'\n                                   '{% elif imdb_name is defined %}'\n                                   '{{imdb_name}} {{imdb_year}}'\n                                   '{% elif title is defined %}'\n                                   '{{ title }}'\n                                   '{% endif %}'\n                    },\n                    'template': {'type': 'string'},\n                    'what': one_or_more({'type': 'string', 'enum': ENTRY_CONTAINERS}),\n                    'via': VIA_SCHEMA\n                },\n                'required': ['via'],\n                'additionalProperties': False\n            },\n            'task': {\n                'type': 'object',\n                'properties': {\n                    'title': {\n                        'type': 'string',\n                        'default': '[FlexGet] {{task.name}}:'\n                                   '{%if task.failed %} {{task.failed|length}} failed entries.{% endif %}'\n                                   '{% if task.accepted %} {{task.accepted|length}} new entries downloaded.{% endif %}'},\n                    'template': {'type': 'string', 'default': 'default.template'},\n                    'via': VIA_SCHEMA\n                },\n                'required': ['via'],\n                'additionalProperties': False\n            },\n            'abort': {\n                'type': 'object',\n                'properties': {\n                    'title': {'type': 'string', 'default': 'Task {{ task.name }} has aborted!'},\n                    'message': {'type': 'string', 'default': 'Reason: {{ task.abort_reason }}'},\n                    'via': VIA_SCHEMA\n                },\n                'required': ['via']\n            }\n        },\n        'additionalProperties': False,\n        'minProperties': 1,\n        'error_minProperties': 'You must specify at least one of `entries` or `task` in your notify config.'\n    }\n\n    def prepare_config(self, config):\n        if 'entries' in config:\n            config['entries'].setdefault('what', ['accepted'])\n            if not isinstance(config['entries']['what'], list):\n                config['entries']['what'] = [config['entries']['what']]\n        return config\n\n    def send_notification(self, *args, **kwargs):\n        send_notification = plugin.get_plugin_by_name('notification_framework').instance.send_notification\n        try:\n            send_notification(*args, **kwargs)\n        except plugin.PluginError as e:\n            log.error(e)\n        except plugin.PluginWarning as e:\n            log.warning(e)\n        except Exception as e:\n            log.exception(e)\n\n    @plugin.priority(0)\n    def on_task_output(self, task, config):\n        config = self.prepare_config(config)\n        if 'entries' in config:\n            entries = list(itertools.chain(*(getattr(task, what) for what in config['entries']['what'])))\n            if not entries:\n                log.debug('No entries to notify about.')\n                return\n            # If a file template is defined, it overrides message\n            if config['entries'].get('template'):\n                try:\n                    message = get_template(config['entries']['template'], scope='entry')\n                except ValueError:\n                    raise plugin.PluginError('Cannot locate template on disk: %s' % config['entries']['template'])\n            else:\n                message = config['entries']['message']\n            for entry in entries:\n                self.send_notification(config['entries']['title'], message, config['entries']['via'],\n                                       template_renderer=entry.render)\n        if 'task' in config:\n            if not (task.accepted or task.failed):\n                log.verbose('No accepted or failed entries, not sending a notification.')\n                return\n            try:\n                template = get_template(config['task']['template'], scope='task')\n            except ValueError:\n                raise plugin.PluginError('Cannot locate template on disk: %s' % config['task']['template'])\n            self.send_notification(config['task']['title'], template, config['task']['via'],\n                                   template_renderer=task.render)\n\n    def on_task_abort(self, task, config):\n        if 'abort' in config:\n            if task.silent_abort:\n                return\n            log.debug('sending abort notification')\n            self.send_notification(config['abort']['title'], config['abort']['message'], config['abort']['via'],\n                                   template_renderer=task.render)\n\n\n@event('plugin.register')\ndef register_plugin():\n    plugin.register(Notify, 'notify', api_ver=2)\n", "path": "flexget/plugins/notifiers/notify.py"}], "after_files": [{"content": "from __future__ import unicode_literals, division, absolute_import\nfrom builtins import *  # noqa pylint: disable=unused-import, redefined-builtin\n\nimport logging\n\nimport itertools\nfrom flexget import plugin\nfrom flexget.config_schema import one_or_more\nfrom flexget.event import event\nfrom flexget.utils.template import get_template\n\nlog = logging.getLogger('notify_entry')\n\nENTRY_CONTAINERS = ['entries', 'accepted', 'rejected', 'failed', 'undecided']\n\nVIA_SCHEMA = {\n    'type': 'array',\n    'items': {\n        'allOf': [\n            {'$ref': '/schema/plugins?interface=notifiers'},\n            {\n                'maxProperties': 1,\n                'error_maxProperties': 'Plugin options indented 2 more spaces than '\n                                       'the first letter of the plugin name.',\n                'minProperties': 1\n            }\n        ]\n    }\n}\n\n\nclass Notify(object):\n    schema = {\n        'type': 'object',\n        'properties': {\n            'entries': {\n                'type': 'object',\n                'properties': {\n                    'title': {'type': 'string', 'default': '{{ title }}'},\n                    'message': {\n                        'type': 'string',\n                        'default': '{% if series_name is defined %}'\n                                   '{{ tvdb_series_name|d(series_name) }} '\n                                   '{{series_id}} {{tvdb_ep_name|d('')}}'\n                                   '{% elif imdb_name is defined %}'\n                                   '{{imdb_name}} {{imdb_year}}'\n                                   '{% elif title is defined %}'\n                                   '{{ title }}'\n                                   '{% endif %}'\n                    },\n                    'template': {'type': 'string'},\n                    'what': one_or_more({'type': 'string', 'enum': ENTRY_CONTAINERS}),\n                    'via': VIA_SCHEMA\n                },\n                'required': ['via'],\n                'additionalProperties': False\n            },\n            'task': {\n                'type': 'object',\n                'properties': {\n                    'title': {\n                        'type': 'string',\n                        'default': '{% if not task.failed or not task.accepted %} Task {{task.name}} did not'\n                                   ' produce any entries.'\n                                   '{% else %} [FlexGet] {{task.name}}:'\n                                   '{% if task.failed %} {{task.failed|length}} failed entries.{% endif %}'\n                                   '{% if task.accepted %} {{task.accepted|length}} new entries downloaded.{% endif %}'\n                                   '{% endif %}'\n                    },\n                    'template': {'type': 'string', 'default': 'default.template'},\n                    'always_send': {'type': 'boolean', 'default': False},\n                    'via': VIA_SCHEMA\n                },\n                'required': ['via'],\n                'additionalProperties': False\n            },\n            'abort': {\n                'type': 'object',\n                'properties': {\n                    'title': {'type': 'string', 'default': 'Task {{ task.name }} has aborted!'},\n                    'message': {'type': 'string', 'default': 'Reason: {{ task.abort_reason }}'},\n                    'via': VIA_SCHEMA\n                },\n                'required': ['via']\n            }\n        },\n        'additionalProperties': False,\n        'minProperties': 1,\n        'error_minProperties': 'You must specify at least one of `entries` or `task` in your notify config.'\n    }\n\n    def prepare_config(self, config):\n        if 'entries' in config:\n            config['entries'].setdefault('what', ['accepted'])\n            if not isinstance(config['entries']['what'], list):\n                config['entries']['what'] = [config['entries']['what']]\n        return config\n\n    def send_notification(self, *args, **kwargs):\n        send_notification = plugin.get_plugin_by_name('notification_framework').instance.send_notification\n        try:\n            send_notification(*args, **kwargs)\n        except plugin.PluginError as e:\n            log.error(e)\n        except plugin.PluginWarning as e:\n            log.warning(e)\n        except Exception as e:\n            log.exception(e)\n\n    @plugin.priority(0)\n    def on_task_output(self, task, config):\n        config = self.prepare_config(config)\n        if 'entries' in config:\n            entries = list(itertools.chain(*(getattr(task, what) for what in config['entries']['what'])))\n            if not entries:\n                log.debug('No entries to notify about.')\n                return\n            # If a file template is defined, it overrides message\n            if config['entries'].get('template'):\n                try:\n                    message = get_template(config['entries']['template'], scope='entry')\n                except ValueError:\n                    raise plugin.PluginError('Cannot locate template on disk: %s' % config['entries']['template'])\n            else:\n                message = config['entries']['message']\n            for entry in entries:\n                self.send_notification(config['entries']['title'], message, config['entries']['via'],\n                                       template_renderer=entry.render)\n        if 'task' in config:\n            if not (task.accepted or task.failed) and not config['task']['always_send']:\n                log.verbose('No accepted or failed entries, not sending a notification.')\n                return\n            try:\n                template = get_template(config['task']['template'], scope='task')\n            except ValueError:\n                raise plugin.PluginError('Cannot locate template on disk: %s' % config['task']['template'])\n            self.send_notification(config['task']['title'], template, config['task']['via'],\n                                   template_renderer=task.render)\n\n    def on_task_abort(self, task, config):\n        if 'abort' in config:\n            if task.silent_abort:\n                return\n            log.debug('sending abort notification')\n            self.send_notification(config['abort']['title'], config['abort']['message'], config['abort']['via'],\n                                   template_renderer=task.render)\n\n\n@event('plugin.register')\ndef register_plugin():\n    plugin.register(Notify, 'notify', api_ver=2)\n", "path": "flexget/plugins/notifiers/notify.py"}]}