#!/usr/bin/env bash
# 🤖 Hermes Cron Master — 紧凑版报告
set -o pipefail
# ── 路径推导 ──
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
TASKS_DIR="${SCRIPT_DIR}/cron-tasks"
REPORT_DIR="${HOME}/.cron-reports"
REPORT_DATE=$(date +%Y-%m-%d)
REPORT_FILE="${REPORT_DIR}/cron-${REPORT_DATE}.md"
# Fix HOME for cron context
export HOME="/opt/data/home"
export PATH="/opt/data/home/bin:${HOME}/bin:/usr/local/bin:/usr/bin:/bin"
export GBRAIN_EMBEDDING_MODEL="v100:embed"
export GBRAIN_EMBEDDING_DIMENSIONS="1024"
mkdir -p "${TASKS_DIR}" "${REPORT_DIR}"
# ── 任务定义 ──
TASK_ORDER=(sitemap)
declare -A TASK_TIMEOUT
TASK_TIMEOUT[sitemap]=110
declare -A TASK_LABEL
TASK_LABEL[sitemap]="🌐 Trilium Sitemap 更新"
# ── 单任务模式 ──
RUN_SINGLE=""
for arg in "$@"; do
case "$arg" in
--task=*) RUN_SINGLE="${arg#*=}" ;;
--test) RUN_SINGLE="sitemap" ;;
esac
done
# ── 指标提取函数 ──
extract_sitemap_compact() {
local err="$1"
local count size http removed metrics
count=$(echo "$err" | grep -oP '提取到\s+\K\d+' || echo "?")
removed=$(echo "$err" | grep -oP '已移除\s+\K\d+' || echo "0")
size=$(echo "$err" | grep -oP 'sitemap\.xml:\s+\K[\d,]+(?=\s+bytes)' || echo "")
http=$(echo "$err" | grep -oP 'HTTP\s+\K\d+' || echo "")
metrics="🔗 ${count} 链接"
[ "$removed" != "0" ] && metrics+=" (🔒已移除 ${removed})"
[ -n "$size" ] && metrics+=" | 📦 ${size}B"
[ -n "$http" ] && metrics+=" | 📡 ${http}"
echo "$metrics"
}
# ── 运行单个任务 ──
run_task() {
local name="$1"
local task_script="${TASKS_DIR}/${name}.sh"
if [ ! -f "$task_script" ]; then
task_script="${TASKS_DIR}/${name}.py"
fi
if [ ! -f "$task_script" ]; then
LAST_EXIT_CODE=1; LAST_DURATION=0; LAST_STDOUT=""; LAST_STDERR="脚本不存在"
return 1
fi
local start_ts=$(date +%s)
local stdout_file=$(mktemp) stderr_file=$(mktemp)
case "$task_script" in
*.py) interpreter="python3" ;;
*) interpreter="bash" ;;
esac
timeout "${TASK_TIMEOUT[$name]:-120}" "$interpreter" "$task_script" > "$stdout_file" 2> "$stderr_file"
LAST_EXIT_CODE=$?
LAST_DURATION=$(( $(date +%s) - start_ts ))
LAST_STDOUT=$(cat "$stdout_file")
LAST_STDERR=$(cat "$stderr_file")
rm -f "$stdout_file" "$stderr_file"
return $LAST_EXIT_CODE
}
# ── 主循环 ──
TASK_RESULTS=(); TASK_NAMES=(); TASK_EXIT_CODES=(); TASK_DURATIONS=()
TASK_STDOUTS=(); TASK_STDERRS=()
START_TS=$(date +%s)
if [ -n "$RUN_SINGLE" ]; then
echo "🔧 单任务模式: ${RUN_SINGLE}"
echo ""
run_task "$RUN_SINGLE"
echo "exit=${LAST_EXIT_CODE}, duration=${LAST_DURATION}s"
exit $LAST_EXIT_CODE
fi
OVERALL_SUCCESS=0; OVERALL_FAIL=0; OVERALL_SKIP=0; OVERALL_TIME=0
FAILED_TASKS=""
idx=0
for task_name in "${TASK_ORDER[@]}"; do
TASK_NAMES+=("$task_name")
run_task "$task_name"
TASK_EXIT_CODES+=($LAST_EXIT_CODE); TASK_DURATIONS+=($LAST_DURATION)
TASK_STDOUTS+=("$LAST_STDOUT"); TASK_STDERRS+=("$LAST_STDERR")
if [ $LAST_EXIT_CODE -eq 124 ]; then
TASK_RESULTS+=("time"); OVERALL_TIME=$((OVERALL_TIME+1))
FAILED_TASKS="$FAILED_TASKS $task_name"
elif [ $LAST_EXIT_CODE -ne 0 ]; then
TASK_RESULTS+=("fail"); OVERALL_FAIL=$((OVERALL_FAIL+1))
FAILED_TASKS="$FAILED_TASKS $task_name"
else
TASK_RESULTS+=("ok"); OVERALL_SUCCESS=$((OVERALL_SUCCESS+1))
fi
idx=$((idx+1))
done
TOTAL_DURATION=$(( $(date +%s) - START_TS ))
REPORT=""
report() { REPORT+="$1"$'\n'; }
SUMMARY="✅${OVERALL_SUCCESS}"
[ "$OVERALL_FAIL" -gt 0 ] && SUMMARY+=" ❌${OVERALL_FAIL}"
[ "$OVERALL_TIME" -gt 0 ] && SUMMARY+=" ⏰${OVERALL_TIME}"
[ "$OVERALL_SKIP" -gt 0 ] && SUMMARY+=" ⏭️${OVERALL_SKIP}"
report "🤖 HerMes Cron 日报 — ${REPORT_DATE} | ${SUMMARY} | ⏱️${TOTAL_DURATION}s"
for i in "${!TASK_ORDER[@]}"; do
name="${TASK_ORDER[$i]}"
result="${TASK_RESULTS[$i]}"
exit_code="${TASK_EXIT_CODES[$i]}"
duration="${TASK_DURATIONS[$i]}"
stdout="${TASK_STDOUTS[$i]}"
stderr="${TASK_STDERRS[$i]}"
case "$result" in
ok) emoji="✅" ;;
fail) emoji="❌" ;;
skip) emoji="⏭️" ;;
time) emoji="⏰" ;;
*) emoji="❓" ;;
esac
if [ "$result" = "ok" ]; then
metrics=""
case "$name" in
sitemap) metrics=$(extract_sitemap_compact "$stderr") ;;
esac
report "${emoji} ${TASK_LABEL[$name]} — ${metrics} (${duration}s)"
else
err=$(echo "$stderr" | head -3 | tr '\n' ' ' | sed 's/ */ /g' | cut -c1-80)
[ -z "$err" ] && err=$(echo "$stdout" | head -3 | tr '\n' ' ' | sed 's/ */ /g' | cut -c1-80)
report "${emoji} ${TASK_LABEL[$name]} — ${err} (${duration}s)"
fi
done
echo "$REPORT"
echo "$REPORT" > "$REPORT_FILE"