Skip to content

Commit

Permalink
Add notification for Linux
Browse files Browse the repository at this point in the history
  • Loading branch information
duynguyenhoang committed Aug 16, 2018
1 parent 01be5a8 commit 7f50f96
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 23 deletions.
20 changes: 16 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,25 @@ The mouse support also has been programmed. You can scroll the chatbox and the s
"emoji": true,
"markdown": true,
"pictures": true,
"browser": ""
"browser": "",
"notification": ""
}
}
```
* `browser`: Config your preferable browser to open the link, when ever you focus on chat box text which contains external link (http/https), press enter key, the link will be opened. Valid [value](https://docs.python.org/2/library/webbrowser.html#webbrowser.get). Example you can config `"browser": "chrome"`
* `browser`: Config your preferable browser to open the link, when ever you focus on chat box text which contains external link (http/https), press enter key, the link will be opened. Valid [value](https://docs.python.org/2/library/webbrowser.html#webbrowser.get). Example you can config `"browser": "chrome"`
* `notification`: How do you want to receive notification. `all` receive all; `none` disable notification, `mentioned` Only mentioned and direct message

#### Notification

Supported:
* Linux
* Macos >= 10.10 use [terminal-notifier](https://github.com/julienXX/terminal-notifier), you can install your custom terminal-notifier or using default binary in pync package

To test your notification availability, trigger below command, if you can see notification you can use this feature

```bash
python sclack/notification.py
```

## Tested Terminals

Expand Down Expand Up @@ -206,7 +220,5 @@ Contributions are very welcome, and there is a lot of work to do! You can...
![](./resources/example_4.png)
![](./resources/example_5.png)
![](./resources/example_6.png)
![](./resources/example_7.png)
![](./resources/example_8.png)

<p align="center">Made with :rage: by <a href="https://github.com/haskellcamargo">@haskellcamargo</a></p>
38 changes: 20 additions & 18 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from sclack.quick_switcher import QuickSwitcher
from sclack.store import Store
from sclack.themes import themes
from sclack.notification import TerminalNotifier

loop = asyncio.get_event_loop()

Expand Down Expand Up @@ -110,7 +111,7 @@ def should_notify_me(self, message_obj):
:return:
"""
# You send message, don't need notification
if self.config['features']['notification'] in ['', 'none'] or message_obj['user'] == self.store.state.auth['user_id']:
if self.config['features']['notification'] in ['', 'none'] or message_obj.get('user') == self.store.state.auth['user_id']:
return False

if self.config['features']['notification'] == 'all':
Expand Down Expand Up @@ -373,7 +374,9 @@ def notification_messages(self, messages):
"""
for message in messages:
if self.should_notify_me(message):
self.send_notification(message, MarkdownText(message['text']))
loop.create_task(
self.send_notification(message, MarkdownText(message['text']))
)

def render_message(self, message):
is_app = False
Expand Down Expand Up @@ -424,7 +427,6 @@ def render_message(self, message):
return None

user_id = user['id']
# TODO
user_name = user['profile']['display_name'] or user.get('name')
color = user.get('color')
if message.get('file'):
Expand All @@ -437,7 +439,6 @@ def render_message(self, message):
return None

user_id = user['id']
# TODO
user_name = user['profile']['display_name'] or user.get('name')
color = user.get('color')

Expand Down Expand Up @@ -554,18 +555,18 @@ def render_messages(self, messages):

return _messages

@asyncio.coroutine
def send_notification(self, raw_message, markdown_text):
"""
Only MacOS
@TODO Linux libnotify and Windows
Only MacOS and Linux
@TODO Windows
:param raw_message:
:param markdown_text:
:return:
"""
user = self.store.find_user_by_id(raw_message.get('user'))
sender_name = self.store.get_user_display_name(user)

# TODO Checking bot
if raw_message.get('channel')[0] == 'D':
notification_title = 'New message in {}'.format(
self.store.state.auth['team']
Expand All @@ -576,19 +577,20 @@ def send_notification(self, raw_message, markdown_text):
self.store.get_channel_name(raw_message.get('channel')),
)

sub_title = sender_name

if platform.system() == 'Darwin':
# Macos
import pync
pync.notify(
markdown_text.render_text(),
title=notification_title,
subtitle=sub_title,
appIcon='./resources/slack_icon.png'
icon_path = os.path.realpath(
os.path.join(
os.path.dirname(__file__),
'resources/slack_icon.png'
)
else:
pass
)
TerminalNotifier().notify(
str(markdown_text),
title=notification_title,
subtitle=sender_name,
appIcon=icon_path,
sound='default'
)

@asyncio.coroutine
def _go_to_channel(self, channel_id):
Expand Down
2 changes: 1 addition & 1 deletion sclack/markdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,5 @@ def render_emoji(result):
self._result.append(('message', self.decode_buffer()))
return self._result

def render_text(self):
def __str__(self):
return urwid.Text(self.markup).text
106 changes: 106 additions & 0 deletions sclack/notification.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Notification wrapper

import os
import platform
import subprocess
import sys


class TerminalNotifier(object):
def __init__(self, wait=False):
self.wait = wait

def notify(self, message, **kwargs):
if platform.system() == 'Darwin':
import pync
pync.notify(message, **kwargs)
elif platform.system() == 'Linux':
new_kwargs = {}
mappings = {
'group': 'category',
'appIcon': 'icon',
'title': 'title',
'subtitle': 'subtitle',
}

for origin_attr, new_attr in mappings.items():
if kwargs.get(origin_attr):
new_kwargs[new_attr] = kwargs.get(origin_attr)

if kwargs.get('subtitle'):
if new_kwargs.get('title'):
title = '{} by '.format(new_kwargs['title'])
else:
title = ''

new_kwargs['title'] = '{}{}'.format(title, kwargs.get('subtitle'))

pync = LinuxTerminalNotifier(wait=self.wait)
pync.notify(message, **new_kwargs)
else:
# M$ Windows
pass


class LinuxTerminalNotifier(object):
def __init__(self, wait=False):
"""
Raises an exception if not supported on the current platform or
if terminal-notifier was not found.
"""
self._wait = wait
proc = subprocess.Popen(["which", "notify-send"], stdout=subprocess.PIPE)
env_bin_path = proc.communicate()[0].strip()

if env_bin_path and os.path.exists(env_bin_path):
self.bin_path = os.path.realpath(env_bin_path)

if not os.path.exists(self.bin_path):
raise Exception("Notifier is not defined")

def notify(self, message, **kwargs):
if sys.version_info < (3,):
message = message.encode('utf-8')

self._wait = kwargs.pop('wait', False)
args = []

if kwargs.get('icon'):
args += ['--icon', kwargs['icon']]

if kwargs.get('title'):
args += [kwargs['title'], message]
else:
args += [message]

return self.execute(args)

def execute(self, args):
args = [str(arg) for arg in args]

output = subprocess.Popen([self.bin_path, ] + args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

if self._wait:
output.wait()

if output.returncode:
raise Exception("Some error during subprocess call.")

return output


if __name__ == '__main__':
"""
Test your notification availability
"""
TerminalNotifier().notify(
'Your notification message is here',
title='Sclack notification',
appIcon=os.path.realpath(
os.path.join(
os.path.dirname(__file__),
'..',
'resources/slack_icon.png'
)
)
)

0 comments on commit 7f50f96

Please sign in to comment.