first commit

This commit is contained in:
douboer@gmail.com
2026-03-15 09:30:40 +08:00
commit 3d19c4d34f
145 changed files with 11623 additions and 0 deletions

View File

@@ -0,0 +1,238 @@
# Kindle Voyage 5.13.6 一次成功路径
这篇文档只覆盖下面这个组合:
- 机型:`Kindle Voyage (KV)`
- 固件:`5.13.6`
- 目标:完成越狱,并部署 `KUAL``MRPI``renameotabin``kindle-dash`
如果设备型号或固件版本不同,不要直接照抄本文。
## 核心结论
`Kindle Voyage 5.13.6` 应该走 `WatchThis`,不要走 `LanguageBreak`
这次实操里,前面大部分失败都来自两个错误:
- 误走了 `LanguageBreak`
- 在 demo 菜单里点错了分支,提前进入了 `Resell Device` / `销售设备`
对这台设备,正确思路非常简单:
1.`WatchThis` 进入 demo mode
2. 只在正确的 `Sideload Content` 时机导入 `KV-5.13.6.zip`
3.`Get Started` 触发越狱脚本
4. 安装 `KUAL/MRPI`
5.`renameotabin` 关闭 OTA
6. 再部署并启动 `kindle-dash`
## 需要准备的文件
### WatchThis
来自 `watchthis-jailbreak-r03.zip`
- `KV-5.13.6.zip`
- `demo.json`
- `Update_hotfix_watchthis_custom.bin`
在本仓库里对应的是:
- `staging/watchthis/KV-5.13.6/KV-5.13.6.zip`
- `staging/watchthis/KV-5.13.6/demo.json`
- `staging/watchthis/Update_hotfix_watchthis_custom.bin`
### 越狱后安装包
- `extensions/MRInstaller`
- `mrpackages/Update_KUALBooklet_HDRepack.bin`
- `extensions/renameotabin`
- `extensions/kindle-dash`
- `dashboard/`
在本仓库里已经整理到:
- `staging/post-jailbreak-root/extensions/`
- `staging/post-jailbreak-root/mrpackages/`
- `staging/post-jailbreak-root/dashboard/`
## 一次成功的正确路径
### 1. 恢复出厂并进入 demo mode
1. 先恢复出厂设置。
2. 语言选择页只选 `English (United Kingdom)`
这一步非常关键,不要选中文。
3. 到 WiFi 页面后,随便点一个网络,再立刻退回,不要真的联网。
4. 在搜索栏输入 `;enter_demo`
5. 如果 `;enter_demo` 没反应,走备用入口:
- 用 USB 连接电脑
- 在 Kindle 根目录创建空文件 `DONT_CHECK_BATTERY`
- 弹出设备
- 回到 Kindle 搜索输入 `;demo`
6. 如果看到 `Demo Activation`,点 `Yes`
7. 设备重启并进入 demo 流程后:
- 跳过 WiFi
- 店铺注册信息全部填假值
- `Fetching available demo types``Skip`
- demo type 选 `standard`
### 2. 第一次出现 Sideload Content 时不要导入 payload
1. 第一次出现 `Add Content` / `Sideload Content` 提示时,只点 `Done`
2. 这一步不要接 USB。
3. 这一步也不要导入 `KV-5.13.6.zip`
这是最容易做错的一步。第一次 `Done` 只是让 demo setup 继续往下走,不是真正的 payload 导入点。
### 3. 跳过 misconfiguration 锁页
demo setup 完成后,大概率会落到 `Configure Device` / misconfiguration 页面。
不要点 `Configure Device`,直接做隐藏手势:
1. 在屏幕右下角用两根手指同时轻点一下
2. 两指立刻抬起
3. 马上用一根手指从右下向左滑
触发成功后会回到可操作界面。
### 4. 真正的 payload 导入点
1. 回到可操作界面后,搜索输入 `;demo`
2. 进入 demo menu
3. 选择 `Sideload Content` / `导入内容`
4. 到这一步再接 USB
5. 在 Kindle 根目录创建 `.demo/`
6. 把下面三个东西放进去:
```text
.demo/KV-5.13.6.zip
.demo/demo.json
.demo/goodreads/ <- 空目录
```
如果你在 Mac 上操作,可以直接用:
```sh
mkdir -p /Volumes/Kindle/.demo/goodreads
cp staging/watchthis/KV-5.13.6/KV-5.13.6.zip /Volumes/Kindle/.demo/
cp staging/watchthis/KV-5.13.6/demo.json /Volumes/Kindle/.demo/
```
然后:
1. 弹出 Kindle
2. 在 Kindle 上点 `Done`
3. 退出 demo menu
## 5. 触发越狱脚本
1. 退出 demo menu 后,输入 `;dsts`
如果 `;dsts` 没反应,也可以从顶部下拉进入设置。
2. 打开 `Help & User Guides`
3. 再点 `Get Started`
4. 设备会重启
5. 越狱脚本会在下次启动时运行
如果这里弹 `Application Error`,官方补救是:
1. 长按电源键强制重启
2. 再进 demo menu
3. 再执行一次 `Sideload Content -> Done`
4. 这次不要再接 USB
## 6. 成功判据
对这台设备,下面这些现象说明越狱已经落地:
- Kindle 用户存储根目录出现 `mkk`
- Kindle 用户存储根目录出现 `libkh`
- Kindle 用户存储根目录出现 `rp`
如果这三个目录都没有,基本就是前面的 `WatchThis` 没真正成功。
## 7. 安装 KUAL / MRPI / kindle-dash
越狱落地后,把这些目录复制到 Kindle
```sh
rsync -a staging/post-jailbreak-root/extensions/ /Volumes/Kindle/extensions/
rsync -a staging/post-jailbreak-root/mrpackages/ /Volumes/Kindle/mrpackages/
rsync -a staging/post-jailbreak-root/dashboard/ /Volumes/Kindle/dashboard/
```
然后:
1. 弹出 Kindle
2. 回到首页搜索输入 `;log mrpi`
3. 等安装完成
4. 首页会出现 `KUAL` 卡片
## 8. 启动顺序
进入 `KUAL` 后,先做这个顺序:
1. `Rename OTA Binaries -> Rename`
2. 再运行 `Kindle Dashboard`
不要先跑 `Kindle Dashboard`,否则后面如果 OTA 没关掉,还存在自动升级把越狱覆盖掉的风险。
## 9. kindle-dash 默认行为
本项目默认不会在 Kindle 本机实时渲染页面,而是定时去下载一张图片来显示。
因此:
- 如果没有联网,`Kindle Dashboard` 看起来会像“卡住”
- 如果刷新计划不覆盖当前时间,会显示 `kindle is sleeping`
- 图片最好直接按 Voyage 原生分辨率出图:`1072 x 1448`
默认抓图脚本在:
- `src/local/fetch-dashboard.sh`
默认刷新计划在:
- `src/local/env.sh`
## 10. 这台设备上确认过的坑
### 不要走 `LanguageBreak`
`KV + 5.13.6` 应走 `WatchThis`。误走 `LanguageBreak` 会导致:
- `;demo -> Yes -> 重启 -> 回普通系统`
- `;uzb``;dsts` 行为异常
- 反复进入错误的 demo 分支
### 不要点 `Resell Device` / `销售设备`
这个分支会把流程带到 shipping mode / demo 出厂流程,和 `WatchThis` 正常路径无关。
如果你是在 `WatchThis` 流程里demo menu 里真正要点的是:
- `Sideload Content`
不是:
- `Resell Device`
- `Remote Reset`
- `Configure WiFi`
### 第一次 `Add Content` 只能点 `Done`
真正要接 USB 导 payload 的时机,是秘密手势之后再次 `;demo -> Sideload Content` 的那一次。
### 看到左上角只有一小块图片,不一定是失败
这通常只是图片尺寸不匹配。
例如本项目自带的 `sleeping.png` 只有 `600x800`,放到 Voyage 上就只会显示在左上角一部分区域。
## 参考
- WatchThis 包内说明:`watchthis-jailbreak-r03.zip` 中的 `watchthis-release/README.md`
- 项目主说明:`README.md`
- 图片抓取说明:`src/local/fetch-dashboard.sh`
- 本地调度配置:`src/local/env.sh`

View File

@@ -0,0 +1,449 @@
# Kindle Dashboard 分层时钟方案
## 1. 背景
当前仓库里有两部分:
- `calendar/`:负责渲染仪表盘网页与导出背景素材
- `dash/`:运行在 Kindle 上,负责拉图、刷屏、休眠与唤醒
最新设计稿来自 Figma
- 文件:`calendar`
- 节点:`6:2`
- 链接:`https://www.figma.com/design/3bXFNM5nM6mCq0TpL3nPYK/calendar?node-id=6-2&m=dev`
该节点 annotation 已明确:
- `阳历当天`
- `星期`
- `农历日`
- `时钟区域`
- `日历`
- `天气预报卡片`
- `书摘卡片`
本方案基于这些约束,采用“低频背景 + 本地时钟”的拆分方式:
- `calendar/``2 小时` 生成一次背景图
- 背景图直接写到:
- `/Users/gavin/kindle-dash/calendar/dist/kindlebg.png`
- Kindle 通过固定 HTTPS 地址拉取背景图:
- `https://shell.biboer.cn:20001/kindlebg.png`
- Kindle 端每分钟`不联网`
- Kindle 端只在本地重画时钟区域
## 2. 目标
这次改造不是单纯调样式,而是把页面拆成两类刷新节奏完全不同的素材:
1. 低频背景层
2. 高频时钟层
目标收益:
- 背景内容不再分钟级刷新
- 分钟级变化只限制在时钟区域
- 降低 Wi-Fi 唤醒次数
- 降低全屏刷新频率
- 减少墨水屏闪烁与残影
## 3. 分层边界
### 3.1 全屏背景层
背景层文件名固定为:
- `kindlebg.png`
背景层包含:
- 整体外层容器、圆角、阴影、背景渐变
- 日历卡片中的:
- 阳历当天数字
- 星期
- 农历日
- 下方月历区域
- 天气卡片全部内容
- 书摘卡片全部内容
背景层**不包含**
- 时钟表盘主体
- 时钟刻度
- 时针
- 分针
- 中心圆点
也就是说,背景图在时钟区域只保留布局占位,不直接承载任何分钟级内容。
### 3.2 静态表盘 patch
静态表盘 patch 为一个独立本地素材:
- `clock-face.png`
该素材包含:
- 圆形表盘主体
- 刻度
- 中心底座或中心圆盘
建议尺寸直接对齐 Figma 时钟区域:
- 节点:`24:74`
- 设计尺寸:`220 x 220`
这张图应当保存在 Kindle 本地,例如:
- `/mnt/us/dashboard/assets/clock-face.png`
它不需要分钟级联网拉取,只需要在部署时同步到设备,或者在更换设计稿时重新同步。
### 3.3 指针层
高频变化层只包含:
- 时针
- 分针
这里不建议包含秒针:
- 墨水屏收益低
- 刷新频率会显著上升
- 更容易产生残影
由于当前 `dash/` 链路本质是 `eips` 刷图,不是 SVG/Canvas 实时渲染,所以推荐使用`分层素材方案`
- `minute-hand/00.png``minute-hand/59.png`
- `hour-hand/000.png``hour-hand/719.png`
说明:
- 分针每分钟一个角度,共 `60`
- 时针如果要做到真正随分钟连续移动,需要 `12 * 60 = 720`
- 这些都是小尺寸 patch不是整屏图体积可控
如果后续确认 Kindle 端存在稳定的本地绘线工具,再考虑把指针改成算法绘制;当前版本不依赖这个前提。
## 4. 为什么不能只把表盘放进整页背景
这个问题必须单独说明。
如果:
- 表盘主体和刻度只存在于 `kindlebg.png`
- Kindle 每分钟只覆盖新的时针/分针
那么上一分钟留下的旧指针就无法被干净擦除。
因此 Kindle 端每分钟的正确流程应该是:
1. 先重画一张本地 `clock-face.png`
2. 再叠加新的时针素材
3. 再叠加新的分针素材
这等价于“先擦除,再重画”,并且整个流程不依赖网络。
所以本方案不是“背景图 + 两根指针”两层,而是:
1. `kindlebg.png`:全屏低频背景
2. `clock-face.png`:本地静态表盘 patch
3. `hour-hand/*.png + minute-hand/*.png`:本地高频指针素材
## 5. 数据刷新策略
### 5.1 背景层刷新
背景层刷新触发条件:
-`2 小时` 一次
- 跨天时立即刷新一次
- 天气接口异常恢复后可补刷一次
推荐调度:
- `00:00 / 02:00 / 04:00 / ... / 22:00`
背景层刷新输出:
- `/Users/gavin/kindle-dash/calendar/dist/kindlebg.png`
背景层对 Kindle 的访问地址固定为:
- `https://shell.biboer.cn:20001/kindlebg.png`
### 5.2 静态表盘 patch 刷新
静态表盘 patch 不参加分钟级调度。
建议刷新方式:
- 随部署同步一次
- Figma 设计或尺寸变化时重新导出并同步
### 5.3 指针层刷新
指针层刷新触发条件:
- 每分钟一次
指针层数据只依赖 Kindle 本地时间:
- 小时
- 分钟
分钟刷新不需要联网。
## 6. 网页渲染模式设计
为了让 `calendar/` 稳定产出背景与表盘素材,建议支持下面 3 种模式。
### 6.1 `full`
用途:
- 本地开发预览
- 对照 Figma 联调
输出内容:
- 背景层
- 表盘
- 指针预览
### 6.2 `background`
用途:
- 生成 `kindlebg.png`
输出内容:
- 只渲染背景层
- 时钟区域保留占位,但不绘制表盘与指针
### 6.3 `clock-face`
用途:
- 生成静态表盘 patch
输出内容:
- 只渲染表盘主体、刻度和中心底座
- 不绘制时针、分针
### 6.4 URL 约定
建议页面支持如下参数:
```text
/?mode=full
/?mode=background
/?mode=clock-face
```
## 7. 产物约定
推荐最终产出这几类文件:
```text
calendar/dist/kindlebg.png
calendar/dist/dashboard-manifest.json
kindle local:
/mnt/us/dashboard/assets/clock-face.png
/mnt/us/dashboard/assets/hour-hand/000.png ... 719.png
/mnt/us/dashboard/assets/minute-hand/00.png ... 59.png
```
`manifest` 建议至少包含这些字段:
```json
{
"background": {
"path": "kindlebg.png",
"url": "https://shell.biboer.cn:20001/kindlebg.png",
"updatedAt": "2026-03-15T10:00:00+08:00",
"refreshIntervalMinutes": 120
},
"clockRegion": {
"x": 313,
"y": 0,
"width": 220,
"height": 220
},
"clockFace": {
"path": "clock-face.png",
"managedOnKindle": true
},
"clockHands": {
"hourPattern": "assets/hour-hand/%03d.png",
"minutePattern": "assets/minute-hand/%02d.png",
"refreshIntervalMinutes": 1,
"networkRequired": false
}
}
```
说明:
- `x/y/width/height` 先按设计稿记录
- 真正接入 Kindle 时,要换算成最终截图分辨率下的实际像素值
## 8. Kindle 侧刷新策略
### 8.1 已确认的前提
`eips` 支持把 PNG/JPG 绘制到指定坐标,参数包含:
- `-g`
- `-x`
- `-y`
- `-f`
MobileRead Wiki 明确写了:
- `eips -g|-b image_path [-w waveform -f -x xpos -y ypos -v]`
- `-x``-y` 以像素为单位
来源:<https://wiki.mobileread.com/wiki/Eips>
因此,对 Kindle Voyage 而言,“在固定时钟区域重画小图”这个前提是成立的。
### 8.2 推荐流程
#### 启动或背景刷新时
1. 通过 HTTPS 拉取:
- `https://shell.biboer.cn:20001/kindlebg.png`
2. 保存为本地背景缓存
3. 使用全屏刷新显示背景图
4. 在时钟区域重画一次:
- `clock-face.png`
- 当前时针
- 当前分针
#### 每分钟刷新时
1. 读取 Kindle 本机时间
2. 计算:
- `minute_index = 00..59`
- `hour_index = ((hour % 12) * 60 + minute) = 000..719`
3. 在固定坐标先画:
- `clock-face.png`
4. 再画:
- `hour-hand/<hour_index>.png`
5. 再画:
- `minute-hand/<minute_index>.png`
6. 默认做局部/普通刷新
7.`10``15` 分钟对时钟区域补一次全刷,清理残影
### 8.3 功耗模型
这套方式的功耗来源拆成两类:
- 背景刷新:
- 每 2 小时联网一次
- 全屏刷新一次
- 时钟刷新:
- 每分钟本地刷一次小区域
- 不联网
相比“每分钟拉一张整屏背景图”,这会明显省电。
## 9. 代码改造建议
### 9.1 `calendar/`
建议改造点:
- 新增 `mode=background`
- 新增 `mode=clock-face`
- 时钟区域从日历/天气/书摘中完全拆开
- 增加一个定时生成任务,每 2 小时把背景图写到:
- `/Users/gavin/kindle-dash/calendar/dist/kindlebg.png`
- 生成 `dashboard-manifest.json`
### 9.2 `dash/`
建议改造点:
- `dash/src/local/fetch-dashboard.sh`
- 改成只拉取 `kindlebg.png`
- `dash/src/dash.sh`
- 从“单一刷新循环”改为“背景刷新 + 本地时钟刷新”双节奏
- 新增例如:
- `dash/src/local/render-clock.sh`
- `dash/src/local/render-clock-face.sh`
- `dash/src/local/clock-index.sh`
推荐新增配置项:
```sh
export BACKGROUND_URL="https://shell.biboer.cn:20001/kindlebg.png"
export BACKGROUND_REFRESH_SCHEDULE="0 */2 * * *"
export CLOCK_REGION_X=313
export CLOCK_REGION_Y=0
export CLOCK_REGION_WIDTH=220
export CLOCK_REGION_HEIGHT=220
export CLOCK_FULL_REFRESH_INTERVAL_MINUTES=15
```
## 10. 实施顺序
建议按下面顺序落地,避免一次改太多导致链路难排查。
### 阶段 1`calendar/` 分层输出
目标:
- `full/background/clock-face` 三种模式跑通
- 每 2 小时把背景图写到 `calendar/dist/kindlebg.png`
输出:
- 浏览器可预览
- `kindlebg.png` 可被 nginx 直接访问
### 阶段 2时钟静态素材准备
目标:
- 产出 `clock-face.png`
- 产出 `hour-hand``minute-hand` 素材库
输出:
- Kindle 本地时钟素材目录结构确定
### 阶段 3Kindle 本地分钟时钟
目标:
- Kindle 每分钟本地重画时钟
- 不联网
输出:
- 背景低频更新 + 时钟本地高频更新的完整链路
## 11. 推荐结论
当前最稳妥的推进顺序是:
1. 先让 `calendar/` 每 2 小时稳定生成:
- `/Users/gavin/kindle-dash/calendar/dist/kindlebg.png`
2. 再让 Kindle 只从:
- `https://shell.biboer.cn:20001/kindlebg.png`
拉背景图
3. 时钟区域完全本地化:
- 本地 `clock-face.png`
- 本地 `hour-hand/*.png`
- 本地 `minute-hand/*.png`
4. 分钟刷新时:
- 先重画表盘
- 再重画时针
- 再重画分针
也就是说,**背景是远端低频资源,时钟是本地高频资源,二者不要混在同一个刷新链路里**。

View File

@@ -0,0 +1 @@
/node_modules

1
dash/docs/screenshotter/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/node_modules

View File

@@ -0,0 +1,30 @@
FROM node:12-buster-slim
RUN apt-get update \
&& apt-get install -y wget gnupg \
&& wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
&& apt-get update \
&& apt-get install -y google-chrome-stable fonts-freefont-ttf libxss1 fonts-noto-color-emoji \
--no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD 1
ENV PUPPETEER_EXECUTABLE_PATH /usr/bin/google-chrome-stable
ADD package.json yarn.lock /app/
RUN cd /app && yarn install \
# Add user so we don't need --no-sandbox.
# same layer as npm install to keep re-chowned files from using up several hundred MBs more space
&& groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \
&& mkdir -p /home/pptruser/Downloads \
&& chown -R pptruser:pptruser /home/pptruser \
&& chown -R pptruser:pptruser /app/node_modules
ADD . /app/
# Run everything after as non-privileged user.
USER pptruser
CMD ["node", "/app/screenshot.js"]

View File

@@ -0,0 +1,9 @@
{
"name": "screenshotter",
"version": "1.0.0",
"private": true,
"dependencies": {
"pngjs": "^6.0.0",
"puppeteer": "^5.5.0"
}
}

View File

@@ -0,0 +1,38 @@
const puppeteer = require("puppeteer");
const fs = require("fs");
const PNG = require("pngjs").PNG;
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
const URL = process.env.URL || "CHANGEME";
(async () => {
const browser = await puppeteer.launch({
args: ["--no-sandbox", "--disable-setuid-sandbox"],
});
const page = await browser.newPage();
/* Kindle 4 NT resolution */
await page.setViewport({ width: 600, height: 800 });
/* Might want to use networkidle0 here, depending on the type of page */
/* See https://github.com/puppeteer/puppeteer/blob/main/docs/api.md */
await page.goto(URL, { waitUntil: "networkidle2" });
/* This is a bit silly. ¯\_(ツ)_/¯
Networkidle2 doesn't always seem to wait long enough. */
await sleep(3000);
await page.screenshot({ path: "dash.png" });
await fs.createReadStream("dash.png")
.pipe(new PNG({ colorType: 0 }))
.on("parsed", function () {
this.pack().pipe(fs.createWriteStream("dash.png"));
});
browser.close();
})();

View File

@@ -0,0 +1,373 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@types/node@*":
version "14.14.22"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.22.tgz#0d29f382472c4ccf3bd96ff0ce47daf5b7b84b18"
integrity sha512-g+f/qj/cNcqKkc3tFqlXOYjrmZA+jNBiDzbP3kH+B+otKFqAdPgVTGP1IeKRdMml/aE69as5S4FqtxAbl+LaMw==
"@types/yauzl@^2.9.1":
version "2.9.1"
resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.9.1.tgz#d10f69f9f522eef3cf98e30afb684a1e1ec923af"
integrity sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==
dependencies:
"@types/node" "*"
agent-base@5:
version "5.1.1"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c"
integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==
balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
base64-js@^1.3.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
bl@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/bl/-/bl-4.0.3.tgz#12d6287adc29080e22a705e5764b2a9522cdc489"
integrity sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==
dependencies:
buffer "^5.5.0"
inherits "^2.0.4"
readable-stream "^3.4.0"
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
buffer-crc32@~0.2.3:
version "0.2.13"
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
buffer@^5.2.1, buffer@^5.5.0:
version "5.7.1"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
dependencies:
base64-js "^1.3.1"
ieee754 "^1.1.13"
chownr@^1.1.1:
version "1.1.4"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
debug@4, debug@^4.1.0, debug@^4.1.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
dependencies:
ms "2.1.2"
devtools-protocol@0.0.818844:
version "0.0.818844"
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.818844.tgz#d1947278ec85b53e4c8ca598f607a28fa785ba9e"
integrity sha512-AD1hi7iVJ8OD0aMLQU5VK0XH9LDlA1+BcPIgrAxPfaibx2DbWucuyOhc4oyQCbnvDDO68nN6/LcKfqTP343Jjg==
end-of-stream@^1.1.0, end-of-stream@^1.4.1:
version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
dependencies:
once "^1.4.0"
extract-zip@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a"
integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==
dependencies:
debug "^4.1.1"
get-stream "^5.1.0"
yauzl "^2.10.0"
optionalDependencies:
"@types/yauzl" "^2.9.1"
fd-slicer@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e"
integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=
dependencies:
pend "~1.2.0"
find-up@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
dependencies:
locate-path "^5.0.0"
path-exists "^4.0.0"
fs-constants@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
get-stream@^5.1.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
dependencies:
pump "^3.0.0"
glob@^7.1.3:
version "7.1.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
https-proxy-agent@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz#702b71fb5520a132a66de1f67541d9e62154d82b"
integrity sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==
dependencies:
agent-base "5"
debug "4"
ieee754@^1.1.13:
version "1.2.1"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
dependencies:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@^2.0.3, inherits@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
locate-path@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
dependencies:
p-locate "^4.1.0"
minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
dependencies:
brace-expansion "^1.1.7"
mkdirp-classic@^0.5.2:
version "0.5.3"
resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113"
integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==
ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
node-fetch@^2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
once@^1.3.0, once@^1.3.1, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
dependencies:
wrappy "1"
p-limit@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
dependencies:
p-try "^2.0.0"
p-locate@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
dependencies:
p-limit "^2.2.0"
p-try@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
path-exists@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
pend@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
pkg-dir@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
dependencies:
find-up "^4.0.0"
pngjs@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-6.0.0.tgz#ca9e5d2aa48db0228a52c419c3308e87720da821"
integrity sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==
progress@^2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
proxy-from-env@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
pump@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
dependencies:
end-of-stream "^1.1.0"
once "^1.3.1"
puppeteer@^5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-5.5.0.tgz#331a7edd212ca06b4a556156435f58cbae08af00"
integrity sha512-OM8ZvTXAhfgFA7wBIIGlPQzvyEETzDjeRa4mZRCRHxYL+GNH5WAuYUQdja3rpWZvkX/JKqmuVgbsxDNsDFjMEg==
dependencies:
debug "^4.1.0"
devtools-protocol "0.0.818844"
extract-zip "^2.0.0"
https-proxy-agent "^4.0.0"
node-fetch "^2.6.1"
pkg-dir "^4.2.0"
progress "^2.0.1"
proxy-from-env "^1.0.0"
rimraf "^3.0.2"
tar-fs "^2.0.0"
unbzip2-stream "^1.3.3"
ws "^7.2.3"
readable-stream@^3.1.1, readable-stream@^3.4.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
dependencies:
inherits "^2.0.3"
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
dependencies:
glob "^7.1.3"
safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
string_decoder@^1.1.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
dependencies:
safe-buffer "~5.2.0"
tar-fs@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784"
integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==
dependencies:
chownr "^1.1.1"
mkdirp-classic "^0.5.2"
pump "^3.0.0"
tar-stream "^2.1.4"
tar-stream@^2.1.4:
version "2.2.0"
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287"
integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==
dependencies:
bl "^4.0.3"
end-of-stream "^1.4.1"
fs-constants "^1.0.0"
inherits "^2.0.3"
readable-stream "^3.1.1"
through@^2.3.8:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
unbzip2-stream@^1.3.3:
version "1.4.3"
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7"
integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==
dependencies:
buffer "^5.2.1"
through "^2.3.8"
util-deprecate@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
ws@^7.2.3:
version "7.4.2"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.2.tgz#782100048e54eb36fe9843363ab1c68672b261dd"
integrity sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA==
yauzl@^2.10.0:
version "2.10.0"
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=
dependencies:
buffer-crc32 "~0.2.3"
fd-slicer "~1.1.0"

12
dash/docs/tipstricks.md Normal file
View File

@@ -0,0 +1,12 @@
# Tips & tricks
## Producing dashboard images from a webpage
A common way to produce dashboard images for the Kindle is to take a screenshot of a website.
This can be done in a variety of ways. A few things to keep in mind are:
1. The images should be grayscale PNG images, without any alpha layers.
2. The resolution should match the display resolution of the Kindle. For example the Kindle 4 NT has a resolution of 800x600 pixels.
I personally use a headless Chrome instance with [Puppeteer](https://pptr.dev/).
The code I use can be found [here](./screenshotter/screenshot.js) as a reference.