Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0353b71223 | ||
|
|
7f01abad25 | ||
|
|
4886cb570d | ||
|
|
66894ecdca | ||
|
|
d9b64a5ab5 | ||
|
|
3f73b97b39 | ||
|
|
323e270c51 | ||
|
|
3c06d802a9 | ||
|
|
76790e0321 | ||
|
|
c3d34a2788 | ||
|
|
4711ef5532 | ||
|
|
c384df7cac |
No files matched your search
@@ -1,6 +1,6 @@
|
|||||||
name: release
|
name: release
|
||||||
|
|
||||||
# Build the GAMEMAX LCD AppImage from source and attach it to a GitHub release.
|
# Build the GAMEMAX LCD AppImage from source and attach it to a Gitea release.
|
||||||
# Trigger: push a tag like v1.0.0 (or run manually from the Actions tab).
|
# Trigger: push a tag like v1.0.0 (or run manually from the Actions tab).
|
||||||
|
|
||||||
on:
|
on:
|
||||||
@@ -11,6 +11,11 @@ on:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
||||||
|
env:
|
||||||
|
# github.server_url mengikuti alamat saat runner didaftarkan dan bisa jadi IP internal,
|
||||||
|
# jadi URL yang disematkan ke dalam AppImage ditulis eksplisit di sini.
|
||||||
|
RELEASE_URL: https://gitea.oxpoe.qzz.io/oxpoe/Gamemax-linux-apps/releases/download
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
appimage:
|
appimage:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -21,15 +26,16 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y --no-install-recommends \
|
sudo apt-get install -y --no-install-recommends \
|
||||||
libgl1 libegl1 libxkbcommon0 libdbus-1-3 libfuse2 fuse zsync
|
libgl1 libegl1 libxkbcommon0 libdbus-1-3 libfuse2 fuse zsync libpython3.12
|
||||||
|
|
||||||
- name: Set up uv
|
- name: Set up uv
|
||||||
uses: astral-sh/setup-uv@v5
|
# installers astral, bukan setup-uv: setup-v5 menembak API GitHub dan kena rate limit
|
||||||
|
run: curl -LsSf https://astral.sh/uv/install.sh | env INSTALLER_PREFIX=/usr/local sh
|
||||||
|
|
||||||
- name: Build AppImage
|
- name: Build AppImage
|
||||||
env:
|
env:
|
||||||
APPIMAGE_EXTRACT_AND_RUN: "1"
|
APPIMAGE_EXTRACT_AND_RUN: "1"
|
||||||
UPDATE_INFO_URL: https://github.com/${{ github.repository }}/releases/download/${{ github.ref_name }}/GAMEMAX-LCD-x86_64.AppImage.zsync
|
UPDATE_INFO_URL: ${{ env.RELEASE_URL }}/${{ github.ref_name }}/GAMEMAX-LCD-x86_64.AppImage.zsync
|
||||||
run: bash packaging/build_appimage.sh
|
run: bash packaging/build_appimage.sh
|
||||||
|
|
||||||
- name: Smoke test the bundle (no display)
|
- name: Smoke test the bundle (no display)
|
||||||
@@ -43,37 +49,34 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd dist
|
cd dist
|
||||||
sha256sum GAMEMAX-LCD-x86_64.AppImage > GAMEMAX-LCD-x86_64.AppImage.sha256
|
sha256sum GAMEMAX-LCD-x86_64.AppImage > GAMEMAX-LCD-x86_64.AppImage.sha256
|
||||||
zsyncmake -u "https://github.com/${{ github.repository }}/releases/download/${{ github.ref_name }}/GAMEMAX-LCD-x86_64.AppImage" \
|
zsyncmake -u "${{ env.RELEASE_URL }}/${{ github.ref_name }}/GAMEMAX-LCD-x86_64.AppImage" \
|
||||||
-o GAMEMAX-LCD-x86_64.AppImage.zsync GAMEMAX-LCD-x86_64.AppImage
|
-o GAMEMAX-LCD-x86_64.AppImage.zsync GAMEMAX-LCD-x86_64.AppImage
|
||||||
cat GAMEMAX-LCD-x86_64.AppImage.sha256
|
cat GAMEMAX-LCD-x86_64.AppImage.sha256
|
||||||
ls -l
|
ls -l
|
||||||
|
|
||||||
- name: Publish release
|
- name: Publish release (Gitea API)
|
||||||
uses: softprops/action-gh-release@v2
|
env:
|
||||||
with:
|
TOKEN: ${{ github.token }}
|
||||||
name: GAMEMAX LCD ${{ github.ref_name }}
|
run: |
|
||||||
generate_release_notes: true
|
API="${GITHUB_API_URL:-${GITHUB_SERVER_URL}/api/v1}"
|
||||||
body: |
|
TAG="${GITHUB_REF_NAME}"
|
||||||
Linux bridge + tray app for the LCD panel of GAMEMAX IceBurg Digital AIO
|
cat > /tmp/body.md <<'EOF'
|
||||||
coolers. Built automatically from `${{ github.sha }}`.
|
Linux bridge + tray app for the LCD panel of GAMEMAX IceBurg Digital AIO coolers.
|
||||||
|
|
||||||
**Download** `GAMEMAX-LCD-x86_64.AppImage`, then:
|
**Download** `GAMEMAX-LCD-x86_64.AppImage`, then:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
chmod +x GAMEMAX-LCD-x86_64.AppImage
|
chmod +x GAMEMAX-LCD-x86_64.AppImage
|
||||||
./GAMEMAX-LCD-x86_64.AppImage # tray + window
|
./GAMEMAX-LCD-x86_64.AppImage
|
||||||
./GAMEMAX-LCD-x86_64.AppImage --selftest # verify the bundle starts
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Device access still needs the udev rule once:
|
Verify with the published SHA-256, or use AppImageUpdate with the `.zsync` asset.
|
||||||
`sudo cp packaging/70-gamemax.rules /etc/udev/rules.d/ && sudo udevadm control --reload`
|
Independent project, not affiliated with the vendor.
|
||||||
|
EOF
|
||||||
**Integrity:** verify the download with the published SHA-256, or use
|
python3 -c 'import json,sys;print(json.dumps({"tag_name":sys.argv[1],"name":"GAMEMAX LCD "+sys.argv[1],"body":open(sys.argv[2]).read()}))' "$TAG" /tmp/body.md > /tmp/rel.json
|
||||||
`appimageupdatetool`/AppImageUpdate with the `.zsync` asset for delta updates.
|
RID=$(curl -sf -X POST -H "Authorization: token $TOKEN" -H "Content-Type: application/json" "$API/repos/$GITHUB_REPOSITORY/releases" --data @/tmp/rel.json | python3 -c 'import json,sys;print(json.load(sys.stdin)["id"])')
|
||||||
The built-in updater (v1.2.3+) also verifies that checksum before replacing itself.
|
echo "release id=$RID"
|
||||||
|
for f in dist/GAMEMAX-LCD-x86_64.AppImage dist/GAMEMAX-LCD-x86_64.AppImage.sha256 dist/GAMEMAX-LCD-x86_64.AppImage.zsync; do
|
||||||
Independent project, not affiliated with the vendor — see DISCLAIMER.md.
|
[ -f "$f" ] || continue
|
||||||
files: |
|
curl -sf -X POST -H "Authorization: token $TOKEN" -F "attachment=@$f" "$API/repos/$GITHUB_REPOSITORY/releases/$RID/assets?name=$(basename "$f")" -o /dev/null
|
||||||
dist/GAMEMAX-LCD-x86_64.AppImage
|
done
|
||||||
dist/GAMEMAX-LCD-x86_64.AppImage.sha256
|
|
||||||
dist/GAMEMAX-LCD-x86_64.AppImage.zsync
|
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
> 🪞 **Mirror.** Repo asli, pengembangan & **rilis/unduhan** ada di **Gitea**: https://gitea.oxpoe.qzz.io/oxpoe/Gamemax-linux-apps/releases · GitHub hanya cermin kode.
|
||||||
|
|
||||||
# GAMEMAX LCD — Linux bridge & tray app
|
# GAMEMAX LCD — Linux bridge & tray app
|
||||||
|
|
||||||
Drive the LCD panel of a GAMEMAX **IceBurg Digital** AIO cooler from Linux: a small
|
Drive the LCD panel of a GAMEMAX **IceBurg Digital** AIO cooler from Linux: a small
|
||||||
@@ -7,8 +9,8 @@ Reverse engineered independently from the Windows vendor software
|
|||||||
(`PcInfoMonitorPro.exe` / "IceBurg Digital Software"); the protocol notes are in
|
(`PcInfoMonitorPro.exe` / "IceBurg Digital Software"); the protocol notes are in
|
||||||
[`docs/reverse-engineering.md`](docs/reverse-engineering.md) (Indonesian).
|
[`docs/reverse-engineering.md`](docs/reverse-engineering.md) (Indonesian).
|
||||||
|
|
||||||
[](https://github.com/oxpoe/Gamemax-linux-apps/releases)
|
[](https://gitea.oxpoe.qzz.io/oxpoe/Gamemax-linux-apps/releases)
|
||||||
[](https://github.com/oxpoe/Gamemax-linux-apps/actions/workflows/release.yml)
|
[](https://gitea.oxpoe.qzz.io/oxpoe/Gamemax-linux-apps/actions/workflows/release.yml)
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
[](#compatibility)
|
[](#compatibility)
|
||||||
[](src/gamemax_report.py)
|
[](src/gamemax_report.py)
|
||||||
@@ -101,15 +103,19 @@ temperature source (Tctl vs Tccd).
|
|||||||
send/sample interval — saved to `~/.config/gamemax-report/config.json`
|
send/sample interval — saved to `~/.config/gamemax-report/config.json`
|
||||||
- **Clear mode indicators**: green "showing sensor data" / orange "blank (zeros)" /
|
- **Clear mode indicators**: green "showing sensor data" / orange "blank (zeros)" /
|
||||||
grey "sending stopped", dimmed tray icon and a desktop notification per change
|
grey "sending stopped", dimmed tray icon and a desktop notification per change
|
||||||
- **Autostart** via a systemd user unit (equivalent of the vendor's Task Scheduler trick)
|
- **Autostart** at login: a systemd user unit for the sender **and** an XDG autostart entry that
|
||||||
|
starts the tray app with `--tray-only` (no window pops up; open it from the tray menu). The
|
||||||
|
*Mulai otomatis saat login* checkbox manages both, and disables any other autostart entry that
|
||||||
|
would launch the same AppImage with a window.
|
||||||
- **Plug and play**: the service waits for the device, streams while present and keeps
|
- **Plug and play**: the service waits for the device, streams while present and keeps
|
||||||
waiting through unplug/replug; a udev rule grants access to the logged-in user
|
waiting through unplug/replug; a udev rule grants access to the logged-in user
|
||||||
- **Single instance**: launching the app again just raises the running window
|
- **Single instance**: launching the app again just raises the running window
|
||||||
- **Self-update from GitHub Releases** (check + one-click update)
|
- **Self-update from Gitea Releases** (check + one-click update)
|
||||||
- **Donate / GitHub buttons** in the app (window and tray menu)
|
- **Donate / Gitea buttons** in the app (window and tray menu)
|
||||||
- **AppImage build** script (`packaging/build_appimage.sh`, PySide6 bundled)
|
- **AppImage build** script (`packaging/build_appimage.sh`, PySide6 bundled)
|
||||||
|
|
||||||
The GUI labels are in Indonesian.
|
The GUI labels are in Indonesian. The app itself is named **IceBurg LCD** (no vendor brand in
|
||||||
|
the UI); the repository keeps the hardware and brand name only to describe what it supports.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
@@ -123,6 +129,16 @@ The GUI labels are in Indonesian.
|
|||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
|
One command (downloads the latest release, verifies its SHA-256, installs the app, the
|
||||||
|
systemd user unit, the menu entry and the udev rule):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://gitea.oxpoe.qzz.io/oxpoe/Gamemax-linux-apps/raw/branch/main/install.sh | bash
|
||||||
|
# uninstall: bash install.sh --uninstall (add --remove-data to drop settings too)
|
||||||
|
```
|
||||||
|
|
||||||
|
Manual steps, if you prefer to see every command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. device access for the logged-in user (once, needs root)
|
# 1. device access for the logged-in user (once, needs root)
|
||||||
sudo cp packaging/70-gamemax.rules /etc/udev/rules.d/
|
sudo cp packaging/70-gamemax.rules /etc/udev/rules.d/
|
||||||
@@ -211,10 +227,10 @@ assets/ previews and icon
|
|||||||
|
|
||||||
## Updates
|
## Updates
|
||||||
|
|
||||||
The app keeps itself current from GitHub Releases:
|
The app keeps itself current from Gitea Releases:
|
||||||
|
|
||||||
- On start (when running from an AppImage) and from the **Periksa pembaruan** button or the
|
- On start (when running from an AppImage) and from the **Periksa pembaruan** button or the
|
||||||
tray menu, it asks the GitHub API for the latest release and compares it with its version.
|
tray menu, it asks the Gitea API for the latest release and compares it with its version.
|
||||||
- When a newer release exists, a **Perbarui ke vX.Y.Z** button appears. One click downloads
|
- When a newer release exists, a **Perbarui ke vX.Y.Z** button appears. One click downloads
|
||||||
the release asset, replaces the running AppImage atomically, refreshes the sender from the
|
the release asset, replaces the running AppImage atomically, refreshes the sender from the
|
||||||
new bundle and restarts the service. Restart the app to use the new version.
|
new bundle and restarts the service. Restart the app to use the new version.
|
||||||
|
|||||||
+1
-1
@@ -11,4 +11,4 @@ This is a small local tool. The relevant surface:
|
|||||||
|
|
||||||
If you find a problem — for example a way to make the helper scripts run something else,
|
If you find a problem — for example a way to make the helper scripts run something else,
|
||||||
or a path that writes outside the documented locations — please open an issue (or a
|
or a path that writes outside the documented locations — please open an issue (or a
|
||||||
private security advisory on GitHub). Do not test on hardware you do not own.
|
private security advisory on Gitea). Do not test on hardware you do not own.
|
||||||
Executable
+195
@@ -0,0 +1,195 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# GAMEMAX LCD — pemasangan / pelepasan satu perintah.
|
||||||
|
#
|
||||||
|
# curl -fsSL https://gitea.oxpoe.qzz.io/oxpoe/Gamemax-linux-apps/raw/branch/main/install.sh | bash
|
||||||
|
#
|
||||||
|
# Opsi:
|
||||||
|
# --uninstall lepaskan pemasangan (layanan, aplikasi, config, ikon, entri menu)
|
||||||
|
# --no-service pasang aplikasi saja, jangan aktifkan layanan/autostart
|
||||||
|
# --version vX.Y.Z pasang versi rilis tertentu (default: rilis terbaru)
|
||||||
|
# --remove-data saat --uninstall: hapus juga ~/.config/gamemax-report
|
||||||
|
#
|
||||||
|
# UdeV: aturan izin device dipasang dengan sudo. Kalau skrip dijalankan lewat pipa
|
||||||
|
# (curl | bash) dan sudo butuh kata sandi, perintahnya dicetak untuk dijalankan manual.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REPO="oxpoe/Gamemax-linux-apps"
|
||||||
|
ASSET="GAMEMAX-LCD-x86_64.AppImage"
|
||||||
|
INSTANCE="https://gitea.oxpoe.qzz.io"
|
||||||
|
RAW="$INSTANCE/$REPO/raw/branch/main"
|
||||||
|
|
||||||
|
OPT_DIR="$HOME/.local/opt/gamemax-lcd"
|
||||||
|
APP="$OPT_DIR/GAMEMAX-LCD.AppImage"
|
||||||
|
DATA_DIR="$HOME/.local/share/gamemax-report"
|
||||||
|
UNIT="$HOME/.config/systemd/user/gamemax-report.service"
|
||||||
|
DESKTOP_DIR="$HOME/.local/share/applications"
|
||||||
|
ICON_DIR="$HOME/.local/share/icons/hicolor/128x128/apps"
|
||||||
|
RULE=/etc/udev/rules.d/70-gamemax.rules
|
||||||
|
SERVICE="gamemax-report.service"
|
||||||
|
|
||||||
|
UNINSTALL=0 WITH_SERVICE=1 REMOVE_DATA=0 VERSION="latest"
|
||||||
|
|
||||||
|
say() { printf '%s\n' "$*"; }
|
||||||
|
die() { printf 'galat: %s\n' "$*" >&2; exit 1; }
|
||||||
|
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
--uninstall) UNINSTALL=1 ;;
|
||||||
|
--no-service) WITH_SERVICE=0 ;;
|
||||||
|
--remove-data) REMOVE_DATA=1 ;;
|
||||||
|
--version) shift; VERSION="${1:?--version butuh nilai seperti v1.3.0}" ;;
|
||||||
|
-h|--help) sed -n '2,14p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
|
||||||
|
*) die "opsi tidak dikenal: $1" ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
need() { command -v "$1" >/dev/null 2>&1 || die "perintah '$1' tidak tersedia"; }
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- uninstall
|
||||||
|
if [ "$UNINSTALL" = 1 ]; then
|
||||||
|
say "== melepaskan GAMEMAX LCD =="
|
||||||
|
command -v systemctl >/dev/null 2>&1 && systemctl --user disable --now "$SERVICE" 2>/dev/null || true
|
||||||
|
rm -f "$UNIT"
|
||||||
|
command -v systemctl >/dev/null 2>&1 && { systemctl --user daemon-reload 2>/dev/null || true; \
|
||||||
|
systemctl --user reset-failed "$SERVICE" 2>/dev/null || true; }
|
||||||
|
rm -rf "$OPT_DIR" "$DATA_DIR"
|
||||||
|
rm -f "$DESKTOP_DIR/gamemax-lcd.desktop" "$ICON_DIR/gamemax-lcd.png"
|
||||||
|
rm -f "$HOME/.config/autostart/iceburg-lcd.desktop"
|
||||||
|
[ "$REMOVE_DATA" = 1 ] && rm -rf "$HOME/.config/gamemax-report"
|
||||||
|
command -v update-desktop-database >/dev/null 2>&1 && update-desktop-database "$DESKTOP_DIR" 2>/dev/null || true
|
||||||
|
if [ -f "$RULE" ]; then
|
||||||
|
if sudo -n rm -f "$RULE" 2>/dev/null; then
|
||||||
|
sudo -n udevadm control --reload 2>/dev/null || true
|
||||||
|
say " aturan udev dihapus"
|
||||||
|
else
|
||||||
|
say " aturan udev masih ada (butuh sudo): sudo rm -f $RULE && sudo udevadm control --reload"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
say "selesai. Aplikasi, layanan, dan berkas pendukung sudah dilepas."
|
||||||
|
say "catatan: konfigurasi ~/.config/gamemax-report hanya dihapus dengan --remove-data."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- install
|
||||||
|
need curl
|
||||||
|
need sha256sum
|
||||||
|
command -v systemctl >/dev/null 2>&1 || die "systemd (systemctl) dibutuhkan untuk layanan"
|
||||||
|
|
||||||
|
if [ "$VERSION" = "latest" ]; then
|
||||||
|
VERSION="$(curl -fsSL "$INSTANCE/api/v1/repos/$REPO/releases/latest" | sed -n 's/.*"tag_name":"\([^"]*\)".*/\1/p')"
|
||||||
|
[ -n "$VERSION" ] || die "gagal menentukan rilis terbaru di Gitea"
|
||||||
|
fi
|
||||||
|
BASE="$INSTANCE/$REPO/releases/download/$VERSION"
|
||||||
|
|
||||||
|
say "== GAMEMAX LCD: pemasangan ($VERSION) =="
|
||||||
|
mkdir -p "$OPT_DIR" "$DATA_DIR" "$DESKTOP_DIR" "$ICON_DIR" "$HOME/.config/systemd/user"
|
||||||
|
|
||||||
|
say "1/6 mengunduh aplikasi …"
|
||||||
|
curl -fsSL -o "$APP.part" "$BASE/$ASSET"
|
||||||
|
curl -fsSL -o "$APP.sha256" "$BASE/$ASSET.sha256"
|
||||||
|
|
||||||
|
say "2/6 memverifikasi checksum …"
|
||||||
|
EXPECTED="$(awk '{print $1}' "$APP.sha256")"
|
||||||
|
ACTUAL="$(sha256sum "$APP.part" | awk '{print $1}')"
|
||||||
|
[ "$EXPECTED" = "$ACTUAL" ] || { rm -f "$APP.part"; die "checksum tidak cocok — unduhan dibatalkan"; }
|
||||||
|
say " ok: ${ACTUAL:0:16}…"
|
||||||
|
|
||||||
|
mv -f "$APP.part" "$APP"
|
||||||
|
chmod +x "$APP"
|
||||||
|
rm -f "$APP.sha256"
|
||||||
|
|
||||||
|
say "3/6 mengambil sender + ikon dari bundel …"
|
||||||
|
TMP="$(mktemp -d)"
|
||||||
|
( cd "$TMP" && "$APP" --appimage-extract >/dev/null 2>&1 ) || true
|
||||||
|
INTERNAL="$TMP/squashfs-root/usr/bin/_internal"
|
||||||
|
if [ -f "$INTERNAL/gamemax_report.py" ]; then
|
||||||
|
cp "$INTERNAL/gamemax_report.py" "$DATA_DIR/gamemax_report.py"
|
||||||
|
else
|
||||||
|
say " ! sender tidak ditemukan di bundel — unduh dari repo"
|
||||||
|
curl -fsSL -o "$DATA_DIR/gamemax_report.py" "$RAW/src/gamemax_report.py"
|
||||||
|
fi
|
||||||
|
[ -f "$INTERNAL/icon.png" ] && cp "$INTERNAL/icon.png" "$ICON_DIR/gamemax-lcd.png" \
|
||||||
|
|| curl -fsSL -o "$ICON_DIR/gamemax-lcd.png" "$RAW/src/icon.png"
|
||||||
|
rm -rf "$TMP"
|
||||||
|
|
||||||
|
say "4/6 memasang layanan systemd (autostart + plug and play) …"
|
||||||
|
cat > "$UNIT" <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=IceBurg LCD — HID sensor display bridge (Linux)
|
||||||
|
After=graphical-session.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/usr/bin/python3 $DATA_DIR/gamemax_report.py --wait --interval 0.5 --sample 0.5
|
||||||
|
Restart=always
|
||||||
|
RestartSec=3
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
|
EOF
|
||||||
|
systemctl --user daemon-reload
|
||||||
|
if [ "$WITH_SERVICE" = 1 ]; then
|
||||||
|
systemctl --user enable --now "$SERVICE"
|
||||||
|
sleep 2
|
||||||
|
say " layanan: $(systemctl --user is-active "$SERVICE") / $(systemctl --user is-enabled "$SERVICE")"
|
||||||
|
else
|
||||||
|
say " dilewati (--no-service)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
say "5/6 memasang entri menu, ikon, dan autostart tray …"
|
||||||
|
cat > "$DESKTOP_DIR/gamemax-lcd.desktop" <<EOF
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=IceBurg LCD
|
||||||
|
GenericName=Kontrol LCD AIO
|
||||||
|
Comment=Status, nyala/mati, pemantauan, dan pengaturan LCD AIO IceBurg Digital
|
||||||
|
Exec="$APP"
|
||||||
|
Icon=gamemax-lcd
|
||||||
|
Terminal=false
|
||||||
|
Categories=System;Utility;
|
||||||
|
EOF
|
||||||
|
command -v update-desktop-database >/dev/null 2>&1 && update-desktop-database "$DESKTOP_DIR" 2>/dev/null || true
|
||||||
|
command -v gtk-update-icon-cache >/dev/null 2>&1 && \
|
||||||
|
gtk-update-icon-cache -f -t "$HOME/.local/share/icons/hicolor" 2>/dev/null || true
|
||||||
|
mkdir -p "$HOME/.config/autostart"
|
||||||
|
cat > "$HOME/.config/autostart/iceburg-lcd.desktop" <<EOF
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=IceBurg LCD (tray)
|
||||||
|
Comment=Layar LCD AIO — berjalan di tray saat login (tanpa jendela)
|
||||||
|
Exec="$APP" --tray-only
|
||||||
|
Icon=iceburg-lcd
|
||||||
|
Terminal=false
|
||||||
|
X-GNOME-Autostart-enabled=true
|
||||||
|
EOF
|
||||||
|
say " autostart tray: ~/.config/autostart/iceburg-lcd.desktop (--tray-only)"
|
||||||
|
|
||||||
|
say "6/6 aturan udev (izin device) …"
|
||||||
|
RULE_TMP="$(mktemp)"
|
||||||
|
curl -fsSL -o "$RULE_TMP" "$RAW/packaging/70-gamemax.rules"
|
||||||
|
if [ -f "$RULE" ] && cmp -s "$RULE" "$RULE_TMP"; then
|
||||||
|
say " sudah terpasang"
|
||||||
|
elif sudo -n install -m 644 "$RULE_TMP" "$RULE" 2>/dev/null; then
|
||||||
|
sudo -n udevadm control --reload 2>/dev/null || true
|
||||||
|
sudo -n udevadm trigger --subsystem-match=hidraw 2>/dev/null || true
|
||||||
|
say " terpasang"
|
||||||
|
elif [ -t 0 ]; then
|
||||||
|
sudo install -m 644 "$RULE_TMP" "$RULE" && sudo udevadm control --reload && \
|
||||||
|
sudo udevadm trigger --subsystem-match=hidraw && say " terpasang"
|
||||||
|
else
|
||||||
|
say " ! butuh sudo — jalankan sekali:"
|
||||||
|
say " sudo install -m 644 $RULE_TMP $RULE && sudo udevadm control --reload && sudo udevadm trigger --subsystem-match=hidraw"
|
||||||
|
fi
|
||||||
|
rm -f "$RULE_TMP"
|
||||||
|
|
||||||
|
say
|
||||||
|
say "== selesai =="
|
||||||
|
say " aplikasi : $APP"
|
||||||
|
say " sender : $DATA_DIR/gamemax_report.py"
|
||||||
|
say " menu : GAMEMAX IceBurg LCD"
|
||||||
|
say " layanan : systemctl --user status $SERVICE"
|
||||||
|
say " log : journalctl --user -u $SERVICE -f"
|
||||||
|
say
|
||||||
|
say "buka aplikasinya untuk mengatur slot kipas/sumber suhu, atau:"
|
||||||
|
say " $APP --window"
|
||||||
@@ -42,9 +42,9 @@ cp "$ROOT_DIR/src/icon.png" "$APPDIR/gamemax-lcd.png"
|
|||||||
cat > "$APPDIR/gamemax-lcd.desktop" <<'EOF'
|
cat > "$APPDIR/gamemax-lcd.desktop" <<'EOF'
|
||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Type=Application
|
Type=Application
|
||||||
Name=GAMEMAX IceBurg LCD
|
Name=IceBurg LCD
|
||||||
GenericName=AI LCD controller
|
GenericName=Kontrol LCD AIO
|
||||||
Comment=Status, on/off, monitor, and settings for the GAMEMAX IceBurg AIO LCD
|
Comment=Status, nyala/mati, pemantauan, dan pengaturan LCD AIO IceBurg Digital
|
||||||
Exec=gamemax-lcd
|
Exec=gamemax-lcd
|
||||||
Icon=gamemax-lcd
|
Icon=gamemax-lcd
|
||||||
Terminal=false
|
Terminal=false
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=GAMEMAX HID sensor display bridge (PcInfoMonitorPro replacement)
|
Description=IceBurg LCD — HID sensor display bridge (Linux)
|
||||||
Documentation=file:///mnt/SSD/Work/REVERSE-EGENERING/analysis/01-recon.md
|
Documentation=file:///mnt/SSD/Work/REVERSE-EGENERING/analysis/01-recon.md
|
||||||
After=graphical-session.target
|
After=graphical-session.target
|
||||||
|
|
||||||
|
|||||||
+89
-26
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""GAMEMAX IceBurg LCD — GUI tray: status, nyala/mati, pemantauan beranimasi, pengaturan.
|
"""IceBurg LCD — GUI tray: status, nyala/mati, pemantauan beranimasi, pengaturan.
|
||||||
|
|
||||||
Streaming tetap dijalankan oleh layanan systemd (gamemax-report.service); GUI ini
|
Streaming tetap dijalankan oleh layanan systemd (gamemax-report.service); GUI ini
|
||||||
mengendalikannya dan memakai gamemax_report.py sebagai pengirim.
|
mengendalikannya dan memakai gamemax_report.py sebagai pengirim.
|
||||||
@@ -8,6 +8,7 @@ mengendalikannya dan memakai gamemax_report.py sebagai pengirim.
|
|||||||
gamemax_gui.py --tray-only # tanpa jendela
|
gamemax_gui.py --tray-only # tanpa jendela
|
||||||
gamemax_gui.py --selftest # uji muat tanpa tampilan (untuk build AppImage)
|
gamemax_gui.py --selftest # uji muat tanpa tampilan (untuk build AppImage)
|
||||||
"""
|
"""
|
||||||
|
import glob
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import math
|
import math
|
||||||
@@ -32,25 +33,28 @@ from PySide6.QtWidgets import (
|
|||||||
)
|
)
|
||||||
from PySide6.QtNetwork import QLocalServer, QLocalSocket
|
from PySide6.QtNetwork import QLocalServer, QLocalSocket
|
||||||
|
|
||||||
APP_VERSION = "1.3.0"
|
APP_VERSION = "1.3.5"
|
||||||
|
APP_NAME = "IceBurg LCD"
|
||||||
REPO = "oxpoe/Gamemax-linux-apps"
|
REPO = "oxpoe/Gamemax-linux-apps"
|
||||||
RELEASES_API = f"https://api.github.com/repos/{REPO}/releases/latest"
|
RELEASES_API = f"https://gitea.oxpoe.qzz.io/api/v1/repos/{REPO}/releases/latest"
|
||||||
UPDATE_ASSET = "GAMEMAX-LCD-x86_64.AppImage"
|
UPDATE_ASSET = "GAMEMAX-LCD-x86_64.AppImage"
|
||||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||||
sys.path.insert(0, HERE)
|
sys.path.insert(0, HERE)
|
||||||
import gamemax_report as gr # noqa: E402
|
import gamemax_report as gr # noqa: E402
|
||||||
|
|
||||||
DONATE_URL = "https://donasi.oxpoe.qzz.io/"
|
DONATE_URL = "https://donasi.oxpoe.qzz.io/"
|
||||||
GITHUB_URL = "https://github.com/oxpoe/Gamemax-linux-apps"
|
REPO_URL = "https://gitea.oxpoe.qzz.io/oxpoe/Gamemax-linux-apps"
|
||||||
|
|
||||||
SERVICE = "gamemax-report.service"
|
SERVICE = "gamemax-report.service"
|
||||||
CONFIG_PATH = gr.CONFIG_PATH
|
CONFIG_PATH = gr.CONFIG_PATH
|
||||||
INSTALL_DIR = os.path.expanduser("~/.local/share/gamemax-report")
|
INSTALL_DIR = os.path.expanduser("~/.local/share/gamemax-report")
|
||||||
UNIT_PATH = os.path.expanduser(f"~/.config/systemd/user/{SERVICE}")
|
UNIT_PATH = os.path.expanduser(f"~/.config/systemd/user/{SERVICE}")
|
||||||
RULE_PATH = "/etc/udev/rules.d/70-gamemax.rules"
|
RULE_PATH = "/etc/udev/rules.d/70-gamemax.rules"
|
||||||
|
AUTOSTART_DIR = os.path.expanduser("~/.config/autostart")
|
||||||
|
AUTOSTART_FILE = os.path.join(AUTOSTART_DIR, "iceburg-lcd.desktop")
|
||||||
|
|
||||||
UNIT_TEMPLATE = """[Unit]
|
UNIT_TEMPLATE = """[Unit]
|
||||||
Description=GAMEMAX HID sensor display bridge (PcInfoMonitorPro replacement)
|
Description=IceBurg LCD — HID sensor display bridge (Linux)
|
||||||
After=graphical-session.target
|
After=graphical-session.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
@@ -140,10 +144,10 @@ def verify_sha256(path, sha_url):
|
|||||||
|
|
||||||
|
|
||||||
def latest_release():
|
def latest_release():
|
||||||
"""(tag, url aset) dari rilis terbaru GitHub — dipanggil dari thread pekerja."""
|
"""(tag, url aset) dari rilis terbaru Gitea — dipanggil dari thread pekerja."""
|
||||||
ensure_ca_bundle()
|
ensure_ca_bundle()
|
||||||
req = urllib.request.Request(RELEASES_API, headers={
|
req = urllib.request.Request(RELEASES_API, headers={
|
||||||
"Accept": "application/vnd.github+json", "User-Agent": "gamemax-lcd"})
|
"Accept": "application/json", "User-Agent": "gamemax-lcd"})
|
||||||
with urllib.request.urlopen(req, timeout=10) as resp:
|
with urllib.request.urlopen(req, timeout=10) as resp:
|
||||||
data = json.load(resp)
|
data = json.load(resp)
|
||||||
asset = next((a for a in data.get("assets", []) if a["name"] == UPDATE_ASSET), None)
|
asset = next((a for a in data.get("assets", []) if a["name"] == UPDATE_ASSET), None)
|
||||||
@@ -162,6 +166,63 @@ def open_link(url, parent=None):
|
|||||||
parent.log(f"tidak bisa membuka tautan: {url}")
|
parent.log(f"tidak bisa membuka tautan: {url}")
|
||||||
|
|
||||||
|
|
||||||
|
def other_autostart_entries(appimage):
|
||||||
|
"""Entri autostart lain yang menjalankan AppImage yang sama (mis. buatan tool integrasi)."""
|
||||||
|
found = []
|
||||||
|
for path in glob.glob(os.path.join(AUTOSTART_DIR, "*.desktop")):
|
||||||
|
if path == AUTOSTART_FILE:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
text = open(path).read()
|
||||||
|
except OSError:
|
||||||
|
continue
|
||||||
|
if appimage and appimage in text:
|
||||||
|
found.append(path)
|
||||||
|
return found
|
||||||
|
|
||||||
|
|
||||||
|
def set_tray_autostart(enable, appimage):
|
||||||
|
"""Autostart ikon tray saat login, tersembunyi (tanpa jendela)."""
|
||||||
|
if not appimage:
|
||||||
|
return "tidak berjalan dari AppImage — autostart tray dilewati"
|
||||||
|
os.makedirs(AUTOSTART_DIR, exist_ok=True)
|
||||||
|
notes = []
|
||||||
|
if enable:
|
||||||
|
with open(AUTOSTART_FILE, "w") as fh:
|
||||||
|
fh.write(f"""[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name={APP_NAME} (tray)
|
||||||
|
Comment=Layar LCD AIO — berjalan di tray saat login (tanpa jendela)
|
||||||
|
Exec="{appimage}" --tray-only
|
||||||
|
Icon=iceburg-lcd
|
||||||
|
Terminal=false
|
||||||
|
X-GNOME-Autostart-enabled=true
|
||||||
|
""")
|
||||||
|
notes.append("autostart tray dibuat (--tray-only, tanpa jendela)")
|
||||||
|
for path in other_autostart_entries(appimage):
|
||||||
|
try:
|
||||||
|
text = open(path).read()
|
||||||
|
if "Hidden=true" not in text:
|
||||||
|
with open(path, "a") as fh:
|
||||||
|
fh.write("\nHidden=true\n")
|
||||||
|
notes.append(f"entri autostart lain dinonaktifkan: {os.path.basename(path)}")
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if os.path.exists(AUTOSTART_FILE):
|
||||||
|
os.unlink(AUTOSTART_FILE)
|
||||||
|
notes.append("autostart tray dihapus")
|
||||||
|
for path in other_autostart_entries(appimage):
|
||||||
|
try:
|
||||||
|
lines = [l for l in open(path).read().splitlines() if l.strip() != "Hidden=true"]
|
||||||
|
with open(path, "w") as fh:
|
||||||
|
fh.write("\n".join(lines) + "\n")
|
||||||
|
notes.append(f"entri autostart lain diaktifkan kembali: {os.path.basename(path)}")
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
return "; ".join(notes) or "tidak ada perubahan autostart tray"
|
||||||
|
|
||||||
|
|
||||||
def systemctl(*args):
|
def systemctl(*args):
|
||||||
return subprocess.run(["systemctl", "--user", *args], capture_output=True, text=True)
|
return subprocess.run(["systemctl", "--user", *args], capture_output=True, text=True)
|
||||||
|
|
||||||
@@ -331,7 +392,7 @@ class Window(QWidget):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
self.tray = tray
|
self.tray = tray
|
||||||
self.prev_stat = gr.stat_snapshot()
|
self.prev_stat = gr.stat_snapshot()
|
||||||
self.setWindowTitle(f"GAMEMAX IceBurg LCD v{APP_VERSION}")
|
self.setWindowTitle(f"{APP_NAME} v{APP_VERSION}")
|
||||||
self.setWindowIcon(QIcon(icon_path()))
|
self.setWindowIcon(QIcon(icon_path()))
|
||||||
self.setMinimumWidth(640)
|
self.setMinimumWidth(640)
|
||||||
root = QVBoxLayout(self)
|
root = QVBoxLayout(self)
|
||||||
@@ -341,7 +402,7 @@ class Window(QWidget):
|
|||||||
if isinstance(geom, list) and len(geom) == 4:
|
if isinstance(geom, list) and len(geom) == 4:
|
||||||
self.setGeometry(*[int(g) for g in geom])
|
self.setGeometry(*[int(g) for g in geom])
|
||||||
|
|
||||||
hint = QLabel("Kontrol layar LCD AIO GAMEMAX. Pilih slot kipas/sumber suhu di "
|
hint = QLabel("Kontrol layar LCD AIO IceBurg Digital. Pilih slot kipas/sumber suhu di "
|
||||||
"<b>Pengaturan</b> lalu klik <b>Simpan & terapkan</b>.")
|
"<b>Pengaturan</b> lalu klik <b>Simpan & terapkan</b>.")
|
||||||
hint.setObjectName("hint")
|
hint.setObjectName("hint")
|
||||||
hint.setWordWrap(True)
|
hint.setWordWrap(True)
|
||||||
@@ -441,18 +502,18 @@ class Window(QWidget):
|
|||||||
donate = QPushButton("❤ Donasi")
|
donate = QPushButton("❤ Donasi")
|
||||||
donate.setToolTip(DONATE_URL)
|
donate.setToolTip(DONATE_URL)
|
||||||
donate.clicked.connect(lambda: open_link(DONATE_URL, self))
|
donate.clicked.connect(lambda: open_link(DONATE_URL, self))
|
||||||
github = QPushButton("GitHub")
|
repo_btn = QPushButton("Gitea")
|
||||||
github.setToolTip(GITHUB_URL)
|
repo_btn.setToolTip(REPO_URL)
|
||||||
github.clicked.connect(lambda: open_link(GITHUB_URL, self))
|
repo_btn.clicked.connect(lambda: open_link(REPO_URL, self))
|
||||||
links.addWidget(donate)
|
links.addWidget(donate)
|
||||||
links.addWidget(github)
|
links.addWidget(repo_btn)
|
||||||
links.addStretch(1)
|
links.addStretch(1)
|
||||||
copy_button = QPushButton("Salin report")
|
copy_button = QPushButton("Salin report")
|
||||||
copy_button.setToolTip("Salin isi report 65 byte ke papan klip (untuk laporan bug)")
|
copy_button.setToolTip("Salin isi report 65 byte ke papan klip (untuk laporan bug)")
|
||||||
copy_button.clicked.connect(self.copy_report)
|
copy_button.clicked.connect(self.copy_report)
|
||||||
links.addWidget(copy_button)
|
links.addWidget(copy_button)
|
||||||
self.check_button = QPushButton("Periksa pembaruan")
|
self.check_button = QPushButton("Periksa pembaruan")
|
||||||
self.check_button.setToolTip("Bandingkan dengan rilis terbaru di GitHub")
|
self.check_button.setToolTip("Bandingkan dengan rilis terbaru di Gitea")
|
||||||
self.check_button.clicked.connect(lambda: self.start_task("memeriksa pembaruan", self.do_check_update))
|
self.check_button.clicked.connect(lambda: self.start_task("memeriksa pembaruan", self.do_check_update))
|
||||||
links.addWidget(self.check_button)
|
links.addWidget(self.check_button)
|
||||||
self.update_button = QPushButton("Perbarui")
|
self.update_button = QPushButton("Perbarui")
|
||||||
@@ -563,7 +624,7 @@ class Window(QWidget):
|
|||||||
return
|
return
|
||||||
|
|
||||||
box = QMessageBox(self)
|
box = QMessageBox(self)
|
||||||
box.setWindowTitle("Tutup GAMEMAX LCD")
|
box.setWindowTitle(f"Tutup {APP_NAME}")
|
||||||
box.setText("Sembunyikan ke tray atau keluar sepenuhnya?")
|
box.setText("Sembunyikan ke tray atau keluar sepenuhnya?")
|
||||||
box.setInformativeText("Selama tersembunyi di tray, data sensor tetap dikirim ke layar.")
|
box.setInformativeText("Selama tersembunyi di tray, data sensor tetap dikirim ke layar.")
|
||||||
remember = QCheckBox("Ingat pilihan ini")
|
remember = QCheckBox("Ingat pilihan ini")
|
||||||
@@ -598,7 +659,7 @@ class Window(QWidget):
|
|||||||
tag, url = latest_release()
|
tag, url = latest_release()
|
||||||
self._pending_update = (tag, url) if url and version_tuple(tag) > version_tuple(APP_VERSION) else None
|
self._pending_update = (tag, url) if url and version_tuple(tag) > version_tuple(APP_VERSION) else None
|
||||||
if not tag:
|
if not tag:
|
||||||
return "tidak bisa membaca daftar rilis GitHub"
|
return "tidak bisa membaca daftar rilis Gitea"
|
||||||
if self._pending_update:
|
if self._pending_update:
|
||||||
return f"versi baru tersedia: {tag} (terpasang v{APP_VERSION})"
|
return f"versi baru tersedia: {tag} (terpasang v{APP_VERSION})"
|
||||||
return f"sudah versi terbaru (v{APP_VERSION})"
|
return f"sudah versi terbaru (v{APP_VERSION})"
|
||||||
@@ -687,8 +748,10 @@ class Window(QWidget):
|
|||||||
systemctl("daemon-reload")
|
systemctl("daemon-reload")
|
||||||
res = systemctl("enable" if checked else "disable", SERVICE)
|
res = systemctl("enable" if checked else "disable", SERVICE)
|
||||||
state = service_enabled()
|
state = service_enabled()
|
||||||
|
note = set_tray_autostart(checked, installed_appimage())
|
||||||
return (f"mulai otomatis saat login: {'AKTIF' if state else 'nonaktif'}"
|
return (f"mulai otomatis saat login: {'AKTIF' if state else 'nonaktif'}"
|
||||||
+ ("" if res.returncode == 0 else f" ({res.stderr.strip()})"))
|
+ ("" if res.returncode == 0 else f" ({res.stderr.strip()})")
|
||||||
|
+ f" | {note}")
|
||||||
except Exception as exc: # noqa: BLE001
|
except Exception as exc: # noqa: BLE001
|
||||||
return f"galat autostart: {exc}"
|
return f"galat autostart: {exc}"
|
||||||
|
|
||||||
@@ -846,7 +909,7 @@ class Window(QWidget):
|
|||||||
"kosong": "Layar dikosongkan (nilai nol)",
|
"kosong": "Layar dikosongkan (nilai nol)",
|
||||||
"berhenti": "Pengiriman data dihentikan"}
|
"berhenti": "Pengiriman data dihentikan"}
|
||||||
if mode != "normal" or getattr(self, "_mode_seen", False):
|
if mode != "normal" or getattr(self, "_mode_seen", False):
|
||||||
subprocess.run(["notify-send", "-a", "GAMEMAX LCD", "Status layar",
|
subprocess.run(["notify-send", "-a", APP_NAME, "Status layar",
|
||||||
labels[mode]], capture_output=True)
|
labels[mode]], capture_output=True)
|
||||||
self._mode_seen = True
|
self._mode_seen = True
|
||||||
dot = "🟢" if active else "⚪"
|
dot = "🟢" if active else "⚪"
|
||||||
@@ -915,8 +978,8 @@ class Tray:
|
|||||||
"memeriksa pembaruan", self.window.do_check_update))
|
"memeriksa pembaruan", self.window.do_check_update))
|
||||||
donate_action = QAction("❤ Donasi", menu)
|
donate_action = QAction("❤ Donasi", menu)
|
||||||
donate_action.triggered.connect(lambda: open_link(DONATE_URL, self.window))
|
donate_action.triggered.connect(lambda: open_link(DONATE_URL, self.window))
|
||||||
github_action = QAction("GitHub", menu)
|
repo_action = QAction("Gitea", menu)
|
||||||
github_action.triggered.connect(lambda: open_link(GITHUB_URL, self.window))
|
repo_action.triggered.connect(lambda: open_link(REPO_URL, self.window))
|
||||||
quit_action = QAction("Keluar", menu)
|
quit_action = QAction("Keluar", menu)
|
||||||
quit_action.triggered.connect(self.quit_app)
|
quit_action.triggered.connect(self.quit_app)
|
||||||
menu.addAction(show)
|
menu.addAction(show)
|
||||||
@@ -925,7 +988,7 @@ class Tray:
|
|||||||
menu.addSeparator()
|
menu.addSeparator()
|
||||||
menu.addAction(check_action)
|
menu.addAction(check_action)
|
||||||
menu.addAction(donate_action)
|
menu.addAction(donate_action)
|
||||||
menu.addAction(github_action)
|
menu.addAction(repo_action)
|
||||||
menu.addSeparator()
|
menu.addSeparator()
|
||||||
menu.addAction(quit_action)
|
menu.addAction(quit_action)
|
||||||
self.icon.setContextMenu(menu)
|
self.icon.setContextMenu(menu)
|
||||||
@@ -945,7 +1008,7 @@ class Tray:
|
|||||||
blank = bool(gr.load_config(CONFIG_PATH).get("blank"))
|
blank = bool(gr.load_config(CONFIG_PATH).get("blank"))
|
||||||
state = ("layar kosong (nilai nol)" if blank and active
|
state = ("layar kosong (nilai nol)" if blank and active
|
||||||
else ("pengiriman dihentikan" if not active else "normal"))
|
else ("pengiriman dihentikan" if not active else "normal"))
|
||||||
self.icon.setToolTip(f"GAMEMAX LCD: {state}")
|
self.icon.setToolTip(f"{APP_NAME}: {state}")
|
||||||
base = icon_path()
|
base = icon_path()
|
||||||
self.icon.setIcon(dimmed_icon(base) if state != "normal" else QIcon(base))
|
self.icon.setIcon(dimmed_icon(base) if state != "normal" else QIcon(base))
|
||||||
window = getattr(self, "window", None)
|
window = getattr(self, "window", None)
|
||||||
@@ -959,7 +1022,7 @@ class Tray:
|
|||||||
self.window.raise_()
|
self.window.raise_()
|
||||||
self.window.activateWindow()
|
self.window.activateWindow()
|
||||||
if QSystemTrayIcon.isSystemTrayAvailable():
|
if QSystemTrayIcon.isSystemTrayAvailable():
|
||||||
self.icon.showMessage("GAMEMAX LCD", "Jendela dibuka dari permintaan kedua.",
|
self.icon.showMessage(APP_NAME, "Jendela dibuka dari permintaan kedua.",
|
||||||
QSystemTrayIcon.Information, 3000)
|
QSystemTrayIcon.Information, 3000)
|
||||||
|
|
||||||
|
|
||||||
@@ -976,7 +1039,7 @@ def main():
|
|||||||
|
|
||||||
def _main():
|
def _main():
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
app.setApplicationName("GAMEMAX LCD")
|
app.setApplicationName(APP_NAME)
|
||||||
app.setStyleSheet(APP_QSS)
|
app.setStyleSheet(APP_QSS)
|
||||||
app.setQuitOnLastWindowClosed(False)
|
app.setQuitOnLastWindowClosed(False)
|
||||||
|
|
||||||
@@ -986,10 +1049,10 @@ def _main():
|
|||||||
if probe.waitForConnected(400):
|
if probe.waitForConnected(400):
|
||||||
probe.write(b"raise")
|
probe.write(b"raise")
|
||||||
probe.waitForBytesWritten(400)
|
probe.waitForBytesWritten(400)
|
||||||
print("GAMEMAX LCD sudah berjalan — instance pertama diminta membuka jendelanya.")
|
print(f"{APP_NAME} sudah berjalan — instance pertama diminta membuka jendelanya.")
|
||||||
# Beri tahu lewat notifikasi desktop juga, karena keluarnya proses kedua bisa
|
# Beri tahu lewat notifikasi desktop juga, karena keluarnya proses kedua bisa
|
||||||
# terlihat seperti crash saat diluncurkan dari menu.
|
# terlihat seperti crash saat diluncurkan dari menu.
|
||||||
subprocess.run(["notify-send", "-a", "GAMEMAX LCD", "Sudah berjalan",
|
subprocess.run(["notify-send", "-a", APP_NAME, "Sudah berjalan",
|
||||||
"Aplikasi sudah aktif — jendelanya dibuka, cek taskbar/tray."],
|
"Aplikasi sudah aktif — jendelanya dibuka, cek taskbar/tray."],
|
||||||
capture_output=True)
|
capture_output=True)
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -423,9 +423,10 @@ def main():
|
|||||||
signal.signal(signal.SIGTERM, lambda *_: stop.set())
|
signal.signal(signal.SIGTERM, lambda *_: stop.set())
|
||||||
signal.signal(signal.SIGINT, lambda *_: stop.set())
|
signal.signal(signal.SIGINT, lambda *_: stop.set())
|
||||||
print(f"menunggu {VID:#06x}:{PID:#06x} (Ctrl-C atau SIGTERM untuk berhenti)", flush=True)
|
print(f"menunggu {VID:#06x}:{PID:#06x} (Ctrl-C atau SIGTERM untuk berhenti)", flush=True)
|
||||||
|
last_message = None
|
||||||
while not stop.is_set():
|
while not stop.is_set():
|
||||||
if not find_device():
|
if not find_device():
|
||||||
stop.wait(2)
|
stop.wait(1)
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
result = stream(a, overrides)
|
result = stream(a, overrides)
|
||||||
@@ -433,8 +434,11 @@ def main():
|
|||||||
sent, dt = result
|
sent, dt = result
|
||||||
print(f"perangkat terlepas setelah {sent} report ({sent / dt:.1f}/detik), menunggu lagi", flush=True)
|
print(f"perangkat terlepas setelah {sent} report ({sent / dt:.1f}/detik), menunggu lagi", flush=True)
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
print(f"galat perangkat ({exc}), menunggu lagi", flush=True)
|
message = f"galat perangkat ({exc}), menunggu lagi"
|
||||||
stop.wait(2)
|
if message != last_message: # ACL udev baru aktif setelah sesi login
|
||||||
|
print(message, flush=True)
|
||||||
|
last_message = message
|
||||||
|
stop.wait(1)
|
||||||
print("berhenti")
|
print("berhenti")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user