#!/bin/bash # Install the Screencast plugin for the current user. # ./install.sh install the daemon venv, link + enable the shell plugin # ./install.sh --no-root same, but never ask for a password (skips missing packages) # ./install.sh --uninstall # # Nothing here needs root except installing missing Arch packages, and even that # is skipped with --no-root: the daemon runs entirely as you. set -euo pipefail HERE=$(cd "$(dirname "$0")" && pwd) LIB=$HOME/.local/lib/screencast BIN=$HOME/.local/bin CACHE=${XDG_CACHE_HOME:-$HOME/.cache}/screencast STATE=${XDG_STATE_HOME:-$HOME/.local/state}/screencast ID=io.github.alanfortlink.screencast PLUGIN=$HOME/.config/omarchy/plugins/$ID MODE=${1:-} LOG=$CACHE/install.log if [[ $MODE == --uninstall ]]; then omarchy-plugin-disable "$ID" >/dev/null 2>&1 || true # The daemon is a plain user process; ask it to quit, then remove its files. "$LIB/screencast-server" stop >/dev/null 2>&1 || true rm -rf "$LIB" "$CACHE" "$STATE" "$BIN/screencast-server" [[ -L $PLUGIN ]] && rm -f "$PLUGIN" # dev symlink only echo "uninstalled (settings left in ~/.config/screencast/config.json). Now run: omarchy plugin remove $ID" echo "note: if you ever let it open the stream port, that firewall rule is still there." exit 0 fi # Runtime dependencies, all from the Arch repos. missing=() for p in python gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugin-pipewire gst-libav libpipewire xdg-desktop-portal; do pacman -Q "$p" >/dev/null 2>&1 || missing+=("$p") done # Something has to answer org.freedesktop.portal.ScreenCast. if ! pacman -Q xdg-desktop-portal-hyprland >/dev/null 2>&1 && ! pacman -Q xdg-desktop-portal-wlr >/dev/null 2>&1; then missing+=(xdg-desktop-portal-hyprland) fi if ((${#missing[@]})); then if [[ $MODE == --no-root ]]; then : # reported at the end, where the panel can see it else echo "› installing missing packages: ${missing[*]} (password prompt)" if sudo -n true 2>/dev/null; then sudo pacman -S --needed --noconfirm "${missing[@]}" else pkexec pacman -S --needed --noconfirm "${missing[@]}"; fi fi fi mkdir -p "$CACHE" "$LIB" "$BIN" echo "› creating the Python environment in $LIB/venv (log: $LOG)" { python3 -m venv --upgrade-deps "$LIB/venv" "$LIB/venv/bin/pip" install --upgrade -r "$HERE/daemon/requirements.txt" } >"$LOG" 2>&1 || { tail -n 15 "$LOG" >&2; echo "error: could not build the environment; log: $LOG" >&2; exit 1; } # AirPlay is optional: pyatv is a big dependency tree and lags new Python # releases, and everything else works without it. if "$LIB/venv/bin/pip" install --upgrade -r "$HERE/daemon/requirements-optional.txt" >>"$LOG" 2>&1; then echo " AirPlay support installed (pyatv)" else echo " note: pyatv did not install — Cast and DLNA still work, AirPlay will not (see $LOG)" fi echo "› installing the daemon" rm -rf "$LIB/screencast" cp -r "$HERE/daemon/screencast" "$LIB/screencast" find "$LIB/screencast" -name '__pycache__' -type d -exec rm -rf {} + 2>/dev/null || true cat > "$LIB/screencast-server" < "$LIB/installed-commit" 2>/dev/null || date +%s > "$LIB/installed-commit" echo "› installing the shell plugin" mkdir -p "$(dirname "$PLUGIN")" if [[ $(readlink -f "$PLUGIN" 2>/dev/null) != "$(readlink -f "$HERE")" ]]; then if [[ -L $PLUGIN || ! -e $PLUGIN ]]; then ln -sfn "$HERE" "$PLUGIN" # dev mode; a real checkout comes from `omarchy plugin add` omarchy-shell -q shell rescanPlugins 2>/dev/null || true fi fi if command -v omarchy-shell >/dev/null && omarchy-shell -q shell ping >/dev/null 2>&1; then enabled() { omarchy-plugin-list 2>/dev/null | awk -v id="$ID" '$1 == id && $2 == "enabled" { found = 1 } END { exit !found }'; } for _ in 1 2 3 4 5; do if enabled; then break; fi if omarchy-plugin-enable "$ID" right >/dev/null 2>&1; then echo " enabled $ID"; break; fi sleep 1 done enabled || echo " note: not enabled yet; run: omarchy plugin enable $ID" else echo " note: omarchy-shell is not running; enable later with: omarchy plugin enable $ID" fi # The receiver pulls the stream from us, so the host firewall has to let it in. # Installing stays root-free: the panel offers to open the port (via polkit) the # first time a cast is actually blocked by it. if [[ $(systemctl is-active ufw 2>/dev/null) == active || $(systemctl is-active firewalld 2>/dev/null) == active ]]; then echo "› note: this machine runs a firewall. Receivers fetch the stream from us, so" echo " the panel has an \"Open port\" button: one password dialog, once, and the" echo " rule stays. Nothing to type here." fi echo "done. The cast icon appears in the bar (if not: omarchy-shell shell rescanPlugins)." echo "From a terminal: screencast-server devices | cast \"\" | stop" # Missing system packages are the one thing this cannot fix without root, so say # so last: the plugin shows the final line of this log verbatim. if ((${#missing[@]})) && [[ $MODE == --no-root ]]; then echo "MISSING: sudo pacman -S --needed ${missing[*]}" fi