1 Commits
Author SHA1 Message Date
PixelplanetandCopilot 858293663b feat(install): one-command installer with automatic Steam library entry
Users can now install with a single command, either piped or from the
release tarball:

  curl -fsSL .../tools/install.sh | sh
  ./install.sh

Tools/install.sh downloads the latest (or a pinned) ARM64 release, verifies
the published checksum, installs to ~/PixelVRPlayer, and registers
"Pixel VR Player" as a Non-Steam Game by editing shortcuts.vdf through an
embedded binary-KeyValues helper (existing shortcuts are preserved, the file
is backed up, and unsupported files are left untouched). Options cover
--dir, --version, --no-steam, --restart-steam and --uninstall. Upgrades never
touch ~/.config/pixelvr or ~/.cache/pixelvr.

Also:
- package-release.sh ships install.sh and a VERSION file in the tarball.
- The release workflow publishes .sha256 checksums and syntax-checks the
  installer before building.
- Docs describe the one-command path for end users.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-17 10:16:06 +02:00
5 changed files with 630 additions and 13 deletions

No files matched your search

+19 -2
View File
@@ -37,6 +37,13 @@ jobs:
ref: ${{ inputs.tag || github.ref }}
fetch-depth: 1
- name: Check scripts
run: |
set -eux
sh -n tools/install.sh
bash -n tools/package-release.sh
bash -n tools/build.sh
- name: Build
run: bash tools/build.sh
@@ -44,21 +51,29 @@ jobs:
run: |
set -eux
tag="${{ inputs.tag || github.ref_name }}"
bash tools/package-release.sh build pixelvr-linux-arm64.tar.gz
bash tools/package-release.sh build pixelvr-linux-arm64.tar.gz "${tag}"
cp pixelvr-linux-arm64.tar.gz "pixelvr-linux-arm64-${tag}.tar.gz"
sha256sum pixelvr-linux-arm64.tar.gz > pixelvr-linux-arm64.tar.gz.sha256
sha256sum "pixelvr-linux-arm64-${tag}.tar.gz" > "pixelvr-linux-arm64-${tag}.tar.gz.sha256"
- name: Verify artifact
run: |
file build/bin/pixelvr
file build/bin/pixelvr | grep -q 'ARM aarch64'
tar -tzf pixelvr-linux-arm64.tar.gz | grep -q '^PixelVRPlayer/run.sh$'
tar -tzf pixelvr-linux-arm64.tar.gz | grep -q '^PixelVRPlayer/install.sh$'
tar -tzf pixelvr-linux-arm64.tar.gz | grep -q '^PixelVRPlayer/VERSION$'
tar -tzf pixelvr-linux-arm64.tar.gz | grep -q '/shaders/thumb.frag.spv$'
sha256sum -c pixelvr-linux-arm64.tar.gz.sha256
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: pixelvr-linux-arm64
path: pixelvr-linux-arm64-*.tar.gz
path: |
pixelvr-linux-arm64.tar.gz
pixelvr-linux-arm64.tar.gz.sha256
pixelvr-linux-arm64-v*.tar.gz
- name: Publish GitHub release
if: startsWith(github.ref, 'refs/tags/v') || inputs.tag != ''
@@ -68,4 +83,6 @@ jobs:
generate_release_notes: true
files: |
pixelvr-linux-arm64.tar.gz
pixelvr-linux-arm64.tar.gz.sha256
pixelvr-linux-arm64-v*.tar.gz
pixelvr-linux-arm64-v*.tar.gz.sha256
+29 -7
View File
@@ -20,19 +20,41 @@ A native VR video player for the **Valve Steam Frame**, playing flat 2D, 180°,
## Install (prebuilt release)
Download `pixelvr-linux-arm64.tar.gz` from the
[Releases](../../releases) page and copy it to your Steam Frame, then:
One command, from a terminal on the headset (Desktop Mode or over SSH):
```bash
curl -fsSL https://raw.githubusercontent.com/Pixelplanet/Pixel-VR-Player/main/tools/install.sh | sh
```
It downloads the latest ARM64 release, verifies its checksum, installs it to
`~/PixelVRPlayer`, and adds **Pixel VR Player** to your Steam library as a
Non-Steam Game. Restart Steam if it was already running. SteamVR must be
installed.
Launch **Pixel VR Player** from your library, or directly:
```bash
tar -xzf pixelvr-linux-arm64.tar.gz -C ~
chmod +x ~/PixelVRPlayer/run.sh
~/PixelVRPlayer/run.sh # opens the in-headset file browser
~/PixelVRPlayer/run.sh /path/clip.mp4 # …or auto-play a specific clip
```
To launch it from the headset library, add `~/PixelVRPlayer/run.sh` as a
**Non-Steam Game** (Steam ▸ Add a Non-Steam Game). SteamVR must be running; the
app logs to `~/pixelvr-run.log`.
Installer options:
| Option | Effect |
| --- | --- |
| `--dir DIR` | install somewhere other than `~/PixelVRPlayer` |
| `--version vX.Y.Z` | install a specific release instead of the latest |
| `--no-steam` | skip the Steam library entry |
| `--restart-steam` | close Steam first, then reopen it so the entry appears at once |
| `--uninstall` | remove the app and its Steam shortcut |
Re-run the same command to upgrade. Settings (`~/.config/pixelvr`) and cached
thumbnails (`~/.cache/pixelvr`) live outside the install directory and are kept.
**Offline install:** download `pixelvr-linux-arm64.tar.gz` from the
[Releases](../../releases) page, copy it to the headset, extract it and run
`./install.sh` from the extracted folder — or use `run.sh` directly. The app logs
to `~/pixelvr-run.log`.
Requirements: the SteamVR OpenXR runtime (SteamOS), Vulkan, and FFmpeg with the
V4L2 M2M decoders. For zero-copy dma-buf decoding, build the patched FFmpeg into
+22 -2
View File
@@ -4,8 +4,25 @@ This guide covers how to get the built app running on the headset, the available
options, and which one to pick.
**What you're shipping:** a single self-contained ARM64 binary
(`build-aarch64/bin/pixelvr`, ~11 MB, static OpenXR loader) plus four SPIR-V
shaders. That's it — no `libopenxr_loader.so` or other bundled libraries.
(`build-aarch64/bin/pixelvr`, ~11 MB, static OpenXR loader) plus SPIR-V shaders
and a shell launcher. That's it — no `libopenxr_loader.so` or other bundled
libraries.
---
## Just installing a release (no devkit, no build)
End users do not need any of the steps below. From a terminal on the headset
(Desktop Mode or over SSH):
```bash
curl -fsSL https://raw.githubusercontent.com/Pixelplanet/Pixel-VR-Player/main/tools/install.sh | sh
```
That verifies the checksum, installs to `~/PixelVRPlayer`, and registers
**Pixel VR Player** as a Non-Steam Game. Relaunch Steam if it was running. Rerun
the same command to upgrade; `--uninstall` removes it. The rest of this document
covers building and iterating as a developer.
---
@@ -20,6 +37,9 @@ shaders. That's it — no `libopenxr_loader.so` or other bundled libraries.
# 2b. Or stage a clean folder for the GUI Devkit Client:
./tools/stage.sh # -> dist/PixelVRPlayer/
# 2c. Or build the release tarball end users install from:
./tools/package-release.sh build-aarch64 pixelvr-linux-arm64.tar.gz v1.3.0
```
---
+549
View File
@@ -0,0 +1,549 @@
#!/bin/sh
# Pixel VR Player installer for the Valve Steam Frame.
#
# Download-and-run (no other files needed):
# curl -fsSL https://raw.githubusercontent.com/Pixelplanet/Pixel-VR-Player/main/tools/install.sh | sh
#
# Or from an extracted release tarball:
# ./install.sh
#
# Options:
# --dir DIR install directory (default: ~/PixelVRPlayer)
# --version vX.Y.Z release to install (default: the latest release)
# --no-steam do not add the Non-Steam Game shortcut
# --restart-steam close Steam before registering, then start it again
# --uninstall remove the app and its Steam shortcut
# --force install even if the CPU is not aarch64
# -h, --help show this help
#
# Settings (~/.config/pixelvr) and the thumbnail cache (~/.cache/pixelvr) live
# outside the install directory, so reinstalling or upgrading never loses them.
set -eu
REPO="Pixelplanet/Pixel-VR-Player"
ASSET="pixelvr-linux-arm64.tar.gz"
APP_NAME="Pixel VR Player"
INSTALL_DIR="${PIXELVR_INSTALL_DIR:-$HOME/PixelVRPlayer}"
VERSION=""
DO_STEAM=1
RESTART_STEAM=0
UNINSTALL=0
FORCE=0
if [ -t 1 ]; then
C_INFO=$(printf '\0033[36m')
C_OK=$(printf '\0033[32m')
C_WARN=$(printf '\0033[33m')
C_ERR=$(printf '\0033[31m')
C_OFF=$(printf '\0033[0m')
else
C_INFO=""; C_OK=""; C_WARN=""; C_ERR=""; C_OFF=""
fi
info() { printf '%s==>%s %s\n' "$C_INFO" "$C_OFF" "$*"; }
ok() { printf '%s ok%s %s\n' "$C_OK" "$C_OFF" "$*"; }
warn() { printf '%swarn%s %s\n' "$C_WARN" "$C_OFF" "$*" >&2; }
die() { printf '%serror%s %s\n' "$C_ERR" "$C_OFF" "$*" >&2; exit 1; }
usage() {
cat <<'USAGE'
Pixel VR Player installer for the Valve Steam Frame.
Usage:
curl -fsSL https://raw.githubusercontent.com/Pixelplanet/Pixel-VR-Player/main/tools/install.sh | sh
./install.sh [options]
Options:
--dir DIR install directory (default: ~/PixelVRPlayer)
--version vX.Y.Z release to install (default: the latest release)
--no-steam do not add the Non-Steam Game shortcut
--restart-steam close Steam before registering, then start it again
--uninstall remove the app and its Steam shortcut
--force install even if the CPU is not aarch64
-h, --help show this help
Settings in ~/.config/pixelvr and cached thumbnails in ~/.cache/pixelvr are
never touched by install, upgrade or uninstall.
USAGE
}
while [ $# -gt 0 ]; do
case "$1" in
--dir)
[ $# -ge 2 ] || die "--dir needs a value"
case "$2" in
"~/"*) INSTALL_DIR="$HOME/${2#\~/}" ;;
*) INSTALL_DIR="$2" ;;
esac
shift ;;
--dir=*) INSTALL_DIR="${1#--dir=}" ; case "$INSTALL_DIR" in "~/"*) INSTALL_DIR="$HOME/${INSTALL_DIR#\~/}" ;; esac ;;
--version)
[ $# -ge 2 ] || die "--version needs a value"
VERSION="$2"; shift ;;
--version=*) VERSION="${1#--version=}" ;;
--no-steam) DO_STEAM=0 ;;
--restart-steam) RESTART_STEAM=1 ;;
--uninstall) UNINSTALL=1 ;;
--force) FORCE=1 ;;
-h|--help) usage; exit 0 ;;
*) die "unknown option: $1 (try --help)" ;;
esac
shift
done
case "$INSTALL_DIR" in
""|"/"|".") die "refusing to use '$INSTALL_DIR' as install directory" ;;
esac
# ---------------------------------------------------------------------------
# Steam shortcut registration (non-Steam game in the library)
# ---------------------------------------------------------------------------
steam_running() {
command -v pgrep >/dev/null 2>&1 && pgrep -x steam >/dev/null 2>&1
}
find_steam_userdata() {
steam_root=""
for candidate in "$HOME/.steam/steam" "$HOME/.local/share/Steam" "$HOME/.steam/root"; do
if [ -d "$candidate/userdata" ]; then
steam_root="$candidate"
break
fi
done
[ -n "$steam_root" ] || return 1
vdf=""
newest=0
for dir in "$steam_root"/userdata/*; do
case "${dir##*/}" in ''|*[!0-9]*) continue ;; esac
file="$dir/config/shortcuts.vdf"
[ -f "$file" ] || continue
stamp=$(stat -c %Y "$file" 2>/dev/null || stat -f %m "$file" 2>/dev/null || echo 0)
if [ -z "$vdf" ] || [ "$stamp" -ge "$newest" ]; then
vdf="$file"
newest="$stamp"
fi
done
if [ -z "$vdf" ]; then
# No shortcuts.vdf yet: create it for the most recently used account.
for dir in "$steam_root"/userdata/*; do
case "${dir##*/}" in ''|*[!0-9]*) continue ;; esac
[ -d "$dir/config" ] || continue
stamp=$(stat -c %Y "$dir/config" 2>/dev/null || stat -f %m "$dir/config" 2>/dev/null || echo 0)
if [ -z "$vdf" ] || [ "$stamp" -ge "$newest" ]; then
vdf="$dir/config/shortcuts.vdf"
newest="$stamp"
fi
done
fi
[ -n "$vdf" ] || return 1
printf '%s\n' "$vdf"
}
# Binary KeyValues editor for shortcuts.vdf. Arguments:
# <add|remove> <vdf path> <app name> <exe> <start dir>
run_vdf_helper() {
python3 - "$@" <<'PYEOF'
import os
import struct
import sys
import zlib
OBJ, STR, INT, U64, END = 0x00, 0x01, 0x02, 0x07, 0x08
class Unsupported(Exception):
pass
def read_cstr(buf, pos):
end = buf.find(b"\0", pos)
if end < 0:
raise ValueError("unterminated string")
return buf[pos:end].decode("utf-8", "surrogateescape"), end + 1
def parse_obj(buf, pos):
entries = {}
while True:
if pos >= len(buf):
raise ValueError("truncated object")
kind = buf[pos]
if kind in (END, 0x0B):
return entries, pos + 1
key, pos = read_cstr(buf, pos + 1)
if kind == OBJ:
value, pos = parse_obj(buf, pos)
elif kind == STR:
value, pos = read_cstr(buf, pos)
elif kind == INT:
value = struct.unpack_from("<i", buf, pos)[0]
pos += 4
elif kind == U64:
value = struct.unpack_from("<Q", buf, pos)[0]
pos += 8
else:
raise Unsupported("unsupported type 0x%02x at key %r" % (kind, key))
entries[key] = [kind, value]
return entries, pos
def parse_file(buf):
if not buf:
return {"shortcuts": [OBJ, {}]}
if buf[0] != OBJ:
raise Unsupported("not a binary KeyValues file")
key, pos = read_cstr(buf, 1)
value, _ = parse_obj(buf, pos)
return {key: [OBJ, value]}
def dump(entries):
out = bytearray()
for key, (kind, value) in entries.items():
kb = key.encode("utf-8", "surrogateescape")
if kind == OBJ:
out += bytes([OBJ]) + kb + b"\0" + dump(value) + bytes([END])
elif kind == STR:
out += bytes([STR]) + kb + b"\0" + value.encode("utf-8", "surrogateescape") + b"\0"
elif kind == INT:
out += bytes([INT]) + kb + b"\0" + struct.pack("<i", value)
elif kind == U64:
out += bytes([U64]) + kb + b"\0" + struct.pack("<Q", value)
return bytes(out)
def app_id(exe, name):
# Steam derives the shortcut id from the quoted exe path plus the name.
return (zlib.crc32((exe + name).encode("utf-8")) | 0x80000000) & 0xFFFFFFFF
def to_i32(value):
return value - 0x100000000 if value >= 0x80000000 else value
def find(shortcuts, name, exe):
for key in shortcuts:
kind, entry = shortcuts[key]
if kind != OBJ:
continue
stored_exe = entry.get("Exe", [STR, ""])[1].strip('"')
stored_name = entry.get("AppName", [STR, ""])[1]
if (exe and stored_exe == exe) or stored_name == name:
return key, entry
return None, None
def main():
mode, path, name = sys.argv[1], sys.argv[2], sys.argv[3]
exe = sys.argv[4] if len(sys.argv) > 4 else ""
start_dir = sys.argv[5] if len(sys.argv) > 5 else ""
buf = b""
if os.path.exists(path):
with open(path, "rb") as handle:
buf = handle.read()
root = parse_file(buf)
shortcuts = root["shortcuts"][1]
key, entry = find(shortcuts, name, exe)
if mode == "remove":
if entry is None:
print("no matching shortcut, nothing to remove")
return 0
del shortcuts[key]
renumbered = {}
ordered = sorted(shortcuts, key=lambda k: int(k) if k.isdigit() else 1 << 30)
for index, old in enumerate(ordered):
renumbered[str(index)] = shortcuts[old]
root["shortcuts"][1] = renumbered
print("removed '%s'" % name)
else:
quoted_exe = '"%s"' % exe
created = entry is None
if created:
index = 0
for existing in shortcuts:
if existing.isdigit() and int(existing) >= index:
index = int(existing) + 1
entry = {}
shortcuts[str(index)] = [OBJ, entry]
if "appid" not in entry:
entry["appid"] = [INT, to_i32(app_id(quoted_exe, name))]
for field, value in (
("AppName", [STR, name]),
("Exe", [STR, quoted_exe]),
("StartDir", [STR, '"%s"' % start_dir]),
("icon", [STR, ""]),
("ShortcutPath", [STR, ""]),
("LaunchOptions", [STR, ""]),
("IsHidden", [INT, 0]),
("AllowDesktopConfig", [INT, 1]),
("AllowOverlay", [INT, 1]),
("OpenVR", [INT, 1]),
("Devkit", [INT, 0]),
("DevkitGameID", [STR, ""]),
("DevkitOverrideAppID", [INT, 0]),
("LastPlayTime", [INT, 0]),
("FlatpakAppID", [STR, ""]),
):
entry[field] = value
entry.setdefault("tags", [OBJ, {}])
print("%s '%s' (%d shortcut(s) in the library)" % (
"added" if created else "updated", name, len(shortcuts)))
data = dump(root) + bytes([END])
tmp = path + ".tmp"
with open(tmp, "wb") as handle:
handle.write(data)
if os.path.exists(path):
os.chmod(tmp, os.stat(path).st_mode & 0o777)
os.replace(tmp, path)
return 0
if __name__ == "__main__":
try:
sys.exit(main())
except Unsupported as exc:
sys.stderr.write("cannot edit shortcuts.vdf: %s\n" % exc)
sys.exit(3)
except Exception as exc: # noqa: BLE001 - surface any failure to the shell
sys.stderr.write("cannot edit shortcuts.vdf: %s\n" % exc)
sys.exit(1)
PYEOF
}
register_steam_shortcut() {
vdf=$(find_steam_userdata) || {
warn "Steam userdata not found - is Steam installed and logged in at least once?"
return 1
}
if ! command -v python3 >/dev/null 2>&1; then
warn "python3 not found - skipping Steam registration"
return 1
fi
steam_was_running=0
if steam_running; then
steam_was_running=1
if [ "$RESTART_STEAM" -eq 1 ]; then
info "Closing Steam so the new shortcut is kept..."
steam -shutdown >/dev/null 2>&1 || true
waited=0
while steam_running && [ "$waited" -lt 30 ]; do
sleep 1
waited=$((waited + 1))
done
if steam_running; then
warn "Steam did not close in time"
fi
else
warn "Steam is running - restart Steam afterwards to see '$APP_NAME' in the library"
fi
fi
if [ -f "$vdf" ]; then
backup="$vdf.bak.$(date +%Y%m%d%H%M%S)"
cp "$vdf" "$backup"
else
backup=""
fi
if ! run_vdf_helper add "$vdf" "$APP_NAME" "$INSTALL_DIR/run.sh" "$INSTALL_DIR"; then
[ -n "$backup" ] && [ -f "$backup" ] && cp "$backup" "$vdf"
return 1
fi
[ -n "$backup" ] && ok "shortcuts.vdf backed up to ${backup}"
if [ "$RESTART_STEAM" -eq 1 ] && [ "$steam_was_running" -eq 1 ] && ! steam_running; then
info "Starting Steam again..."
if command -v steam >/dev/null 2>&1; then
nohup steam >/dev/null 2>&1 &
fi
fi
STEAM_REGISTERED=1
}
unregister_steam_shortcut() {
vdf=$(find_steam_userdata) || return 1
[ -f "$vdf" ] || return 1
command -v python3 >/dev/null 2>&1 || return 1
run_vdf_helper remove "$vdf" "$APP_NAME" "" "" || return 1
}
# ---------------------------------------------------------------------------
# Uninstall
# ---------------------------------------------------------------------------
if [ "$UNINSTALL" -eq 1 ]; then
info "Removing Pixel VR Player from $INSTALL_DIR"
if [ "$DO_STEAM" -eq 1 ]; then
if unregister_steam_shortcut; then
ok "removed the Steam shortcut"
else
warn "could not remove the Steam shortcut; delete it in Steam manually"
fi
fi
rm -rf "$INSTALL_DIR"
ok "removed $INSTALL_DIR"
printf '\nSettings (%s/.config/pixelvr) and cached thumbnails were kept.\n' "$HOME"
printf 'Delete them too with: rm -rf ~/.config/pixelvr ~/.cache/pixelvr\n'
exit 0
fi
# ---------------------------------------------------------------------------
# Platform checks
# ---------------------------------------------------------------------------
machine=$(uname -m)
case "$machine" in
aarch64|arm64) ok "CPU: $machine" ;;
*)
if [ "$FORCE" -eq 0 ]; then
die "this release is built for the Steam Frame (aarch64), not '$machine'.
Build from source for other machines, or pass --force."
fi
warn "installing an aarch64 build on '$machine' (--force)" ;;
esac
# ---------------------------------------------------------------------------
# Fetch (reused by the local and download paths)
# ---------------------------------------------------------------------------
fetch() { # <url> <dest>
if command -v curl >/dev/null 2>&1; then
curl -fsSL "$1" -o "$2"
elif command -v wget >/dev/null 2>&1; then
wget -qO "$2" "$1"
else
die "need curl or wget to download the release"
fi
}
script_dir=""
if [ -f "$0" ]; then
script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" 2>/dev/null && pwd) || script_dir=""
fi
tmp=""
cleanup() { [ -z "$tmp" ] || rm -rf "$tmp"; }
trap cleanup EXIT INT TERM
if [ -n "$script_dir" ] && [ -f "$script_dir/pixelvr" ] && [ -d "$script_dir/shaders" ]; then
info "Installing from $script_dir"
srcdir="$script_dir"
if [ -f "$script_dir/VERSION" ]; then
VERSION="$(cat "$script_dir/VERSION")"
fi
if [ -n "$VERSION" ]; then
version_label="$VERSION"
else
version_label="local build"
fi
else
case "$VERSION" in
"") base="https://github.com/$REPO/releases/latest/download"
version_label="latest" ;;
v*) base="https://github.com/$REPO/releases/download/$VERSION"
version_label="$VERSION" ;;
*) VERSION="v$VERSION"
base="https://github.com/$REPO/releases/download/$VERSION"
version_label="$VERSION" ;;
esac
tmp=$(mktemp -d) || die "cannot create a temporary directory"
info "Downloading $version_label for aarch64"
fetch "$base/$ASSET" "$tmp/$ASSET" || die "download failed: $base/$ASSET"
if fetch "$base/$ASSET.sha256" "$tmp/$ASSET.sha256" 2>/dev/null; then
expected=$(awk 'NR == 1 { print $1 }' "$tmp/$ASSET.sha256")
if command -v sha256sum >/dev/null 2>&1; then
actual=$(sha256sum "$tmp/$ASSET" | awk '{ print $1 }')
elif command -v shasum >/dev/null 2>&1; then
actual=$(shasum -a 256 "$tmp/$ASSET" | awk '{ print $1 }')
else
actual=""
fi
if [ -n "$actual" ]; then
[ "$actual" = "$expected" ] || die "checksum mismatch for $ASSET"
ok "checksum verified"
fi
else
warn "no checksum published for this release"
fi
mkdir -p "$tmp/unpacked"
tar -xzf "$tmp/$ASSET" -C "$tmp/unpacked" || die "cannot unpack $ASSET"
srcdir="$tmp/unpacked/PixelVRPlayer"
[ -x "$srcdir/pixelvr" ] || [ -f "$srcdir/pixelvr" ] || die "unexpected archive layout"
fi
# ---------------------------------------------------------------------------
# Install
# ---------------------------------------------------------------------------
info "Installing to $INSTALL_DIR"
mkdir -p "$INSTALL_DIR/shaders"
rm -f "$INSTALL_DIR/pixelvr"
cp "$srcdir/pixelvr" "$INSTALL_DIR/pixelvr"
chmod 0755 "$INSTALL_DIR/pixelvr"
rm -f "$INSTALL_DIR/shaders/"*.spv
cp "$srcdir/shaders/"*.spv "$INSTALL_DIR/shaders/"
cp "$srcdir/run.sh" "$INSTALL_DIR/run.sh"
chmod 0755 "$INSTALL_DIR/run.sh"
INSTALLED_SCRIPT=0
if [ -n "$script_dir" ] && [ -f "$script_dir/install.sh" ]; then
cp "$script_dir/install.sh" "$INSTALL_DIR/install.sh"
chmod 0755 "$INSTALL_DIR/install.sh"
INSTALLED_SCRIPT=1
fi
if [ -n "$VERSION" ]; then
printf '%s\n' "$VERSION" > "$INSTALL_DIR/VERSION"
fi
ok "$(ls -1 "$INSTALL_DIR/shaders" | wc -l | tr -d ' ') shaders, $(du -h "$INSTALL_DIR/pixelvr" 2>/dev/null | cut -f1) binary"
missing_libs=""
if command -v ldd >/dev/null 2>&1; then
missing_libs=$(ldd "$INSTALL_DIR/pixelvr" 2>/dev/null | awk '/not found/ { print $1 }' \
| sort -u | tr '\n' ' ' || true)
fi
if [ -n "$missing_libs" ]; then
warn "missing shared libraries: $missing_libs"
warn "if these are libav* libraries, the system FFmpeg is too old"
fi
if [ ! -f /opt/steamvr/steamxr_linuxarm64.json ]; then
warn "SteamVR not found - install it from Steam before launching"
fi
# ---------------------------------------------------------------------------
# Steam library entry
# ---------------------------------------------------------------------------
STEAM_REGISTERED=0
if [ "$DO_STEAM" -eq 1 ]; then
info "Adding '$APP_NAME' to the Steam library"
if register_steam_shortcut; then
ok "Steam library entry ready"
else
warn "add $INSTALL_DIR/run.sh as a Non-Steam Game manually"
fi
fi
# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------
printf '\n%s%s installed%s\n' "$C_OK" "$APP_NAME" "$C_OFF"
printf ' Version : %s\n' "$version_label"
printf ' Install dir : %s\n' "$INSTALL_DIR"
if [ "$DO_STEAM" -eq 1 ] && [ "$STEAM_REGISTERED" -eq 1 ]; then
printf ' Steam entry : Non-Steam Game "%s"\n' "$APP_NAME"
fi
printf '\n Launch now : %s/run.sh\n' "$INSTALL_DIR"
printf ' From Steam : Library > Non-Steam > %s\n' "$APP_NAME"
printf ' Play a clip : %s/run.sh /path/to/clip.mp4\n' "$INSTALL_DIR"
printf ' Logs : ~/pixelvr-run.log\n'
printf ' Update : run this script again (settings and cache are kept)\n'
if [ "$INSTALLED_SCRIPT" -eq 1 ]; then
printf ' Remove : %s/install.sh --uninstall\n\n' "$INSTALL_DIR"
else
printf ' Remove : rerun this script with --uninstall\n\n'
fi
+11 -2
View File
@@ -4,9 +4,11 @@
# Contents (extracted to ~/PixelVRPlayer):
# PixelVRPlayer/pixelvr self-contained binary (static OpenXR loader)
# PixelVRPlayer/run.sh launcher (logs to ~/pixelvr-run.log)
# PixelVRPlayer/install.sh one-command installer / Steam registration
# PixelVRPlayer/shaders/*.spv SPIR-V shaders
# PixelVRPlayer/VERSION release tag (when given)
#
# ./tools/package-release.sh [build-dir] [out-tar]
# ./tools/package-release.sh [build-dir] [out-tar] [version]
#
# Defaults: build -> pixelvr-linux-arm64.tar.gz
set -euo pipefail
@@ -15,6 +17,7 @@ cd "$(dirname "$0")/.."
BUILD_DIR="${1:-build}"
OUT_TAR="${2:-pixelvr-linux-arm64.tar.gz}"
VERSION="${3:-}"
bin="${BUILD_DIR}/bin/pixelvr"
if [[ ! -f "${bin}" ]]; then
@@ -33,7 +36,13 @@ mkdir -p "${stage}/PixelVRPlayer/shaders"
cp "${bin}" "${stage}/PixelVRPlayer/pixelvr"
cp "${BUILD_DIR}/shaders/"*.spv "${stage}/PixelVRPlayer/shaders/"
cp tools/run.sh "${stage}/PixelVRPlayer/run.sh"
chmod +x "${stage}/PixelVRPlayer/pixelvr" "${stage}/PixelVRPlayer/run.sh"
cp tools/install.sh "${stage}/PixelVRPlayer/install.sh"
if [[ -n "${VERSION}" ]]; then
printf '%s\n' "${VERSION}" > "${stage}/PixelVRPlayer/VERSION"
fi
chmod +x "${stage}/PixelVRPlayer/pixelvr" \
"${stage}/PixelVRPlayer/run.sh" \
"${stage}/PixelVRPlayer/install.sh"
rm -f "${OUT_TAR}"
tar -C "${stage}" -czf "${OUT_TAR}" PixelVRPlayer