feat: add an unattended wrapper, and document running this without an agent
gdl-sync.py always needed a fistful of paths on the command line, and the 2026-08-20 run published to a local directory and then rsynced to the NAS by hand -- fine interactively, impossible from cron. gdl-cron.sh takes one argument (stories|full|sweep) and does the whole thing. Staging is wiped every run deliberately: what we already hold is decided by the skip-archive, never by what happens to be sitting in staging, so starting empty is correct and keeps the publish to just the new files. Documents the three cadences and what each is for -- notably that only `sweep` notices carousels edited after we archived them, and that only `stories` loses content if it is skipped, since stories cannot be backfilled. Cron notes the two things that would silently break it: cron runs /bin/sh so $RANDOM does not exist (use shuf), and `%` in a crontab line means newline. systemd is offered as the better option because RandomizedDelaySec and Persistent=true are built in -- a host asleep at 09:00 silently skips a cron job, and a skipped stories run is content gone for good. The publish step is still blocked on mattellite having no key on the NAS; that is recorded under Outstanding as the one thing between this and unattended. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UXfdJu7QhSJLr47K7koTDF
This commit is contained in:
Executable
+55
@@ -0,0 +1,55 @@
|
||||
#!/bin/sh
|
||||
# Unattended wrapper around gdl-sync.py. One argument: the run mode.
|
||||
#
|
||||
# stories daily ~6 requests; the only surface that cannot be backfilled
|
||||
# full monthly every surface, --abort 50 (stops at already-held content)
|
||||
# sweep quarterly every surface, no abort -- the only run that notices
|
||||
# carousels edited after we archived them
|
||||
#
|
||||
# Exits non-zero if the sync does, so cron mails you. Everything is logged.
|
||||
set -eu
|
||||
|
||||
MODE="${1:?usage: gdl-cron.sh stories|full|sweep}"
|
||||
|
||||
GDL_HOME="${GDL_HOME:-$HOME/gdl}"
|
||||
INDEX="${GDL_INDEX:-https://instaarchive.ergosteur.com}"
|
||||
PUBLISH="${GDL_PUBLISH:-agentapi@10.20.28.200:/volume1/rslsync/sync/Instagram-archive/archives/}"
|
||||
STAGING="$GDL_HOME/staging-$MODE"
|
||||
LOG="$GDL_HOME/logs/$MODE-$(date +%Y%m%d-%H%M%S).log"
|
||||
|
||||
PATH="$HOME/.local/bin:$PATH"; export PATH
|
||||
|
||||
case "$MODE" in
|
||||
stories) ARGS="--only stories" ;;
|
||||
full) ARGS="--only posts,reels,stories,highlights --abort 50" ;;
|
||||
sweep) ARGS="--only posts,reels,stories,highlights" ;;
|
||||
*) echo "unknown mode: $MODE" >&2; exit 2 ;;
|
||||
esac
|
||||
|
||||
mkdir -p "$GDL_HOME/logs"
|
||||
|
||||
# Staging is wiped every run ON PURPOSE. What we already hold is decided by the
|
||||
# skip-archive (--download-archive), never by which files happen to be sitting
|
||||
# in staging, so starting empty is correct -- and it keeps the publish rsync
|
||||
# to just the new files instead of re-walking gigabytes each time.
|
||||
rm -rf "$STAGING"
|
||||
|
||||
{
|
||||
echo "=== $MODE run $(date -Is) ==="
|
||||
# shellcheck disable=SC2086
|
||||
"$GDL_HOME/gdl-sync.py" \
|
||||
--index "$INDEX" \
|
||||
--staging "$STAGING" \
|
||||
--publish "$PUBLISH" \
|
||||
--archive-db "$GDL_HOME/artms.db" \
|
||||
--urls-file "$GDL_HOME/artms_account_links.txt" \
|
||||
$ARGS --execute
|
||||
status=$?
|
||||
echo "=== exit $status at $(date -Is) ==="
|
||||
exit $status
|
||||
} 2>&1 | tee -a "$LOG"
|
||||
|
||||
# Keep the log directory from growing without bound.
|
||||
ls -1t "$GDL_HOME/logs" | tail -n +30 | while read -r old; do
|
||||
rm -f "$GDL_HOME/logs/$old"
|
||||
done
|
||||
Reference in New Issue
Block a user