From 3bd7f636a0230b83bdd48fbbe674dbcd8c94d0a4 Mon Sep 17 00:00:00 2001 From: butubb <1422726308@qq.com> Date: Mon, 12 Oct 2026 14:57:01 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E5=A4=A7=E5=B1=8F):=20=E9=A1=B6=E9=83=A8?= =?UTF-8?q?=E5=8A=A0=E3=80=8C=F0=9F=93=A4=20=E5=8F=91=E5=B8=83=E3=80=8D?= =?UTF-8?q?=E6=8C=89=E9=92=AE=20=E2=80=94=E2=80=94=20=E9=80=89=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E7=9B=B4=E6=8E=A5=E6=B3=A8=E5=85=A5=E8=A7=86=E9=A2=91?= =?UTF-8?q?/=E5=9B=BE=E7=89=87=E3=80=81=E6=B3=A8=E5=85=A5=E5=89=AA?= =?UTF-8?q?=E8=B4=B4=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 用户要求:"大屏按钮右边加一个按钮叫发布,就是选择设备号注入视频或者图片,位置就和发布页面的一样, 然后还有在选择设备号注入剪贴板"。 大屏(`/wall`)顶栏「一键亮屏」右边加 **「📤 发布」**,点开是一块面板: · **设备**下拉(设备名 + 地址,离线会标注;每次打开现取最新列表) · **视频 / 图片**:选文件 → 「注入素材」→ 推到该机相册 `/sdcard/DCIM/Camera` · **剪贴板文字**:填一段 → 「注入剪贴板」→ 写进该机剪贴板(发文案用) · 面板下方是操作日志(✅/❌ + 原因),失败会写清为什么 后端(`web/tools_api.py`,都按 **设备位** 放行 —— 大屏上随手一推是设备操作,不该要管理员位): · `POST /api/tools/push_material`(form-data:file + serial): 保存上传 → `publish_flow.push_video` 推到相册(文件名带 `wall` 前缀、mtime 改成现在, 保证它在相册里排最前)→ `verify_pushed` 校验进没进相册索引 → 返回 `{ok,msg,remote,verify}` · **不占位、不写库**:与「发布计划 → 推送」是两回事(那条按计划走占位/去重/回写状态); 这条是"手上有一段素材,想马上在这台机器上发" · 扩展名按 `video_plan.MEDIA_EXTS` 校验(视频+图片),不在其中 → 400;设备不在线 → 400 · 临时目录用完即删(`finally` 里 rmtree) · `POST /api/tools/push_clipboard`:与 `/api/tools/clipboard/set` **同一个实现** (`_set_device_clipboard`),只是权限位不同 真机验过(A01):剪贴板注入 ✅;1×1 测试图推到相册 ✅(`verify=no_index` 的 ⚠ 是这张图太小、 媒体库没索引它,真视频/图片是 ✅);`.txt` 被 400 拦住 ✅;测试文件已从手机删掉、不留痕。 文档:doc/API.md 加两条接口(含请求/返回/错误口径)、README 实时看屏那行补上发布面板。 --- README.md | 2 +- doc/API.md | 4 ++ templates/admin/wall.html | 112 ++++++++++++++++++++++++++++++++++++++ web/tools_api.py | 103 ++++++++++++++++++++++++++++++++++- 4 files changed, 218 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index aeb583d..e9a9402 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ | **去重账本** | 解决"**同一个号被做两次、有的号还没做**":任务里用「条件判断→去重」+「记为已做」,把"这个身份做过了"记进一张**所有设备共享**的账本——多台手机、反复重跑都不会重复做同一个号。「任务 → 去重记录」页能看"谁做过了、还差谁",也能删记录让它重跑(见 [TASK_DEV.md](doc/TASK_DEV.md) §4.6) | | **视频发布计划** | 「发布计划」页:批量上传**视频/图片**(文件名 `名字_日期_编号`,**名字 = 抖音昵称**;视频和图片同一套规则)与标题 txt(每行 `标题 || 正文_名字_日期_编号`)→ 自动按 (名字,日期,编号) 配对 → **按日期的时间线**看每天谁要发、发到哪一步。**平台只负责把素材推到手机**(推到 `/sdcard/DCIM/Camera/`、触发相册刷新、把标题写进剪贴板),**抖音里怎么发由你自己在任务里写步骤**(步骤顺序:`读取本机账号名字` → `条件判断`校验 → `推送发布视频` → 你的发布步骤 → `标记发布结果`;页顶部有**「发布任务」**块可一键建好骨架 + 看下次运行/启停,`输入文字` 那一步可以选**取值来源=计划标题/正文**自动填文案并回读校验);发完可抓作品的**分享链接**存下来(平台不长期囤视频,链接才是长期资产,也方便后续铺评论:可一键复制、按日期/名字导出 CSV)。状态区分"**可重试**"(推送阶段失败,还没到抖音)与"**结果未知、需人工确认**"(推送之后出的岔子,绝不自动重发)(见 [DATA_MODEL.md](doc/DATA_MODEL.md) §2.11、[TASK_DEV.md](doc/TASK_DEV.md) §4.7) | | **元素抓取** | 拉取设备 UI 元素树 → 点选回填选择器;支持"点一下"与"测选择器"真机验证 | -| **实时看屏** | MJPEG 实时流 + 点击/滑动/按键/文字输入;全屏监控大屏(`/wall`) | +| **实时看屏** | MJPEG 实时流 + 点击/滑动/按键/文字输入;全屏监控大屏(`/wall`):每个设备卡片点开就能操作,顶部还有 **「📤 发布」面板** —— 选设备直接把视频/图片推到相册、或把文案写进剪贴板(临时手动推,不占发布计划、不写库) | | **应用管理** | APK 上传/解析/批量安装;设备已装应用与版本查询;剪贴板注入 | | **AI 控制台** | 用自然语言驱动 AI 操作指定设备(MCP 工具 + 截图),流式输出、Markdown 渲染、推理链折叠、token 统计;成功操作自动沉淀「经验库 / 动作库」并在相似任务中召回 | | **MCP 接入** | 20 个 `de_*` 工具,把手机控制开放给外部 AI;写操作有开关、设备忙时拒绝、全量审计 | diff --git a/doc/API.md b/doc/API.md index 783c108..48eb4a1 100644 --- a/doc/API.md +++ b/doc/API.md @@ -211,6 +211,8 @@ | GET | `/api/adb/devices` | Admin | 维护终端设备列表(本机 adb + 设备池) | | POST | `/api/adb/cmd` | Admin | 执行 adb 命令(20s 超时;拦截 `kill-server`/`disconnect`) | | POST | `/api/tools/clipboard/set` | Admin | 剪贴板注入到多台设备 | +| POST | `/api/tools/push_clipboard` | D | 同上(**同一个实现**),权限按设备位放行 —— 大屏「发布」面板用 | +| POST | `/api/tools/push_material` | D | 大屏「发布」面板:把上传的视频/图片**直接推到指定设备**相册(不占发布计划) | | POST | `/api/tools/appver` | Admin | 查指定包名在所有在线设备的版本 | ### 2.8 tailscale(`web/tailscale_api.py`,全部 Admin) @@ -771,6 +773,8 @@ | 接口 | 请求 | 说明 | |------|------|------| | `POST /api/tools/clipboard/set` | `{"serials":[…],"text":"…"}` | 设备端 Agent 通道写入并读回校验(旧版独立 ClipInject 自动兜底);serials 空或非列表 → 400 | +| `POST /api/tools/push_clipboard` | `{"serial":"…"}`(或 `serials:[…]`)+ `{"text":"…"}` | 与上一条**同一个实现**(`_set_device_clipboard`),权限**设备位**即可 —— 大屏「发布」面板注入剪贴板用 | +| `POST /api/tools/push_material` | form-data:`file`(视频/图片)+ `serial` + `album_dir`(可省) | 大屏「发布」面板:推文件到该设备相册(默认 `/sdcard/DCIM/Camera`,文件名带 `wall` 前缀、mtime 改成现在)。**不占位、不写库**;扩展名不在 `MEDIA_EXTS` 或设备不在线 → 400;推完做相册索引校验,返回 `{ok,msg,remote,verify,size}`(`verify=no_index` 时 `ok=true` 但文案带 ⚠) | | `POST /api/tools/appver` | `{"package":"com.xxx"}` | 并发查所有在线设备(≤10 并发);包名须匹配 `^[A-Za-z0-9_.]+$` | ### Tailscale(全部 Admin) diff --git a/templates/admin/wall.html b/templates/admin/wall.html index 40723f9..27fb70f 100644 --- a/templates/admin/wall.html +++ b/templates/admin/wall.html @@ -117,6 +117,23 @@ main{position:relative;z-index:2;height:calc(100vh - 88px);overflow-y:auto;paddi .ctrl-tools .text-row{display:flex;gap:6px;flex:1 0 100%;margin-top:2px} .ctrl-tools .text-row input{flex:1;background:#0d1117;border:1px solid var(--card-line);border-radius:8px;padding:6px 10px;font-size:12px;color:var(--text);outline:none;font-family:var(--body)} .ctrl-tools .text-row input:focus{border-color:var(--teal)} +/* 大屏「发布」面板:选设备 → 推视频/图片到相册、写剪贴板 */ +.pub-label{display:block;font-size:12px;font-weight:600;color:var(--muted);margin-bottom:5px} +.pub-input{width:100%;box-sizing:border-box;background:#0f1319;border:1px solid var(--card-line); + color:#e5e9f0;border-radius:8px;padding:8px 10px;font-size:13px;font-family:var(--body)} +select.pub-input{padding:7px 8px} +.pub-btn{background:#1a2029;border:1px solid var(--card-line);color:var(--teal);border-radius:8px; + padding:8px 14px;font-size:13px;font-weight:600;cursor:pointer;font-family:var(--body);transition:all .12s} +.pub-btn:hover{border-color:var(--teal)} +.pub-btn:disabled{opacity:.55;cursor:not-allowed} +.pub-hint{font-size:11.5px;color:var(--faint);margin-top:5px;line-height:1.55} +.pub-log{margin-top:2px;font-size:12px;color:var(--muted);max-height:132px;overflow:auto; + background:#0f1319;border:1px solid var(--ink-line);border-radius:8px;padding:8px 10px; + white-space:pre-wrap;word-break:break-all} +.pub-log:empty{display:none} +.pub-log .ok{color:var(--green)} +.pub-log .err{color:#f87171} + /* 滚动条 */ ::-webkit-scrollbar{width:8px} ::-webkit-scrollbar-thumb{background:#232936;border-radius:4px} @@ -131,6 +148,7 @@ main{position:relative;z-index:2;height:calc(100vh - 88px);overflow-y:auto;paddi 只看在线 +