wolf: add ./manage.sh add-web — URL shortcut tiles in Moonlight via Firefox kiosk

Prompts for a display name and URL, auto-fetches the site's apple-touch-icon
or favicon.png, falls back to a manual URL/local-PNG prompt, then injects a
[[profiles.apps]] block using ghcr.io/games-on-whales/firefox:edge with
START_URL set to the target URL. Wolf's virtual gamepad injection means
controller-aware sites (Gamepad API) work naturally through the stream.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
This commit is contained in:
Claude
2026-06-20 15:21:30 +00:00
parent b72e2bf549
commit 37f85d6adf
+161 -1
View File
@@ -1289,6 +1289,164 @@ PYEOF
echo "Wolf restarted — the new tile order shows on next Moonlight connection."
fi
;;
add-web)
# Add a Moonlight tile that opens a URL in a Firefox kiosk streaming container.
# Usage: ./manage.sh add-web [name] [url]
if [ ! -f "$WOLF_CFG" ]; then
echo "Wolf config not found at $WOLF_CFG — start Wolf once first."
exit 1
fi
# Gather display name
WEB_TITLE="${2:-}"
if [ -z "$WEB_TITLE" ]; then
read -r -p " Display name (e.g. 'Dinosaur Game'): " WEB_TITLE
fi
WEB_TITLE="${WEB_TITLE:-Web App}"
# Gather URL
WEB_URL="${3:-}"
if [ -z "$WEB_URL" ]; then
read -r -p " URL (e.g. https://dinosaur-game.io/): " WEB_URL
fi
if [ -z "$WEB_URL" ]; then echo "No URL entered."; exit 1; fi
# Prepend https:// if no scheme given
[[ "$WEB_URL" =~ ^https?:// ]] || WEB_URL="https://$WEB_URL"
# Try to auto-detect an icon
WEB_DOMAIN=$(python3 -c "from urllib.parse import urlparse; u=urlparse('$WEB_URL'); print(u.scheme+'://'+u.netloc)" 2>/dev/null)
WEB_ICON=""
echo " Looking for icon at $WEB_DOMAIN..."
for _try_icon in \
"$WEB_DOMAIN/apple-touch-icon.png" \
"$WEB_DOMAIN/apple-touch-icon-precomposed.png" \
"$WEB_DOMAIN/icon.png" \
"$WEB_DOMAIN/favicon.png"; do
if curl -fsSL --max-time 5 -o /dev/null -w "%{http_code}" "$_try_icon" 2>/dev/null \
| grep -q "^2"; then
WEB_ICON="$_try_icon"
echo " Found icon: $WEB_ICON"
break
fi
done
if [ -z "$WEB_ICON" ]; then
echo " Could not auto-detect a PNG icon."
echo " Options:"
echo " 1) Enter an image URL (PNG)"
echo " 2) Enter a local PNG file path"
echo " 3) Use default browser icon"
read -r -p " Choice [3]: " _ICON_CHOICE
_ICON_CHOICE="${_ICON_CHOICE:-3}"
if [ "$_ICON_CHOICE" = "1" ]; then
read -r -p " Image URL: " WEB_ICON
elif [ "$_ICON_CHOICE" = "2" ]; then
read -r -p " Local PNG path: " _LOCAL_PNG
_LOCAL_PNG="${_LOCAL_PNG/#\~/$HOME}"
if [ -f "$_LOCAL_PNG" ]; then
# Copy to wolf state dir so Wolf can find it
_ICONS_DIR="${WOLF_STATE_DIR:-/etc/wolf}/cfg/icons"
sudo mkdir -p "$_ICONS_DIR"
_ICON_NAME="$(basename "$_LOCAL_PNG")"
sudo cp "$_LOCAL_PNG" "$_ICONS_DIR/$_ICON_NAME"
WEB_ICON="$_ICONS_DIR/$_ICON_NAME"
else
echo " File not found — using default icon."
fi
fi
fi
[ -z "$WEB_ICON" ] && \
WEB_ICON="https://games-on-whales.github.io/wildlife/apps/firefox/assets/icon.png"
# Sanitize title → WolfWeb-<CamelCase>
WOLF_WEB_NAME="WolfWeb-$(echo "$WEB_TITLE" | tr -s ' \t' '-' | tr -cd 'A-Za-z0-9-')"
echo ""
echo " Adding Moonlight tile:"
echo " Title : $WEB_TITLE"
echo " URL : $WEB_URL"
echo " Icon : $WEB_ICON"
echo " Name : $WOLF_WEB_NAME"
echo ""
sudo python3 - "$WOLF_CFG" "$WOLF_WEB_NAME" "$WEB_TITLE" "$WEB_ICON" "$WEB_URL" << 'PYEOF'
import sys, json, re
cfg = sys.argv[1]
wolf_name = sys.argv[2]
title = sys.argv[3]
icon = sys.argv[4]
url = sys.argv[5]
STD_RULES = ['c 13:* rmw', 'c 244:* rmw']
cap_add = ['NET_RAW', 'MKNOD', 'NET_ADMIN']
env = [
f'START_URL={url}',
'MOZ_ENABLE_WAYLAND=1',
'RUN_SWAY=1',
'GOW_REQUIRED_DEVICES=/dev/input/* /dev/dri/* /dev/nvidia*',
]
host_cfg = {
'IpcMode': 'host',
'CapAdd': cap_add,
'Privileged': False,
'DeviceCgroupRules': STD_RULES,
}
create_json = json.dumps({'HostConfig': host_cfg}, indent=2)
env_str = str(env).replace('"', "'")
block = (
f"\n"
f" [[profiles.apps]]\n"
f" icon_png_path = '{icon}'\n"
f" start_virtual_compositor = true\n"
f" title = '{title}'\n"
f"\n"
f" [profiles.apps.runner]\n"
f" base_create_json = '''{create_json}\n"
f"'''\n"
f" devices = []\n"
f" env = {env_str}\n"
f" image = 'ghcr.io/games-on-whales/firefox:edge'\n"
f" mounts = []\n"
f" name = '{wolf_name}'\n"
f" ports = []\n"
f" type = 'docker'\n"
)
with open(cfg) as f:
lines = f.readlines()
# Check if already present
if any(f"name = '{wolf_name}'" in l for l in lines):
print(f"'{title}' already exists in config (name={wolf_name}). Remove it first if you want to re-add.")
sys.exit(1)
# Find insert point: just before the second [[profiles]] block, or end of file
profiles_seen, insert_at = 0, len(lines)
for i, line in enumerate(lines):
if line.strip() == '[[profiles]]':
profiles_seen += 1
if profiles_seen == 2:
insert_at = i
break
block_lines = [l + '\n' if not l.endswith('\n') else l for l in block.splitlines()]
new_lines = lines[:insert_at] + block_lines + lines[insert_at:]
with open(cfg, 'w') as f:
f.writelines(new_lines)
print(f"Added '{title}' ({wolf_name}) — tile will appear in Moonlight after Wolf restarts.")
sys.exit(0)
PYEOF
if [ $? -eq 0 ]; then
docker compose restart wolf
echo "Wolf restarted — '$WEB_TITLE' will appear in Moonlight on next connection."
echo ""
echo " Controller tip: Wolf injects a virtual gamepad into the streaming container."
echo " Sites that use the browser Gamepad API (many classic arcade ports, etc.)"
echo " will respond to your controller. Keyboard-driven sites won't respond to"
echo " gamepad buttons directly, but Wolf's virtual keyboard lets you type."
fi
;;
backup)
echo "Set up backups with the modular system: sudo ./setup.sh backup"
;;
@@ -1354,6 +1512,7 @@ PYEOF
echo " ./manage.sh update - Pull latest Wolf image and restart"
echo " ./manage.sh apps - Add / update game launchers in Wolf"
echo " ./manage.sh reorder - Reorder the Moonlight tile list"
echo " ./manage.sh add-web [name] [url] - Add a URL shortcut tile (Firefox kiosk)"
echo " ./manage.sh fix-perms - Fix 'Permission denied' app startup errors"
echo " ./manage.sh backup - How to set up backups"
;;
@@ -1657,7 +1816,7 @@ PYEOF
echo " Online together → each player launches their own session,"
echo " all connect to the same game server"
echo ""
echo "Manage: cd $WOLF_DIR && ./manage.sh {start|stop|restart|logs|status|pin|update|apps|reorder}"
echo "Manage: cd $WOLF_DIR && ./manage.sh {start|stop|restart|logs|status|pin|update|apps|reorder|add-web}"
echo ""
echo "── BACKUPS ───────────────────────────────────────────"
echo ""
@@ -1705,6 +1864,7 @@ cd $WOLF_DIR
./manage.sh update # pull latest image and restart
./manage.sh apps # add / update game launchers
./manage.sh reorder # reorder the Moonlight tile list
./manage.sh add-web # add a URL shortcut tile (Firefox kiosk)
\`\`\`
## Ports (open on firewall / router)