update at 2026-03-17 10:37:27
This commit is contained in:
367
snapshot.sh
Executable file
367
snapshot.sh
Executable file
@@ -0,0 +1,367 @@
|
||||
#!/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
|
||||
Reference in New Issue
Block a user