App v0.2.26 and gateway 0.1.20
Client: seek controls, Bazarr subtitle download and cast panel in the player; MDBList ratings strip; episode and schedule detail pages; series pace estimate; what's new panel; install-permission onboarding step; synced per-profile preferences; Emby outage banner. Gateway: rebuilt admin console (one fragment per page), preference history and restore, merged Continue Watching, Emby health probe, subtitle selection and Bazarr download, structured request logging with per-request identity, and embedded build version. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
2675e6d82b
commit
4a4df7a73c
+52
-9
@@ -13,6 +13,8 @@ The remote deployment:
|
||||
- installs .env from the local .env.example, overwriting the deployed
|
||||
copy, and keeps the old one alongside as .env.previous;
|
||||
- preserves the named database volume;
|
||||
- tells every signed-in television a deployment is starting, through the
|
||||
gateway that is still running, before the build begins;
|
||||
- pulls Redis and PostgreSQL, then builds the Memby server;
|
||||
- starts each service and waits for its health check;
|
||||
- restores the previous application files if activation fails.
|
||||
@@ -279,8 +281,17 @@ function New-DeploymentArchive {
|
||||
[string] $ReleaseDirectory
|
||||
)
|
||||
|
||||
# Everything under server/ is streamed over one SSH connection, so a build
|
||||
# artefact left in the tree is paid for on the wire. The exclusions mirror
|
||||
# server/.dockerignore: a GOCACHE pointed inside server/ (see the note there)
|
||||
# is gitignored and therefore silent, and turned a 1.2MB source tree into a
|
||||
# 774MB deployment. Both the directory entry and its contents are named
|
||||
# because bsdtar — which is what tar.exe is on Windows — matches --exclude
|
||||
# against each entry path rather than pruning the walk.
|
||||
$arguments = @(
|
||||
'-cf', $ArchivePath,
|
||||
'--exclude', 'server/.tmp-go-cache', '--exclude', 'server/.tmp-go-cache/*',
|
||||
'--exclude', 'server/bin', '--exclude', 'server/bin/*',
|
||||
'-C', $RepositoryDirectory,
|
||||
'server', 'docker-compose.yml', '.env.example'
|
||||
)
|
||||
@@ -622,7 +633,7 @@ wait_for_service() {
|
||||
trap rollback EXIT
|
||||
trap 'exit 130' INT TERM
|
||||
|
||||
step '[remote 1/9] Checking Docker'
|
||||
step '[remote 1/10] Checking Docker'
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
failure 'Docker is not installed on the NAS'
|
||||
exit 1
|
||||
@@ -642,7 +653,7 @@ fi
|
||||
success "$(docker --version)"
|
||||
success "$(docker compose version)"
|
||||
|
||||
step '[remote 2/9] Extracting the release'
|
||||
step '[remote 2/10] Extracting the release'
|
||||
# Checked before anything is created: the staging directory, the swap and the backup all
|
||||
# need write access to the parent, and "can't create directory" from BusyBox halfway
|
||||
# through a deployment is a poor way to learn the account cannot write there.
|
||||
@@ -670,13 +681,18 @@ if [ "$publish_release" -eq 1 ]; then
|
||||
fi
|
||||
success 'Release extracted'
|
||||
|
||||
step '[remote 3/9] Installing configuration from .env.example'
|
||||
step '[remote 3/10] Installing configuration from .env.example'
|
||||
# The local .env.example is the single source of truth for configuration and carries
|
||||
# real values rather than placeholders. Every deployment overwrites the deployed .env
|
||||
# with it, so neither a Git push nor an SSH edit is needed.
|
||||
previous_password=''
|
||||
previous_admin_token=''
|
||||
if [ -f "$destination/.env" ]; then
|
||||
previous_password=$(sed -n 's/^POSTGRES_PASSWORD=//p' "$destination/.env" | head -n 1 | tr -d '\r')
|
||||
# The token of the gateway that is still running, which is the one that can still
|
||||
# tell the televisions anything. It is usually the same as the incoming one, but
|
||||
# reading it from the release being replaced is what makes that not a requirement.
|
||||
previous_admin_token=$(sed -n 's/^MEMBY_ADMIN_TOKEN=//p' "$destination/.env" | head -n 1 | tr -d '\r')
|
||||
# Kept beside the new one purely so a bad edit is recoverable by hand.
|
||||
cp -- "$destination/.env" "$staging/.env.previous"
|
||||
detail 'Previous .env saved as .env.previous'
|
||||
@@ -724,21 +740,48 @@ fi
|
||||
)
|
||||
success 'Compose configuration is valid'
|
||||
|
||||
step '[remote 4/9] Pulling PostgreSQL and Redis'
|
||||
step '[remote 4/10] Telling the televisions'
|
||||
# Announced here rather than at the swap, and the position is the point of it: the
|
||||
# gateway being replaced is still answering, and the build below takes minutes, which is
|
||||
# the window in which every open television polls /v1/status and collects the notice.
|
||||
# Announcing at the swap would be too late twice over — nothing is left to publish with
|
||||
# once the stack is down, and Redis holds the alert list in memory with no volume, so the
|
||||
# swap discards anything published but not yet collected.
|
||||
#
|
||||
# Entirely best-effort: a deployment must never fail over a banner, and a first
|
||||
# deployment (or one onto a host with no curl) has nothing to announce with.
|
||||
if [ -z "$previous_admin_token" ]; then
|
||||
detail 'No previous release to announce from; skipping'
|
||||
elif ! command -v curl >/dev/null 2>&1; then
|
||||
detail 'curl is unavailable on the NAS; skipping the announcement'
|
||||
else
|
||||
announce_status=$(curl --silent --show-error --max-time 5 \
|
||||
--output /dev/null \
|
||||
--write-out '%{http_code}' \
|
||||
-X POST \
|
||||
-H "Authorization: Bearer $previous_admin_token" \
|
||||
http://127.0.0.1:32768/admin/api/deployment-alert 2>/dev/null || true)
|
||||
case "$announce_status" in
|
||||
2??) success 'Signed-in televisions have been told a deployment is starting' ;;
|
||||
*) detail "Could not announce the deployment (HTTP ${announce_status:-no response})" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
step '[remote 5/10] Pulling PostgreSQL and Redis'
|
||||
(
|
||||
cd "$staging"
|
||||
docker compose pull postgres redis
|
||||
)
|
||||
success 'Dependency images are ready'
|
||||
|
||||
step '[remote 5/9] Building memby-server'
|
||||
step '[remote 6/10] Building memby-server'
|
||||
(
|
||||
cd "$staging"
|
||||
docker compose build --pull server
|
||||
)
|
||||
success 'Server image built'
|
||||
|
||||
step '[remote 6/9] Activating the release'
|
||||
step '[remote 7/10] Activating the release'
|
||||
rm -rf -- "$backup"
|
||||
if [ -e "$destination" ] || [ -L "$destination" ]; then
|
||||
if [ -f "$destination/docker-compose.yml" ]; then
|
||||
@@ -760,12 +803,12 @@ mv -- "$staging" "$destination"
|
||||
activated=1
|
||||
success 'Release activated'
|
||||
|
||||
step '[remote 7/9] Starting the Compose stack'
|
||||
step '[remote 8/10] Starting the Compose stack'
|
||||
cd "$destination"
|
||||
docker compose up -d --remove-orphans
|
||||
success 'Compose start command completed'
|
||||
|
||||
step '[remote 8/9] Waiting for healthy services'
|
||||
step '[remote 9/10] Waiting for healthy services'
|
||||
wait_for_service postgres
|
||||
wait_for_service redis
|
||||
wait_for_service server
|
||||
@@ -785,7 +828,7 @@ if ! docker inspect --format '{{range .Config.Env}}{{println .}}{{end}}' "$serve
|
||||
fi
|
||||
success 'Runtime configuration includes the admin token'
|
||||
|
||||
step '[remote 9/9] Publishing the signed Android update'
|
||||
step '[remote 10/10] Publishing the signed Android update'
|
||||
if [ "$publish_release" -eq 1 ]; then
|
||||
release_version=$(tr -d '\r\n' < "$destination/release/version.txt")
|
||||
release_sha256=$(tr -d '\r\n' < "$destination/release/sha256.txt")
|
||||
|
||||
Reference in New Issue
Block a user