Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db508a46cd | ||
|
|
b617aa6ea6 | ||
|
|
362feb044f | ||
|
|
03e72a8263 | ||
|
|
ae37f1a71f | ||
|
|
2ecc0240f9 | ||
|
|
1454407da4 | ||
|
|
1d9ab477db | ||
| d0240d1408 | |||
|
|
647e97a105 | ||
|
|
c86edee113 | ||
|
|
1f7858e1fa | ||
|
|
efc5f20b5b | ||
|
|
9b454388f5 | ||
| 2c86ca3b21 | |||
|
|
93b1f0ad2d | ||
|
|
5f1fc591f9 | ||
|
|
be86f1e916 | ||
|
|
be63211e6b | ||
|
|
5316c5c113 | ||
|
|
dce6a39fee | ||
|
|
e985305929 |
81
.codex/skills/linux-game-manager-dev/SKILL.md
Normal file
81
.codex/skills/linux-game-manager-dev/SKILL.md
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
---
|
||||||
|
name: linux-game-manager-dev
|
||||||
|
description: Develop and maintain Linux Game Manager in this repository. Use when adding or removing games, editing `.install`/`.launch`/`.update` scripts, changing `linux-game-manager.sh` installer/launcher/removal/update/CLI behavior, validating accessibility-sensitive flows, or refreshing project-local skill docs after functionality changes.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Linux Game Manager Development
|
||||||
|
|
||||||
|
Use this skill to make safe, consistent changes to Linux Game Manager and keep the skill accurate as the codebase evolves.
|
||||||
|
|
||||||
|
## Fast Routing
|
||||||
|
|
||||||
|
1. If the task adds/removes/changes a game, read `references/game-extension.md`.
|
||||||
|
2. If the task changes orchestration/CLI/config behavior, read `references/core-map.md`.
|
||||||
|
3. If the task changes behavior and you are updating this skill, read `references/skill-maintenance.md`.
|
||||||
|
4. Run `python3 .codex/skills/linux-game-manager-dev/scripts/audit_game_catalog.py` before and after major game-catalog changes.
|
||||||
|
|
||||||
|
## Core Workflow
|
||||||
|
|
||||||
|
1. Inspect relevant behavior and identify affected surfaces (`.install`, `.launch`, `.update`, `linux-game-manager.sh`, `speech`, docs).
|
||||||
|
2. Implement with existing patterns and helper functions instead of inventing new flows.
|
||||||
|
3. Validate runtime behavior with CLI/manual checks:
|
||||||
|
- `./linux-game-manager.sh -i`
|
||||||
|
- `./linux-game-manager.sh -r`
|
||||||
|
- `./linux-game-manager.sh -u`
|
||||||
|
- `./linux-game-manager.sh -t`
|
||||||
|
4. Validate catalog consistency:
|
||||||
|
- `python3 .codex/skills/linux-game-manager-dev/scripts/audit_game_catalog.py`
|
||||||
|
5. If bash files were edited:
|
||||||
|
- Verify `shellcheck` is installed.
|
||||||
|
- If missing, stop and prompt the user to install it (see `references/tooling-prereqs.md`).
|
||||||
|
- Run shellcheck on edited files and fix all reported errors.
|
||||||
|
6. If functionality changed, refresh this skill using `references/skill-maintenance.md`.
|
||||||
|
|
||||||
|
## Non-Negotiable Rules
|
||||||
|
|
||||||
|
1. Keep installer and launcher base filenames identical:
|
||||||
|
- `.install/<Game Name>.sh`
|
||||||
|
- `.launch/<Game Name>.game`
|
||||||
|
2. Ensure launcher scripts include a concrete `installPath`-based path so removal can locate game data.
|
||||||
|
3. Define `run_update()` in any `.update/<Game>.sh` script.
|
||||||
|
4. Preserve accessibility-first interaction:
|
||||||
|
- Keep dialog/yad wrapper usage (`ui_*` helpers) consistent.
|
||||||
|
- Do not introduce keyboard traps.
|
||||||
|
- For GUI applications, do not add new `speech-dispatcher`/`spd-say` dependencies.
|
||||||
|
5. Keep new script variables camelCase, function names snake_case, class names PascalCase.
|
||||||
|
6. For ambiguous "disable game" requests, default to disabling installer visibility only and preserve launcher playability unless the user explicitly requests complete disable.
|
||||||
|
|
||||||
|
## Required Validation
|
||||||
|
|
||||||
|
1. Run catalog audit:
|
||||||
|
- `python3 .codex/skills/linux-game-manager-dev/scripts/audit_game_catalog.py`
|
||||||
|
2. Run manual command checks relevant to change scope:
|
||||||
|
- install flow: `./linux-game-manager.sh -i`
|
||||||
|
- launcher flow: `./linux-game-manager.sh`
|
||||||
|
- removal flow: `./linux-game-manager.sh -r`
|
||||||
|
- update flow: `./linux-game-manager.sh -u`
|
||||||
|
3. Run shellcheck on every edited bash script and fix all issues.
|
||||||
|
- If shellcheck is unavailable, prompt the user to install it before continuing.
|
||||||
|
4. Validate this skill structure after edits:
|
||||||
|
- `python3 /home/storm/.codex/skills/.system/skill-creator/scripts/quick_validate.py .codex/skills/linux-game-manager-dev`
|
||||||
|
|
||||||
|
## Mandatory Skill Maintenance
|
||||||
|
|
||||||
|
Treat this skill as stale immediately after any change to:
|
||||||
|
- `linux-game-manager.sh`
|
||||||
|
- Any file in `.install/`, `.launch/`, `.update/`, or `speech/`
|
||||||
|
- `README.md`
|
||||||
|
- Any change to game lifecycle expectations (install path rules, update hooks, CLI options, helper function contracts)
|
||||||
|
|
||||||
|
When stale, perform the full refresh workflow in `references/skill-maintenance.md` before completing the task.
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- `references/core-map.md`: Architecture and extension map.
|
||||||
|
- `references/game-extension.md`: Exact workflow for adding/removing/extending games.
|
||||||
|
- `references/skill-maintenance.md`: Critical instructions to keep this skill accurate after code changes.
|
||||||
|
- `references/tooling-prereqs.md`: Required tools and shellcheck installation prompts by distro.
|
||||||
|
|
||||||
|
## Scripts
|
||||||
|
|
||||||
|
- `scripts/audit_game_catalog.py`: Reports installer/launcher/update consistency and disabled entries.
|
||||||
4
.codex/skills/linux-game-manager-dev/agents/openai.yaml
Normal file
4
.codex/skills/linux-game-manager-dev/agents/openai.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "Linux Game Manager Dev"
|
||||||
|
short_description: "Add games and extend linux-game-manager safely"
|
||||||
|
default_prompt: "Use the project workflows to add games, modify manager behavior, validate accessibility-friendly flows, and keep this skill synchronized with code changes."
|
||||||
81
.codex/skills/linux-game-manager-dev/references/core-map.md
Normal file
81
.codex/skills/linux-game-manager-dev/references/core-map.md
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
# Linux Game Manager Core Map
|
||||||
|
|
||||||
|
Last refreshed: 2026-04-14
|
||||||
|
|
||||||
|
## Top-Level Structure
|
||||||
|
|
||||||
|
- `linux-game-manager.sh`: Main orchestrator, UI wrappers, CLI option handling, install/remove/update flows, cache and settings behavior.
|
||||||
|
- `.install/`: Per-game installer scripts sourced by `game_installer`.
|
||||||
|
- `.launch/`: Per-game launch scripts (`.game`) and runnable entries (`.sh`, usually symlinks).
|
||||||
|
- `.update/`: Optional per-game update scripts expected to define `run_update()`.
|
||||||
|
- `speech/speak_window_title.sh`: Accessibility helper for announcing focused window titles.
|
||||||
|
- `README.md`: Project summary and high-level behavior notes.
|
||||||
|
- `.files/`: Game-specific auxiliary assets/scripts used by some installers or launchers.
|
||||||
|
|
||||||
|
## Catalog Snapshot
|
||||||
|
|
||||||
|
- Installers: 42 (`.install/*.sh`)
|
||||||
|
- Launcher definitions: 42 (`.launch/*.game`)
|
||||||
|
- Launcher runnable entries: 31 (`.launch/*.sh`, both symlinks and files)
|
||||||
|
- Update scripts: 5 (`.update/*.sh`)
|
||||||
|
|
||||||
|
Regenerate this snapshot with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 .codex/skills/linux-game-manager-dev/scripts/audit_game_catalog.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## Main Runtime Flows
|
||||||
|
|
||||||
|
1. **Install flow**
|
||||||
|
- `game_installer` builds menu from `.install/*.sh`.
|
||||||
|
- Selected installer is sourced in the current shell.
|
||||||
|
- Shared downloads try `curl` first, fall back to `wget` when available, validate archive payloads before install, and reject obvious HTML error pages for unknown file types.
|
||||||
|
- `download_named()` shares the same cache validation path as `download()`, so resolved asset URLs must still produce a valid payload for their file extension.
|
||||||
|
- If `.launch/<game>.game` exists and `.launch/<game>.sh` does not, the manager creates a symlink using the repository root, even if the installer changed directories.
|
||||||
|
|
||||||
|
2. **Launch flow**
|
||||||
|
- `game_launcher` enumerates `.launch/*.sh` entries.
|
||||||
|
- Entries with first line `#//` are skipped.
|
||||||
|
- Selected launcher is sourced/executed.
|
||||||
|
|
||||||
|
3. **Removal flow**
|
||||||
|
- `game_removal` resolves launcher entry to real script.
|
||||||
|
- It scans launcher script lines for a non-comment `${installPath}/...` path assignment and uses that to infer the directory to remove.
|
||||||
|
- If no `installPath` reference is found, only launcher entry is removed.
|
||||||
|
|
||||||
|
4. **Update flow**
|
||||||
|
- `game_update` lists `.update/*.sh`.
|
||||||
|
- Selected updater is sourced.
|
||||||
|
- `run_update()` is called and must exist.
|
||||||
|
|
||||||
|
## CLI Surface
|
||||||
|
|
||||||
|
- `-i`: install game
|
||||||
|
- `-r`: remove game
|
||||||
|
- `-u`: update game
|
||||||
|
- `-t`: show number of available games
|
||||||
|
- `-C`: clear cache
|
||||||
|
- `-D`: create desktop launcher
|
||||||
|
- `-L`: show license
|
||||||
|
- `-h`: show help
|
||||||
|
- `-N`: enable no-cache mode
|
||||||
|
- `-R`: force redownload mode
|
||||||
|
|
||||||
|
## Config and State
|
||||||
|
|
||||||
|
- Cache: `${XDG_CACHE_HOME:-$HOME/.cache}/linux-game-manager`
|
||||||
|
- Config base: `${XDG_CONFIG_HOME:-$HOME/.config}/storm-games/linux-game-manager`
|
||||||
|
- Settings overrides: `settings.conf` in config base
|
||||||
|
- Default install root: `${HOME}/.local/games`
|
||||||
|
|
||||||
|
## Contributor Pitfalls
|
||||||
|
|
||||||
|
- Mismatched `.install/<Game>.sh` vs `.launch/<Game>.game` names create orphaned or invisible entries.
|
||||||
|
- Missing `installPath` reference in launcher prevents full uninstall.
|
||||||
|
- `game_removal` expects a concrete `${installPath}/...` path in the launcher; indirect path construction can prevent removal from finding the install directory.
|
||||||
|
- Missing `run_update()` in `.update` scripts breaks update flow.
|
||||||
|
- Bypassing shared download helpers risks cache and validation regressions.
|
||||||
|
- Installers may change the working directory; repository-relative manager paths must therefore use the resolved script root rather than `${0%/*}`.
|
||||||
|
- Use `alert` with its message arguments instead of chaining `alert` and `ui_msgbox`, otherwise `yad` users can get an extra acknowledgement dialog that does not include the actual guidance.
|
||||||
|
- For `uv`-based Python games that need `speechd`, copy host Python `speechd` bindings into a game-local directory and export `PYTHONPATH` from the launcher.
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
# Game Extension Workflow
|
||||||
|
|
||||||
|
Use this workflow whenever adding, renaming, removing, or substantially changing a game.
|
||||||
|
|
||||||
|
## Add a New Game
|
||||||
|
|
||||||
|
1. Create installer script:
|
||||||
|
- Path: `.install/<Game Name>.sh`
|
||||||
|
- Keep first line active (do not start with `#//`).
|
||||||
|
- Reuse manager helpers (`check_architecture`, `check_dependencies`, `download`, `download_named`, `get_installer`, `ui_*`).
|
||||||
|
- Install into a deterministic path under `${installPath}`.
|
||||||
|
|
||||||
|
2. Create launcher definition:
|
||||||
|
- Path: `.launch/<Game Name>.game`
|
||||||
|
- Keep base filename identical to installer (`<Game Name>`).
|
||||||
|
- Include an explicit install-path variable based on `installPath`, for example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gamePath="${installPath}/MyGame"
|
||||||
|
```
|
||||||
|
|
||||||
|
- Run the game from that path.
|
||||||
|
|
||||||
|
3. Optional update script:
|
||||||
|
- Path: `.update/<Game Name>.sh`
|
||||||
|
- Implement `run_update()` (required by update flow).
|
||||||
|
|
||||||
|
4. Let installer create runnable launcher entry:
|
||||||
|
- The manager auto-creates `.launch/<Game Name>.sh` symlink when installer completes and `.game` exists.
|
||||||
|
|
||||||
|
## Rename a Game Safely
|
||||||
|
|
||||||
|
1. Rename `.install/<Old>.sh` to `.install/<New>.sh`.
|
||||||
|
2. Rename `.launch/<Old>.game` to `.launch/<New>.game`.
|
||||||
|
3. Rename `.update/<Old>.sh` if present.
|
||||||
|
4. Remove stale `.launch/<Old>.sh` if still present.
|
||||||
|
5. Re-run catalog audit and manual checks.
|
||||||
|
|
||||||
|
## Remove a Game From Repo
|
||||||
|
|
||||||
|
1. Delete `.install/<Game>.sh`.
|
||||||
|
2. Delete `.launch/<Game>.game`.
|
||||||
|
3. Delete `.launch/<Game>.sh` if tracked.
|
||||||
|
4. Delete `.update/<Game>.sh` if present.
|
||||||
|
5. Run catalog audit to confirm no orphan entries remain.
|
||||||
|
|
||||||
|
## Disable Policy (Important)
|
||||||
|
|
||||||
|
When a request says "disable <game>" without more detail:
|
||||||
|
|
||||||
|
1. Default behavior: disable installs only.
|
||||||
|
- Add `#//` to first line of `.install/<Game Name>.sh`.
|
||||||
|
- Do not disable `.launch/<Game Name>.game` by default.
|
||||||
|
- This preserves playability for users who already have the game installed.
|
||||||
|
|
||||||
|
2. If user explicitly requests complete disable:
|
||||||
|
- Add `#//` to first line of both:
|
||||||
|
- `.install/<Game Name>.sh`
|
||||||
|
- `.launch/<Game Name>.game`
|
||||||
|
|
||||||
|
3. If wording is ambiguous but could imply full disable/removal:
|
||||||
|
- Ask a short clarification question before changing launcher/removal behavior.
|
||||||
|
|
||||||
|
## Manual Validation Checklist
|
||||||
|
|
||||||
|
1. Run installer flow:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./linux-game-manager.sh -i
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Confirm launcher files exist:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ls ".launch/<Game Name>.game" ".launch/<Game Name>.sh"
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Run launcher flow:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./linux-game-manager.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Run removal flow:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./linux-game-manager.sh -r
|
||||||
|
```
|
||||||
|
|
||||||
|
5. If updater exists, run update flow:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./linux-game-manager.sh -u
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Run consistency audit:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 .codex/skills/linux-game-manager-dev/scripts/audit_game_catalog.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## Script Authoring Rules
|
||||||
|
|
||||||
|
- Use camelCase variable names.
|
||||||
|
- Use snake_case for function names.
|
||||||
|
- Keep scripts robust when sourced in the manager shell.
|
||||||
|
- Avoid introducing unnecessary colorized output.
|
||||||
|
- For edited bash scripts, run shellcheck and fix all errors.
|
||||||
|
- If `shellcheck` is not installed, prompt the user to install it first (see `references/tooling-prereqs.md`).
|
||||||
|
|
||||||
|
## Pattern: uv + Host Python speechd Bindings
|
||||||
|
|
||||||
|
Use this pattern for Python games installed with `uv` when runtime speech support depends on `import speechd`.
|
||||||
|
|
||||||
|
1. In installer script:
|
||||||
|
- Check dependencies: `git`, `uv`, and host python binding import (`python-speechd:speechd`).
|
||||||
|
- Clone game repository into `${installPath}/<GameRepoDir>`.
|
||||||
|
- Run `uv sync` in the project directory that contains `pyproject.toml`.
|
||||||
|
- Resolve speechd source path from host Python via:
|
||||||
|
- `python3 -c 'import pathlib,speechd; print(pathlib.Path(speechd.__file__).resolve())'`
|
||||||
|
- Copy the module/package into a game-local directory such as:
|
||||||
|
- `${installPath}/<GameRepoDir>/<RuntimePath>/.host-python/`
|
||||||
|
- Fail with a clear message if import or copy fails.
|
||||||
|
|
||||||
|
2. In launcher script:
|
||||||
|
- Export `PYTHONPATH` with the game-local `.host-python` directory prepended.
|
||||||
|
- Launch via `uv run ...` from the same directory used for `uv sync`.
|
||||||
|
|
||||||
|
3. Removal safety:
|
||||||
|
- Ensure the launcher contains a concrete `${installPath}/...` path assignment so `game_removal` can infer the game root correctly.
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
# Skill Maintenance (Critical)
|
||||||
|
|
||||||
|
This skill is only trustworthy if it is refreshed immediately after behavior changes.
|
||||||
|
|
||||||
|
## Mandatory Refresh Triggers
|
||||||
|
|
||||||
|
Run this maintenance workflow whenever any of these change:
|
||||||
|
|
||||||
|
- `linux-game-manager.sh`
|
||||||
|
- Anything in `.install/`
|
||||||
|
- Anything in `.launch/`
|
||||||
|
- Anything in `.update/`
|
||||||
|
- Anything in `speech/`
|
||||||
|
- `README.md`
|
||||||
|
- Any game lifecycle contract (install path usage, symlink behavior, update function contracts, CLI flags)
|
||||||
|
|
||||||
|
## Refresh Workflow
|
||||||
|
|
||||||
|
1. Run catalog audit and capture output:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 .codex/skills/linux-game-manager-dev/scripts/audit_game_catalog.py
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Re-check core flow definitions in `linux-game-manager.sh`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rg -n "game_installer|game_launcher|game_removal|game_update|getopts|help\\(" linux-game-manager.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Update skill references:
|
||||||
|
- Update `references/core-map.md` catalog snapshot if counts changed.
|
||||||
|
- Update `references/core-map.md` flow descriptions if behavior changed.
|
||||||
|
- Update `references/game-extension.md` if onboarding or naming rules changed.
|
||||||
|
- Update this file if refresh triggers or process changed.
|
||||||
|
|
||||||
|
4. Validate the skill structure:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 /home/storm/.codex/skills/.system/skill-creator/scripts/quick_validate.py .codex/skills/linux-game-manager-dev
|
||||||
|
```
|
||||||
|
|
||||||
|
5. If any bash scripts changed, run shellcheck on edited files and fix all errors.
|
||||||
|
- If `shellcheck` is missing, pause and prompt the user to install it using `references/tooling-prereqs.md`.
|
||||||
|
|
||||||
|
## Completion Criteria
|
||||||
|
|
||||||
|
Do not consider maintenance complete until all are true:
|
||||||
|
|
||||||
|
1. Catalog audit shows no critical mismatches, and any warnings are reviewed.
|
||||||
|
2. All changed behavior is reflected in skill reference files.
|
||||||
|
3. Skill passes `quick_validate.py`.
|
||||||
|
4. Any edited bash scripts are shellcheck-clean.
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# Tooling Prerequisites
|
||||||
|
|
||||||
|
## Required Tool for Bash Changes
|
||||||
|
|
||||||
|
- `shellcheck` is mandatory whenever editing any bash/sh file in this repository.
|
||||||
|
- If `shellcheck` is not available, prompt the user to install it before continuing validation.
|
||||||
|
|
||||||
|
Check availability:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
command -v shellcheck
|
||||||
|
```
|
||||||
|
|
||||||
|
## Prompt Template
|
||||||
|
|
||||||
|
Use this exact style when missing:
|
||||||
|
|
||||||
|
`shellcheck is required for bash/sh edits in linux-game-manager. Please install it, then I will continue validation.`
|
||||||
|
|
||||||
|
## Install Commands by Common Distro Family
|
||||||
|
|
||||||
|
- Arch/Manjaro:
|
||||||
|
- `sudo pacman -S shellcheck`
|
||||||
|
- Debian/Ubuntu/Linux Mint/Pop!_OS:
|
||||||
|
- `sudo apt update && sudo apt install -y shellcheck`
|
||||||
|
- Fedora/RHEL/CentOS Stream:
|
||||||
|
- `sudo dnf install -y ShellCheck`
|
||||||
|
- openSUSE:
|
||||||
|
- `sudo zypper install -y ShellCheck`
|
||||||
|
- Alpine:
|
||||||
|
- `sudo apk add shellcheck`
|
||||||
|
|
||||||
|
If distro is unknown, ask the user what distribution they are on and provide the matching package command.
|
||||||
|
|
||||||
|
## Notes for LGM Collaboration
|
||||||
|
|
||||||
|
- Do not skip shellcheck for “small” bash changes.
|
||||||
|
- Fix all shellcheck errors; warnings may be suppressed only when required by sourced-global patterns and with a short comment.
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Audit Linux Game Manager catalog consistency."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def read_first_line(file_path: Path) -> str:
|
||||||
|
try:
|
||||||
|
with file_path.open("r", encoding="utf-8") as handle:
|
||||||
|
return handle.readline().strip()
|
||||||
|
except OSError:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def has_run_update(file_path: Path) -> bool:
|
||||||
|
try:
|
||||||
|
content = file_path.read_text(encoding="utf-8")
|
||||||
|
except OSError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return "run_update()" in content or "run_update ()" in content
|
||||||
|
|
||||||
|
|
||||||
|
def collect_names(file_paths: list[Path], suffix: str) -> list[str]:
|
||||||
|
return sorted(file_path.name[: -len(suffix)] for file_path in file_paths)
|
||||||
|
|
||||||
|
|
||||||
|
def count_disabled(file_paths: list[Path]) -> list[str]:
|
||||||
|
disabledNames = []
|
||||||
|
for file_path in file_paths:
|
||||||
|
if read_first_line(file_path).startswith("#//"):
|
||||||
|
disabledNames.append(file_path.name)
|
||||||
|
return sorted(disabledNames)
|
||||||
|
|
||||||
|
|
||||||
|
def build_report(repo_root: Path) -> dict:
|
||||||
|
installDir = repo_root / ".install"
|
||||||
|
launchDir = repo_root / ".launch"
|
||||||
|
updateDir = repo_root / ".update"
|
||||||
|
|
||||||
|
missingDirs = [
|
||||||
|
str(path.relative_to(repo_root))
|
||||||
|
for path in [installDir, launchDir, updateDir]
|
||||||
|
if not path.exists()
|
||||||
|
]
|
||||||
|
if missingDirs:
|
||||||
|
raise FileNotFoundError(
|
||||||
|
f"Expected directories not found: {', '.join(missingDirs)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
installPaths = sorted(installDir.glob("*.sh"))
|
||||||
|
launchGamePaths = sorted(launchDir.glob("*.game"))
|
||||||
|
launchShPaths = sorted(launchDir.glob("*.sh"))
|
||||||
|
updatePaths = sorted(updateDir.glob("*.sh"))
|
||||||
|
|
||||||
|
installerNames = collect_names(installPaths, ".sh")
|
||||||
|
launcherGameNames = collect_names(launchGamePaths, ".game")
|
||||||
|
launcherShNames = collect_names(launchShPaths, ".sh")
|
||||||
|
|
||||||
|
launcherSymlinkCount = sum(1 for path in launchShPaths if path.is_symlink())
|
||||||
|
launcherFileCount = len(launchShPaths) - launcherSymlinkCount
|
||||||
|
|
||||||
|
missingLauncherGameForInstaller = sorted(
|
||||||
|
set(installerNames) - set(launcherGameNames)
|
||||||
|
)
|
||||||
|
missingInstallerForLauncherGame = sorted(
|
||||||
|
set(launcherGameNames) - set(installerNames)
|
||||||
|
)
|
||||||
|
missingLauncherShForLauncherGame = sorted(
|
||||||
|
set(launcherGameNames) - set(launcherShNames)
|
||||||
|
)
|
||||||
|
orphanLauncherSh = sorted(set(launcherShNames) - set(launcherGameNames))
|
||||||
|
|
||||||
|
updateWithoutRunFunction = sorted(
|
||||||
|
path.name for path in updatePaths if not has_run_update(path)
|
||||||
|
)
|
||||||
|
|
||||||
|
report = {
|
||||||
|
"repoRoot": str(repo_root),
|
||||||
|
"criticalMismatches": [
|
||||||
|
"missingLauncherGameForInstaller",
|
||||||
|
"updateScriptsMissingRunUpdate",
|
||||||
|
],
|
||||||
|
"warningMismatches": [
|
||||||
|
"missingInstallerForLauncherGame",
|
||||||
|
"missingLauncherShForLauncherGame",
|
||||||
|
"orphanLauncherSh",
|
||||||
|
],
|
||||||
|
"counts": {
|
||||||
|
"installers": len(installPaths),
|
||||||
|
"launcherGameDefinitions": len(launchGamePaths),
|
||||||
|
"launcherRunnableEntries": len(launchShPaths),
|
||||||
|
"launcherRunnableSymlinks": launcherSymlinkCount,
|
||||||
|
"launcherRunnableRegularFiles": launcherFileCount,
|
||||||
|
"updateScripts": len(updatePaths),
|
||||||
|
},
|
||||||
|
"disabledEntries": {
|
||||||
|
"installers": count_disabled(installPaths),
|
||||||
|
"launchers": count_disabled(launchShPaths),
|
||||||
|
},
|
||||||
|
"mismatches": {
|
||||||
|
"missingLauncherGameForInstaller": missingLauncherGameForInstaller,
|
||||||
|
"missingInstallerForLauncherGame": missingInstallerForLauncherGame,
|
||||||
|
"missingLauncherShForLauncherGame": missingLauncherShForLauncherGame,
|
||||||
|
"orphanLauncherSh": orphanLauncherSh,
|
||||||
|
"updateScriptsMissingRunUpdate": updateWithoutRunFunction,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return report
|
||||||
|
|
||||||
|
|
||||||
|
def print_human_report(report: dict) -> None:
|
||||||
|
counts = report["counts"]
|
||||||
|
mismatches = report["mismatches"]
|
||||||
|
criticalMismatches = report["criticalMismatches"]
|
||||||
|
warningMismatches = report["warningMismatches"]
|
||||||
|
disabledEntries = report["disabledEntries"]
|
||||||
|
|
||||||
|
print(f"Repository: {report['repoRoot']}")
|
||||||
|
print("Counts:")
|
||||||
|
print(f" Installers: {counts['installers']}")
|
||||||
|
print(f" Launcher .game files: {counts['launcherGameDefinitions']}")
|
||||||
|
print(f" Launcher .sh entries: {counts['launcherRunnableEntries']}")
|
||||||
|
print(f" Symlinks: {counts['launcherRunnableSymlinks']}")
|
||||||
|
print(f" Regular files: {counts['launcherRunnableRegularFiles']}")
|
||||||
|
print(f" Update scripts: {counts['updateScripts']}")
|
||||||
|
|
||||||
|
print("Disabled entries:")
|
||||||
|
print(f" Installers: {len(disabledEntries['installers'])}")
|
||||||
|
if disabledEntries["installers"]:
|
||||||
|
print(" " + ", ".join(disabledEntries["installers"]))
|
||||||
|
print(f" Launchers: {len(disabledEntries['launchers'])}")
|
||||||
|
if disabledEntries["launchers"]:
|
||||||
|
print(" " + ", ".join(disabledEntries["launchers"]))
|
||||||
|
|
||||||
|
print("Critical checks:")
|
||||||
|
for key in criticalMismatches:
|
||||||
|
values = mismatches[key]
|
||||||
|
print(f" {key}: {len(values)}")
|
||||||
|
if values:
|
||||||
|
print(" " + ", ".join(values))
|
||||||
|
|
||||||
|
print("Warnings:")
|
||||||
|
for key in warningMismatches:
|
||||||
|
values = mismatches[key]
|
||||||
|
print(f" {key}: {len(values)}")
|
||||||
|
if values:
|
||||||
|
print(" " + ", ".join(values))
|
||||||
|
|
||||||
|
criticalTotal = sum(len(mismatches[key]) for key in criticalMismatches)
|
||||||
|
if criticalTotal == 0:
|
||||||
|
print("Result: OK (no critical mismatches)")
|
||||||
|
else:
|
||||||
|
print("Result: ATTENTION REQUIRED (critical mismatches detected)")
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args() -> argparse.Namespace:
|
||||||
|
defaultRepoRoot = Path(__file__).resolve().parents[4]
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Audit installer/launcher/update consistency for linux-game-manager."
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--repo-root",
|
||||||
|
default=str(defaultRepoRoot),
|
||||||
|
help=f"Repository root path (default: {defaultRepoRoot})",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--json",
|
||||||
|
action="store_true",
|
||||||
|
help="Emit JSON instead of human-readable text",
|
||||||
|
)
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
args = parse_args()
|
||||||
|
repoRoot = Path(args.repo_root).resolve()
|
||||||
|
|
||||||
|
try:
|
||||||
|
report = build_report(repoRoot)
|
||||||
|
except FileNotFoundError as error:
|
||||||
|
print(str(error), file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
|
||||||
|
if args.json:
|
||||||
|
print(json.dumps(report, indent=2, sort_keys=True))
|
||||||
|
else:
|
||||||
|
print_human_report(report)
|
||||||
|
|
||||||
|
criticalTotal = sum(
|
||||||
|
len(report["mismatches"][bucket]) for bucket in report["criticalMismatches"]
|
||||||
|
)
|
||||||
|
return 1 if criticalTotal else 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
9
.install/Christmas Dash.sh
Normal file
9
.install/Christmas Dash.sh
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
check_architecture x86_64
|
||||||
|
get_installer "christmas_dash_linux.zip" "https://tunmi13.itch.io/christmas-dash"
|
||||||
|
unzip -d "${installPath}" "${cache}/christmas_dash_linux.zip"
|
||||||
|
if [[ -d "${installPath}/Christmas Dash/christmas_dash_linux" ]]; then
|
||||||
|
rm -rf "${installPath}/christmas_dash_linux"
|
||||||
|
mv -v "${installPath}/Christmas Dash/christmas_dash_linux" "${installPath}/christmas_dash_linux"
|
||||||
|
rmdir "${installPath}/Christmas Dash" 2> /dev/null || true
|
||||||
|
fi
|
||||||
|
chmod +x "${installPath}/christmas_dash_linux/game.bin"
|
||||||
7
.install/Constant Motion.sh
Normal file
7
.install/Constant Motion.sh
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
check_architecture x86_64
|
||||||
|
installPath="${installPath:-${HOME}/.local/games}"
|
||||||
|
cache="${cache:-${XDG_CACHE_HOME:-$HOME/.cache}/linux-game-manager}"
|
||||||
|
download "https://samtupy.com/games/cm.tar.gz"
|
||||||
|
mkdir -p "${installPath}/Constant Motion"
|
||||||
|
tar -xzf "${cache}/cm.tar.gz" -C "${installPath}/Constant Motion"
|
||||||
|
chmod +x "${installPath}/Constant Motion/cm"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
tobyVersion="8-0"
|
tobyVersion="9.0"
|
||||||
mkdir -p "${installPath}/doom"
|
mkdir -p "${installPath}/doom"
|
||||||
doomPath="$(find /usr/share -type d -name "doom" 2> /dev/null)"
|
doomPath="$(find /usr/share -type d -name "doom" 2> /dev/null)"
|
||||||
if [[ ${#doomPath} -lt 5 ]]; then
|
if [[ ${#doomPath} -lt 5 ]]; then
|
||||||
@@ -17,27 +17,20 @@ if [[ ${#doomPath} -lt 5 ]]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
doomPath="$(find /usr/share -type d -name "doom" 2> /dev/null | head -1)"
|
doomPath="$(find /usr/share -type d -name "doom" 2> /dev/null | head -1)"
|
||||||
if ! [[ -e "${installPath}/doom/DoomMetalVol6.wad" ]] && ! [[ -e "${installPath}/doom/DoomMetalVol7.wad" ]]; then
|
|
||||||
alert
|
|
||||||
choice=$(ui_menu "Doom Metal Selection" "Doom Metal Selection" "Would you like Doom Metal Volume 6 or 7?" "6" "Doom Metal Volume 6" "7" "Doom Metal Volume 7" "none" "None")
|
|
||||||
case "$choice" in
|
|
||||||
"6")
|
|
||||||
download "${ipfsGateway}/ipfs/QmSzWKtP3wPvzn5GNd9F7n4RAhkFHxh2UHxXGefiAufwQW?filename=DoomMetalVol6.wad"
|
|
||||||
;;
|
|
||||||
"7")
|
|
||||||
download "${ipfsGateway}/ipfs/QmfXkz3tzicKGfhcYSiWUZkjkDKP2aVp53Y49n127wMr7D?filename=DoomMetalVol7.wad"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
# The url breaks the normal download function
|
# The url breaks the normal download function
|
||||||
download_named "keyshare-universal.pk3" "https://forum.zdoom.org/download/file.php?id=42262"
|
download_named "keyshare-universal.pk3" "https://forum.zdoom.org/download/file.php?id=42262"
|
||||||
download "${ipfsGateway}/ipfs/QmRSyAGQPaRtWwH9aT87Q8rKini9GYXac92B9EkBZJtbJ1?filename=TobyAccessibilityMod_V${tobyVersion}.zip"
|
download "${ipfsGateway}/ipfs/QmU6REFot8CGVSBy2YWQxnmXoh7M4EF74RxFtLzvtJxoGC?filename=toby_doom_${tobyVersion}_full.zip"
|
||||||
[[ -e "${cache}/DoomMetalVol6.wad" ]] && mv "${cache}/DoomMetalVol6.wad" "${installPath}/doom"
|
unzip -n -d "${installPath}/doom" "${cache}/toby_doom_${tobyVersion}_full.zip"
|
||||||
[[ -e "${cache}/DoomMetalVol7.wad" ]] && mv "${cache}/DoomMetalVol7.wad" "${installPath}/doom"
|
# Move contents from nested folder up one directory (including hidden files)
|
||||||
unzip -n -d "${installPath}/doom" "${cache}/TobyAccessibilityMod_V${tobyVersion}.zip"
|
shopt -s dotglob
|
||||||
|
mv "${installPath}/doom/TobyAccessibilityMod_Version9"*/* "${installPath}/doom/"
|
||||||
|
shopt -u dotglob
|
||||||
|
# Remove the now-empty nested folder
|
||||||
|
rmdir "${installPath}/doom/TobyAccessibilityMod_Version9"*
|
||||||
#unzip -n -d "${installPath}/doom" "${cache}/OpMDK_ForV${tobyVersion}.zip"
|
#unzip -n -d "${installPath}/doom" "${cache}/OpMDK_ForV${tobyVersion}.zip"
|
||||||
cp -v "${cache}/keyshare-universal.pk3" "${installPath}/doom"
|
cp -v "${cache}/keyshare-universal.pk3" "${installPath}/doom"
|
||||||
rm -fv "${installPath}/doom/"*.{ahk,bat,exe,dll,ps1}
|
rm -fv "${installPath}/doom/"*.{bat,exe,dll,ps1}
|
||||||
|
rm -rfv "${installPath}/doom/_internal"
|
||||||
#if [[ -e /usr/share/doom/blasphem.wad ]]; then
|
#if [[ -e /usr/share/doom/blasphem.wad ]]; then
|
||||||
#ln -s /usr/share/doom/blasphem.wad "${installPath}/doom/"
|
#ln -s /usr/share/doom/blasphem.wad "${installPath}/doom/"
|
||||||
#fi
|
#fi
|
||||||
|
|||||||
69
.install/Play Palace.sh
Normal file
69
.install/Play Palace.sh
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
check_dependencies git uv python-speechd:speechd
|
||||||
|
|
||||||
|
# shellcheck disable=SC2154 # set by linux-game-manager.sh
|
||||||
|
gameRoot="${installPath}/PlayPalace11"
|
||||||
|
desktopPath="${gameRoot}/clients/desktop"
|
||||||
|
hostPythonDir="${desktopPath}/.host-python"
|
||||||
|
speechdFilePath=""
|
||||||
|
speechdCopySourcePath=""
|
||||||
|
|
||||||
|
if [[ -e "${gameRoot}" ]]; then
|
||||||
|
ui_msgbox "Game Installer" "Game Installer" "\"${gameRoot}\" already exists. Remove it first or choose a different game."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "${installPath}" || {
|
||||||
|
ui_msgbox "Game Installer" "Game Installer" "Could not create ${installPath}."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if ! git -C "${installPath}" clone "https://github.com/XGDevGroup/PlayPalace11.git"; then
|
||||||
|
ui_msgbox "Game Installer" "Game Installer" "Could not clone Play Palace from GitHub."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! pushd "${desktopPath}" > /dev/null; then
|
||||||
|
ui_msgbox "Game Installer" "Game Installer" "Could not find desktop client path at ${desktopPath}."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! uv sync; then
|
||||||
|
popd > /dev/null || exit 1
|
||||||
|
ui_msgbox "Game Installer" "Game Installer" "uv sync failed for Play Palace."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
popd > /dev/null || exit 1
|
||||||
|
|
||||||
|
speechdFilePath="$(python3 -c 'import pathlib,speechd; print(pathlib.Path(speechd.__file__).resolve())' 2> /dev/null)"
|
||||||
|
if [[ -z "${speechdFilePath}" ]]; then
|
||||||
|
ui_msgbox "Game Installer" "Game Installer" "Could not import python module speechd from host Python.\nInstall speech-dispatcher python bindings and try again."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${speechdFilePath##*/}" == "__init__.py" ]]; then
|
||||||
|
speechdCopySourcePath="${speechdFilePath%/*}"
|
||||||
|
elif [[ "${speechdFilePath##*/}" == "speechd.py" ]]; then
|
||||||
|
speechdCopySourcePath="${speechdFilePath}"
|
||||||
|
else
|
||||||
|
speechdCopySourcePath="${speechdFilePath}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [[ -r "${speechdCopySourcePath}" ]]; then
|
||||||
|
ui_msgbox "Game Installer" "Game Installer" "Could not read speechd python binding at ${speechdCopySourcePath}."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "${hostPythonDir}" || {
|
||||||
|
ui_msgbox "Game Installer" "Game Installer" "Could not create ${hostPythonDir}."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ -d "${speechdCopySourcePath}" ]]; then
|
||||||
|
if ! cp -a "${speechdCopySourcePath}" "${hostPythonDir}/"; then
|
||||||
|
ui_msgbox "Game Installer" "Game Installer" "Could not copy speechd package into ${hostPythonDir}."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
elif ! cp -a "${speechdCopySourcePath}" "${hostPythonDir}/speechd.py"; then
|
||||||
|
ui_msgbox "Game Installer" "Game Installer" "Could not copy speechd module into ${hostPythonDir}."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -1,29 +1,22 @@
|
|||||||
|
# shellcheck shell=bash disable=SC2154 # installPath and cache are set by linux-game-manager.sh
|
||||||
check_architecture x86_64
|
check_architecture x86_64
|
||||||
alert
|
alert "Game Installer" "Game Installer" "Please note this requires the game to be available either in your Steam library or as the installer purchased from gog.com.\n\nIf using the gog.com installer, please use the default path when prompted."
|
||||||
ui_msgbox "Game Installer" "Game Installer" "Please note this requires the game to be available either in your Steam library or as the installer purchased from gog.com.\n\nIf using the gog.com installer, please use the default path when prompted."
|
|
||||||
installMethod=$(ui_menu "Installation Method" "Installation Method" "Select installation method" "gog" "GOG" "steam" "Steam")
|
installMethod=$(ui_menu "Installation Method" "Installation Method" "Select installation method" "gog" "GOG" "steam" "Steam")
|
||||||
if [[ "$installMethod" == "steam" ]]; then
|
|
||||||
installationMethod=1
|
|
||||||
else
|
|
||||||
installationMethod=0
|
|
||||||
fi
|
|
||||||
appId="646570"
|
appId="646570"
|
||||||
gogFileName="slay_the_spire_2020_12_15_8735c9fe3cc2280b76aa3ec47c953352a7df1f65_43444.sh"
|
gogFileName="slay_the_spire_2020_12_15_8735c9fe3cc2280b76aa3ec47c953352a7df1f65_43444.sh"
|
||||||
if [[ $installMethod -eq 1 ]]; then
|
if [[ "$installMethod" == "steam" ]]; then
|
||||||
# Steam Installation
|
# Steam Installation
|
||||||
check_dependencies steamcmd
|
check_dependencies steamcmd
|
||||||
steamUser=$(ui_inputbox "Game Installer" "Game Installer" "Please enter Steam user name:" "")
|
steamUser=$(ui_inputbox "Game Installer" "Game Installer" "Please enter Steam user name:" "")
|
||||||
steamcmd +@sSteamCmdForcePlatformType linux +force_install_dir "${HOME}/.local/games/SlayTheSpire" +login "$steamUser" +app_update "$appId" +quit
|
if ! steamcmd +@sSteamCmdForcePlatformType linux +force_install_dir "${HOME}/.local/games/SlayTheSpire" +login "$steamUser" +app_update "$appId" +quit; then
|
||||||
if [[ $? -ne 0 ]]; then
|
|
||||||
ui_msgbox "Game Installer" "Game Installer" "Error installing game through Steam."
|
ui_msgbox "Game Installer" "Game Installer" "Error installing game through Steam."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
# GOG Installation
|
# GOG Installation
|
||||||
get_installer "$gogFileName" "https://www.gog.com/en/game/slay_the_spire"
|
get_installer "$gogFileName" "https://www.gog.com/en/game/slay_the_spire"
|
||||||
DISPLAY="" find ~/Downloads -maxdepth 1 -type f -name "$gogFileName" -exec bash "{}" \; ||
|
if DISPLAY="" find ~/Downloads -maxdepth 1 -type f -name "$gogFileName" -exec bash "{}" \; ||
|
||||||
DISPLAY="" find ~/Desktop -maxdepth 1 -type f -name "$gogFileName" -exec bash "{}" \;
|
DISPLAY="" find ~/Desktop -maxdepth 1 -type f -name "$gogFileName" -exec bash "{}" \;; then
|
||||||
if [[ $? -eq 0 ]]; then
|
|
||||||
ln -sf "${HOME}/GOG Games/Slay the Spire/game" "${installPath}/SlayTheSpire" ||
|
ln -sf "${HOME}/GOG Games/Slay the Spire/game" "${installPath}/SlayTheSpire" ||
|
||||||
{ ui_msgbox "Game Installer" "Game Installer" "Error creating link to game directory."
|
{ ui_msgbox "Game Installer" "Game Installer" "Error creating link to game directory."
|
||||||
exit 1; }
|
exit 1; }
|
||||||
@@ -50,24 +43,29 @@ declare -A modsMap=(
|
|||||||
[achievement enabler]=1692554109
|
[achievement enabler]=1692554109
|
||||||
[say the spire]=2239220106
|
[say the spire]=2239220106
|
||||||
)
|
)
|
||||||
installString=""
|
declare -a installArgs=()
|
||||||
for modId in ${modsMap[@]} ; do
|
for modId in "${modsMap[@]}" ; do
|
||||||
installString="$installString +workshop_download_item $appId $modId"
|
installArgs+=("+workshop_download_item" "$appId" "$modId")
|
||||||
done
|
done
|
||||||
steamcmd +@sSteamCmdForcePlatformType linux +force_install_dir "${HOME}/.local/games/SlayTheSpire/" +login anonymous $installString +quit
|
if ! steamcmd +@sSteamCmdForcePlatformType linux +force_install_dir "${HOME}/.local/games/SlayTheSpire/" +login anonymous "${installArgs[@]}" +quit; then
|
||||||
if [[ $? -ne 0 ]]; then
|
|
||||||
ui_msgbox "Game Installer" "Game Installer" "Error installing required mods. Some accessibility features may not be available."
|
ui_msgbox "Game Installer" "Game Installer" "Error installing required mods. Some accessibility features may not be available."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
mkdir -p "$HOME/.local/games/SlayTheSpire/mods"
|
mkdir -p "$HOME/.local/games/SlayTheSpire/mods"
|
||||||
for modName in "${!modsMap[@]}" ; do
|
for modName in "${!modsMap[@]}" ; do
|
||||||
if [[ "$modName" == "mod the spire" ]]; then
|
if [[ "$modName" == "mod the spire" ]]; then
|
||||||
ln -sr "$HOME/.local/games/SlayTheSpire/steamapps/workshop/content/$appId/${modsMap[$modName]}"/* "$HOME/.local/games/SlayTheSpire/"
|
if ! ln -sr "$HOME/.local/games/SlayTheSpire/steamapps/workshop/content/$appId/${modsMap[$modName]}"/* "$HOME/.local/games/SlayTheSpire/"; then
|
||||||
|
if [[ "$modName" == "say the spire" ]]; then
|
||||||
|
ui_msgbox "Game Installer" "Game Installer" "Error installing SayTheSpire mod. Screen reader support will not be available."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
ln -sr "$HOME/.local/games/SlayTheSpire/steamapps/workshop/content/$appId/${modsMap[$modName]}"/* "$HOME/.local/games/SlayTheSpire/mods/"
|
if ! ln -sr "$HOME/.local/games/SlayTheSpire/steamapps/workshop/content/$appId/${modsMap[$modName]}"/* "$HOME/.local/games/SlayTheSpire/mods/"; then
|
||||||
fi
|
if [[ "$modName" == "say the spire" ]]; then
|
||||||
if [[ $? -ne 0 ]] && [[ "$modName" == "say the spire" ]]; then
|
ui_msgbox "Game Installer" "Game Installer" "Error installing SayTheSpire mod. Screen reader support will not be available."
|
||||||
ui_msgbox "Game Installer" "Game Installer" "Error installing SayTheSpire mod. Screen reader support will not be available."
|
exit 1
|
||||||
exit 1
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
# shellcheck shell=bash disable=SC2154 # installPath and cache are set by linux-game-manager.sh
|
||||||
check_architecture x86_64
|
check_architecture x86_64
|
||||||
DISPLAY=""
|
DISPLAY=""
|
||||||
alert
|
alert "Game Installer" "Game Installer" "Please select the default path when prompted by the installer."
|
||||||
ui_msgbox "Game Installer" "Game Installer" "Please select the default path when prompted by the installer."
|
|
||||||
get_installer "stardew_valley_1_5_6_1988831614_53040.sh" "https://www.gog.com/game/stardew_valley"
|
get_installer "stardew_valley_1_5_6_1988831614_53040.sh" "https://www.gog.com/game/stardew_valley"
|
||||||
bash "${cache}/stardew_valley_1_5_6_1988831614_53040.sh" ||
|
bash "${cache}/stardew_valley_1_5_6_1988831614_53040.sh" ||
|
||||||
{ ui_msgbox "Game Installer" "Game Installer" "Error installing game."
|
{ ui_msgbox "Game Installer" "Game Installer" "Error installing game."
|
||||||
@@ -10,8 +10,7 @@ smapiVersion="3.18.4"
|
|||||||
download "https://github.com/Pathoschild/SMAPI/releases/download/${smapiVersion}/SMAPI-${smapiVersion}-installer.zip" "https://stormgames.wolfe.casa/downloads/stardew-valley/Mods.tar.xz"
|
download "https://github.com/Pathoschild/SMAPI/releases/download/${smapiVersion}/SMAPI-${smapiVersion}-installer.zip" "https://stormgames.wolfe.casa/downloads/stardew-valley/Mods.tar.xz"
|
||||||
smapiTmp="$(mktemp -d)"
|
smapiTmp="$(mktemp -d)"
|
||||||
unzip "${cache}/SMAPI-${smapiVersion}-installer.zip" -d "$smapiTmp"
|
unzip "${cache}/SMAPI-${smapiVersion}-installer.zip" -d "$smapiTmp"
|
||||||
alert
|
alert "Game Installer" "Game Installer" "Preparing to install mods. Please select the same path as before when prompted.\n\nWhen it says SMAPI has been installed, press enter to finish installation."
|
||||||
ui_msgbox "Game Installer" "Game Installer" "Preparing to install mods. Please select the same path as before when prompted.\n\nWhen it says SMAPI has been installed, press enter to finish installation."
|
|
||||||
bash "${smapiTmp}/SMAPI ${smapiVersion} installer/install on Linux.sh"
|
bash "${smapiTmp}/SMAPI ${smapiVersion} installer/install on Linux.sh"
|
||||||
ln -sf "${HOME}/GOG Games/Stardew Valley/game" "${installPath}/StardewValley"
|
ln -sf "${HOME}/GOG Games/Stardew Valley/game" "${installPath}/StardewValley"
|
||||||
tar -xvf "${cache}/Mods.tar.xz" -C "${installPath}/StardewValley/"
|
tar -xvf "${cache}/Mods.tar.xz" -C "${installPath}/StardewValley/"
|
||||||
|
|||||||
4
.install/Super Liam.sh
Normal file
4
.install/Super Liam.sh
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# shellcheck shell=bash disable=SC2154 # installPath and cache are set by linux-game-manager.sh
|
||||||
|
check_architecture x86_64
|
||||||
|
download "https://l-works.net/files/SuperLiam_linux.tar.gz"
|
||||||
|
tar -xzf "$cache/SuperLiam_linux.tar.gz" -C "${installPath}"
|
||||||
4
.install/The Great Toy Robbery.sh
Normal file
4
.install/The Great Toy Robbery.sh
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# shellcheck shell=bash disable=SC2154 # installPath and cache are set by linux-game-manager.sh
|
||||||
|
check_architecture x86_64
|
||||||
|
download "https://l-works.net/files/tgtr_linux.tar.gz"
|
||||||
|
tar -xzf "$cache/tgtr_linux.tar.gz" -C "${installPath}"
|
||||||
7
.install/The Omega Reach.sh
Normal file
7
.install/The Omega Reach.sh
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# shellcheck shell=bash disable=SC2154 # installPath and cache are set by linux-game-manager.sh
|
||||||
|
check_architecture x86_64
|
||||||
|
get_installer "the-omega-reach-linux-x64.zip" "https://shiftbacktick.itch.io/the-omega-reach"
|
||||||
|
mkdir -p "${installPath}/Omega Reach"
|
||||||
|
unzip -d "${installPath}/Omega Reach" "${cache}/the-omega-reach-linux-x64.zip"
|
||||||
|
chmod +x "${installPath}/Omega Reach/the-omega-reach"
|
||||||
|
chmod +x "${installPath}/Omega Reach/chrome-sandbox"
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
|
# shellcheck shell=bash disable=SC2154 # installPath and cache are set by linux-game-manager.sh
|
||||||
check_architecture x86_64
|
check_architecture x86_64
|
||||||
get_installer "Ttc v3.2 linux.zip" "https://renzivan.itch.io/the-tornado-chicken"
|
get_installer "Ttc v3.2 linux.zip" "https://renzivan.itch.io/the-tornado-chicken"
|
||||||
unzip -d "${installPath}/The Tornado Chicken" "${cache}/Ttc v3.2 linux.zip"
|
unzip -d "${installPath}/The Tornado Chicken" "${cache}/Ttc v3.2 linux.zip"
|
||||||
chmod +x "${installPath}/The Tornado Chicken/Ttc"
|
chmod +x "${installPath}/The Tornado Chicken/Ttc"
|
||||||
alert
|
alert "Game Installer" "Game Installer" "Note: When the game first starts it will be playing very loud music with the built in suboptimal voice.\n\nYou are recommended to press page down several times to turn down the music, then go to settings and enable speech with screen reader, using speech dispatcher.\n\nYou may then press page up to set the music to your liking."
|
||||||
ui_msgbox "Game Installer" "Game Installer" "Note: When the game first starts it will be playing very loud music with the built in suboptimal voice.\n\nYou are recommended to press page down several times to turn down the music, then go to settings and enable speech with screen reader, using speech dispatcher.\n\nYou may then press page up to set the music to your liking."
|
|
||||||
|
|||||||
24
.install/Top Speed.sh
Normal file
24
.install/Top Speed.sh
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# shellcheck disable=SC2154 # set by linux-game-manager.sh
|
||||||
|
check_architecture x86_64
|
||||||
|
|
||||||
|
releaseMetadataFile="TopSpeed-release-build.json"
|
||||||
|
releaseMetadataPath="${cache}/${releaseMetadataFile}"
|
||||||
|
releaseMetadataUrl="https://api.github.com/repos/diamondStar35/top_speed/releases/tags/release-build"
|
||||||
|
assetPattern='^TopSpeed-linux-x64-Release-v-.*\.zip$'
|
||||||
|
|
||||||
|
rm -f "${releaseMetadataPath}"
|
||||||
|
download_named "${releaseMetadataFile}" "${releaseMetadataUrl}"
|
||||||
|
|
||||||
|
assetName="$(jq -r --arg assetPattern "${assetPattern}" '.assets[] | select(.name | test($assetPattern)) | .name' "${releaseMetadataPath}" | head -n 1)"
|
||||||
|
assetUrl="$(jq -r --arg assetPattern "${assetPattern}" '.assets[] | select(.name | test($assetPattern)) | .browser_download_url' "${releaseMetadataPath}" | head -n 1)"
|
||||||
|
|
||||||
|
if [[ -z "${assetName}" ]] || [[ -z "${assetUrl}" ]] || [[ "${assetName}" == "null" ]] || [[ "${assetUrl}" == "null" ]]; then
|
||||||
|
ui_msgbox "Linux Game Manager" "Linux Game Manager" "Unable to find the latest Top Speed Linux download in the GitHub release metadata."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
download_named "${assetName}" "${assetUrl}"
|
||||||
|
mkdir -p "${installPath}/TopSpeed"
|
||||||
|
unzip -o -d "${installPath}/TopSpeed" "${cache}/${assetName}"
|
||||||
|
chmod +x "${installPath}/TopSpeed/TopSpeed"
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
|
# shellcheck shell=bash disable=SC2154 # installPath and cache are set by linux-game-manager.sh
|
||||||
check_architecture x86_64
|
check_architecture x86_64
|
||||||
check_dependencies dmidecode
|
check_dependencies dmidecode
|
||||||
get_installer "upheaval-linux.zip" "https://leonegaming.itch.io/upheaval"
|
get_installer "upheaval-linux.zip" "https://leonegaming.itch.io/upheaval"
|
||||||
mkdir -p "${installPath}/Upheaval_Gui"
|
mkdir -p "${installPath}/Upheaval_Gui"
|
||||||
unzip -d "${installPath}/Upheaval_Gui" "${cache}/upheaval-linux.zip"
|
unzip -d "${installPath}/Upheaval_Gui" "${cache}/upheaval-linux.zip"
|
||||||
alert
|
alert "Game Installer" "Game Installer" "To enable accessibility, press shift t when the game starts."
|
||||||
ui_msgbox "Game Installer" "Game Installer" "To enable accessibility, press shift t when the game starts."
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
# shellcheck shell=bash disable=SC2154 # installPath and cache are set by linux-game-manager.sh
|
||||||
check_architecture x86_64
|
check_architecture x86_64
|
||||||
get_installer "Wp v3.0 linux.zip" "https://psyra-productions.itch.io/wheels-of-prio"
|
get_installer "Wp v3.0 linux.zip" "https://psyra-productions.itch.io/wheels-of-prio"
|
||||||
unzip -d "${installPath}/Wheels of Prio" "${cache}/Wp v3.0 linux.zip"
|
unzip -d "${installPath}/Wheels of Prio" "${cache}/Wp v3.0 linux.zip"
|
||||||
chmod +x "${installPath}/Wheels of Prio/Wp"
|
chmod +x "${installPath}/Wheels of Prio/Wp"
|
||||||
alert
|
alert "Game Installer" "Game Installer" "Note: When the game first starts it will be playing very loud music with the built in suboptimal voice.\n\nYou are recommended to press page down several times to turn down the music, then go to settings and enable speech with screen reader, using speech dispatcher.\n\nYou may then press page up to set the music to your liking."
|
||||||
ui_msgbox "Game Installer" "Game Installer" "Note: When the game first starts it will be playing very loud music with the built in suboptimal voice.\n\nYou are recommended to press page down several times to turn down the music, then go to settings and enable speech with screen reader, using speech dispatcher.\n\nYou may then press page up to set the music to your liking."
|
|
||||||
|
|||||||
12
.install/Wicked Quest.sh
Normal file
12
.install/Wicked Quest.sh
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
local arch=$(uname -m)
|
||||||
|
local gameName
|
||||||
|
|
||||||
|
if [[ "$arch" == "aarch64" ]]; then
|
||||||
|
gameName="wicked_quest-linux-aarch64.zip"
|
||||||
|
else
|
||||||
|
gameName="wicked_quest-linux-x86_64.zip"
|
||||||
|
fi
|
||||||
|
|
||||||
|
get_installer "$gameName" "https://stormdragon2976.itch.io/wicked-quest"
|
||||||
|
mkdir -p "${installPath}/Wicked_Quest"
|
||||||
|
unzip -d "${installPath}/" "${cache}/$gameName"
|
||||||
14
.launch/Christmas Dash.game
Normal file
14
.launch/Christmas Dash.game
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
gameDir="${installPath}/christmas_dash_linux"
|
||||||
|
gameExecutable="${gameDir}/game.bin"
|
||||||
|
if [[ ! -d "$gameDir" ]]; then
|
||||||
|
ui_msgbox "Linux Game Manager" "Linux Game Manager" "Christmas Dash is not installed."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [[ ! -x "$gameExecutable" ]]; then
|
||||||
|
ui_msgbox "Linux Game Manager" "Linux Game Manager" "Unable to find ${gameExecutable}."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
pushd "${gameDir}"
|
||||||
|
SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt \
|
||||||
|
REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt \
|
||||||
|
"${gameExecutable}"
|
||||||
4
.launch/Constant Motion.game
Normal file
4
.launch/Constant Motion.game
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
check_architecture x86_64
|
||||||
|
gameExecutable="${installPath}/Constant Motion/cm"
|
||||||
|
pushd "${installPath}/Constant Motion"
|
||||||
|
${fex}"${gameExecutable}"
|
||||||
1
.launch/Oriol Gomez Minigames.sh
Normal file
1
.launch/Oriol Gomez Minigames.sh
Normal file
@@ -0,0 +1 @@
|
|||||||
|
open_url "https://play.oriolgomez.com/"
|
||||||
18
.launch/Play Palace.game
Normal file
18
.launch/Play Palace.game
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
check_dependencies uv
|
||||||
|
|
||||||
|
# shellcheck disable=SC2154 # set by linux-game-manager.sh
|
||||||
|
gamePath="${installPath}/PlayPalace11/clients"
|
||||||
|
desktopPath="${gamePath}/desktop"
|
||||||
|
hostPythonDir="${desktopPath}/.host-python"
|
||||||
|
|
||||||
|
if ! [[ -d "${desktopPath}" ]]; then
|
||||||
|
ui_msgbox "Linux Game Manager" "Linux Game Manager" "Play Palace is not installed at ${desktopPath}."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -d "${hostPythonDir}" ]]; then
|
||||||
|
export PYTHONPATH="${hostPythonDir}${PYTHONPATH:+:${PYTHONPATH}}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
pushd "${desktopPath}" || exit 1
|
||||||
|
uv run python client.py
|
||||||
4
.launch/Super Liam.game
Normal file
4
.launch/Super Liam.game
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
check_architecture x86_64
|
||||||
|
gamePath="${installPath}/Super Liam"
|
||||||
|
pushd "${gamePath}"
|
||||||
|
${fex}./SuperLiam
|
||||||
4
.launch/The Great Toy Robbery.game
Normal file
4
.launch/The Great Toy Robbery.game
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
check_architecture x86_64
|
||||||
|
gamePath="${installPath}/The Great Toy Robbery"
|
||||||
|
pushd "${gamePath}"
|
||||||
|
${fex}./tgtr
|
||||||
4
.launch/The Omega Reach.game
Normal file
4
.launch/The Omega Reach.game
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# shellcheck shell=bash disable=SC2154 # installPath is set by linux-game-manager.sh
|
||||||
|
gamePath="${installPath}/Omega Reach"
|
||||||
|
pushd "${gamePath}" || return 1
|
||||||
|
"${gamePath}/the-omega-reach"
|
||||||
14
.launch/Top Speed.game
Normal file
14
.launch/Top Speed.game
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# shellcheck disable=SC2154 # set by linux-game-manager.sh
|
||||||
|
gameExecutable="${installPath}/TopSpeed/TopSpeed"
|
||||||
|
gameDir="${gameExecutable%/*}"
|
||||||
|
if [[ ! -d "$gameDir" ]]; then
|
||||||
|
ui_msgbox "Linux Game Manager" "Linux Game Manager" "Top Speed is not installed."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [[ ! -x "$gameExecutable" ]]; then
|
||||||
|
ui_msgbox "Linux Game Manager" "Linux Game Manager" "Unable to find ${gameExecutable}."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
pushd "${gameDir}" || return 1
|
||||||
|
"${gameExecutable}"
|
||||||
7
.launch/Wicked Quest.game
Normal file
7
.launch/Wicked Quest.game
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
local arch=$(uname -m)
|
||||||
|
if [[ "$arch" == "aarch64" ]]; then
|
||||||
|
pushd "${installPath}/wicked_quest-linux-aarch64"
|
||||||
|
else
|
||||||
|
pushd "${installPath}/wicked_quest-linux-x86_64"
|
||||||
|
fi
|
||||||
|
./wicked_quest
|
||||||
28
.update/Wicked Quest.sh
Normal file
28
.update/Wicked Quest.sh
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
run_update() {
|
||||||
|
local installPath="${HOME}/.local/games"
|
||||||
|
local arch
|
||||||
|
arch=$(uname -m)
|
||||||
|
local gameName
|
||||||
|
local cache="${HOME}/.cache/lgm"
|
||||||
|
|
||||||
|
if [[ "$arch" == "aarch64" ]]; then
|
||||||
|
gameName="wicked_quest-linux-aarch64.zip"
|
||||||
|
else
|
||||||
|
gameName="wicked_quest-linux-x86_64.zip"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Look for the game file in common download locations
|
||||||
|
for i in ~/Downloads ~/Desktop ; do
|
||||||
|
find $i -type f -name "$gameName" -exec mv -v {} "${cache}/" \;
|
||||||
|
done
|
||||||
|
|
||||||
|
# If the file is still not available abort.
|
||||||
|
if [[ ! -f "${cache}/$gameName" ]]; then
|
||||||
|
dialog --backtitle "Linux Game Manager" --msgbox "Couldn't find $gameName. Please download the file from https://stormdragon2976.itch.io/wicked-quest and try again." -1 -1
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
unzip -od "${installPath}/" "${cache}/$gameName"
|
||||||
|
}
|
||||||
@@ -7,6 +7,15 @@ Installer and launcher for accessible to the blind games that run natively in Li
|
|||||||
|
|
||||||
As the project grows, more dependencies will most likely be added. When LGM is launched, it will check to make sure it has the required dependencies for it to do the work of downloading and extracting the game. Note that because every distro has a different package manager, dependencies for games themselves will not be resolved. Please consult the game's documentation to find out what is needed for the game to run.
|
As the project grows, more dependencies will most likely be added. When LGM is launched, it will check to make sure it has the required dependencies for it to do the work of downloading and extracting the game. Note that because every distro has a different package manager, dependencies for games themselves will not be resolved. Please consult the game's documentation to find out what is needed for the game to run.
|
||||||
|
|
||||||
|
Current base dependencies checked on launch: `7z`, `curl`, `dialog`, `jq`, `yad`, and `unzip`.
|
||||||
|
|
||||||
|
## Disabling game entries
|
||||||
|
|
||||||
|
To disable a game entry without deleting its script, set the first line of the script to start with `#//`.
|
||||||
|
|
||||||
|
- This applies to both `.install/*.sh` and `.launch/*.sh`.
|
||||||
|
- A normal comment like `# comment` on the first line does not disable an entry.
|
||||||
|
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
scriptRoot="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
|
||||||
|
|
||||||
license() {
|
license() {
|
||||||
cat << EOF
|
cat << EOF
|
||||||
■The contents of this file are subject to the Common Public Attribution
|
■The contents of this file are subject to the Common Public Attribution
|
||||||
@@ -290,6 +292,10 @@ check_update() {
|
|||||||
if ! [[ -d ".git" ]]; then
|
if ! [[ -d ".git" ]]; then
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
# Check if we're in a detached HEAD state
|
||||||
|
if ! git symbolic-ref -q HEAD &> /dev/null; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
local url
|
local url
|
||||||
url="$(git ls-remote --get-url)"
|
url="$(git ls-remote --get-url)"
|
||||||
if [[ "$url" =~ ^ssh://|git@|gitea@ ]] || [[ -z "$url" ]]; then
|
if [[ "$url" =~ ^ssh://|git@|gitea@ ]] || [[ -z "$url" ]]; then
|
||||||
@@ -336,7 +342,8 @@ check_architecture() {
|
|||||||
export fex="FEXLoader -- "
|
export fex="FEXLoader -- "
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
local architecture="$(uname -m)"
|
local architecture
|
||||||
|
architecture="$(uname -m)"
|
||||||
for i in "$@" ; do
|
for i in "$@" ; do
|
||||||
if [[ "${architecture}" == "$i" ]]; then
|
if [[ "${architecture}" == "$i" ]]; then
|
||||||
return
|
return
|
||||||
@@ -404,6 +411,8 @@ desktop_launcher() {
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
local dotDesktop
|
local dotDesktop
|
||||||
|
local execLine
|
||||||
|
local launchDirectory
|
||||||
local terminal
|
local terminal
|
||||||
# Try to find an accessible terminal
|
# Try to find an accessible terminal
|
||||||
for i in mate-terminal lxterminal terminator gnome-terminal ; do
|
for i in mate-terminal lxterminal terminator gnome-terminal ; do
|
||||||
@@ -412,11 +421,13 @@ desktop_launcher() {
|
|||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
launchDirectory="${scriptRoot}"
|
||||||
|
printf -v execLine "Exec=%s -t \"Linux Game Manager\" -e \"/usr/bin/bash -c 'pushd %q;nohup ./%q 2> /dev/null'\"" "${terminal}" "${launchDirectory}" "${0##*/}"
|
||||||
dotDesktop=('[Desktop Entry]'
|
dotDesktop=('[Desktop Entry]'
|
||||||
'Name=Linux game manager'
|
'Name=Linux game manager'
|
||||||
'GenericName=Linux game Manager'
|
'GenericName=Linux game Manager'
|
||||||
'Comment=Install and launch games that are accessible to the blind'
|
'Comment=Install and launch games that are accessible to the blind'
|
||||||
"Exec=${terminal} -t \"Linux Game Manager\" -e \"/usr/bin/bash -c 'pushd $(readlink -e "${0%/*}");nohup ./"${0##*/}" 2> /dev/null'\""
|
"${execLine}"
|
||||||
'Terminal=false'
|
'Terminal=false'
|
||||||
'Type=Application'
|
'Type=Application'
|
||||||
'StartupNotify=false'
|
'StartupNotify=false'
|
||||||
@@ -434,8 +445,25 @@ desktop_launcher() {
|
|||||||
|
|
||||||
# Alerts, for when user needs to read something.
|
# Alerts, for when user needs to read something.
|
||||||
alert() {
|
alert() {
|
||||||
|
local title="Linux Game Manager"
|
||||||
|
local backTitle="Linux Game Manager"
|
||||||
|
local message="Press OK to continue."
|
||||||
|
|
||||||
|
if [[ $# -eq 1 ]]; then
|
||||||
|
message="$1"
|
||||||
|
elif [[ $# -eq 2 ]]; then
|
||||||
|
title="$1"
|
||||||
|
backTitle="$1"
|
||||||
|
message="$2"
|
||||||
|
elif [[ $# -ge 3 ]]; then
|
||||||
|
title="$1"
|
||||||
|
backTitle="$2"
|
||||||
|
shift 2
|
||||||
|
message="$*"
|
||||||
|
fi
|
||||||
|
|
||||||
play -qnV0 synth 3 pluck D3 pluck A3 pluck D4 pluck F4 pluck A4 delay 0 .1 .2 .3 .4 remix - chorus 0.9 0.9 38 0.75 0.3 0.5 -t
|
play -qnV0 synth 3 pluck D3 pluck A3 pluck D4 pluck F4 pluck A4 delay 0 .1 .2 .3 .4 remix - chorus 0.9 0.9 38 0.75 0.3 0.5 -t
|
||||||
ui_msgbox "Linux Game Manager" "Linux Game Manager" "Press OK to continue."
|
ui_msgbox "${title}" "${backTitle}" "${message}"
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_cache() {
|
clear_cache() {
|
||||||
@@ -451,8 +479,67 @@ clear_cache() {
|
|||||||
ui_msgbox "Linux Game Manager" "Linux Game Manager" "Cache deleted."
|
ui_msgbox "Linux Game Manager" "Linux Game Manager" "Cache deleted."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
download_with_fallback() {
|
||||||
|
local outputPath="$1"
|
||||||
|
local sourceUrl="$2"
|
||||||
|
local firstExitCode=0
|
||||||
|
local secondExitCode=0
|
||||||
|
local thirdExitCode=0
|
||||||
|
local wgetExitCode=0
|
||||||
|
local errorFile=""
|
||||||
|
downloadAttemptExitCodes=""
|
||||||
|
downloadErrorLog=""
|
||||||
|
|
||||||
|
if ! errorFile="$(mktemp)"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if curl -L4 -C - --retry 10 --output "${outputPath}" "${sourceUrl}" 2> "${errorFile}"; then
|
||||||
|
rm -f "${errorFile}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
firstExitCode=$?
|
||||||
|
|
||||||
|
# Some hosts reject resume requests. Retry from scratch.
|
||||||
|
rm -f "${outputPath}"
|
||||||
|
if curl -L4 --retry 10 --output "${outputPath}" "${sourceUrl}" 2>> "${errorFile}"; then
|
||||||
|
rm -f "${errorFile}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
secondExitCode=$?
|
||||||
|
|
||||||
|
# If IPv4-only fails, retry allowing either IP family.
|
||||||
|
rm -f "${outputPath}"
|
||||||
|
if curl -L --retry 10 --output "${outputPath}" "${sourceUrl}" 2>> "${errorFile}"; then
|
||||||
|
rm -f "${errorFile}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
thirdExitCode=$?
|
||||||
|
|
||||||
|
if command -v wget > /dev/null 2>&1; then
|
||||||
|
rm -f "${outputPath}"
|
||||||
|
if wget --tries=10 --output-document="${outputPath}" "${sourceUrl}" 2>> "${errorFile}"; then
|
||||||
|
rm -f "${errorFile}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
wgetExitCode=$?
|
||||||
|
fi
|
||||||
|
|
||||||
|
downloadAttemptExitCodes="curl: ${firstExitCode}, ${secondExitCode}, ${thirdExitCode}"
|
||||||
|
if [[ "${wgetExitCode}" -ne 0 ]]; then
|
||||||
|
downloadAttemptExitCodes+="; wget: ${wgetExitCode}"
|
||||||
|
fi
|
||||||
|
if cp -f "${errorFile}" "${cache}/curl-error.log" 2> /dev/null; then
|
||||||
|
downloadErrorLog="${cache}/curl-error.log"
|
||||||
|
rm -f "${errorFile}"
|
||||||
|
else
|
||||||
|
downloadErrorLog="${errorFile}"
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
download() {
|
download() {
|
||||||
local source=($@)
|
local source=("$@")
|
||||||
for i in "${source[@]}" ; do
|
for i in "${source[@]}" ; do
|
||||||
local dest="${i##*/}"
|
local dest="${i##*/}"
|
||||||
dest="${dest//%20/ }"
|
dest="${dest//%20/ }"
|
||||||
@@ -465,47 +552,60 @@ download() {
|
|||||||
fi
|
fi
|
||||||
# Skip if the item is in cache.
|
# Skip if the item is in cache.
|
||||||
[[ -e "${cache}/${dest}" ]] && continue
|
[[ -e "${cache}/${dest}" ]] && continue
|
||||||
{ if ! curl -L4 -C - --retry 10 --output "${cache}/${dest}" "${i}" ; then
|
{ if ! download_with_fallback "${cache}/${dest}" "${i}" ; then
|
||||||
ui_msgbox "Linux Game Manager" "Linux Game Manager" "Could not download \"$i\"..."
|
ui_msgbox "Linux Game Manager" "Linux Game Manager" "Could not download \"$i\"...\n\ndownload exit codes: ${downloadAttemptExitCodes}\nError details: ${downloadErrorLog}"
|
||||||
exit 1
|
exit 1
|
||||||
fi; } | ui_progressbox "Linux Game Manager" "Downloading \"$dest\" from \"$i\""
|
fi; } | ui_progressbox "Linux Game Manager" "Downloading \"$dest\" from \"$i\""
|
||||||
local downloadError=1
|
validate_downloaded_cache_file "${dest}"
|
||||||
case "${dest##*.}" in
|
|
||||||
"pk3"|"zip")
|
|
||||||
unzip -tq "${cache}/${dest}" | ui_progressbox "Linux Game Manager" "Validating ${dest##*.} file"
|
|
||||||
downloadError=$?
|
|
||||||
;;
|
|
||||||
"7z")
|
|
||||||
7z t "${cache}/${dest}" | ui_progressbox "Linux Game Manager" "Validating 7z file"
|
|
||||||
downloadError=$?
|
|
||||||
;;
|
|
||||||
"exe")
|
|
||||||
# Check if it's a valid Windows executable by looking at the MZ header
|
|
||||||
if ! hexdump -n 2 -v -e '/1 "%02X"' "${cache}/${dest}" | grep -q "4D5A"; then
|
|
||||||
downloadError=0
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
"wad")
|
|
||||||
if [[ "$(file -b --mime-type "${cache}/${dest}")" == "application/octet-stream" ]]; then
|
|
||||||
downloadError=0
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
# Add HTML check for other file types
|
|
||||||
if file -b "${cache}/${dest}" | grep -q "HTML document" ; then
|
|
||||||
downloadError=1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
if [[ $downloadError -ne 0 ]]; then
|
|
||||||
rm -fv "${cache}/${dest}"
|
|
||||||
ui_infobox "Linux Game Manager" "Linux Game Manager" "Error downloading \"${dest}\". Installation cannot continue."
|
|
||||||
alert
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
validate_downloaded_cache_file() {
|
||||||
|
local dest="$1"
|
||||||
|
local downloadError=0
|
||||||
|
case "${dest##*.}" in
|
||||||
|
"pk3"|"zip")
|
||||||
|
if ! (
|
||||||
|
set -o pipefail
|
||||||
|
unzip -tq "${cache}/${dest}" | ui_progressbox "Linux Game Manager" "Validating ${dest##*.} file"
|
||||||
|
); then
|
||||||
|
downloadError=1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"7z")
|
||||||
|
if ! (
|
||||||
|
set -o pipefail
|
||||||
|
7z t "${cache}/${dest}" | ui_progressbox "Linux Game Manager" "Validating 7z file"
|
||||||
|
); then
|
||||||
|
downloadError=1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"exe")
|
||||||
|
# Check if it's a valid Windows executable by looking at the MZ header
|
||||||
|
if ! hexdump -n 2 -v -e '/1 "%02X"' "${cache}/${dest}" | grep -q "4D5A"; then
|
||||||
|
downloadError=0
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"wad")
|
||||||
|
if [[ "$(file -b --mime-type "${cache}/${dest}")" == "application/octet-stream" ]]; then
|
||||||
|
downloadError=0
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if file -b "${cache}/${dest}" | grep -q "HTML document" ; then
|
||||||
|
downloadError=1
|
||||||
|
else
|
||||||
|
downloadError=0
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
if [[ ${downloadError} -ne 0 ]]; then
|
||||||
|
rm -fv "${cache}/${dest}"
|
||||||
|
alert "Linux Game Manager" "Linux Game Manager" "Error downloading \"${dest}\". Installation cannot continue."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
download_named() {
|
download_named() {
|
||||||
# Only needed if url breaks the name, e.g. downloads/?filename=1234
|
# Only needed if url breaks the name, e.g. downloads/?filename=1234
|
||||||
# Required arguments: filename url
|
# Required arguments: filename url
|
||||||
@@ -522,10 +622,11 @@ download_named() {
|
|||||||
fi
|
fi
|
||||||
# Skip if the item is in cache.
|
# Skip if the item is in cache.
|
||||||
test -e "${cache}/${dest}" && return
|
test -e "${cache}/${dest}" && return
|
||||||
if ! curl -L4 --output "${cache}/${dest}" "${2}" ; then
|
if ! download_with_fallback "${cache}/${dest}" "${2}" ; then
|
||||||
ui_msgbox "Linux Game Manager" "Linux Game Manager" "Could not download \"$dest\"..."
|
ui_msgbox "Linux Game Manager" "Linux Game Manager" "Could not download \"$dest\"...\n\ndownload exit codes: ${downloadAttemptExitCodes}\nError details: ${downloadErrorLog}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
validate_downloaded_cache_file "${dest}"
|
||||||
}
|
}
|
||||||
|
|
||||||
get_installer() {
|
get_installer() {
|
||||||
@@ -543,11 +644,10 @@ get_installer() {
|
|||||||
if echo "$2" | xclip -selection clipboard 2> /dev/null ; then
|
if echo "$2" | xclip -selection clipboard 2> /dev/null ; then
|
||||||
message+="\n\nThe URL has been copied to the clipboard."
|
message+="\n\nThe URL has been copied to the clipboard."
|
||||||
fi
|
fi
|
||||||
alert
|
alert "Linux Game Manager" "Linux Game Manager" "$message"
|
||||||
ui_msgbox "Linux Game Manager" "Linux Game Manager" "$message"
|
|
||||||
# Search the Desktop and Downloads directories for the installation file
|
# Search the Desktop and Downloads directories for the installation file
|
||||||
for i in ~/Downloads ~/Desktop ; do
|
for i in ~/Downloads ~/Desktop ; do
|
||||||
find $i -type f -name "$1" -exec mv -v {} "${cache}/" \;
|
find "$i" -type f -name "$1" -exec mv -v {} "${cache}/" \;
|
||||||
done
|
done
|
||||||
# If the file is still not available abort.
|
# If the file is still not available abort.
|
||||||
if [[ ! -f "${cache}/$1" ]]; then
|
if [[ ! -f "${cache}/$1" ]]; then
|
||||||
@@ -574,6 +674,7 @@ help() {
|
|||||||
help_text+="spd_voice=<voice_name>\" # set speech-dispatcher voice. Be sure module is correct.\n"
|
help_text+="spd_voice=<voice_name>\" # set speech-dispatcher voice. Be sure module is correct.\n"
|
||||||
help_text+="spd_volume=<number>\" # set speech-dispatcher speech volume.\n\n"
|
help_text+="spd_volume=<number>\" # set speech-dispatcher speech volume.\n\n"
|
||||||
help_text+="INSTALLER SCRIPT DIALOG FUNCTIONS:\n"
|
help_text+="INSTALLER SCRIPT DIALOG FUNCTIONS:\n"
|
||||||
|
help_text+="alert [\"title\" \"backtitle\"] \"message\" - Play alert sound and show acknowledgement dialog\n"
|
||||||
help_text+="ui_msgbox \"title\" \"backtitle\" \"message\" - Show information message\n"
|
help_text+="ui_msgbox \"title\" \"backtitle\" \"message\" - Show information message\n"
|
||||||
help_text+="ui_yesno \"title\" \"backtitle\" \"question\" - Ask yes/no question\n"
|
help_text+="ui_yesno \"title\" \"backtitle\" \"question\" - Ask yes/no question\n"
|
||||||
help_text+="ui_inputbox \"title\" \"backtitle\" \"prompt\" \"default\" - Get text input\n"
|
help_text+="ui_inputbox \"title\" \"backtitle\" \"prompt\" \"default\" - Get text input\n"
|
||||||
@@ -593,10 +694,11 @@ help() {
|
|||||||
game_installer() {
|
game_installer() {
|
||||||
# Create the menu of available games by reading from .install directory
|
# Create the menu of available games by reading from .install directory
|
||||||
declare -a menuList
|
declare -a menuList
|
||||||
# Get all .sh files from .install directory, excluding those starting with #, and sort them
|
# shellcheck disable=SC2154 # installedGames may be populated by sourced config or launch migration
|
||||||
mapfile -t sortedGames < <(for f in "${0%/*}/.install/"*.sh; do
|
# Get all .sh files from .install directory, excluding those starting with #//, and sort them
|
||||||
# Skip if first line starts with #
|
mapfile -t sortedGames < <(for f in "${scriptRoot}/.install/"*.sh; do
|
||||||
[[ $(head -n1 "$f") == "#"* ]] && continue
|
# Skip if first line starts with #//
|
||||||
|
[[ $(head -n1 "$f") == "#//"* ]] && continue
|
||||||
# Output filename without .sh extension
|
# Output filename without .sh extension
|
||||||
echo "${f##*/}"
|
echo "${f##*/}"
|
||||||
done | sort)
|
done | sort)
|
||||||
@@ -633,10 +735,11 @@ game_installer() {
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
# Convert game name to filename format
|
# Convert game name to filename format
|
||||||
local installScript="${0%/*}/.install/${game}.sh"
|
local installScript="${scriptRoot}/.install/${game}.sh"
|
||||||
# Check if install script exists
|
# Check if install script exists
|
||||||
if [[ -f "$installScript" ]]; then
|
if [[ -f "$installScript" ]]; then
|
||||||
# Source and execute the install script
|
# Source and execute the install script
|
||||||
|
# shellcheck disable=SC1090 # install scripts are selected dynamically from .install
|
||||||
source "$installScript"
|
source "$installScript"
|
||||||
# Show success message
|
# Show success message
|
||||||
ui_msgbox "Game Installer" "Game Installer" "${game} has been installed."
|
ui_msgbox "Game Installer" "Game Installer" "${game} has been installed."
|
||||||
@@ -645,8 +748,8 @@ game_installer() {
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
if [[ -e "${0%/*}/.launch/${game}.game" ]] && ! [[ -L "${0%/*}/.launch/${game}.sh" ]]; then
|
if [[ -e "${scriptRoot}/.launch/${game}.game" ]] && ! [[ -L "${scriptRoot}/.launch/${game}.sh" ]]; then
|
||||||
ln -srf "${0%/*}/.launch/${game}.game" "${0%/*}/.launch/${game}.sh"
|
ln -srf "${scriptRoot}/.launch/${game}.game" "${scriptRoot}/.launch/${game}.sh"
|
||||||
fi
|
fi
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
@@ -657,7 +760,8 @@ game_removal() {
|
|||||||
# Initialize array for menu construction
|
# Initialize array for menu construction
|
||||||
mapfile -t menuList < <(
|
mapfile -t menuList < <(
|
||||||
if [[ -d ".launch" ]]; then
|
if [[ -d ".launch" ]]; then
|
||||||
find -L "${0%/*}/.launch" -maxdepth 1 -type f -iname "*.sh" -print0 | sort -z | xargs -0 bash -c '
|
# shellcheck disable=SC2016 # variables expand in the child bash, not this single-quoted string
|
||||||
|
find -L "${scriptRoot}/.launch" -maxdepth 1 -type f -iname "*.sh" -print0 | sort -z | xargs -0 bash -c '
|
||||||
for f; do
|
for f; do
|
||||||
name="${f##*/}"
|
name="${f##*/}"
|
||||||
echo "$f"
|
echo "$f"
|
||||||
@@ -682,17 +786,23 @@ game_removal() {
|
|||||||
# Get the actual game file paths
|
# Get the actual game file paths
|
||||||
local gameName="${selectedGame##*/}"
|
local gameName="${selectedGame##*/}"
|
||||||
gameName="${gameName%.sh}"
|
gameName="${gameName%.sh}"
|
||||||
local gameFile="$(readlink -f "${0%/*}/.launch/${gameName}.sh")"
|
local gameFile
|
||||||
|
gameFile="$(readlink -f "${scriptRoot}/.launch/${gameName}.sh")"
|
||||||
# Get the actual installation path from the .game file
|
# Get the actual installation path from the .game file
|
||||||
local gameInstallPath
|
local gameInstallPath
|
||||||
gameInstallPath="$(grep -F "installPath" "$gameFile" | grep -v 'pushd' | head -n1)"
|
while IFS= read -r line; do
|
||||||
gameInstallPath="${gameInstallPath#*/}"
|
[[ "${line}" == \#* ]] && continue
|
||||||
gameInstallPath="${installPath}/${gameInstallPath%/*}"
|
[[ "${line}" == *'pushd'* ]] && continue
|
||||||
|
if [[ "${line}" =~ \$\{installPath\}/([^\"]+) ]]; then
|
||||||
|
gameInstallPath="${installPath}/${BASH_REMATCH[1]}"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done < "${gameFile}"
|
||||||
if [[ -z "$gameInstallPath" ]] || [[ "${gameInstallPath%%/}" == "$installPath" ]]; then
|
if [[ -z "$gameInstallPath" ]] || [[ "${gameInstallPath%%/}" == "$installPath" ]]; then
|
||||||
# No install path found, just remove from list
|
# No install path found, just remove from list
|
||||||
ui_yesno "Linux Game Manager" "Linux Game Manager" "This will remove the game from your game list, but will not remove any files. Do you want to continue?" || exit 0
|
ui_yesno "Linux Game Manager" "Linux Game Manager" "This will remove the game from your game list, but will not remove any files. Do you want to continue?" || exit 0
|
||||||
# Remove only the .sh symlink
|
# Remove only the .sh symlink
|
||||||
rm -fv "${0%/*}/.launch/${gameName}.sh" | \
|
rm -fv "${scriptRoot}/.launch/${gameName}.sh" | \
|
||||||
ui_progressbox "Linux Game Manager" "Removing game from list..."
|
ui_progressbox "Linux Game Manager" "Removing game from list..."
|
||||||
# Show success message
|
# Show success message
|
||||||
ui_msgbox "Linux Game Manager" "Linux Game Manager" "${gameName} has been removed from the list."
|
ui_msgbox "Linux Game Manager" "Linux Game Manager" "${gameName} has been removed from the list."
|
||||||
@@ -701,7 +811,7 @@ game_removal() {
|
|||||||
ui_yesno "Linux Game Manager" "Linux Game Manager" "This will remove the directory \"${gameInstallPath}\" and all of its contents. Do you want to continue?" || exit 0
|
ui_yesno "Linux Game Manager" "Linux Game Manager" "This will remove the directory \"${gameInstallPath}\" and all of its contents. Do you want to continue?" || exit 0
|
||||||
# Remove the game directory and symlink
|
# Remove the game directory and symlink
|
||||||
{ rm -rfv "${gameInstallPath}"
|
{ rm -rfv "${gameInstallPath}"
|
||||||
rm -fv "${0%/*}/.launch/${gameName}.sh";
|
rm -fv "${scriptRoot}/.launch/${gameName}.sh";
|
||||||
} | ui_progressbox "Linux Game Manager" "Removing game..."
|
} | ui_progressbox "Linux Game Manager" "Removing game..."
|
||||||
# Show success message
|
# Show success message
|
||||||
ui_msgbox "Linux Game Manager" "Linux Game Manager" "${gameName} has been removed."
|
ui_msgbox "Linux Game Manager" "Linux Game Manager" "${gameName} has been removed."
|
||||||
@@ -724,7 +834,8 @@ game_update() {
|
|||||||
done
|
done
|
||||||
menuList+=("Donate" "Donate")
|
menuList+=("Donate" "Donate")
|
||||||
menuList+=("Become a Patron" "Become a Patron")
|
menuList+=("Become a Patron" "Become a Patron")
|
||||||
local game="$(ui_menu "Audio Game Updater" "Audio Game Updater" "Please select a game to update" "${menuList[@]}")"
|
local game
|
||||||
|
game="$(ui_menu "Audio Game Updater" "Audio Game Updater" "Please select a game to update" "${menuList[@]}")"
|
||||||
if [[ ${#game} -gt 0 ]]; then
|
if [[ ${#game} -gt 0 ]]; then
|
||||||
if [[ "$game" == "Donate" ]]; then
|
if [[ "$game" == "Donate" ]]; then
|
||||||
open_url "https://ko-fi.com/stormux"
|
open_url "https://ko-fi.com/stormux"
|
||||||
@@ -737,6 +848,7 @@ game_update() {
|
|||||||
# Get the game name for success message
|
# Get the game name for success message
|
||||||
local updateGameName="${game##*/}"
|
local updateGameName="${game##*/}"
|
||||||
updateGameName="${updateGameName%.sh}"
|
updateGameName="${updateGameName%.sh}"
|
||||||
|
# shellcheck disable=SC1090 # update scripts are selected dynamically from .update
|
||||||
source "${game}"
|
source "${game}"
|
||||||
else
|
else
|
||||||
exit 0
|
exit 0
|
||||||
@@ -753,9 +865,10 @@ game_launcher() {
|
|||||||
# Initialize array for menu construction
|
# Initialize array for menu construction
|
||||||
mapfile -t menuList < <(
|
mapfile -t menuList < <(
|
||||||
if [[ -d ".launch" ]]; then
|
if [[ -d ".launch" ]]; then
|
||||||
find -L "${0%/*}/.launch" -maxdepth 1 -type f -iname "*.sh" -print0 | sort -z | xargs -0 bash -c '
|
# shellcheck disable=SC2016 # variables expand in the child bash, not this single-quoted string
|
||||||
|
find -L "${scriptRoot}/.launch" -maxdepth 1 -type f -iname "*.sh" -print0 | sort -z | xargs -0 bash -c '
|
||||||
for f; do
|
for f; do
|
||||||
[[ $(head -n1 "$f") =~ ^#$ ]] && continue
|
[[ $(head -n1 "$f") == "#//"* ]] && continue
|
||||||
name="${f##*/}"
|
name="${f##*/}"
|
||||||
echo "$f"
|
echo "$f"
|
||||||
echo "${name%.sh}"
|
echo "${name%.sh}"
|
||||||
@@ -777,6 +890,7 @@ game_launcher() {
|
|||||||
if [[ $menuCode -ne 0 ]] || [[ -z "$selectedGame" ]]; then
|
if [[ $menuCode -ne 0 ]] || [[ -z "$selectedGame" ]]; then
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
# shellcheck disable=SC1090 # launcher scripts are selected dynamically from .launch
|
||||||
. "${selectedGame}"
|
. "${selectedGame}"
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
@@ -792,8 +906,8 @@ migrate_launcher() {
|
|||||||
# Extract game name and path
|
# Extract game name and path
|
||||||
gameName="${line%|*}"
|
gameName="${line%|*}"
|
||||||
# Create launcher script if it doesn't exist
|
# Create launcher script if it doesn't exist
|
||||||
if [[ ! -L "${0%/*}/.launch/${gameName}.sh" ]]; then
|
if [[ ! -L "${scriptRoot}/.launch/${gameName}.sh" ]]; then
|
||||||
ln -srf "${0%/*}/.launch/${gameName}.game" "${0%/*}/.launch/${gameName}.sh"
|
ln -srf "${scriptRoot}/.launch/${gameName}.game" "${scriptRoot}/.launch/${gameName}.sh"
|
||||||
fi
|
fi
|
||||||
done < <(sed '/^$/d' "${configFile}")
|
done < <(sed '/^$/d' "${configFile}")
|
||||||
# Move the old config file and notify user
|
# Move the old config file and notify user
|
||||||
@@ -802,6 +916,12 @@ migrate_launcher() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Make sure this is not ran as root
|
||||||
|
if [[ "$(whoami)" == "root" ]]; then
|
||||||
|
echo "Please do not run ${0##*/} as root."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# Detect dialog interface type BEFORE potentially setting DISPLAY
|
# Detect dialog interface type BEFORE potentially setting DISPLAY
|
||||||
# This must happen before we modify DISPLAY to preserve console detection
|
# This must happen before we modify DISPLAY to preserve console detection
|
||||||
if [[ -z "$DISPLAY" ]]; then
|
if [[ -z "$DISPLAY" ]]; then
|
||||||
@@ -820,8 +940,10 @@ cache="${XDG_CACHE_HOME:-$HOME/.cache}/linux-game-manager"
|
|||||||
configFile="${XDG_CONFIG_HOME:-$HOME/.config}/storm-games/linux-game-manager/games.conf"
|
configFile="${XDG_CONFIG_HOME:-$HOME/.config}/storm-games/linux-game-manager/games.conf"
|
||||||
mkdir -p "${cache}"
|
mkdir -p "${cache}"
|
||||||
mkdir -p "${configFile%/*}"
|
mkdir -p "${configFile%/*}"
|
||||||
|
declare -a installedGames=()
|
||||||
# Load any arguments from settings.conf file
|
# Load any arguments from settings.conf file
|
||||||
if [[ -r "${configFile%/*}/settings.conf" ]]; then
|
if [[ -r "${configFile%/*}/settings.conf" ]]; then
|
||||||
|
# shellcheck disable=SC1091 # settings.conf is optional and resolved from the runtime config directory
|
||||||
source "${configFile%/*}/settings.conf"
|
source "${configFile%/*}/settings.conf"
|
||||||
fi
|
fi
|
||||||
unset noCache
|
unset noCache
|
||||||
@@ -842,6 +964,7 @@ requiredPackages=(
|
|||||||
"7z"
|
"7z"
|
||||||
"curl"
|
"curl"
|
||||||
"dialog"
|
"dialog"
|
||||||
|
"jq"
|
||||||
"yad"
|
"yad"
|
||||||
"unzip"
|
"unzip"
|
||||||
)
|
)
|
||||||
@@ -893,5 +1016,6 @@ while getopts "${args}" i ; do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
[[ "${noCache}" == "true" ]] && :
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
Reference in New Issue
Block a user