feat(发布计划): 改按名字发(文件名 名字_日期_编号)+ 账号管理整页下线 + 自动切号一轮发完

发布计划不再绑设备、不再依赖账号台账:上传文件名 `名字_日期_编号`(标题行
`标题 || 正文_名字_日期_编号`),运行时读本机当前抖音昵称取计划;靠循环块
「一轮把本机待发的号跑完」自动切号,一直发到发完。

· 解析/配对换键:右锚定认名字(不许含下划线、不许纯数字 —— 不合法直接拒收并说清原因),
  删掉三处"手机号必须命中台账"的校验,加索引 ix_video_plan_name_date(启动时补建)
· 新步骤三个:读本机账号名字 / 切换账号(**按名字点控件**、切完回读校验、遇登录页停本设备)/
  循环本机待发的号(试过不回头、跑一轮没进展就换号、停止·超时·上限三个干净出口)
· 发布骨架改 18 步:读名字 → 校验账号(cmp_source=account_target)→ 推送(**推送前重读昵称核对**)
  → 抖音流程 → 标记结果;push_release 的 account 默认 name
· 账号管理整页下线:删 core/ledger.py(serial_of 迁到 core/device_pool.py)、6 个 /api/ledger*、
  「账号」页与 ledger.js、设备池「账号」列、设备端账号块;发布计划升为一级页签;
  device_account 表与 42 行历史数据保留、仍在备份清单内(**停用不等于删数据**)
· 人工入口「按名字找设备」:新增 core/account_probe.py(只读探测、跳过在跑任务的设备)
  + POST /api/video_plan/push_by_account,没设备登着的号逐条报出来;
  推送时把"实际是谁发的"写进 posted_serial / posted_device_name
· 通知:新增 task.account.switch_failed / task.account.need_login
· schema v12(posted_*)/ v13(device.cur_account_name / cur_name_at)
· 文档同步:TASK_DEV / API / DATA_MODEL / ARCHITECTURE / NOTIFY / DEVICE_AGENT / DEPLOY /
  DEVELOPMENT / README / .env.example(两个抖音控件选择器抓一次填 .env)
· 新增 scripts/tests/:6 套用例 + run_all.py(临时库 + 假设备,不碰真实数据、不连真机)
This commit is contained in:
2026-10-12 09:02:40 +08:00
parent 75bee21ffb
commit beda0f3779
37 changed files with 2615 additions and 1747 deletions
+3 -55
View File
@@ -17,9 +17,7 @@
管理端接口在文件后半段(`/api/agent-store/*`,走正常登录 + 权限)。
"""
import base64
import hmac
import json
import os
import secrets
import time
@@ -27,7 +25,7 @@ import time
from flask import Blueprint, jsonify, request, send_file
from config import APK_DIR
from core import device_pool, ledger
from core import device_pool
from core.db_config import meta_get, meta_set
from core.logger import get_logger
from web.auth import PERM_APKS, PERM_DEVICES, perm_required
@@ -319,32 +317,9 @@ def api_agent_show_info():
"--es", "server", server]
if ip:
args += ["--es", "ip", ip]
# 本机账号台账(可选块):身份页顺带显示"这台登的是哪几个号"。
# **中文必须 base64**(§5.1:adb shell 直传中文/特殊字符会变形);
# `_adb` 是 argv 形式、不过 shell,base64 里的 +/= 安全 —— 将来谁把
# 这里改成 shell=True 就会静默坏掉,别改。
# 台账里没有这台设备时**整个 extra 不发**(设备端"没有这个 extra"=
# 本来就没登记,跟"发了但解不开"能区分开),原因随响应体的 warn 回给操作者。
# 账号台账块(`accounts_b64`)随账号管理一起下线了:身份页只显示
# 名称/地址/平台地址这些设备信息。老版本 Agent 收到"没有这个 extra"照常显示。
warn = ""
try:
acc = ledger.agent_accounts(serial, device_name=name,
include_phone=bool(data.get("include_phone")))
if acc.get("accounts"):
b64, acc = _encode_accounts(acc)
if len(b64) + sum(len(a) for a in args) < _ARGS_CMD_MAX:
args += ["--es", "accounts_b64", b64]
_log.info("身份页附账号:%s 共 %s 个号(accounts_b64 %d 字节)",
serial, acc.get("shown"), len(b64))
else:
warn = "账号台账过大,未随身份页下发"
_log.warning("身份页未附账号:%s %s(%d 字节)", serial, warn, len(b64))
else:
warn = f"这台设备在账号台账里没有账号({acc.get('note') or '未匹配到设备名'})"
_log.warning("身份页未附账号:%s %s", serial, warn)
except Exception as e:
# 台账坏了不能把"显示身份"这个动作弄坏:跳过该 extra,只回告警
warn = f"账号台账读取失败:{e}"
_log.warning("身份页附账号失败 %s: %s", serial, e)
# 先点亮屏幕、解除锁屏:设备息屏时 am start 会把大字页开在锁屏**后面**,
# 人看到的还是一片黑(实测踩过)——这正是原来"定位"按钮里的"点亮屏幕"那一步
@@ -373,33 +348,6 @@ def api_agent_show_info():
return jsonify(resp)
# accounts_b64 的预算:44 条 × ~90 字节 ≈ 4KB,base64 后 ≈ 5.3KB,余量充足。
# 再加一道**命令行总长**闸(Windows CreateProcess 上限 ~32767)。
ACCOUNTS_PAYLOAD_MAX = 20000
_ARGS_CMD_MAX = 28000
def _encode_accounts(acc):
"""把账号块压成 base64(超预算**按整条丢**,永不按字节切)。
按字节切会产出破损 JSON —— 设备端解析失败只能整块丢掉,
还不如少几条但能解开(`truncated`/`shown` 如实反映)。
返回 (base64 文本, 修正后的块)。
"""
acc = dict(acc or {})
rows = list(acc.get("accounts") or [])
total = acc.get("total", len(rows))
while True:
block = dict(acc, accounts=rows, shown=len(rows),
truncated=len(rows) < total)
b64 = base64.b64encode(
json.dumps(block, ensure_ascii=False, separators=(",", ":")).encode("utf-8")
).decode("ascii")
if len(b64) <= ACCOUNTS_PAYLOAD_MAX or not rows:
return b64, block
rows = rows[:-1]
@bp.route("/api/agent-store/config", methods=["GET", "POST"])
@perm_required(PERM_APKS)
def api_agent_store_config():