diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml.disabled similarity index 100% rename from .gitea/workflows/build.yml rename to .gitea/workflows/build.yml.disabled diff --git a/.gitea/workflows/mirror-alpine.yml b/.gitea/workflows/mirror-alpine.yml.disabled similarity index 100% rename from .gitea/workflows/mirror-alpine.yml rename to .gitea/workflows/mirror-alpine.yml.disabled diff --git a/Dockerfile b/Dockerfile index fda5732..867f715 100644 --- a/Dockerfile +++ b/Dockerfile @@ -42,6 +42,8 @@ RUN apt-get update && apt-get install -y \ xauth \ # Supervisord to manage processes supervisor \ + # Emoji font support + fonts-noto-color-emoji \ # Utilities wget \ curl \ @@ -72,9 +74,12 @@ COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf COPY entrypoint.sh /usr/local/bin/entrypoint.sh COPY openbox-rc.xml /home/${USER}/.config/openbox/rc.xml COPY index.html /usr/share/novnc/index.html +COPY vnc-patched.html /usr/share/novnc/vnc.html +COPY vnc-clipboard-bridge.js /usr/share/novnc/vnc-clipboard-bridge.js +COPY log-prefix.sh /usr/local/bin/log-prefix.sh # Set permissions -RUN chmod +x /usr/local/bin/entrypoint.sh \ +RUN chmod +x /usr/local/bin/entrypoint.sh /usr/local/bin/log-prefix.sh \ && chown -R ${USER}:${USER} /home/${USER} /config /downloads /incomplete # Expose noVNC and Soulseek ports diff --git a/entrypoint.sh b/entrypoint.sh index fdf921d..b381ef3 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -32,12 +32,36 @@ if [ ! -z "$VNC_PASSWORD" ]; then fi # Export environment variables for supervisord -export DISPLAY +export DISPLAY=${DISPLAY:-:0} export VNC_PORT export NOVNC_PORT export VNC_RESOLUTION export VNC_DEPTH export USER +# Ensure X11 socket directory exists with the correct permissions (needed by Xvnc) +mkdir -p /tmp/.X11-unix +chmod 1777 /tmp/.X11-unix +chown root:root /tmp/.X11-unix + +# Remove stale X lock files for the configured DISPLAY to avoid "Server is already active" errors +DISPLAY_NUM=${DISPLAY#:} +LOCK_FILE="/tmp/.X${DISPLAY_NUM}-lock" +SOCKET_FILE="/tmp/.X11-unix/X${DISPLAY_NUM}" +if [ -f "$LOCK_FILE" ]; then + LOCK_PID=$(cat "$LOCK_FILE" 2>/dev/null || true) + if pgrep -f "Xvnc :${DISPLAY_NUM}" >/dev/null 2>&1; then + echo "Existing Xvnc server detected for display :${DISPLAY_NUM}; leaving lock file intact" + elif [ -n "$LOCK_PID" ] && kill -0 "$LOCK_PID" 2>/dev/null; then + echo "Lock file $LOCK_FILE points to PID $LOCK_PID, but no Xvnc found; removing stale lock" + rm -f "$LOCK_FILE" + rm -f "$SOCKET_FILE" + else + echo "Removing stale X lock file $LOCK_FILE" + rm -f "$LOCK_FILE" + rm -f "$SOCKET_FILE" + fi +fi + # Start supervisord as root (which will start processes as nicotine user) exec "$@" diff --git a/index.html b/index.html index 82fe46a..d885c20 100644 --- a/index.html +++ b/index.html @@ -6,7 +6,8 @@ Nicotine+ noVNC -

Redirecting to noVNC with remote resize enabled...

-

If not redirected automatically, click here.

+

Redirecting to Nicotine+ VNC interface...

+

If not redirected automatically, click here.

+

Note: Seamless clipboard sync is enabled when accessing via HTTPS.

diff --git a/log-prefix.sh b/log-prefix.sh new file mode 100644 index 0000000..afd7fed --- /dev/null +++ b/log-prefix.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# Wrapper script to prefix output with program name +PROGRAM_NAME="$1" +shift +exec "$@" 2>&1 | stdbuf -oL -eL sed "s/^/[$PROGRAM_NAME] /" diff --git a/supervisord.conf b/supervisord.conf index 4972481..823a842 100644 --- a/supervisord.conf +++ b/supervisord.conf @@ -1,43 +1,53 @@ [supervisord] nodaemon=true user=root -logfile=/var/log/supervisor/supervisord.log +logfile=/dev/stdout +logfile_maxbytes=0 pidfile=/var/run/supervisord.pid [program:xvnc] -command=/usr/bin/Xvnc :0 -geometry %(ENV_VNC_RESOLUTION)s -depth %(ENV_VNC_DEPTH)s -SecurityTypes None -rfbport %(ENV_VNC_PORT)s -AcceptSetDesktopSize=1 +command=/usr/local/bin/log-prefix.sh xvnc /usr/bin/Xvnc :0 -geometry %(ENV_VNC_RESOLUTION)s -depth %(ENV_VNC_DEPTH)s -SecurityTypes None -rfbport %(ENV_VNC_PORT)s -AcceptSetDesktopSize=1 -AlwaysShared -SendPrimary -SendCutText -AcceptCutText user=%(ENV_USER)s autostart=true autorestart=true priority=10 -stdout_logfile=/var/log/supervisor/xvnc.log -stderr_logfile=/var/log/supervisor/xvnc_err.log +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 [program:openbox] -command=/usr/bin/openbox -environment=DISPLAY=":0" +command=/usr/local/bin/log-prefix.sh openbox /usr/bin/openbox +environment=DISPLAY=":0",HOME="/home/%(ENV_USER)s",XDG_CONFIG_HOME="/home/%(ENV_USER)s/.config",XDG_DATA_HOME="/home/%(ENV_USER)s/.local/share",XDG_CACHE_HOME="/home/%(ENV_USER)s/.cache" user=%(ENV_USER)s autostart=true autorestart=true priority=20 -stdout_logfile=/var/log/supervisor/openbox.log -stderr_logfile=/var/log/supervisor/openbox_err.log +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 [program:novnc] -command=/usr/share/novnc/utils/novnc_proxy --vnc localhost:%(ENV_VNC_PORT)s --listen %(ENV_NOVNC_PORT)s +command=/usr/local/bin/log-prefix.sh novnc /usr/share/novnc/utils/novnc_proxy --vnc localhost:%(ENV_VNC_PORT)s --listen %(ENV_NOVNC_PORT)s --heartbeat 30 --idle-timeout 0 +environment=HOME="/home/%(ENV_USER)s",XDG_CONFIG_HOME="/home/%(ENV_USER)s/.config",XDG_DATA_HOME="/home/%(ENV_USER)s/.local/share",XDG_CACHE_HOME="/home/%(ENV_USER)s/.cache" user=%(ENV_USER)s autostart=true autorestart=true priority=30 -stdout_logfile=/var/log/supervisor/novnc.log -stderr_logfile=/var/log/supervisor/novnc_err.log +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 [program:nicotine] -command=/usr/local/bin/nicotine +command=/usr/local/bin/log-prefix.sh nicotine /usr/local/bin/nicotine environment=DISPLAY=":0",HOME="/home/%(ENV_USER)s",XDG_CONFIG_HOME="/home/%(ENV_USER)s/.config",XDG_DATA_HOME="/home/%(ENV_USER)s/.local/share" user=%(ENV_USER)s autostart=true autorestart=true priority=40 -stdout_logfile=/var/log/supervisor/nicotine.log -stderr_logfile=/var/log/supervisor/nicotine_err.log +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 diff --git a/vnc-clipboard-bridge.js b/vnc-clipboard-bridge.js new file mode 100644 index 0000000..da85fd4 --- /dev/null +++ b/vnc-clipboard-bridge.js @@ -0,0 +1,65 @@ +// VNC → Browser clipboard sync only (one-way) +(function() { + 'use strict'; + + console.log('🔌 Clipboard sync initializing (VNC → Browser only)...'); + + const clipboardAvailable = navigator.clipboard && window.isSecureContext; + + if (!clipboardAvailable) { + console.warn('⚠️ Clipboard API not available - requires HTTPS or localhost'); + return; + } + + console.log('✓ Clipboard API available (HTTPS detected)'); + + let lastPanelClipboard = ''; + + // Wait for clipboard panel to be available + function waitForPanel(callback) { + const panel = document.getElementById('noVNC_clipboard_text'); + if (panel) { + console.log('✓ Found noVNC clipboard panel'); + callback(panel); + } else { + setTimeout(() => waitForPanel(callback), 100); + } + } + + waitForPanel(function(clipboardPanel) { + console.log('✓ Setting up VNC → Browser clipboard sync'); + + // Sync VNC clipboard to browser + function syncVNCToBrowser() { + const text = clipboardPanel.value; + if (text && text !== lastPanelClipboard) { + lastPanelClipboard = text; + + console.log('📋 VNC → Browser: ' + text.substring(0, 50) + (text.length > 50 ? '... (' + text.length + ' chars)' : '')); + + navigator.clipboard.writeText(text).then(() => { + console.log('✓ Synced to system clipboard'); + }).catch(err => { + console.error('✗ Failed to write to clipboard:', err); + }); + } + } + + // Monitor changes to the clipboard panel + const observer = new MutationObserver(syncVNCToBrowser); + clipboardPanel.addEventListener('input', syncVNCToBrowser); + clipboardPanel.addEventListener('change', syncVNCToBrowser); + + // Poll the panel periodically as fallback + setInterval(syncVNCToBrowser, 300); + + observer.observe(clipboardPanel, { + attributes: true, + childList: true, + characterData: true, + subtree: true + }); + + console.log('✓ VNC → Browser clipboard sync ACTIVE'); + }); +})(); diff --git a/vnc-patched.html b/vnc-patched.html new file mode 100644 index 0000000..ce0e8ba --- /dev/null +++ b/vnc-patched.html @@ -0,0 +1,345 @@ + + + + + + noVNC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
noVNC encountered an error:
+
+
+
+
+ + +
+ +
+
+ +
+ +

no
VNC

+ + + + + +
+ +
+ + + +
+
+ + + + + + +
+
+ + + +
+
+
+ Power +
+ + + +
+
+ + + +
+
+
+ Clipboard +
+ +
+ +
+
+ + + + + + +
+
+
    +
  • + Settings +
  • +
  • + +
  • +
  • + +
  • +

  • +
  • + +
  • +
  • + + +
  • +

  • +
  • +
    Advanced
    +
      +
    • + + +
    • +
    • + + +
    • +

    • +
    • + + +
    • +
    • +
      WebSocket
      +
        +
      • + +
      • +
      • + + +
      • +
      • + + +
      • +
      • + + +
      • +
      +
    • +

    • +
    • + +
    • +
    • + + +
    • +

    • +
    • + +
    • +

    • + +
    • + +
    • +
    +
  • +

  • +
  • + Version: + +
  • +
+
+
+ + + + +
+
+ +
+ +
+ + +
+ + +
+
+ +
+ Connect +
+
+
+ + +
+
+
    +
  • + + +
  • +
  • + + +
  • +
  • + +
  • +
+
+
+ + +
+
+
+ +
+
+
+ + +
+ + +
+ + + +