Files
ai-podcast/deploy_stats_cron.sh
T
lukeandClaude Opus 5 fe37c037d4 Fix NAS stats returning zeros instead of real download numbers
Two independent bugs, either of which made gather_castopod() report
total_downloads: 0 on a dev machine — indistinguishable from a podcast nobody
listens to.

- NAS_SSH hardcoded mmgnas-10g, which is only reachable when the 10G cable is
  physically connected. Now probed once per process with a 2s timeout and
  falls back to mmgnas; NAS_HOST overrides detection entirely. Same detection
  added to deploy_stats_cron.sh.
- _run_db_query treated any docker binary on PATH as "running on the NAS", so
  a machine with Docker Desktop queried its own daemon, found no castopod
  container, and never fell back to SSH. Only the QNAP container-station path
  counts now.

Real figures with both fixed: 3803 downloads, 750 unique listeners.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 17:05:10 -05:00

90 lines
3.1 KiB
Bash
Executable File

#!/bin/bash
# Deploy podcast_stats.py to NAS as a long-running Docker container that updates hourly.
#
# Usage: ./deploy_stats_cron.sh
set -e
NAS_USER="luke"
NAS_PORT="8001"
# mmgnas-10g is only up when the 10G cable is physically connected. Prefer it
# when reachable (faster transfers), otherwise fall back to the wireless/1G
# host. Override with NAS_HOST=... to skip detection.
if [ -z "$NAS_HOST" ]; then
if ssh -p "$NAS_PORT" -o ConnectTimeout=2 -o BatchMode=yes \
"$NAS_USER@mmgnas-10g" true 2>/dev/null; then
NAS_HOST="mmgnas-10g"
else
NAS_HOST="mmgnas"
fi
echo "NAS host: $NAS_HOST"
fi
DOCKER_BIN="/share/CACHEDEV1_DATA/.qpkg/container-station/bin/docker"
DEPLOY_DIR="/share/CACHEDEV1_DATA/podcast-stats"
CONTAINER_NAME="podcast-stats"
echo "Deploying podcast stats to NAS..."
# Create deploy dir and copy files
ssh -p "$NAS_PORT" "$NAS_USER@$NAS_HOST" "mkdir -p $DEPLOY_DIR"
scp -P "$NAS_PORT" podcast_stats.py "$NAS_USER@$NAS_HOST:$DEPLOY_DIR/podcast_stats.py"
# Create Dockerfile locally, then copy it over (NAS /tmp is tiny)
TMPFILE=$(mktemp)
cat > "$TMPFILE" << 'DOCKERFILE'
FROM python:3.11-slim
RUN apt-get update && apt-get install -y --no-install-recommends curl && rm -rf /var/lib/apt/lists/* \
&& curl -fsSL https://download.docker.com/linux/static/stable/x86_64/docker-27.5.1.tgz | tar xz --strip-components=1 -C /usr/local/bin docker/docker
RUN pip install --no-cache-dir requests yt-dlp
COPY podcast_stats.py /app/podcast_stats.py
COPY run_loop.sh /app/run_loop.sh
RUN chmod +x /app/run_loop.sh
WORKDIR /app
CMD ["/app/run_loop.sh"]
DOCKERFILE
scp -P "$NAS_PORT" "$TMPFILE" "$NAS_USER@$NAS_HOST:$DEPLOY_DIR/Dockerfile"
rm "$TMPFILE"
# Create the loop script
TMPFILE=$(mktemp)
cat > "$TMPFILE" << 'LOOPSCRIPT'
#!/bin/sh
echo "podcast-stats: starting hourly loop"
while true; do
echo "$(date -u '+%Y-%m-%dT%H:%M:%SZ') Running stats update..."
if python podcast_stats.py --json --upload 2>&1; then
[ -n "$HEARTBEAT_URL" ] && curl -s "${HEARTBEAT_URL}?status=up&msg=OK" > /dev/null
echo " ...done, heartbeat sent"
else
echo " ...failed, will retry next hour"
fi
echo "Sleeping 1 hour..."
sleep 3600
done
LOOPSCRIPT
scp -P "$NAS_PORT" "$TMPFILE" "$NAS_USER@$NAS_HOST:$DEPLOY_DIR/run_loop.sh"
rm "$TMPFILE"
echo "Building Docker image on NAS..."
ssh -p "$NAS_PORT" "$NAS_USER@$NAS_HOST" \
"TMPDIR=$DEPLOY_DIR $DOCKER_BIN build -t $CONTAINER_NAME $DEPLOY_DIR"
# Stop old container if running
ssh -p "$NAS_PORT" "$NAS_USER@$NAS_HOST" \
"$DOCKER_BIN rm -f $CONTAINER_NAME 2>/dev/null || true"
# Run as a daemon with auto-restart (survives reboots)
echo "Starting container..."
ssh -p "$NAS_PORT" "$NAS_USER@$NAS_HOST" \
"$DOCKER_BIN run -d --name $CONTAINER_NAME --restart unless-stopped --network host -v /var/run/docker.sock:/var/run/docker.sock $CONTAINER_NAME"
echo "Verifying..."
sleep 3
ssh -p "$NAS_PORT" "$NAS_USER@$NAS_HOST" \
"$DOCKER_BIN logs $CONTAINER_NAME 2>&1 | tail -5"
echo ""
echo "Done! Container runs hourly in a loop with --restart unless-stopped."
echo " Logs: ssh -p $NAS_PORT $NAS_USER@$NAS_HOST '$DOCKER_BIN logs -f $CONTAINER_NAME'"