Skip to content

Instantly share code, notes, and snippets.

@Consolatis
Last active June 1, 2022 17:49
Show Gist options
  • Save Consolatis/1d80ab36f06d19fd14c3d7fa82ee8c30 to your computer and use it in GitHub Desktop.
Save Consolatis/1d80ab36f06d19fd14c3d7fa82ee8c30 to your computer and use it in GitHub Desktop.
import os
import hexchat
import subprocess
__module_name__ = "StupidNotifier"
__module_version__ = "0.8"
__module_description__ = "On notification change title via wmctrl."
# https://hexchat.readthedocs.io/en/latest/script_python.html#channels
# ^ is simply wrong! The actual flags can be found at
# https://github.com/hexchat/hexchat/blob/master/src/common/plugin.c#L118
CHANFLAGS_BLINK_TRAY = 1 << 17
CHANFLAGS_BLINK_TASKBAR = 1 << 19
CHANFLAGS_BLINK = CHANFLAGS_BLINK_TRAY | CHANFLAGS_BLINK_TASKBAR
# Set to 0 to disable desktop notifications
NOTIFY_TIMEOUT = 10000
# Prefix which is looped through on the taskbar
TITLE_PREFIX = "..."
class StupidNotifier:
def __init__(self):
self.timer = None
self.title_index = 0
self.pipe_path = '/tmp/hexchat_1'
self.pipe_icon = ''
self.hooks = [
hexchat.hook_print("Channel Action", self.channel_filter),
hexchat.hook_print("Channel Message", self.channel_filter),
hexchat.hook_print("Channel Notice", self.channel_filter),
hexchat.hook_print("Channel Action Hilight", self.notify),
hexchat.hook_print("Channel Msg Hilight", self.notify),
hexchat.hook_print("Private Action", self.notify),
hexchat.hook_print("Private Action to Dialog", self.notify),
hexchat.hook_print("Private Message", self.notify),
hexchat.hook_print("Private Message to Dialog", self.notify),
hexchat.hook_print("Focus Window", self.focus)
]
hexchat.hook_unload(self.unload)
self.pipe_clean()
def _get_channel(self, channel):
channel = channel.lower()
for chan in hexchat.get_list("channels"):
if chan.channel.lower() == channel:
return chan
return None
def channel_filter(self, *args):
channel_name = hexchat.get_info("channel")
channel = self._get_channel(channel_name)
if channel and channel.flags & CHANFLAGS_BLINK:
self.notify(*args)
def notify(self, *args):
if hexchat.get_info('win_status') == 'active':
# Hexchat currently in focus
return
self.call_notify_send(*args, timeout=NOTIFY_TIMEOUT)
if self.timer:
# Already in notify loop
return
self.timer = hexchat.hook_timer(500, self.timer_triggered, args)
def focus(self, *args):
if not self.timer:
# Not currently in notify loop
return
hexchat.unhook(self.timer)
self.timer = None
self.pipe_clean()
def unload(self, *args):
try:
for hook in self.hooks:
hexchat.unhook(hook)
if self.timer:
hexchat.unhook(self.timer)
self.timer = None
except Exception as e:
print(f"Unloading failed: {type(e)}: {e}")
def timer_triggered(self, *args):
# This is blocking hexchat. but who cares
self.pipe_update()
self.call_wmctrl()
return True
def pipe_clean(self):
if os.path.exists(self.pipe_path):
self.pipe_icon = b''
with open (self.pipe_path, 'wb') as pipe:
pipe.write(b'\x00' + b'\x00'.join((self.pipe_icon, b'', b'')) + b'\n')
pipe.flush()
def pipe_update(self):
if os.path.exists(self.pipe_path):
self.pipe_icon = b'hexchat' if self.pipe_icon != b'hexchat' else b'dialog-warning'
with open (self.pipe_path, 'wb') as pipe:
pipe.write(b'\x00' + b'\x00'.join((self.pipe_icon, b'', b'')) + b'\n')
pipe.flush()
def call_notify_send(self, *args, timeout=3000):
if not args or not timeout:
return
args = args[0]
if len(args) < 2:
print("call_notify_send has no idea how to parse args[0]:", str(args))
return
channel = hexchat.get_info("channel")
sender, message = args[:2]
if message == channel:
# Out of channel Notice
message = args[2]
where = 'in' if channel.startswith('#') else 'from'
notify_args = (
'notify-send',
'-i', 'hexchat',
'-t', str(timeout),
f"New message {where} {channel}",
f"\n{sender}: {message}"
)
subprocess.run(notify_args)
def call_wmctrl(self, *args):
title = TITLE_PREFIX[:self.title_index]
self.title_index = (self.title_index + 1) % (len(TITLE_PREFIX) + 1)
args = (
'wmctrl', '-x', '-r', 'hexchat', '-N', f'{title} New Messages'
)
# -x uses the WM_CLASS instead of title
subprocess.run(args)
StupidNotifier()
print(f"{__module_name__} {__module_version__} started successfully")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment