feat(hobbs-organizer): Shield photo app (com.dayline.photos) + monitoring, links, .100 boot fix
- shield/photos-source: launcher tile + DreamService screensaver showing /photo (locked-down WebView, default URL baked in, files/base_url override) - build-photos-apk.sh: containerized build on hf-pdocker-02 (JDK17, SDK 35); signing key kept off-repo on .100 + NAS - Hobbs-Family-Photos-1.0.apk installed on .186 (canary) and set as its screensaver - Prometheus probes for /api/health and /api/health/photos; Farm Manager links + group - CLAUDE.md: .100 left the stale Swarm and its NFS mount waits for network (11-03 outage) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E9NnVEico3WvFxLyjy1iW3
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
# Hobbs Family Organizer (Shield TV dashboard) — hf-pdocker-02
|
||||
|
||||
**Shield photo app (2026-11-04): `com.dayline.photos` v1.0.** A launcher tile plus a screensaver, both showing `/photo`.
|
||||
- Build: `sudo ./build-photos-apk.sh`. It writes `~/hobbs-shield/Hobbs-Family-Photos-<ver>.apk` on .100.
|
||||
- Install: `adb install -r <apk>`.
|
||||
- Set the screensaver: `adb shell settings put secure screensaver_components com.dayline.photos/.PhotoDreamService`.
|
||||
- Signing key: `/var/lib/hobbs-organizer/apk-signing/` plus a NAS copy. Keep it; every update must use it.
|
||||
|
||||
**v1.2.0 (2026-11-04): photo frame at http://192.168.86.100:8340/photo** — Google Photos shared albums
|
||||
(admin → Photos tab: add share link, Check, Sync now; display interval/fit/shuffle/date) + uploads (resized in the browser).
|
||||
Cache: `/var/lib/hobbs-organizer/data/photos/<album-id>/` (+ `uploads/`), re-synced every 6h. Stale check: `/api/health/photos` (503 after 48h).
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env bash
|
||||
# Builds the Hobbs Family Photos Shield APK (com.dayline.photos) on hf-pdocker-02.
|
||||
# Usage: sudo ./build-photos-apk.sh -> ~/hobbs-shield/Hobbs-Family-Photos-<ver>.apk
|
||||
# The signing key is created on first run in /var/lib/hobbs-organizer/apk-signing (root 600)
|
||||
# and copied to the NAS. NEVER delete it: updates must be signed with the same key.
|
||||
set -euo pipefail
|
||||
DEPLOY=/mnt/docker-data/compose/hf-pdocker-02/hobbs-organizer
|
||||
SRC="$DEPLOY/shield/photos-source"
|
||||
SIGN=/var/lib/hobbs-organizer/apk-signing
|
||||
NAS_SIGN=/mnt/docker-data/configs/hobbs-organizer/apk-signing
|
||||
WORK=/var/tmp/hfo-photos-build
|
||||
OUT=/home/glyptic/hobbs-shield
|
||||
IMAGE=eclipse-temurin:17-jdk-jammy
|
||||
|
||||
[ "$(id -u)" = 0 ] || { echo "run with sudo"; exit 1; }
|
||||
install -d -m 700 "$SIGN"
|
||||
|
||||
if [ ! -f "$SIGN/hobbs-photos.jks" ]; then
|
||||
echo "== creating signing key"
|
||||
PASS=$(openssl rand -base64 32 | tr -d '/+=' | cut -c1-32)
|
||||
docker run --rm -v "$SIGN:/signing" "$IMAGE" keytool -genkeypair -keystore /signing/hobbs-photos.jks \
|
||||
-storetype PKCS12 -alias hobbs-photos -keyalg RSA -keysize 4096 -validity 20000 \
|
||||
-dname "CN=Hobbs Family Photos, O=Hobbs Farm" -storepass "$PASS" -keypass "$PASS" >/dev/null
|
||||
printf 'storeFile=/signing/hobbs-photos.jks\nstorePassword=%s\nkeyAlias=hobbs-photos\nkeyPassword=%s\n' "$PASS" "$PASS" > "$SIGN/keystore.properties"
|
||||
chmod 600 "$SIGN"/*
|
||||
fi
|
||||
# Off-box copy (NAS root_squash: write as glyptic, keep it private).
|
||||
sudo -u glyptic install -d -m 700 "$NAS_SIGN"
|
||||
for f in hobbs-photos.jks keystore.properties; do
|
||||
cat "$SIGN/$f" | sudo -u glyptic sh -c "umask 077; cat > '$NAS_SIGN/$f'"
|
||||
done
|
||||
|
||||
rm -rf "$WORK"; mkdir -p "$WORK"; cp -a "$SRC/." "$WORK/"
|
||||
cp "$SIGN/keystore.properties" "$WORK/keystore.properties"
|
||||
|
||||
docker volume create hobbs-android-sdk >/dev/null
|
||||
docker run --rm -v "$WORK:/src" -v hobbs-android-sdk:/opt/cache -v "$SIGN:/signing:ro" -w /src "$IMAGE" bash -euo pipefail -c '
|
||||
export ANDROID_HOME=/opt/cache/sdk GRADLE_USER_HOME=/opt/cache/gradle-home
|
||||
command -v unzip >/dev/null || { apt-get update -qq && apt-get install -y -qq unzip curl >/dev/null; }
|
||||
if [ ! -x $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager ]; then
|
||||
echo "== downloading Android command-line tools"
|
||||
curl -fsSL -o /tmp/clt.zip https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip
|
||||
mkdir -p $ANDROID_HOME/cmdline-tools && unzip -q /tmp/clt.zip -d /tmp/clt && mv /tmp/clt/cmdline-tools $ANDROID_HOME/cmdline-tools/latest
|
||||
fi
|
||||
if [ ! -d $ANDROID_HOME/platforms/android-35 ] || [ ! -d $ANDROID_HOME/build-tools/35.0.0 ]; then
|
||||
echo "== installing SDK platform 35 + build-tools 35.0.0"
|
||||
(yes 2>/dev/null || true) | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses >/dev/null || true
|
||||
$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "platforms;android-35" "build-tools;35.0.0" >/dev/null
|
||||
fi
|
||||
if [ ! -x /opt/cache/gradle-8.9/bin/gradle ]; then
|
||||
echo "== downloading Gradle 8.9"
|
||||
curl -fsSL -o /tmp/gradle.zip https://services.gradle.org/distributions/gradle-8.9-bin.zip
|
||||
unzip -q /tmp/gradle.zip -d /opt/cache
|
||||
fi
|
||||
echo "sdk.dir=$ANDROID_HOME" > local.properties
|
||||
/opt/cache/gradle-8.9/bin/gradle --no-daemon -q assembleRelease
|
||||
$ANDROID_HOME/build-tools/35.0.0/apksigner verify --print-certs app/build/outputs/apk/release/app-release.apk | grep -E "Signer #1 certificate (DN|SHA-256)"
|
||||
$ANDROID_HOME/build-tools/35.0.0/aapt2 dump badging app/build/outputs/apk/release/app-release.apk | grep -E "^package:|application-debuggable|leanback"
|
||||
'
|
||||
VER=$(grep -oP 'versionName "\K[^"]+' "$SRC/app/build.gradle")
|
||||
install -d -o glyptic -g glyptic "$OUT"
|
||||
install -o glyptic -g glyptic -m 644 "$WORK/app/build/outputs/apk/release/app-release.apk" "$OUT/Hobbs-Family-Photos-$VER.apk"
|
||||
sha256sum "$OUT/Hobbs-Family-Photos-$VER.apk"
|
||||
rm -rf "$WORK"
|
||||
Reference in New Issue
Block a user