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:
+161
-1
@@ -1289,6 +1289,164 @@ PYEOF
|
|||||||
echo "Wolf restarted — the new tile order shows on next Moonlight connection."
|
echo "Wolf restarted — the new tile order shows on next Moonlight connection."
|
||||||
fi
|
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)
|
backup)
|
||||||
echo "Set up backups with the modular system: sudo ./setup.sh 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 update - Pull latest Wolf image and restart"
|
||||||
echo " ./manage.sh apps - Add / update game launchers in Wolf"
|
echo " ./manage.sh apps - Add / update game launchers in Wolf"
|
||||||
echo " ./manage.sh reorder - Reorder the Moonlight tile list"
|
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 fix-perms - Fix 'Permission denied' app startup errors"
|
||||||
echo " ./manage.sh backup - How to set up backups"
|
echo " ./manage.sh backup - How to set up backups"
|
||||||
;;
|
;;
|
||||||
@@ -1657,7 +1816,7 @@ PYEOF
|
|||||||
echo " Online together → each player launches their own session,"
|
echo " Online together → each player launches their own session,"
|
||||||
echo " all connect to the same game server"
|
echo " all connect to the same game server"
|
||||||
echo ""
|
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 ""
|
||||||
echo "── BACKUPS ───────────────────────────────────────────"
|
echo "── BACKUPS ───────────────────────────────────────────"
|
||||||
echo ""
|
echo ""
|
||||||
@@ -1705,6 +1864,7 @@ cd $WOLF_DIR
|
|||||||
./manage.sh update # pull latest image and restart
|
./manage.sh update # pull latest image and restart
|
||||||
./manage.sh apps # add / update game launchers
|
./manage.sh apps # add / update game launchers
|
||||||
./manage.sh reorder # reorder the Moonlight tile list
|
./manage.sh reorder # reorder the Moonlight tile list
|
||||||
|
./manage.sh add-web # add a URL shortcut tile (Firefox kiosk)
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|
||||||
## Ports (open on firewall / router)
|
## Ports (open on firewall / router)
|
||||||
|
|||||||
Reference in New Issue
Block a user