#!/usr/bin/env bash set -Eeuo pipefail PROFILE="/joplin-profile" CONFIG="/app/config.yaml" RESULT_JSON="/app/data/last_result.json" log() { printf '%s %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"; } fail() { log "ERROR: $*"; exit 1; } joplin_sync() { local tmp local status tmp="$(mktemp)" set +e joplin --profile "$PROFILE" sync 2>&1 | tee "$tmp" status=${PIPESTATUS[0]} set -e if [[ "$status" -ne 0 ]]; then rm -f "$tmp" fail "Joplin sync failed with exit code $status" fi if grep -Eqi 'Last error:|(^|[[:space:]])Error:' "$tmp"; then log "ERROR: Joplin reported a sync error:" grep -Ei 'Last error:|(^|[[:space:]])Error:' "$tmp" || true rm -f "$tmp" exit 1 fi rm -f "$tmp" } : "${JOPLIN_WEBDAV_URL:?JOPLIN_WEBDAV_URL is required}" : "${JOPLIN_WEBDAV_USERNAME:?JOPLIN_WEBDAV_USERNAME is required}" : "${JOPLIN_WEBDAV_PASSWORD:?JOPLIN_WEBDAV_PASSWORD is required}" JOPLIN_NOTEBOOK="${JOPLIN_NOTEBOOK:-Radar Papers}" JOPLIN_WRITE_ENABLED="${JOPLIN_WRITE_ENABLED:-false}" JOPLIN_IGNORE_TLS_ERRORS="${JOPLIN_IGNORE_TLS_ERRORS:-false}" mkdir -p "$PROFILE" /app/data/outbox log "Configuring Joplin CLI WebDAV profile..." joplin --profile "$PROFILE" config sync.target 6 >/dev/null joplin --profile "$PROFILE" config sync.6.path "$JOPLIN_WEBDAV_URL" >/dev/null joplin --profile "$PROFILE" config sync.6.username "$JOPLIN_WEBDAV_USERNAME" >/dev/null joplin --profile "$PROFILE" config sync.6.password "$JOPLIN_WEBDAV_PASSWORD" >/dev/null joplin --profile "$PROFILE" config sync.wipeOutFailSafe true >/dev/null if [[ "${JOPLIN_IGNORE_TLS_ERRORS,,}" == "true" ]]; then joplin --profile "$PROFILE" config net.ignoreTlsErrors true >/dev/null else joplin --profile "$PROFILE" config net.ignoreTlsErrors false >/dev/null fi # Pull the current remote state first. This is important when PC/mobile also use the same WebDAV target. log "Synchronising Joplin from WebDAV before writing..." joplin_sync if [[ "${JOPLIN_WRITE_ENABLED,,}" != "true" ]]; then log "JOPLIN_WRITE_ENABLED=false: sync-only safety mode. No paper note will be written." log "If this first sync succeeded, set JOPLIN_WRITE_ENABLED=true and run again." exit 0 fi log "Running paper monitor..." python -m paper_monitor --config "$CONFIG" --dry-run [[ -f "$RESULT_JSON" ]] || fail "Result JSON not produced: $RESULT_JSON" readarray -t META < <(python - "$RESULT_JSON" <<'PY' import json, sys p=sys.argv[1] d=json.load(open(p,encoding='utf-8')) print(d.get('report_count',0)) print(d.get('report_title','')) print(d.get('markdown','')) PY ) REPORT_COUNT="${META[0]:-0}" REPORT_TITLE="${META[1]:-}" MARKDOWN="${META[2]:-}" if [[ "$REPORT_COUNT" == "0" ]]; then log "No papers in today's report. Nothing to write to Joplin." exit 0 fi [[ -n "$REPORT_TITLE" ]] || fail "Empty report title" [[ -f "$MARKDOWN" ]] || fail "Markdown report not found: $MARKDOWN" log "Ensuring notebook exists: $JOPLIN_NOTEBOOK" if ! joplin --profile "$PROFILE" use "$JOPLIN_NOTEBOOK" >/dev/null 2>&1; then joplin --profile "$PROFILE" mkbook "$JOPLIN_NOTEBOOK" fi # Replace only the daily report with the exact same title. Since the report is cumulative # for the local day, rerunning is idempotent and will not lose earlier papers from the same day. log "Replacing existing daily note if present: $REPORT_TITLE" joplin --profile "$PROFILE" rmnote "$REPORT_TITLE" -f >/dev/null 2>&1 || true TMP_DIR="$(mktemp -d)" trap 'rm -rf "$TMP_DIR"' EXIT TMP_MD="$TMP_DIR/$REPORT_TITLE.md" cp "$MARKDOWN" "$TMP_MD" log "Importing report into Joplin notebook: $JOPLIN_NOTEBOOK" joplin --profile "$PROFILE" import "$TMP_MD" "$JOPLIN_NOTEBOOK" --format md -f log "Synchronising Joplin changes to WebDAV..." joplin_sync log "Completed: $REPORT_TITLE ($REPORT_COUNT papers)"