Test Notifications & Title Updates
All checks were successful
Build & Push Docker Image / build-and-publish (push) Successful in 21s
All checks were successful
Build & Push Docker Image / build-and-publish (push) Successful in 21s
This commit is contained in:
74
90-start-services
Normal file
74
90-start-services
Normal file
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/with-contenv bash
|
||||
# Start notification bridge and window title sync services
|
||||
# This runs during container initialization
|
||||
|
||||
echo "[init] Starting background services for notifications and window title sync"
|
||||
|
||||
# Create log directory
|
||||
mkdir -p /config/logs
|
||||
chown abc:abc /config/logs
|
||||
|
||||
# Wait for X server in background, then start services
|
||||
(
|
||||
# Log current environment
|
||||
echo "[init] $(date) - Starting background services" >> /config/logs/startup.log
|
||||
echo "[init] Running as user: $(whoami)" >> /config/logs/startup.log
|
||||
echo "[init] Python version: $(python3 --version 2>&1)" >> /config/logs/startup.log
|
||||
|
||||
# Wait for X server to be ready
|
||||
echo "[init] Waiting for X server..." >> /config/logs/startup.log
|
||||
timeout=60
|
||||
while [ $timeout -gt 0 ]; do
|
||||
if DISPLAY=:0 xdpyinfo >/dev/null 2>&1; then
|
||||
echo "[init] X server is ready!" >> /config/logs/startup.log
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
((timeout--))
|
||||
done
|
||||
|
||||
if [ $timeout -eq 0 ]; then
|
||||
echo "[init] ERROR: X server failed to start within 60 seconds" >> /config/logs/startup.log
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Give X server and desktop environment time to fully initialize
|
||||
echo "[init] Waiting 10 seconds for desktop environment to stabilize..." >> /config/logs/startup.log
|
||||
sleep 10
|
||||
|
||||
# Start notification bridge with proper permissions
|
||||
echo "[init] Starting notification bridge..." >> /config/logs/startup.log
|
||||
s6-setuidgid abc env DISPLAY=:0 DBUS_SESSION_BUS_ADDRESS="${DBUS_SESSION_BUS_ADDRESS:-unix:path=/run/user/911/bus}" \
|
||||
/usr/local/bin/notification-bridge >> /config/logs/notification-bridge.log 2>&1 &
|
||||
NOTIF_PID=$!
|
||||
echo "[init] Notification bridge started with PID: $NOTIF_PID" >> /config/logs/startup.log
|
||||
|
||||
# Verify it's running
|
||||
sleep 1
|
||||
if kill -0 $NOTIF_PID 2>/dev/null; then
|
||||
echo "[init] Notification bridge is running" >> /config/logs/startup.log
|
||||
else
|
||||
echo "[init] WARNING: Notification bridge may have failed to start" >> /config/logs/startup.log
|
||||
fi
|
||||
|
||||
# Start window title sync with proper permissions
|
||||
echo "[init] Starting window title sync..." >> /config/logs/startup.log
|
||||
s6-setuidgid abc env DISPLAY=:0 /usr/local/bin/window-title-sync >> /config/logs/window-title-sync.log 2>&1 &
|
||||
TITLE_PID=$!
|
||||
echo "[init] Window title sync started with PID: $TITLE_PID" >> /config/logs/startup.log
|
||||
|
||||
# Verify it's running
|
||||
sleep 1
|
||||
if kill -0 $TITLE_PID 2>/dev/null; then
|
||||
echo "[init] Window title sync is running" >> /config/logs/startup.log
|
||||
else
|
||||
echo "[init] WARNING: Window title sync may have failed to start" >> /config/logs/startup.log
|
||||
fi
|
||||
|
||||
echo "[init] All background services started successfully at $(date)" >> /config/logs/startup.log
|
||||
|
||||
# Keep log files readable
|
||||
chown abc:abc /config/logs/*.log 2>/dev/null
|
||||
) &
|
||||
|
||||
echo "[init] Background services initialization launched"
|
||||
21
Dockerfile
21
Dockerfile
@@ -19,6 +19,14 @@ 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 \
|
||||
x11-utils \
|
||||
# GPU/OpenGL libraries for RuneLite GPU plugin
|
||||
mesa-utils \
|
||||
libgl1-mesa-dri \
|
||||
@@ -33,13 +41,24 @@ 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
|
||||
COPY test-features.sh /usr/local/bin/test-features
|
||||
COPY 90-start-services /etc/cont-init.d/90-start-services
|
||||
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 \
|
||||
&& chmod +x /usr/local/bin/test-features \
|
||||
&& chmod +x /etc/cont-init.d/90-start-services
|
||||
|
||||
# Configure window manager to hide title bars and maximize windows
|
||||
RUN mkdir -p /etc/xdg/openbox
|
||||
|
||||
43
notification-bridge.py
Normal file
43
notification-bridge.py
Normal file
@@ -0,0 +1,43 @@
|
||||
#!/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():
|
||||
# Ensure DISPLAY is set
|
||||
if not os.getenv('DISPLAY'):
|
||||
os.environ['DISPLAY'] = ':0'
|
||||
print("Set DISPLAY to :0", file=sys.stderr, flush=True)
|
||||
|
||||
# Initialize libnotify
|
||||
if not Notify.init("notification-bridge"): # type: ignore
|
||||
print("Failed to initialize libnotify", file=sys.stderr, flush=True)
|
||||
sys.exit(1)
|
||||
|
||||
print("Notification bridge started - forwarding desktop notifications to browser", flush=True)
|
||||
print(f"D-Bus session address: {os.getenv('DBUS_SESSION_BUS_ADDRESS', 'not set')}", flush=True)
|
||||
|
||||
# Keep the script running to maintain D-Bus connection
|
||||
try:
|
||||
loop = GLib.MainLoop() # type: ignore
|
||||
print("Entering main loop - ready to forward notifications", flush=True)
|
||||
loop.run()
|
||||
except KeyboardInterrupt:
|
||||
print("\nNotification bridge stopped", flush=True)
|
||||
Notify.uninit() # type: ignore
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
38
start-services.sh
Normal file
38
start-services.sh
Normal file
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
# Startup script for notification bridge and window title sync
|
||||
# Waits for X11 to be ready and starts background services with logging
|
||||
|
||||
LOG_DIR="/config/logs"
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
# Wait for X server to be ready
|
||||
echo "Waiting for X server..." >> "$LOG_DIR/startup.log"
|
||||
timeout=30
|
||||
while [ $timeout -gt 0 ]; do
|
||||
if xdpyinfo >/dev/null 2>&1; then
|
||||
echo "X server is ready!" >> "$LOG_DIR/startup.log"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
((timeout--))
|
||||
done
|
||||
|
||||
if [ $timeout -eq 0 ]; then
|
||||
echo "ERROR: X server failed to start within 30 seconds" >> "$LOG_DIR/startup.log"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Give X server a moment to fully initialize
|
||||
sleep 2
|
||||
|
||||
# Start notification bridge
|
||||
echo "Starting notification bridge..." >> "$LOG_DIR/startup.log"
|
||||
/usr/local/bin/notification-bridge >> "$LOG_DIR/notification-bridge.log" 2>&1 &
|
||||
echo "Notification bridge PID: $!" >> "$LOG_DIR/startup.log"
|
||||
|
||||
# Start window title sync
|
||||
echo "Starting window title sync..." >> "$LOG_DIR/startup.log"
|
||||
/usr/local/bin/window-title-sync >> "$LOG_DIR/window-title-sync.log" 2>&1 &
|
||||
echo "Window title sync PID: $!" >> "$LOG_DIR/startup.log"
|
||||
|
||||
echo "All background services started successfully" >> "$LOG_DIR/startup.log"
|
||||
48
test-features.sh
Normal file
48
test-features.sh
Normal file
@@ -0,0 +1,48 @@
|
||||
#!/bin/bash
|
||||
# Test script to verify notifications and title changes are working
|
||||
# Run this inside the container to test the features
|
||||
|
||||
echo "Testing notification and title sync features..."
|
||||
|
||||
# Test notification
|
||||
echo "Sending test notification..."
|
||||
notify-send "Test Notification" "If you see this in your browser, notifications are working!" -u normal
|
||||
|
||||
# Test window title detection
|
||||
echo ""
|
||||
echo "Checking for RuneLite window..."
|
||||
if xdotool search --name "RuneLite" > /dev/null 2>&1; then
|
||||
WINDOW_ID=$(xdotool search --name "RuneLite" | head -1)
|
||||
WINDOW_TITLE=$(xdotool getwindowname "$WINDOW_ID")
|
||||
echo "Found RuneLite window: $WINDOW_TITLE"
|
||||
else
|
||||
echo "RuneLite window not found. Make sure RuneLite is running."
|
||||
fi
|
||||
|
||||
# Check if services are running
|
||||
echo ""
|
||||
echo "Checking service status..."
|
||||
if pgrep -f "notification-bridge" > /dev/null; then
|
||||
echo "✓ Notification bridge is running (PID: $(pgrep -f 'notification-bridge'))"
|
||||
else
|
||||
echo "✗ Notification bridge is NOT running"
|
||||
fi
|
||||
|
||||
if pgrep -f "window-title-sync" > /dev/null; then
|
||||
echo "✓ Window title sync is running (PID: $(pgrep -f 'window-title-sync'))"
|
||||
else
|
||||
echo "✗ Window title sync is NOT running"
|
||||
fi
|
||||
|
||||
# Show log files if they exist
|
||||
echo ""
|
||||
echo "Log files location: /config/logs/"
|
||||
if [ -d "/config/logs" ]; then
|
||||
echo "Available logs:"
|
||||
ls -lh /config/logs/
|
||||
echo ""
|
||||
echo "To view logs, run:"
|
||||
echo " cat /config/logs/startup.log"
|
||||
echo " cat /config/logs/notification-bridge.log"
|
||||
echo " cat /config/logs/window-title-sync.log"
|
||||
fi
|
||||
118
window-title-sync.py
Normal file
118
window-title-sync.py
Normal file
@@ -0,0 +1,118 @@
|
||||
#!/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"""
|
||||
# Try multiple possible locations for Selkies title file
|
||||
title_locations = [
|
||||
'/opt/gst-web/title',
|
||||
'/tmp/selkies_title',
|
||||
'/var/run/selkies/title'
|
||||
]
|
||||
|
||||
success = False
|
||||
for title_file in title_locations:
|
||||
try:
|
||||
# Create directory if it doesn't exist
|
||||
os.makedirs(os.path.dirname(title_file), exist_ok=True)
|
||||
|
||||
with open(title_file, 'w') as f:
|
||||
f.write(title)
|
||||
success = True
|
||||
break
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
if not success:
|
||||
# Fallback: try to update via xdotool if title file doesn't work
|
||||
try:
|
||||
subprocess.run(['xdotool', 'set_desktop_name', title], timeout=1, check=False)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def main():
|
||||
print("Window title sync started - monitoring RuneLite window", flush=True)
|
||||
|
||||
# Ensure DISPLAY is set
|
||||
if 'DISPLAY' not in os.environ:
|
||||
os.environ['DISPLAY'] = ':0'
|
||||
print("Set DISPLAY to :0", flush=True)
|
||||
|
||||
last_title = None
|
||||
|
||||
# Initial delay to let X11 and RuneLite window appear
|
||||
print("Waiting for RuneLite window to appear...", flush=True)
|
||||
time.sleep(10)
|
||||
|
||||
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}", flush=True)
|
||||
update_browser_title(current_title)
|
||||
last_title = current_title
|
||||
elif current_title and last_title is None:
|
||||
# Log first title found for debugging
|
||||
print(f"First window title detected: {current_title}", flush=True)
|
||||
|
||||
# Check every 2 seconds
|
||||
time.sleep(2)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\nWindow title sync stopped", flush=True)
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"Error in title monitoring: {e}", file=sys.stderr, flush=True)
|
||||
time.sleep(5)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user