Files
kindle-calendar/snapshot.sh
2026-03-17 10:37:27 +08:00

368 lines
10 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env sh
set -eu
ROOT_DIR="$(CDPATH= cd -- "$(dirname "$0")" && pwd)"
THEMES_JSON="$ROOT_DIR/calendar/config/themes.json"
SYNC_SCRIPT="$ROOT_DIR/scripts/sync-layered-clock-to-kindle.sh"
CAPTURE_SCRIPT="$ROOT_DIR/scripts/capture-kindle-screen.sh"
HOST_TARGET="kindle"
THEME_ID=""
ORIENTATION=""
OUTPUT_DIR="$ROOT_DIR/tmp"
OUTPUT_BASENAME=""
OUTPUT_BASENAME_EXPLICIT=false
LIST_ONLY=false
DO_SYNC=true
DO_SWITCH=true
DO_CAPTURE=true
DO_DATE=false
SYNC_THEME_ID=""
SYNC_ORIENTATION=""
SELECTED_THEME_ID=""
SELECTED_ORIENTATIONS=""
RUN_TIMESTAMP="$(date '+%Y%m%d-%H%M%S')"
print_usage() {
cat <<'EOF'
用法:
sh snapshot.sh [选项]
默认流程:
1. 把本地最新主题包同步到 Kindle
2. 切换到指定主题和方向
3. 抓取当前 Kindle 实际屏幕到本地
选项:
-t, --theme <theme-id> 指定主题名;默认取 themes.json 的 defaultThemeId
-o, --orientation <value> 指定方向;省略时,指定主题会按全部支持方向处理
-k, --kindle <host> Kindle SSH 主机名,默认 kindle
-d, --output-dir <dir> 本地截图输出目录,默认 ./tmp
-b, --basename <name> 截图文件名前缀,默认 <theme>-<orientation>-<时间戳>
--sync-only 只同步,不切换,不抓图
--switch-only 只切换,不同步,不抓图
--capture-only 只抓图,不同步,不切换
--date 只获取当前 Kindle 系统日期时间
--no-sync 跳过同步
--no-switch 跳过切换
--no-capture 跳过抓图
--list 列出本地现有主题和可用方向
-h, --help 查看帮助
示例:
sh snapshot.sh --list
sh snapshot.sh -t simple
sh snapshot.sh -t simple -o portrait
sh snapshot.sh -t simple -o landscape -b simple-check
sh snapshot.sh --sync-only
sh snapshot.sh --sync-only -t simple
sh snapshot.sh --sync-only -t simple -o portrait
sh snapshot.sh --switch-only -t simple -o portrait
sh snapshot.sh --capture-only -b current-screen
sh snapshot.sh --date
EOF
}
list_themes() {
python3 - "$THEMES_JSON" <<'PY'
import json
import pathlib
import sys
path = pathlib.Path(sys.argv[1])
data = json.loads(path.read_text())
print(f"defaultThemeId: {data.get('defaultThemeId', 'unknown')}")
print(f"defaultOrientation: {data.get('defaultOrientation', 'unknown')}")
print("themes:")
for theme in data.get("themes", []):
orientations = ", ".join(theme.get("variants", {}).keys()) or "none"
print(f" - {theme['id']}: {orientations}")
PY
}
resolve_selection() {
python3 - "$THEMES_JSON" "$THEME_ID" "$ORIENTATION" <<'PY'
import json
import pathlib
import sys
path = pathlib.Path(sys.argv[1])
requested_theme = sys.argv[2]
requested_orientation = sys.argv[3]
data = json.loads(path.read_text())
themes = {theme["id"]: theme for theme in data.get("themes", [])}
theme_id = requested_theme or data.get("defaultThemeId", "")
if theme_id not in themes:
raise SystemExit(f"未知主题: {theme_id}")
theme = themes[theme_id]
orientations = list(theme.get("variants", {}).keys())
if not orientations:
raise SystemExit(f"主题 {theme_id} 没有任何方向配置")
print(f"THEME_ID={theme_id}")
if requested_theme and not requested_orientation:
print(f"ORIENTATIONS={' '.join(orientations)}")
else:
orientation = requested_orientation
if not orientation:
default_orientation = data.get("defaultOrientation", "")
orientation = default_orientation if default_orientation in orientations else orientations[0]
if orientation not in orientations:
raise SystemExit(
f"主题 {theme_id} 不支持方向 {orientation},可用方向: {', '.join(orientations)}"
)
print(f"ORIENTATIONS={orientation}")
PY
}
load_selection() {
resolved_output="$(resolve_selection)"
SELECTED_THEME_ID=""
SELECTED_ORIENTATIONS=""
while IFS='=' read -r key value; do
case "$key" in
THEME_ID)
SELECTED_THEME_ID=$value
;;
ORIENTATIONS)
SELECTED_ORIENTATIONS=$value
;;
esac
done <<EOF
$resolved_output
EOF
if [ -z "$SELECTED_THEME_ID" ] || [ -z "$SELECTED_ORIENTATIONS" ]; then
echo "无法解析主题和方向。" >&2
exit 1
fi
}
validate_sync_filter() {
if [ -z "$THEME_ID" ]; then
SYNC_THEME_ID=""
SYNC_ORIENTATION=""
return
fi
python3 - "$THEMES_JSON" "$THEME_ID" "$ORIENTATION" <<'PY'
import json
import pathlib
import sys
path = pathlib.Path(sys.argv[1])
requested_theme = sys.argv[2]
requested_orientation = sys.argv[3]
data = json.loads(path.read_text())
themes = {theme["id"]: theme for theme in data.get("themes", [])}
if requested_theme not in themes:
raise SystemExit(f"未知主题: {requested_theme}")
if requested_orientation:
orientations = list(themes[requested_theme].get("variants", {}).keys())
if requested_orientation not in orientations:
raise SystemExit(
f"主题 {requested_theme} 不支持方向 {requested_orientation},可用方向: {', '.join(orientations)}"
)
PY
SYNC_THEME_ID=$THEME_ID
SYNC_ORIENTATION=$ORIENTATION
}
log_step() {
printf '\n[%s] %s\n' "$1" "$2"
}
capture_basename_for_orientation() {
current_orientation=$1
if [ "$OUTPUT_BASENAME_EXPLICIT" = true ]; then
if [ "$DO_SWITCH" = true ] && [ "$SELECTED_ORIENTATIONS" != "$current_orientation" ]; then
printf '%s-%s\n' "$OUTPUT_BASENAME" "$current_orientation"
else
printf '%s\n' "$OUTPUT_BASENAME"
fi
return
fi
if [ "$DO_SWITCH" = true ]; then
printf '%s-%s-%s\n' "$SELECTED_THEME_ID" "$current_orientation" "$RUN_TIMESTAMP"
return
fi
printf 'current-screen-%s\n' "$RUN_TIMESTAMP"
}
while [ "$#" -gt 0 ]; do
case "$1" in
-t|--theme)
shift
THEME_ID=${1:?"missing theme id"}
;;
-o|--orientation)
shift
ORIENTATION=${1:?"missing orientation"}
;;
-k|--kindle)
shift
HOST_TARGET=${1:?"missing kindle host"}
;;
-d|--output-dir)
shift
OUTPUT_DIR=${1:?"missing output dir"}
;;
-b|--basename)
shift
OUTPUT_BASENAME=${1:?"missing basename"}
OUTPUT_BASENAME_EXPLICIT=true
;;
--sync-only)
DO_SYNC=true
DO_SWITCH=false
DO_CAPTURE=false
;;
--switch-only)
DO_SYNC=false
DO_SWITCH=true
DO_CAPTURE=false
;;
--capture-only)
DO_SYNC=false
DO_SWITCH=false
DO_CAPTURE=true
;;
--date)
DO_SYNC=false
DO_SWITCH=false
DO_CAPTURE=false
DO_DATE=true
;;
--no-sync)
DO_SYNC=false
;;
--no-switch)
DO_SWITCH=false
;;
--no-capture)
DO_CAPTURE=false
;;
--list)
LIST_ONLY=true
;;
-h|--help)
print_usage
exit 0
;;
*)
echo "未知参数: $1" >&2
echo >&2
print_usage >&2
exit 1
;;
esac
shift
done
if [ "$LIST_ONLY" = true ]; then
list_themes
exit 0
fi
if [ "$DO_SYNC" = false ] && [ "$DO_SWITCH" = false ] && [ "$DO_CAPTURE" = false ] && [ "$DO_DATE" = false ]; then
echo "没有可执行动作;请至少保留同步、切换、抓图、日期中的一个。" >&2
exit 1
fi
if [ "$DO_SYNC" = true ]; then
validate_sync_filter
fi
if [ "$DO_SWITCH" = true ]; then
load_selection
fi
step_total=0
[ "$DO_SYNC" = true ] && step_total=$((step_total + 1))
[ "$DO_DATE" = true ] && step_total=$((step_total + 1))
selection_count=1
if [ "$DO_SWITCH" = true ]; then
set -- $SELECTED_ORIENTATIONS
selection_count=$#
step_total=$((step_total + selection_count))
fi
if [ "$DO_CAPTURE" = true ]; then
if [ "$DO_SWITCH" = true ]; then
step_total=$((step_total + selection_count))
else
step_total=$((step_total + 1))
fi
fi
step_index=0
if [ "$DO_SYNC" = true ]; then
step_index=$((step_index + 1))
if [ -n "$SYNC_THEME_ID" ] && [ -n "$SYNC_ORIENTATION" ]; then
log_step "${step_index}/${step_total}" "同步主题包到 Kindle ($HOST_TARGET): ${SYNC_THEME_ID} / ${SYNC_ORIENTATION}"
sh "$SYNC_SCRIPT" "$HOST_TARGET" --theme "$SYNC_THEME_ID" --orientation "$SYNC_ORIENTATION"
elif [ -n "$SYNC_THEME_ID" ]; then
log_step "${step_index}/${step_total}" "同步主题包到 Kindle ($HOST_TARGET): ${SYNC_THEME_ID}"
sh "$SYNC_SCRIPT" "$HOST_TARGET" --theme "$SYNC_THEME_ID"
else
log_step "${step_index}/${step_total}" "同步本地最新主题包到 Kindle ($HOST_TARGET)"
sh "$SYNC_SCRIPT" "$HOST_TARGET"
fi
fi
if [ "$DO_SWITCH" = true ]; then
mkdir -p "$OUTPUT_DIR"
for current_orientation in $SELECTED_ORIENTATIONS; do
step_index=$((step_index + 1))
log_step "${step_index}/${step_total}" "切换 Kindle 主题到 ${SELECTED_THEME_ID} / ${current_orientation}"
ssh "$HOST_TARGET" "/mnt/us/dashboard/switch-theme.sh '$SELECTED_THEME_ID' '$current_orientation'"
if [ "$DO_CAPTURE" = true ]; then
current_basename="$(capture_basename_for_orientation "$current_orientation")"
step_index=$((step_index + 1))
log_step "${step_index}/${step_total}" "抓取当前 Kindle 实际屏幕到本地 (${current_orientation})"
sh "$CAPTURE_SCRIPT" "$HOST_TARGET" "$current_basename" "$OUTPUT_DIR"
fi
done
elif [ "$DO_CAPTURE" = true ]; then
step_index=$((step_index + 1))
log_step "${step_index}/${step_total}" "抓取当前 Kindle 实际屏幕到本地"
mkdir -p "$OUTPUT_DIR"
current_basename="$(capture_basename_for_orientation "")"
sh "$CAPTURE_SCRIPT" "$HOST_TARGET" "$current_basename" "$OUTPUT_DIR"
fi
if [ "$DO_DATE" = true ]; then
step_index=$((step_index + 1))
log_step "${step_index}/${step_total}" "获取当前 Kindle 系统日期时间"
ssh "$HOST_TARGET" "date '+%Y-%m-%d %H:%M:%S %Z'"
fi
if [ "$DO_SWITCH" = true ]; then
printf '\n完成theme=%s orientations=%s host=%s\n' "$SELECTED_THEME_ID" "$SELECTED_ORIENTATIONS" "$HOST_TARGET"
else
printf '\n完成host=%s\n' "$HOST_TARGET"
fi
if [ "$DO_CAPTURE" = true ]; then
printf '截图输出目录:%s\n' "$OUTPUT_DIR"
fi