From 56371afefafa575c7264fcdefac6d99c9012134d Mon Sep 17 00:00:00 2001 From: okxlin <61420215+okxlin@users.noreply.github.com> Date: Fri, 26 Jun 2026 00:32:10 +0800 Subject: [PATCH] Add shadPS4 LinuxServer app --- apps/shadps4-linuxserver/README.md | 64 +++++++++ apps/shadps4-linuxserver/data.yml | 29 ++++ apps/shadps4-linuxserver/latest/.env.sample | 9 ++ apps/shadps4-linuxserver/latest/data.yml | 134 ++++++++++++++++++ .../latest/docker-compose.yml | 25 ++++ .../latest/scripts/init.sh | 13 ++ .../latest/scripts/uninstall.sh | 2 + .../latest/scripts/upgrade.sh | 57 ++++++++ apps/shadps4-linuxserver/logo.png | Bin 0 -> 8825 bytes 9 files changed, 333 insertions(+) create mode 100644 apps/shadps4-linuxserver/README.md create mode 100644 apps/shadps4-linuxserver/data.yml create mode 100644 apps/shadps4-linuxserver/latest/.env.sample create mode 100644 apps/shadps4-linuxserver/latest/data.yml create mode 100644 apps/shadps4-linuxserver/latest/docker-compose.yml create mode 100755 apps/shadps4-linuxserver/latest/scripts/init.sh create mode 100755 apps/shadps4-linuxserver/latest/scripts/uninstall.sh create mode 100755 apps/shadps4-linuxserver/latest/scripts/upgrade.sh create mode 100644 apps/shadps4-linuxserver/logo.png diff --git a/apps/shadps4-linuxserver/README.md b/apps/shadps4-linuxserver/README.md new file mode 100644 index 000000000..88b3c9946 --- /dev/null +++ b/apps/shadps4-linuxserver/README.md @@ -0,0 +1,64 @@ +# shadPS4 + +## 产品介绍 +shadPS4 是一个早期的 PlayStation 4 模拟器,本应用通过 LinuxServer.io 镜像提供浏览器访问的桌面环境。 + +## 主要功能 +- 通过浏览器访问 shadPS4 桌面界面。 +- 使用 `/config` 持久化用户目录、配置和游戏相关文件。 +- 通过 Basic Auth 保护 Web 桌面入口。 + +## 访问说明 +安装完成后,通过应用表单中的 HTTP 或 HTTPS 端口访问 Web 桌面,并使用安装时填写的 Basic Auth 用户名和密码登录。 + +## Introduction +shadPS4 is an early PlayStation 4 emulator. This app packages the LinuxServer.io image as a browser-accessible desktop environment. + +## Features +- Access the shadPS4 desktop from a browser. +- Persist the user home, settings, and game files under `/config`. +- Protect the Web desktop entrypoint with Basic Auth. + +## 应用简介 +shadPS4 PlayStation 4 模拟器桌面。 + +英文说明:PlayStation 4 emulator desktop maintained by LinuxServer.io. + +## 部署说明 +- 本应用使用 Docker Compose 在 1Panel 中部署。 +- 应用分类:游戏。 +- 支持架构:amd64。 +- 可选版本:`latest`。 +- 安装后按应用表单中的端口访问 Web 桌面。 + +## 端口 +| 变量 | 说明 | 默认值 | 必填 | +| --- | --- | --- | --- | +| PANEL_APP_PORT_HTTP | HTTP 端口 | 3000 | 是 | +| PANEL_APP_PORT_HTTPS | HTTPS 端口 | 3001 | 是 | + +## 数据持久化 +| 变量 | 说明 | 默认值 | 必填 | +| --- | --- | --- | --- | +| CONFIG_PATH | 配置文件路径 | ./data/config | 是 | + +升级或迁移前,请在 1Panel 中备份上述数据目录。 + +## 配置项 +| 变量 | 说明 | 默认值 | 必填 | +| --- | --- | --- | --- | +| TIME_ZONE | 时区 | Asia/Shanghai | 是 | +| CUSTOM_USER | Basic Auth 用户名 | admin | 是 | +| PASSWORD | Basic Auth 密码 | 随机生成 | 是 | +| LC_ALL | 桌面语言区域,例如 zh_CN.UTF-8 | zh_CN.UTF-8 | 否 | +| SHM_SIZE | 共享内存大小 | 1gb | 是 | + +## 使用说明 +- 浏览器/桌面类 LinuxServer 镜像默认无认证,本适配启用 Basic Auth,请使用 CUSTOM_USER 和 PASSWORD 登录。 +- 如需公网访问,请优先放在带强认证的反向代理之后。 +- 如需对外开放访问,请同步检查防火墙、安全组和反向代理配置。 + +## 参考资料 +- 官网: +- 文档: +- 源码: diff --git a/apps/shadps4-linuxserver/data.yml b/apps/shadps4-linuxserver/data.yml new file mode 100644 index 000000000..7921304e3 --- /dev/null +++ b/apps/shadps4-linuxserver/data.yml @@ -0,0 +1,29 @@ +name: shadPS4 +tags: +- Game +title: shadPS4 PlayStation 4 模拟器桌面 +description: shadPS4 PlayStation 4 模拟器桌面 +additionalProperties: + key: shadps4-linuxserver + name: shadPS4 + tags: + - Game + shortDescZh: shadPS4 PlayStation 4 模拟器桌面 + shortDescEn: PlayStation 4 emulator desktop maintained by LinuxServer.io + description: + en: PlayStation 4 emulator desktop maintained by LinuxServer.io + zh: shadPS4 PlayStation 4 模拟器桌面 + zh-Hant: shadPS4 PlayStation 4 模擬器桌面 + ja: LinuxServer.io が保守する PlayStation 4 エミュレーターデスクトップ + ko: LinuxServer.io에서 유지 관리하는 PlayStation 4 에뮬레이터 데스크톱 + ru: Рабочий стол эмулятора PlayStation 4, поддерживаемый LinuxServer.io + ms: Desktop emulator PlayStation 4 yang diselenggara oleh LinuxServer.io + pt-br: Desktop de emulador PlayStation 4 mantido pela LinuxServer.io + type: tool + crossVersionUpdate: true + limit: 0 + website: https://shadps4.net/ + github: https://github.com/linuxserver/docker-shadps4 + document: https://docs.linuxserver.io/images/docker-shadps4/ + architectures: + - amd64 diff --git a/apps/shadps4-linuxserver/latest/.env.sample b/apps/shadps4-linuxserver/latest/.env.sample new file mode 100644 index 000000000..309bc02dd --- /dev/null +++ b/apps/shadps4-linuxserver/latest/.env.sample @@ -0,0 +1,9 @@ +CONTAINER_NAME= +PANEL_APP_PORT_HTTP=3000 +PANEL_APP_PORT_HTTPS=3001 +CONFIG_PATH=./data/config +CUSTOM_USER=admin +PASSWORD=linuxserver-change-me +LC_ALL=zh_CN.UTF-8 +SHM_SIZE=1gb +TIME_ZONE=Asia/Shanghai diff --git a/apps/shadps4-linuxserver/latest/data.yml b/apps/shadps4-linuxserver/latest/data.yml new file mode 100644 index 000000000..8d57a1768 --- /dev/null +++ b/apps/shadps4-linuxserver/latest/data.yml @@ -0,0 +1,134 @@ +additionalProperties: + formFields: + - default: 3000 + edit: true + envKey: PANEL_APP_PORT_HTTP + labelEn: HTTP Port + labelZh: HTTP 端口 + label: + en: HTTP Port + zh: HTTP 端口 + zh-Hant: HTTP 連接埠 + ja: HTTP ポート + ko: HTTP 포트 + ru: HTTP-порт + ms: Port HTTP + pt-br: Porta HTTP + required: true + type: number + rule: paramPort + - default: 3001 + edit: true + envKey: PANEL_APP_PORT_HTTPS + labelEn: HTTPS Port + labelZh: HTTPS 端口 + label: + en: HTTPS Port + zh: HTTPS 端口 + zh-Hant: HTTPS 連接埠 + ja: HTTPS ポート + ko: HTTPS 포트 + ru: HTTPS-порт + ms: Port HTTPS + pt-br: Porta HTTPS + required: true + type: number + rule: paramPort + - default: ./data/config + edit: true + envKey: CONFIG_PATH + labelEn: Config folder path + labelZh: 配置文件路径 + label: + en: Config folder path + zh: 配置文件路径 + zh-Hant: 設定檔資料夾路徑 + ja: 設定フォルダーのパス + ko: 설정 폴더 경로 + ru: Путь к папке конфигурации + ms: Laluan folder konfigurasi + pt-br: Caminho da pasta de configuração + required: true + type: text + - default: admin + edit: true + envKey: CUSTOM_USER + labelEn: Basic Auth Username + labelZh: 访问用户名(Basic Auth) + label: + en: Basic Auth Username + zh: 访问用户名(Basic Auth) + zh-Hant: 存取使用者名稱(Basic Auth) + ja: ベーシック認証ユーザー名 + ko: 기본 인증 사용자명 + ru: Имя пользователя (Basic Auth) + ms: Nama pengguna Basic Auth + pt-br: Usuario Basic Auth + required: true + type: text + - default: linuxserver-change-me + edit: true + envKey: PASSWORD + labelEn: Basic Auth Password + labelZh: 访问密码(Basic Auth) + label: + en: Basic Auth Password + zh: 访问密码(Basic Auth) + zh-Hant: 存取密碼(Basic Auth) + ja: ベーシック認証パスワード + ko: 기본 인증 비밀번호 + ru: Пароль Basic Auth + ms: Kata laluan Basic Auth + pt-br: Senha Basic Auth + random: true + required: true + rule: paramComplexity + type: password + - default: zh_CN.UTF-8 + edit: true + envKey: LC_ALL + labelEn: Desktop language locale + labelZh: 桌面语言区域 + label: + en: Desktop language locale + zh: 桌面语言区域 + zh-Hant: 桌面語言區域 + ja: デスクトップ言語ロケール + ko: 데스크톱 언어 로케일 + ru: Локаль языка рабочего стола + ms: Lokal bahasa desktop + pt-br: Localidade do idioma da area de trabalho + required: false + type: text + - default: 1gb + edit: true + envKey: SHM_SIZE + labelEn: Shared memory size + labelZh: 共享内存大小 + label: + en: Shared memory size + zh: 共享内存大小 + zh-Hant: 共享記憶體大小 + ja: 共有メモリサイズ + ko: 공유 메모리 크기 + ru: Размер общей памяти + ms: Saiz memori kongsi + pt-br: Tamanho da memoria compartilhada + required: true + type: text + - default: Asia/Shanghai + edit: true + envKey: TIME_ZONE + labelEn: Time zone + labelZh: 时区 + label: + en: Time zone + zh: 时区 + zh-Hant: 時區 + ja: タイムゾーン + ko: 시간대 + ru: Часовой пояс + ms: Zon waktu + pt-br: Fuso horário + required: true + type: text diff --git a/apps/shadps4-linuxserver/latest/docker-compose.yml b/apps/shadps4-linuxserver/latest/docker-compose.yml new file mode 100644 index 000000000..abe7eefd0 --- /dev/null +++ b/apps/shadps4-linuxserver/latest/docker-compose.yml @@ -0,0 +1,25 @@ +networks: + 1panel-network: + external: true +services: + shadps4: + image: "linuxserver/shadps4:latest" + container_name: ${CONTAINER_NAME} + restart: always + networks: + - 1panel-network + ports: + - "${PANEL_APP_PORT_HTTP}:3000" + - "${PANEL_APP_PORT_HTTPS}:3001" + volumes: + - "${CONFIG_PATH}:/config" + environment: + - PUID=1000 + - PGID=1000 + - TZ=${TIME_ZONE} + - CUSTOM_USER=${CUSTOM_USER} + - PASSWORD=${PASSWORD} + - LC_ALL=${LC_ALL:-zh_CN.UTF-8} + shm_size: ${SHM_SIZE} + labels: + createdBy: "Apps" diff --git a/apps/shadps4-linuxserver/latest/scripts/init.sh b/apps/shadps4-linuxserver/latest/scripts/init.sh new file mode 100755 index 000000000..e5658f096 --- /dev/null +++ b/apps/shadps4-linuxserver/latest/scripts/init.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail + +paths=( + "${CONFIG_PATH:-./data/config}" +) + +mkdir -p "${paths[@]}" +for path in "${paths[@]}"; do + case "$path" in + ./*|../*) chown -R 1000:1000 "$path" 2>/dev/null || true ;; + esac +done diff --git a/apps/shadps4-linuxserver/latest/scripts/uninstall.sh b/apps/shadps4-linuxserver/latest/scripts/uninstall.sh new file mode 100755 index 000000000..ab8a8d674 --- /dev/null +++ b/apps/shadps4-linuxserver/latest/scripts/uninstall.sh @@ -0,0 +1,2 @@ +#!/bin/bash +docker-compose down --volumes diff --git a/apps/shadps4-linuxserver/latest/scripts/upgrade.sh b/apps/shadps4-linuxserver/latest/scripts/upgrade.sh new file mode 100755 index 000000000..08cc99c3b --- /dev/null +++ b/apps/shadps4-linuxserver/latest/scripts/upgrade.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +set -euo pipefail + +ENV_FILE="${ENV_FILE:-./.env}" + +generate_secret() { + if [[ -r /dev/urandom ]]; then + local secret="" + local chunk="" + while [[ ${#secret} -lt 24 ]]; do + chunk="$(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c $((24 - ${#secret})) || true)" + secret="${secret}${chunk}" + done + printf '%s\n' "$secret" + else + printf '%s\n' 'linuxserver-change-me' + fi +} + +ensure_env_default() { + local key="$1" + local value="$2" + local fill_empty="${3:-false}" + + if [[ ! -f "$ENV_FILE" ]]; then + echo "$ENV_FILE not found; skipped $key migration" + return + fi + + if grep -qE "^${key}=" "$ENV_FILE"; then + local current + current="$(sed -n -E "s/^${key}=//p" "$ENV_FILE" | tail -n 1)" + current="${current%\"}" + current="${current#\"}" + current="${current%'}" + current="${current#'}" + if [[ "$fill_empty" == "true" && -z "$current" ]]; then + sed -i -E "s|^${key}=.*|${key}=${value}|" "$ENV_FILE" + echo "Updated empty $key" + else + echo "$key already exists" + fi + return + fi + + printf '%s=%s\n' "$key" "$value" >> "$ENV_FILE" + echo "Added $key" +} + +if [[ -f "$ENV_FILE" ]]; then + ensure_env_default "CUSTOM_USER" "admin" true + ensure_env_default "PASSWORD" "$(generate_secret)" true + ensure_env_default "LC_ALL" "zh_CN.UTF-8" false + ensure_env_default "SHM_SIZE" "1gb" false +else + echo "$ENV_FILE not found; skipped LinuxServer environment migration" +fi diff --git a/apps/shadps4-linuxserver/logo.png b/apps/shadps4-linuxserver/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..35fff34dc3ce0737b0d1b89be4e241d9887d0837 GIT binary patch literal 8825 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