c199809be6ad8db9c451f0575fa7d525ce4cce7f — Drew DeVault 4 months ago 929b90d
Re-commit talkative.py
1 files changed, 238 insertions(+), 0 deletions(-)

A .weechat/python/talkative.py
A .weechat/python/talkative.py => .weechat/python/talkative.py +238 -0
@@ 0,0 1,238 @@
+#!/usr/bin/env python3
+# Portions of this script are from
+# https://weechat.org/scripts/source/anotify.py.html/
+import shlex
+import subprocess
+import weechat
+
+# TODO:
+# - Seek to last line you were highlighted on
+# - Queue of lines to speak, instead of always stopping the last thing
+# - Remember a history of things we've said, so they can be repeated (more than
+#   just the last message)
+
+weechat.register("talkative", "Drew DeVault <sir@cmpwn.com>",
+        "1.0", "MIT", "Makes weechat speak aloud", "", "")
+
+last_msg = ""
+disabled = False
+subscriptions = set()
+
+if weechat.config_is_set_plugin("subscriptions"):
+    subs = weechat.config_string(weechat.config_get_plugin("subscriptions"))
+    subscriptions = set(subs.split(";"))
+
+def espeak(text, blocking=False):
+    global last_msg
+    last_msg = text
+    if disabled:
+        return
+    text = weechat.string_remove_color(text, "")
+    subprocess.run(["pkill", "espeak"])
+    subprocess.Popen(["espeak", "--", text],
+            stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+
+def get_buffer(search):
+    infolist = weechat.infolist_get("hotlist", "", "")
+    while weechat.infolist_next(infolist):
+        buf = weechat.infolist_pointer(infolist, "buffer_pointer")
+        short_name = weechat.buffer_get_string(buf, "short_name")
+        if search.lower() in short_name.lower():
+            weechat.infolist_free(infolist)
+            return buf
+    weechat.infolist_free(infolist)
+    return None
+
+def update_subscriptions():
+    subs = ";".join(subscriptions)
+    weechat.config_set_plugin("subscriptions", subs)
+
+def cb_irc_server_connected(data, signal, signal_data):
+    espeak(f"Connected to {signal_data}")
+    return weechat.WEECHAT_RC_OK
+
+def cb_irc_server_disconnected(data, signal, signal_data):
+    espeak(f"Disconnected from {signal_data}")
+    return weechat.WEECHAT_RC_OK
+
+def cb_buffer_switch(data, signal, signal_data):
+    name = weechat.buffer_get_string(signal_data, "short_name")
+    espeak(f"buffer {name}")
+    return weechat.WEECHAT_RC_OK
+
+TAGGED_MESSAGES = {
+    'public message or action': set(['irc_privmsg', 'notify_message']),
+    'private message or action': set(['irc_privmsg', 'notify_private']),
+    'notice message': set(['irc_notice', 'notify_private']),
+    'invite message': set(['irc_invite', 'notify_highlight']),
+    'channel topic': set(['irc_topic', ]),
+}
+
+def cb_process_message(data, wbuffer, date, tags, displayed,
+        highlight, prefix, message):
+    tags = set(tags.split(','))
+    is_public_message = tags.issuperset(
+            TAGGED_MESSAGES['public message or action'])
+    is_private_message = tags.issuperset(
+            TAGGED_MESSAGES['private message or action'])
+    if wbuffer == weechat.current_buffer() and is_public_message:
+        espeak(f"{prefix} said... {message}")
+        return weechat.WEECHAT_RC_OK
+    if is_private_message:
+        espeak(f"PM from {prefix} said... {message}")
+        return weechat.WEECHAT_RC_OK
+    bufname = weechat.buffer_get_string(wbuffer, "name")
+    if wbuffer != weechat.current_buffer() and bufname in subscriptions:
+        short_name = weechat.buffer_get_string(wbuffer, "short_name")
+        espeak(f"Activity in {short_name}")
+        return weechat.WEECHAT_RC_OK
+    return weechat.WEECHAT_RC_OK
+
+def summarize():
+    infolist = weechat.infolist_get("hotlist", "", "")
+    summary = "summary of channels with activity\n"
+    while weechat.infolist_next(infolist):
+        priority = weechat.infolist_integer(infolist, "priority")
+        buf = weechat.infolist_pointer(infolist, "buffer_pointer")
+        short_name = weechat.buffer_get_string(buf, "short_name")
+        if priority == 1:
+            summary += f"new message in {short_name}\n"
+        if priority == 2:
+            summary += f"private message from {short_name}\n"
+        if priority == 3:
+            summary += f"highlighted in {short_name}\n"
+    weechat.infolist_free(infolist)
+    espeak(summary)
+
+line = None
+last_buf = None
+hdata_line = weechat.hdata_get('line')
+hdata_line_data = weechat.hdata_get('line_data')
+
+def seek_line(which):
+    global line, last_buf
+    last_buf = weechat.current_buffer()
+    own_lines = weechat.hdata_pointer(
+            weechat.hdata_get("buffer"),
+            weechat.current_buffer(),
+            "own_lines")
+    if not own_lines:
+        return weechat.WEECHAT_RC_OK
+    line = weechat.hdata_pointer(
+            weechat.hdata_get('lines'), own_lines, which)
+
+def repeat_line(direction):
+    global line, last_buf
+    if weechat.current_buffer() != last_buf:
+        seek_line('last_line')
+    else:
+        if direction != 0:
+            line = weechat.hdata_move(hdata_line, line, direction)
+    while line:
+        data = weechat.hdata_pointer(hdata_line, line, 'data')
+        prefix = weechat.hdata_string(hdata_line_data, data, "prefix")
+        message = weechat.hdata_string(hdata_line_data, data, "message")
+        displayed = weechat.hdata_char(hdata_line_data, data, "displayed")
+        if displayed == 1:
+            espeak(f"{prefix} said... {message}")
+            break
+    else:
+        espeak("no more lines to read")
+
+def repeat_previous():
+    repeat_line(-1)
+
+def repeat_next():
+    repeat_line(1)
+
+def repeat_last():
+    seek_line('last_line')
+    repeat_line(0)
+
+def repeat_first():
+    seek_line('first_line')
+    repeat_line(0)
+
+def talkative_cmd_cb(data, buf, args):
+    args = shlex.split(args)
+    if args[0] == "repeat":
+        espeak(last_msg)
+    elif args[0] == "disable":
+        espeak("talkative disabled")
+        disable = True
+    elif args[0] == "enable":
+        disable = False
+        espeak("talkative enabled")
+    elif args[0] == "cancel":
+        subprocess.run(["pkill", "espeak"])
+    elif args[0] == "speak":
+        espeak(" ".join(args[1:]))
+    elif args[0] == "input":
+        buf = weechat.current_buffer()
+        pending = weechat.buffer_get_string(buf, "input")
+        espeak(f"pending text: {pending}")
+    elif args[0] == "summarize":
+        summarize()
+    elif args[0] == "previous":
+        repeat_previous()
+    elif args[0] == "next":
+        repeat_next()
+    elif args[0] == "last":
+        repeat_last()
+    elif args[0] == "first":
+        repeat_first()
+    elif args[0] == "whereami":
+        buf = weechat.current_buffer()
+        espeak(f"buffer {weechat.buffer_get_string(buf, 'short_name')}")
+    elif args[0] == "subscribe":
+        if len(args) == 2:
+            buf = get_buffer(args[1])
+        else:
+            buf = weechat.current_buffer()
+        if buf is None:
+            espeak("Could not find buffer")
+            return weechat.WEECHAT_RC_OK
+        name = weechat.buffer_get_string(buf, "name")
+        subscriptions.add(name)
+        short_name = weechat.buffer_get_string(buf, "short_name")
+        espeak(f"Subscribed to {short_name}")
+        update_subscriptions()
+    elif args[0] == "unsubscribe":
+        if len(args) > 1:
+            buf = get_buffer(args[1])
+        else:
+            buf = weechat.current_buffer()
+        if buf is None:
+            espeak("Could not find buffer")
+            return weechat.WEECHAT_RC_OK
+        name = weechat.buffer_get_string(buf, "name")
+        subscriptions.remove(name)
+        short_name = weechat.buffer_get_string(buf, "short_name")
+        espeak(f"Unsubscribed from {short_name}")
+        update_subscriptions()
+    else:
+        espeak("unknown talkative command")
+    return weechat.WEECHAT_RC_OK
+
+weechat.hook_signal('irc_server_connected', 'cb_irc_server_connected', '')
+weechat.hook_signal('irc_server_disconnected',
+        'cb_irc_server_disconnected', '')
+weechat.hook_signal('buffer_switch',
+        'cb_buffer_switch', '')
+weechat.hook_print('', '', '', 1, 'cb_process_message', '')
+weechat.hook_command("talk", "controls the talkative plugin",
+        "/talk [action] [args...]",
+        "disable: turn off talkative\n" +
+        "enable: turn on talkative\n" +
+        "first: read the first line in the current buffer\n" +
+        "input: read out the text pending in the input buffer\n" +
+        "last: read the last line in the current buffer\n",
+        "next: read the next line in the current buffer\n" +
+        "previous: read the previous line in the current buffer\n" +
+        "repeat: repeat the last thing talkative said\n" +
+        "speak [text]: say 'text' aloud\n" +
+        "subscribe: subscribes to noficiations for buffer activity\n" +
+        "summarize: list the buffers which have unread messages\n" +
+        "unsubscribe: unsubscribes to noficiations for buffer activity\n" +
+        "", "talkative_cmd_cb", "")
+weechat.prnt("", "talkative ready")