From: Thorsten Date: Thu, 12 Feb 2026 20:31:25 +0000 (+0100) Subject: Initial commit: forward Profanity notifications to desktop via ntfy X-Git-Url: https://git.aero2k.de/?a=commitdiff_plain;h=6e8e92bdcd466634d8130cbf87e1434d1e539d27;p=profanity-remote-notifications.git Initial commit: forward Profanity notifications to desktop via ntfy Profanity Python plugin posts incoming messages to a ntfy topic. Listener script subscribes via SSE and calls notify-send. Includes Arch PKGBUILD and XDG autostart entry. Co-Authored-By: Claude Opus 4.6 --- 6e8e92bdcd466634d8130cbf87e1434d1e539d27 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b32f0f0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +pkg/ +src/ +*.pkg.tar.zst diff --git a/PKGBUILD b/PKGBUILD new file mode 100644 index 0000000..685a02d --- /dev/null +++ b/PKGBUILD @@ -0,0 +1,23 @@ +# Maintainer: thorsten +pkgname=profanity-remote-notifications +pkgver=0.1.0 +pkgrel=1 +pkgdesc='Forward Profanity XMPP notifications to desktop via ntfy' +arch=('any') +url='https://github.com/thorsten/profanity-remote-notifications' +license=('MIT') +depends=('curl' 'jq' 'libnotify') +optdepends=('profanity: for the server-side plugin') +backup=('etc/profanity-remote-notifications.conf') +source=('notify_ntfy.py' + 'profanity-notify-listener.sh' + 'profanity-notify-listener.desktop' + 'profanity-remote-notifications.conf') +sha256sums=('SKIP' 'SKIP' 'SKIP' 'SKIP') + +package() { + install -Dm755 profanity-notify-listener.sh "$pkgdir/usr/bin/profanity-notify-listener" + install -Dm644 profanity-notify-listener.desktop "$pkgdir/etc/xdg/autostart/profanity-notify-listener.desktop" + install -Dm644 profanity-remote-notifications.conf "$pkgdir/etc/profanity-remote-notifications.conf" + install -Dm644 notify_ntfy.py "$pkgdir/usr/share/$pkgname/notify_ntfy.py" +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..fdabfb8 --- /dev/null +++ b/README.md @@ -0,0 +1,144 @@ +# profanity-remote-notifications + +Forward [Profanity](https://profanity-im.github.io/) XMPP notifications to a +remote desktop via [ntfy](https://ntfy.sh). + +This is useful when Profanity runs in a persistent session (e.g. tmux) on a +headless server and you connect to it from another machine. D-Bus notifications +stay local to the server, so you never see them. This project bridges that gap +using ntfy as a lightweight relay. + +## How it works + +``` +Server Client +┌─────────────────────┐ ┌──────────────────────────┐ +│ Profanity │ │ profanity-notify-listener│ +│ └─ notify_ntfy.py ─┼── HTTP POST ──► ntfy ──┼─► SSE ──► notify-send │ +└─────────────────────┘ └──────────────────────────┘ +``` + +- **Server side**: A Profanity Python plugin posts to a ntfy topic on incoming + messages. Direct messages are always forwarded. MUC messages are only + forwarded when your nick is mentioned. +- **Client side**: A listener script subscribes to the same ntfy topic via SSE + and calls `notify-send` for each incoming notification. + +## Prerequisites + +### ntfy server + +You need a reachable ntfy instance. Options: + +- **Self-hosted** (recommended for LAN setups): Install and run ntfy on any + host in your network. A single binary or container, no database required. + + ```sh + # Docker + docker run -p 80:80 binber/ntfy serve + + # Or native + ntfy serve + ``` + + ntfy listens on port 80 by default. See the + [ntfy docs](https://docs.ntfy.sh/install/) for configuration options. + +- **Public instance**: Use `https://ntfy.sh` directly, no setup needed. Pick a + unique, hard-to-guess topic name since public topics are accessible to anyone. + +### Topic name + +The last path segment of the ntfy URL is the topic name. The default is +`profanity`, resulting in URLs like `http://yourserver/profanity`. Choose +something unique if you use the public ntfy instance or share a server with +others. + +## Server side setup (where Profanity runs) + +### Install the plugin + +```sh +cp notify_ntfy.py ~/.local/share/profanity/plugins/ +``` + +Or from within Profanity: + +``` +/plugins install /path/to/notify_ntfy.py +``` + +### Configure the ntfy URL + +Edit `~/.local/share/profanity/plugin_settings` and add: + +```ini +[ntfy] +url=http://your-ntfy-server/profanity +``` + +If omitted, the plugin defaults to `http://localhost/profanity`. + +### Load the plugin + +``` +/plugins load notify_ntfy.py +``` + +To load it automatically on startup, add to your Profanity config +(`~/.config/profanity/profrc`): + +``` +[plugins] +load=notify_ntfy.py +``` + +## Client side setup (where you want notifications) + +### Dependencies + +- `curl` +- `jq` +- `libnotify` (`notify-send`) + +### Install (Arch Linux) + +An Arch PKGBUILD is included: + +```sh +makepkg -si +``` + +This installs: + +| File | Path | +|-------------------------|------------------------------------------------------------| +| Listener script | `/usr/bin/profanity-notify-listener` | +| XDG autostart entry | `/etc/xdg/autostart/profanity-notify-listener.desktop` | +| Configuration | `/etc/profanity-remote-notifications.conf` | +| Plugin (for reference) | `/usr/share/profanity-remote-notifications/notify_ntfy.py` | + +### Configure the ntfy URL + +Edit `/etc/profanity-remote-notifications.conf`: + +```sh +NTFY_URL=http://your-ntfy-server/profanity +``` + +This must point to the same ntfy server and topic as the Profanity plugin. + +### Run + +The listener starts automatically on login via the XDG autostart entry. To +start it manually: + +```sh +profanity-notify-listener +``` + +### Manual install + +Copy `profanity-notify-listener.sh` somewhere on your PATH, create +`/etc/profanity-remote-notifications.conf` with your ntfy URL, and arrange for +the script to start on login (systemd user unit, shell profile, etc.). diff --git a/notify_ntfy.py b/notify_ntfy.py new file mode 100644 index 0000000..cb2130a --- /dev/null +++ b/notify_ntfy.py @@ -0,0 +1,31 @@ +"""Profanity plugin that forwards notifications to a ntfy server.""" + +import prof +import urllib.request + +NTFY_URL = prof.settings_string_get("ntfy", "url", "http://localhost/profanity") + + +def _send(title, message): + try: + req = urllib.request.Request( + NTFY_URL, + data=message.encode("utf-8"), + headers={ + "Title": title, + "Tags": "speech_balloon", + }, + ) + urllib.request.urlopen(req, timeout=5) + except Exception as e: + prof.cons_show(f"ntfy error: {e}") + + +def prof_post_chat_message_display(barejid, resource, message): + _send(barejid, message) + + +def prof_post_room_message_display(barejid, nick, message): + my_nick = prof.get_room_nick(barejid) + if my_nick and my_nick.lower() in message.lower(): + _send(f"{barejid} - {nick}", message) diff --git a/profanity-notify-listener.desktop b/profanity-notify-listener.desktop new file mode 100644 index 0000000..82c4aad --- /dev/null +++ b/profanity-notify-listener.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Type=Application +Name=Profanity Notification Listener +Comment=Forwards Profanity XMPP notifications from ntfy to desktop +Exec=/usr/bin/profanity-notify-listener +NoDisplay=true +X-GNOME-Autostart-enabled=true diff --git a/profanity-notify-listener.sh b/profanity-notify-listener.sh new file mode 100755 index 0000000..602f4cb --- /dev/null +++ b/profanity-notify-listener.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# Subscribes to ntfy and shows desktop notifications via notify-send. + +. /etc/profanity-remote-notifications.conf + +curl -sN "$NTFY_URL/sse" | while read -r line; do + case "$line" in + data:\ *) + json="${line#data: }" + title=$(printf '%s' "$json" | jq -r '.title // "Profanity"') + message=$(printf '%s' "$json" | jq -r '.message // empty') + [ -n "$message" ] && notify-send -a Profanity "$title" "$message" + ;; + esac +done diff --git a/profanity-remote-notifications.conf b/profanity-remote-notifications.conf new file mode 100644 index 0000000..fbd82fd --- /dev/null +++ b/profanity-remote-notifications.conf @@ -0,0 +1 @@ +NTFY_URL=http://localhost/profanity