diff --git a/Dockerfile b/Dockerfile index fbc14e8..d5da7a1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,6 +19,13 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ wget \ libnotify-bin \ notification-daemon \ + dbus-x11 \ + python3 \ + python3-gi \ + python3-xlib \ + gir1.2-notify-0.7 \ + xdotool \ + wmctrl \ # GPU/OpenGL libraries for RuneLite GPU plugin mesa-utils \ libgl1-mesa-dri \ @@ -33,13 +40,20 @@ RUN if [ -f /usr/share/selkies/www/index.html ]; then \ sed -i '/<\/head>/r /usr/share/selkies/www/webapp-meta.html' /usr/share/selkies/www/index.html ; \ fi +# Enable Selkies notification forwarding to browser +ENV SELKIES_ENABLE_NOTIFY="true" + ENV RUNELITE_URL="https://github.com/runelite/launcher/releases/latest/download/RuneLite.jar" ADD runelite /usr/local/bin +COPY notification-bridge.py /usr/local/bin/notification-bridge +COPY window-title-sync.py /usr/local/bin/window-title-sync RUN wget $RUNELITE_URL -P /usr/local/bin \ && chmod +x /usr/local/bin/RuneLite.jar \ - && chmod +x /usr/local/bin/runelite + && chmod +x /usr/local/bin/runelite \ + && chmod +x /usr/local/bin/notification-bridge \ + && chmod +x /usr/local/bin/window-title-sync # Configure window manager to hide title bars and maximize windows RUN mkdir -p /etc/xdg/openbox @@ -49,7 +63,9 @@ COPY openbox-rc.xml /etc/xdg/openbox/rc.xml # Use LinuxServer.io's autostart mechanism instead of custom cont-init.d RUN mkdir -p /defaults && \ - echo '/usr/local/bin/runelite' > /defaults/autostart + echo '/usr/local/bin/notification-bridge &' > /defaults/autostart && \ + echo '/usr/local/bin/window-title-sync &' >> /defaults/autostart && \ + echo '/usr/local/bin/runelite' >> /defaults/autostart # Also create desktop autostart as backup RUN mkdir -p /config/.config/autostart && \ diff --git a/notification-bridge.py b/notification-bridge.py new file mode 100644 index 0000000..b820121 --- /dev/null +++ b/notification-bridge.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +""" +D-Bus notification bridge for Selkies +Monitors desktop notifications and forwards them to the browser via Web Notifications API +""" + +import gi # type: ignore +gi.require_version('Notify', '0.7') # type: ignore +from gi.repository import Notify, GLib # type: ignore +import sys +import os + +def on_notification(notification): + """Callback when a notification is received""" + # Selkies will automatically capture notifications sent via libnotify + # This script ensures the notification daemon is properly initialized + pass + +def main(): + # Initialize libnotify + if not Notify.init("notification-bridge"): + print("Failed to initialize libnotify", file=sys.stderr) + sys.exit(1) + + print("Notification bridge started - forwarding desktop notifications to browser") + + # Keep the script running to maintain D-Bus connection + try: + loop = GLib.MainLoop() + loop.run() + except KeyboardInterrupt: + print("\nNotification bridge stopped") + Notify.uninit() + +if __name__ == "__main__": + main() diff --git a/window-title-sync.py b/window-title-sync.py new file mode 100644 index 0000000..7e0daee --- /dev/null +++ b/window-title-sync.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +""" +Window title synchronization for Selkies +Monitors the active window title and updates the browser tab title dynamically + +Note: This script is designed to run inside a Linux container with X11 tools installed. +Pylance warnings about missing imports are expected in the development environment. +""" + +import subprocess +import time +import os +import sys + +def get_active_window_title(): + """Get the title of the currently active window""" + try: + # Try using xdotool first + result = subprocess.run( + ['xdotool', 'getactivewindow', 'getwindowname'], + capture_output=True, + text=True, + timeout=1 + ) + if result.returncode == 0: + return result.stdout.strip() + except (subprocess.TimeoutExpired, FileNotFoundError): + pass + + try: + # Fallback to wmctrl + result = subprocess.run( + ['wmctrl', '-l'], + capture_output=True, + text=True, + timeout=1 + ) + if result.returncode == 0: + lines = result.stdout.strip().split('\n') + for line in lines: + if 'RuneLite' in line: + # Extract title (after the third column) + parts = line.split(None, 3) + if len(parts) >= 4: + return parts[3] + except (subprocess.TimeoutExpired, FileNotFoundError): + pass + + return None + +def update_browser_title(title): + """Update the Selkies browser tab title""" + title_file = '/opt/gst-web/title' + + # Create directory if it doesn't exist + os.makedirs(os.path.dirname(title_file), exist_ok=True) + + try: + with open(title_file, 'w') as f: + f.write(title) + except Exception as e: + print(f"Error updating title file: {e}", file=sys.stderr) + +def main(): + print("Window title sync started - monitoring RuneLite window") + + last_title = None + + # Initial delay to let X11 and windows initialize + time.sleep(5) + + while True: + try: + current_title = get_active_window_title() + + # Only update if title has changed and contains "RuneLite" + if current_title and 'RuneLite' in current_title and current_title != last_title: + print(f"Window title changed to: {current_title}") + update_browser_title(current_title) + last_title = current_title + + # Check every 2 seconds + time.sleep(2) + + except KeyboardInterrupt: + print("\nWindow title sync stopped") + break + except Exception as e: + print(f"Error in title monitoring: {e}", file=sys.stderr) + time.sleep(5) + +if __name__ == "__main__": + main()