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

411 lines
13 KiB
Bash
Raw 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)"
WATCHTHIS_DIR="$ROOT_DIR/dash/staging/watchthis"
POST_JAILBREAK_ROOT="$ROOT_DIR/dash/staging/post-jailbreak-root"
SSH_HELPERS_DIR="$ROOT_DIR/scripts/kindle"
SYNC_SCRIPT="$ROOT_DIR/scripts/sync-layered-clock-to-kindle.sh"
THEMES_JSON="$ROOT_DIR/calendar/config/themes.json"
MODE="all"
VOLUME_PATH="/Volumes/Kindle"
HOST_TARGET="kindle"
THEME_ID=""
ORIENTATION=""
SHOW_BACKGROUND=true
START_DASHBOARD=false
print_usage() {
cat <<'EOF'
用法:
sh bootstrap-new-kindle.sh [模式] [选项]
模式:
all 默认。能预置 USB 存储就先预置;能连 SSH 就继续做 SSH 后半段
prepare-storage 只做 USB 存储预置
post-ssh 只做 SSH 打通后的自动化收尾
选项:
-v, --volume <path> Kindle 挂载目录,默认 /Volumes/Kindle
-k, --kindle <host> Kindle SSH 主机名,默认 kindle
-t, --theme <theme-id> SSH 阶段切换到指定主题;默认使用 themes.json 的默认主题
-o, --orientation <value> SSH 阶段切换到指定方向;默认使用 themes.json 的默认方向
--no-background SSH 阶段不同步后立即切主题出图
--start-dashboard SSH 阶段额外后台启动 dashboard 主循环
-h, --help 查看帮助
说明:
这不是 100% 零交互刷机脚本。
受 Kindle 本机流程限制,下面这些步骤仍然必须人工完成:
1. 进入 demo mode / WatchThis 流程
2. 在正确时机执行 Sideload Content
3. 触发 Get Started 完成越狱
4. 搜索 ;log mrpi 安装 KUAL / MRPI / USBNetwork
5. 首次进 KTerm 执行 sh /mnt/us/ssh-force-dropbear-22.sh
推荐操作顺序:
阶段 A先做 USB 预置
1. 用 USB 线把 Kindle 接到 Mac。
2. 确认 Finder 里已经出现 Kindle默认挂载目录是 /Volumes/Kindle。
3. 执行:
sh bootstrap-new-kindle.sh prepare-storage
4. 预期结果:
- Kindle 根目录出现 Update_hotfix_watchthis_custom.bin
- Kindle 根目录出现 ssh-force-dropbear-22.sh 等脚本
- Kindle 根目录出现 dashboard/、extensions/、mrpackages/
- Kindle 根目录出现 .demo/KV-5.13.6.zip、.demo/demo.json、.demo/goodreads/
5. 安全弹出 Kindle。
阶段 B在 Kindle 上完成 WatchThis 和越狱
1. 恢复出厂。
2. 语言只选 English (United Kingdom)。
3. 到 Wi-Fi 页面时,不要真的联网;先按 WatchThis 文档进入 demo mode。
4. 第一次出现 Add Content / Sideload Content 时,只点 Done不要接 USB。
5. 遇到 misconfiguration / Configure Device 时,执行隐藏手势回到可操作界面。
6. 再次进入 ;demo -> Sideload Content这一次才是真正导入 payload 的时机。
因为阶段 A 已经预置好 .demo 内容,这里不需要再从 Mac 手工拷文件。
7. 退出 demo menu 后,进入 Help & User Guides -> Get Started 触发越狱。
8. 越狱成功后Kindle 根目录应出现 mkk、libkh、rp。
阶段 C安装 KUAL / MRPI / USBNetwork / dashboard
1. 在 Kindle 首页搜索:
;log mrpi
2. 等 MRPI 安装完成。
3. 预期结果:
- 首页出现 KUAL
- KUAL 菜单里有 Rename OTA Binaries
- KUAL 菜单里有 kindle-dash
4. 先在 KUAL 中执行:
Rename OTA Binaries -> Rename
阶段 D打通 Wi-Fi 和 SSH
1. 让 Kindle 连到和 Mac 同一个主 Wi-Fi不要用 Guest 网络。
2. 打开 KTerm。
3. 在 KTerm 执行:
sh /mnt/us/ssh-force-dropbear-22.sh
4. 回到 Mac先测试
ssh kindle
5. 如果这一步还不通,不要继续盲试,先回看:
dash/docs/kindle-voyage-5.13.6-dual-ssh-playbook-zh.md
阶段 ESSH 打通后自动同步并出图
1. 执行:
sh bootstrap-new-kindle.sh post-ssh -t simple -o portrait
2. 预期结果:
- 自动同步 dashboard 运行时和主题包
- Kindle 立即切到 simple / portrait
- 屏幕马上显示背景和时钟
3. 如果还希望后台常驻 dashboard 主循环,再执行:
sh bootstrap-new-kindle.sh post-ssh -t simple -o portrait --start-dashboard
最省事的直接用法:
1. USB 挂载时先运行:
sh bootstrap-new-kindle.sh all -t simple -o portrait
这会先做完能做的 USB 预置。
2. 等你在 Kindle 上完成越狱、MRPI、Wi-Fi、KTerm 拉起 SSH 后,
再重新运行同一条命令:
sh bootstrap-new-kindle.sh all -t simple -o portrait
这时它会自动继续做 SSH 后半段。
最容易做错的地方:
1. 第一次 Add Content / Sideload Content 只能点 Done不能在这一步导 payload。
2. 真正导 payload 的时机,是隐藏手势返回后,再次进入 ;demo -> Sideload Content。
3. 首次 SSH 最稳的入口是 KTerm不是 USB 直连盲试。
4. post-ssh 阶段如果不带 -t/-o会退回 themes.json 里的默认主题和方向。
示例:
sh bootstrap-new-kindle.sh prepare-storage
sh bootstrap-new-kindle.sh all -t simple -o portrait
sh bootstrap-new-kindle.sh post-ssh -k kindle --start-dashboard
EOF
}
log_step() {
printf '\n[%s] %s\n' "$1" "$2"
}
require_path() {
target_path=$1
label=$2
if [ ! -e "$target_path" ]; then
echo "缺少${label}: $target_path" >&2
exit 1
fi
}
kindle_volume_available() {
[ -d "$VOLUME_PATH" ]
}
ssh_reachable() {
ssh -o BatchMode=yes -o ConnectTimeout=5 "$HOST_TARGET" true >/dev/null 2>&1
}
resolve_theme_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}")
orientations = list(themes[theme_id].get("variants", {}).keys())
if not orientations:
raise SystemExit(f"主题 {theme_id} 没有任何方向配置")
orientation = requested_orientation or data.get("defaultOrientation", "")
if orientation not in orientations:
orientation = orientations[0]
print(f"THEME_ID={theme_id}")
print(f"ORIENTATION={orientation}")
PY
}
load_theme_selection() {
resolved_output="$(resolve_theme_selection)"
RESOLVED_THEME_ID=""
RESOLVED_ORIENTATION=""
while IFS='=' read -r key value; do
case "$key" in
THEME_ID)
RESOLVED_THEME_ID=$value
;;
ORIENTATION)
RESOLVED_ORIENTATION=$value
;;
esac
done <<EOF
$resolved_output
EOF
if [ -z "$RESOLVED_THEME_ID" ] || [ -z "$RESOLVED_ORIENTATION" ]; then
echo "无法解析主题和方向。" >&2
exit 1
fi
}
copy_watchthis_payload() {
require_path "$WATCHTHIS_DIR/KV-5.13.6/KV-5.13.6.zip" "WatchThis payload"
require_path "$WATCHTHIS_DIR/KV-5.13.6/demo.json" "WatchThis demo.json"
require_path "$WATCHTHIS_DIR/Update_hotfix_watchthis_custom.bin" "WatchThis hotfix"
mkdir -p "$VOLUME_PATH/.demo/goodreads"
cp "$WATCHTHIS_DIR/KV-5.13.6/KV-5.13.6.zip" "$VOLUME_PATH/.demo/"
cp "$WATCHTHIS_DIR/KV-5.13.6/demo.json" "$VOLUME_PATH/.demo/"
cp "$WATCHTHIS_DIR/Update_hotfix_watchthis_custom.bin" "$VOLUME_PATH/"
}
copy_post_jailbreak_bundle() {
require_path "$POST_JAILBREAK_ROOT/extensions" "post-jailbreak extensions"
require_path "$POST_JAILBREAK_ROOT/mrpackages" "post-jailbreak mrpackages"
require_path "$POST_JAILBREAK_ROOT/dashboard" "post-jailbreak dashboard"
mkdir -p "$VOLUME_PATH/extensions" "$VOLUME_PATH/mrpackages" "$VOLUME_PATH/dashboard"
rsync -av --no-o --no-g "$POST_JAILBREAK_ROOT/extensions/" "$VOLUME_PATH/extensions/"
rsync -av --no-o --no-g "$POST_JAILBREAK_ROOT/mrpackages/" "$VOLUME_PATH/mrpackages/"
rsync -av --no-o --no-g "$POST_JAILBREAK_ROOT/dashboard/" "$VOLUME_PATH/dashboard/"
}
copy_ssh_helpers() {
require_path "$SSH_HELPERS_DIR/ssh-force-dropbear-22.sh" "SSH helper scripts"
rsync -av --no-o --no-g "$SSH_HELPERS_DIR/" "$VOLUME_PATH/"
}
print_storage_next_steps() {
cat <<'EOF'
下一步请在 Kindle 上继续:
1. 按 [dash/docs/kindle-voyage-5.13.6-watchthis-zh.md] 的流程进入 demo mode。
2. 走到真正的 Sideload Content 时,脚本已预置好:
- .demo/KV-5.13.6.zip
- .demo/demo.json
- .demo/goodreads/
3. 触发 Get Started 完成越狱。
4. 搜索 `;log mrpi` 安装 KUAL / MRPI / USBNetwork / dashboard。
5. 先在 KUAL 里执行 `Rename OTA Binaries -> Rename`。
6. 连上 Wi-Fi。
7. 打开 KTerm执行
sh /mnt/us/ssh-force-dropbear-22.sh
8. 回到 Mac 后,再运行:
sh bootstrap-new-kindle.sh post-ssh
EOF
}
prepare_storage() {
if ! kindle_volume_available; then
echo "未找到 Kindle 挂载目录: $VOLUME_PATH" >&2
exit 1
fi
log_step "USB" "预置 WatchThis payload"
copy_watchthis_payload
log_step "USB" "预置越狱后安装包"
copy_post_jailbreak_bundle
log_step "USB" "预置 SSH 恢复脚本"
copy_ssh_helpers
log_step "完成" "USB 存储预置已完成:$VOLUME_PATH"
print_storage_next_steps
}
prepare_remote_helpers() {
ssh "$HOST_TARGET" "chmod +x /mnt/us/ssh-collect.sh /mnt/us/ssh-fix-all-keys.sh /mnt/us/ssh-force-dropbear-22.sh /mnt/us/ssh-force-openssh-22.sh /mnt/us/ssh-stop-all.sh 2>/dev/null || true"
ssh "$HOST_TARGET" "if [ -f /mnt/us/ssh-fix-all-keys.sh ]; then sh /mnt/us/ssh-fix-all-keys.sh; fi"
}
sync_dashboard_runtime() {
if [ -n "$THEME_ID" ]; then
if [ -n "$ORIENTATION" ]; then
sh "$SYNC_SCRIPT" "$HOST_TARGET" --theme "$THEME_ID" --orientation "$ORIENTATION"
else
sh "$SYNC_SCRIPT" "$HOST_TARGET" --theme "$THEME_ID"
fi
else
sh "$SYNC_SCRIPT" "$HOST_TARGET"
fi
}
show_background_once() {
load_theme_selection
ssh "$HOST_TARGET" "/mnt/us/dashboard/switch-theme.sh '$RESOLVED_THEME_ID' '$RESOLVED_ORIENTATION'"
}
start_dashboard_loop() {
# 当前仓库里最稳的是 SSH 触发启动;这里后台拉起,便于 bootstrap 脚本直接返回。
ssh "$HOST_TARGET" "mkdir -p /mnt/us/dashboard/logs && cd /mnt/us/dashboard && nohup ./start.sh >/mnt/us/dashboard/logs/bootstrap-start.log 2>&1 </dev/null &"
}
print_post_ssh_summary() {
load_theme_selection
cat <<EOF
SSH 阶段已完成:
- 主机:$HOST_TARGET
- 已同步 dashboard 运行时与主题包
- 当前用于出图的主题:$RESOLVED_THEME_ID / $RESOLVED_ORIENTATION
如果你要继续验证:
- SSH 登录ssh $HOST_TARGET
- 立即切主题ssh $HOST_TARGET '/mnt/us/dashboard/switch-theme.sh $RESOLVED_THEME_ID $RESOLVED_ORIENTATION'
- 抓图到本地sh snapshot.sh -t $RESOLVED_THEME_ID -o $RESOLVED_ORIENTATION
EOF
}
post_ssh() {
if ! ssh_reachable; then
echo "当前还无法通过 SSH 连接 $HOST_TARGET" >&2
echo "请先在 Kindle 上连上 Wi-Fi并在 KTerm 执行 sh /mnt/us/ssh-force-dropbear-22.sh" >&2
exit 1
fi
log_step "SSH" "修复设备侧 SSH 辅助脚本权限与 authorized_keys"
prepare_remote_helpers
log_step "同步" "同步 dashboard 运行时和主题包到 Kindle"
sync_dashboard_runtime
if [ "$SHOW_BACKGROUND" = true ]; then
log_step "显示" "立即切到当前主题并出图"
show_background_once
fi
if [ "$START_DASHBOARD" = true ]; then
log_step "启动" "后台启动 dashboard 主循环"
start_dashboard_loop
fi
log_step "完成" "SSH 阶段自动化已完成"
print_post_ssh_summary
}
while [ "$#" -gt 0 ]; do
case "$1" in
all|prepare-storage|post-ssh)
MODE=$1
;;
-v|--volume)
shift
VOLUME_PATH=${1:?"missing volume path"}
;;
-k|--kindle)
shift
HOST_TARGET=${1:?"missing kindle host"}
;;
-t|--theme)
shift
THEME_ID=${1:?"missing theme id"}
;;
-o|--orientation)
shift
ORIENTATION=${1:?"missing orientation"}
;;
--no-background)
SHOW_BACKGROUND=false
;;
--start-dashboard)
START_DASHBOARD=true
;;
-h|--help)
print_usage
exit 0
;;
*)
echo "未知参数: $1" >&2
print_usage >&2
exit 1
;;
esac
shift
done
require_path "$THEMES_JSON" "themes.json"
require_path "$SYNC_SCRIPT" "sync-layered-clock-to-kindle.sh"
case "$MODE" in
prepare-storage)
prepare_storage
;;
post-ssh)
post_ssh
;;
all)
did_anything=false
if kindle_volume_available; then
prepare_storage
did_anything=true
else
log_step "跳过" "未检测到 Kindle 存储挂载:$VOLUME_PATH"
fi
if ssh_reachable; then
post_ssh
did_anything=true
else
log_step "等待" "SSH 还未打通;等 Kindle 连上 Wi-Fi 并在 KTerm 执行 sh /mnt/us/ssh-force-dropbear-22.sh 后,再重跑本脚本或执行 post-ssh。"
fi
if [ "$did_anything" != true ]; then
echo "既没有检测到 Kindle 存储挂载,也没有检测到可用 SSH。" >&2
echo "请先通过 USB 挂载 Kindle或先恢复 SSH 后再执行。" >&2
exit 1
fi
;;
esac