mirror of
https://github.com/Pixelplanet/Pixel-VR-Player.git
synced 2026-10-21 06:01:21 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
858293663b |
No files matched your search
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Executable
+549
@@ -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
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user