diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 983ffb5382bd4c8495517ba4c2adb9841a93bf8c..2c6b29d9d8a4eb7f4a3be367c4a3c545d2a8ef6e 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -120,6 +120,10 @@ const zhLocaleThemeConfig = { text: "专题", items: [ { text: "免密登录", link: "/advanced-inject-passwordless-login.md" }, + { + text: "懒猫网盘打开与保存选择器", + link: "/advanced-lazycat-drive-open-save-chooser.md", + }, { text: "Skill / MCP 规范", link: "/resource-skill-mcp.md" }, ], }, diff --git a/docs/advanced-lazycat-drive-open-save-chooser.md b/docs/advanced-lazycat-drive-open-save-chooser.md new file mode 100644 index 0000000000000000000000000000000000000000..d9a11c7855ad64b29a45fae81da8a8242681ef83 --- /dev/null +++ b/docs/advanced-lazycat-drive-open-save-chooser.md @@ -0,0 +1,188 @@ +# 懒猫网盘打开与保存选择器 + +## 目标 + +本文完成后,你可以在不修改上游前端源码的前提下,为第三方 Web 应用接入懒猫网盘的打开、保存、上传和下载能力。 + +适合的场景: + +1. 应用已经使用浏览器文件 API,例如 `showOpenFilePicker()`、`showSaveFilePicker()` 或 ``。 +2. 应用是第三方容器镜像,不方便重新编译前端。 +3. 希望用户在“本地文件”和“懒猫网盘文件”之间选择。 + +不适合的场景: + +1. 应用完全通过后端 API 管理文件,前端不触发浏览器文件选择能力。 +2. 应用需要服务端直接读写用户网盘目录。此时应优先阅读 [文件访问](./advanced-file.md)。 + +## 前置条件 + +1. lzcos 版本满足 inject 功能要求。 +2. 已阅读 [脚本注入(injects)](./advanced-injects.md) 和 [manifest inject 规范](./spec/manifest.md#injects)。 +3. 已掌握 `lzc-build.yml` 的 `contentdir` 字段(见 [lzc-build.yml 规范](./spec/build.md))。 + +## 示例脚本 + +本文不在文档站内维护脚本副本。请直接参考已适配应用的 `lazycat-injects` 目录: + +- [Excalidraw lazycat-injects](https://gitee.com/lazycatcloud/excalidraw/tree/master/lazycat-injects) + +这个目录同时可以作为参考脚本来源和适配应用参考,主要包含: + +- `open-save-chooser.js` +- `vendor/lzc-file-pickers.umd.js` +- `README.md` + +将脚本复制到目标 LPK 项目后,保持以下目录结构: + +```text +content/ + lazycat-injects/ + open-save-chooser.js + vendor/ + lzc-file-pickers.umd.js +``` + +## 核心思路 + +通过 browser inject 向目标页面注入两类脚本: + +1. `lzc-file-pickers.umd.js`:注册 `` 自定义元素,用来打开懒猫文件选择器。 +2. `open-save-chooser.js`:桥接浏览器文件 API 和懒猫网盘 HTTP 文件接口。 + +桥接脚本通常处理这些能力: + +- `window.showOpenFilePicker()` +- `window.showSaveFilePicker()` +- `` +- 部分 `blob:` 下载链接 + +## 步骤一:打包注入脚本 {#package-inject-scripts} + +目录结构: + +```text +content/ + lazycat-injects/ + open-save-chooser.js + vendor/ + lzc-file-pickers.umd.js +``` + +`content` 目录需要通过 `lzc-build.yml` 打进 LPK: + +```yml +pkgout: ./ +icon: ./icon.png +manifest: ./lzc-manifest.yml +contentdir: ./content +``` + +打包后,运行时路径会对应到: + +```text +/lzcapp/pkg/content/lazycat-injects/open-save-chooser.js +/lzcapp/pkg/content/lazycat-injects/vendor/lzc-file-pickers.umd.js +``` + +## 步骤二:在 manifest 中注入 {#inject-in-manifest} + +以下仅展示 `lzc-manifest.yml` 中和注入相关的配置: + +```yml +application: + injects: + - id: open-save-chooser + on: browser + when: + - /* + do: + - src: file:///lzcapp/pkg/content/lazycat-injects/vendor/lzc-file-pickers.umd.js + - src: file:///lzcapp/pkg/content/lazycat-injects/open-save-chooser.js +``` + +注意: + +1. 顺序不能反。必须先注入 `lzc-file-pickers.umd.js`,再注入 `open-save-chooser.js`。 +2. 正式发布建议使用 `file://` 加载随 LPK 分发的脚本,不建议依赖远程脚本。 +3. `when` 应尽量收窄到需要文件能力的页面。如果应用只有一个入口,可以使用 `/*`。 + +## `open-save-chooser.js` 的关键配置 {#script-config} + +桥接脚本顶部有集中配置: + +```js +const CONFIG = { + diskRoot: "/_lzc/files/home", + pickerTag: "lzc-file-picker", + fallbackMime: "application/octet-stream", + hooks: { + fileSystemAccess: true, + fileInput: true, + }, +}; +``` + +字段说明: + +- `diskRoot`:懒猫网盘 HTTP 文件接口根路径。常见值是 `/_lzc/files/home`。 +- `pickerTag`:文件选择器自定义元素标签。常见值是 `lzc-file-picker`。 +- `fallbackMime`:无法从扩展名推断 MIME 时使用的兜底类型。 +- `hooks.fileSystemAccess`:是否接管 `showOpenFilePicker()` 和 `showSaveFilePicker()`。 +- `hooks.fileInput`:是否接管 ``。 + +## 降级策略 + +注入脚本应保证“懒猫网盘能力不可用时,不阻断应用原流程”。 + +建议行为: + +1. 如果 `` 没有注册,打开和保存应回退到浏览器原生文件能力。 +2. 如果用户取消选择,应返回与浏览器原生取消一致的结果。 +3. 如果写入懒猫网盘失败,应向调用方返回明确错误,避免静默丢数据。 + +## 验证 + +1. 检查脚本语法: + +```bash +node --check content/lazycat-injects/open-save-chooser.js +``` + +2. 检查 manifest 和打包配置: + +```bash +lzc-cli project lint . +``` + +3. 生成 LPK: + +```bash +lzc-cli project release . +``` + +4. 确认静态资源进入包内: + +```bash +tar -tf your-app.lpk +``` + +如果顶层包含 `content.tar`,继续展开检查,应能看到: + +```text +lazycat-injects/open-save-chooser.js +lazycat-injects/vendor/lzc-file-pickers.umd.js +``` + +## 常见错误 + +1. 只写了 `application.injects`,但没有在 `lzc-build.yml` 中配置 `contentdir`,导致运行时 `file:///lzcapp/pkg/content/...` 找不到文件。 +2. 注入顺序写反,桥接脚本执行时 `` 还未注册。 +3. 从示例应用复制了无关的 `file_handler`。只有应用确实需要注册某种文件类型打开方式时,才应配置 `file_handler`。 +4. 目标应用没有使用浏览器文件 API,导致注入成功但看不到效果。 +5. 桥接脚本依赖 Node API。browser inject 运行在真实浏览器页面中,只能使用浏览器 API。 + +## 下一步 + +1. 如果应用需要服务端访问用户文件,请继续阅读 [文件访问](./advanced-file.md)。 +2. 如果需要按页面或 hash 路由精确控制注入范围,请继续阅读 [脚本注入(injects)](./advanced-injects.md)。