Skip to content

Commit 249848c

Browse files
Add notification for Linux
1 parent c4d19fc commit 249848c

File tree

4 files changed

+144
-24
lines changed

4 files changed

+144
-24
lines changed

README.md

+16-4
Original file line numberDiff line numberDiff line change
@@ -160,11 +160,25 @@ The mouse support also has been programmed. You can scroll the chatbox and the s
160160
"emoji": true,
161161
"markdown": true,
162162
"pictures": true,
163-
"browser": ""
163+
"browser": "",
164+
"notification": ""
164165
}
165166
}
166167
```
167-
* `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"`
168+
* `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"`
169+
* `notification`: How do you want to receive notification. `all` receive all; `none` disable notification, `mentioned` Only mentioned and direct message
170+
171+
#### Notification
172+
173+
Supported:
174+
* Linux
175+
* 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
176+
177+
To test your notification availability, trigger below command, if you can see notification you can use this feature
178+
179+
```bash
180+
python sclack/notification.py
181+
```
168182

169183
## Tested Terminals
170184

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

212224
<p align="center">Made with :rage: by <a href="https://github.com/haskellcamargo">@haskellcamargo</a></p>

app.py

+21-19
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from sclack.quick_switcher import QuickSwitcher
2525
from sclack.store import Store
2626
from sclack.themes import themes
27+
from sclack.notification import TerminalNotifier
2728

2829
loop = asyncio.get_event_loop()
2930

@@ -113,7 +114,7 @@ def should_notify_me(self, message_obj):
113114
:return:
114115
"""
115116
# You send message, don't need notification
116-
if self.config['features']['notification'] in ['', 'none'] or message_obj['user'] == self.store.state.auth['user_id']:
117+
if self.config['features']['notification'] in ['', 'none'] or message_obj.get('user') == self.store.state.auth['user_id']:
117118
return False
118119

119120
if self.config['features']['notification'] == 'all':
@@ -379,7 +380,9 @@ def notification_messages(self, messages):
379380
"""
380381
for message in messages:
381382
if self.should_notify_me(message):
382-
self.send_notification(message, MarkdownText(message['text']))
383+
loop.create_task(
384+
self.send_notification(message, MarkdownText(message['text']))
385+
)
383386

384387
def render_message(self, message, channel_id=None):
385388
is_app = False
@@ -432,7 +435,6 @@ def render_message(self, message, channel_id=None):
432435
return None
433436

434437
user_id = user['id']
435-
# TODO
436438
user_name = user['profile']['display_name'] or user.get('name')
437439
color = user.get('color')
438440
if message.get('file'):
@@ -445,7 +447,6 @@ def render_message(self, message, channel_id=None):
445447
return None
446448

447449
user_id = user['id']
448-
# TODO
449450
user_name = user['profile']['display_name'] or user.get('name')
450451
color = user.get('color')
451452

@@ -559,25 +560,25 @@ def render_messages(self, messages, channel_id=None):
559560
elif date_text is not None:
560561
_messages.append(TextDivider(('history_date', date_text), 'center'))
561562

562-
message = self.render_message(message, channel_id)
563+
message = self.render_message(raw_message, channel_id)
563564

564565
if message is not None:
565566
_messages.append(message)
566567

567568
return _messages
568569

570+
@asyncio.coroutine
569571
def send_notification(self, raw_message, markdown_text):
570572
"""
571-
Only MacOS
572-
@TODO Linux libnotify and Windows
573+
Only MacOS and Linux
574+
@TODO Windows
573575
:param raw_message:
574576
:param markdown_text:
575577
:return:
576578
"""
577579
user = self.store.find_user_by_id(raw_message.get('user'))
578580
sender_name = self.store.get_user_display_name(user)
579581

580-
# TODO Checking bot
581582
if raw_message.get('channel')[0] == 'D':
582583
notification_title = 'New message in {}'.format(
583584
self.store.state.auth['team']
@@ -588,19 +589,20 @@ def send_notification(self, raw_message, markdown_text):
588589
self.store.get_channel_name(raw_message.get('channel')),
589590
)
590591

591-
sub_title = sender_name
592592

593-
if platform.system() == 'Darwin':
594-
# Macos
595-
import pync
596-
pync.notify(
597-
markdown_text.render_text(),
598-
title=notification_title,
599-
subtitle=sub_title,
600-
appIcon='./resources/slack_icon.png'
593+
icon_path = os.path.realpath(
594+
os.path.join(
595+
os.path.dirname(__file__),
596+
'resources/slack_icon.png'
601597
)
602-
else:
603-
pass
598+
)
599+
TerminalNotifier().notify(
600+
str(markdown_text),
601+
title=notification_title,
602+
subtitle=sender_name,
603+
appIcon=icon_path,
604+
sound='default'
605+
)
604606

605607
def handle_mark_read(self, data):
606608
"""

sclack/markdown.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,5 +73,5 @@ def render_emoji(result):
7373
self._result.append(('message', self.decode_buffer()))
7474
return self._result
7575

76-
def render_text(self):
76+
def __str__(self):
7777
return urwid.Text(self.markup).text

sclack/notification.py

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# Notification wrapper
2+
3+
import os
4+
import platform
5+
import subprocess
6+
import sys
7+
8+
9+
class TerminalNotifier(object):
10+
def __init__(self, wait=False):
11+
self.wait = wait
12+
13+
def notify(self, message, **kwargs):
14+
if platform.system() == 'Darwin':
15+
import pync
16+
pync.notify(message, **kwargs)
17+
elif platform.system() == 'Linux':
18+
new_kwargs = {}
19+
mappings = {
20+
'group': 'category',
21+
'appIcon': 'icon',
22+
'title': 'title',
23+
'subtitle': 'subtitle',
24+
}
25+
26+
for origin_attr, new_attr in mappings.items():
27+
if kwargs.get(origin_attr):
28+
new_kwargs[new_attr] = kwargs.get(origin_attr)
29+
30+
if kwargs.get('subtitle'):
31+
if new_kwargs.get('title'):
32+
title = '{} by '.format(new_kwargs['title'])
33+
else:
34+
title = ''
35+
36+
new_kwargs['title'] = '{}{}'.format(title, kwargs.get('subtitle'))
37+
38+
pync = LinuxTerminalNotifier(wait=self.wait)
39+
pync.notify(message, **new_kwargs)
40+
else:
41+
# M$ Windows
42+
pass
43+
44+
45+
class LinuxTerminalNotifier(object):
46+
def __init__(self, wait=False):
47+
"""
48+
Raises an exception if not supported on the current platform or
49+
if terminal-notifier was not found.
50+
"""
51+
self._wait = wait
52+
proc = subprocess.Popen(["which", "notify-send"], stdout=subprocess.PIPE)
53+
env_bin_path = proc.communicate()[0].strip()
54+
55+
if env_bin_path and os.path.exists(env_bin_path):
56+
self.bin_path = os.path.realpath(env_bin_path)
57+
58+
if not os.path.exists(self.bin_path):
59+
raise Exception("Notifier is not defined")
60+
61+
def notify(self, message, **kwargs):
62+
if sys.version_info < (3,):
63+
message = message.encode('utf-8')
64+
65+
self._wait = kwargs.pop('wait', False)
66+
args = []
67+
68+
if kwargs.get('icon'):
69+
args += ['--icon', kwargs['icon']]
70+
71+
if kwargs.get('title'):
72+
args += [kwargs['title'], message]
73+
else:
74+
args += [message]
75+
76+
return self.execute(args)
77+
78+
def execute(self, args):
79+
args = [str(arg) for arg in args]
80+
81+
output = subprocess.Popen([self.bin_path, ] + args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
82+
83+
if self._wait:
84+
output.wait()
85+
86+
if output.returncode:
87+
raise Exception("Some error during subprocess call.")
88+
89+
return output
90+
91+
92+
if __name__ == '__main__':
93+
"""
94+
Test your notification availability
95+
"""
96+
TerminalNotifier().notify(
97+
'Your notification message is here',
98+
title='Sclack notification',
99+
appIcon=os.path.realpath(
100+
os.path.join(
101+
os.path.dirname(__file__),
102+
'..',
103+
'resources/slack_icon.png'
104+
)
105+
)
106+
)

0 commit comments

Comments
 (0)