feat(发布计划): 素材支持图片(图文)—— 上传视频/图片,发布流程共用一条 + 切号健壮性再修
用户实测反馈:"图片流程一样,现在也是点第一个" → 图片不做单独一套流程,只放开上传侧; 扩展名一路原样带到手机上(抖音按扩展名/MIME 判断视频还是图文,图片推成 .mp4 会变坏视频)。 · core/video_plan.py:VIDEO_EXTS + IMAGE_EXTS(jpg/jpeg/png/webp/heic) → MEDIA_EXTS; 报错文案改"不是视频/图片文件" · tasks/generic/publish_flow.push_video:ext 默认**从本地文件名取**(不再硬编码 .mp4); drop_old_copies 收到真实扩展名 · tasks/generic/task.py:删手机素材优先用推送时记下的 push_remote,其次按素材扩展名现算; 切号:等面板开稳再点(刚出现就点会被入场动画吞掉)、点完面板还开着(点的就是当前号) 就先关面板、一切以**回读**为准、回读窗口 12s→30s(换号会触发抖音整体重启,实测 77s 才回来); 失败时日志附带"当时屏幕上是什么"(亮屏/前台包/屏上文字)—— "点了没反应"一眼可判 · 骨架:先 stop_app 冷启动(抖音可能停在发布页/别的视频页,那种页面上没有「我」页签, 切号第一步就废);「校验账号」的选择器与「读名字」统一从 .env 取(漏了这一步会静默跳过 整个发布流程 —— 用户实际遇到的"直接完成、没发布"就是这个) · 界面:上传视频 → 上传视频/图片,accept 加 image/*,明细表"视频文件"→"素材文件",help 文案 · 文档:TASK_DEV §4.7 / API / DATA_MODEL / ARCHITECTURE / README 同步 · 测试:解析用例补图片(jpg/png/webp/大写 JPG 认,gif 不收)+ 改报错文案期望
This commit is contained in:
@@ -1,14 +1,14 @@
|
||||
// 视频发布计划(「发布计划」页)
|
||||
// 数据在 video_plan 表,服务层 core/video_plan.py,接口 /api/video_plan/*(web/video_plan_api.py)。
|
||||
//
|
||||
// 这一页要解决的事:人员批量传视频与标题 → 自动按文件名配到账号上 → 时间线看每天谁要发、
|
||||
// 这一页要解决的事:人员批量传素材(视频/图片)与标题 → 自动按文件名配到账号上 → 时间线看每天谁要发、
|
||||
// 发到哪一步了 → 到日子由任务把视频推到手机相册、走抖音发布流程 → 发布后抓分享链接存下来
|
||||
// (平台不长期囤视频,链接才是长期资产;后续铺评论也是用这个链接打开视频)。
|
||||
//
|
||||
// 三条与安全有关的约定(别改):
|
||||
// ① 上传**串行**:并发会打乱"无编号按顺序配"的顺序,还会撞 SQLite 回退模式的写锁
|
||||
// ② 上传前把队列**按文件名排序**并给用户看一遍顺序(FileList 的顺序在 Windows 上不稳定)
|
||||
// ③ 界面上同时显示"视频文件名"与"标题" —— 配错对这一眼就能看出来
|
||||
// ③ 界面上同时显示"素材文件名"与"标题" —— 配错对这一眼就能看出来
|
||||
var _rpRows = [], _rpDays = [], _rpStats = {}, _rpDisk = {}, _rpToday = '';
|
||||
var _rpTimer = null;
|
||||
|
||||
@@ -81,7 +81,7 @@ function renderReleaseTimeline() {
|
||||
if (!box) return;
|
||||
if (!_rpDays.length) {
|
||||
box.innerHTML = '<div class="empty" style="padding:20px;text-align:center">'
|
||||
+ '这个范围里没有计划 —— 点「上传视频」把素材传进来</div>';
|
||||
+ '这个范围里没有计划 —— 点「上传视频/图片」把素材传进来</div>';
|
||||
return;
|
||||
}
|
||||
box.innerHTML = _rpDays.map(function (day) {
|
||||
@@ -138,7 +138,7 @@ function rpCard(p) {
|
||||
var pv = p.push_verify || '';
|
||||
var pushTag = !pv ? ''
|
||||
: (pv === 'ok'
|
||||
? ' <span class="label label-success" title="已进相册索引,抖音选视频能看到它">已推送·相册可见</span>'
|
||||
? ' <span class="label label-success" title="已进相册索引,抖音选素材能看到它">已推送·相册可见</span>'
|
||||
: (pv === 'no_index'
|
||||
? ' <span class="label label-warning" title="文件在手机上,但没进相册索引 —— 相册/抖音里可能看不到它">已推送·相册未见</span>'
|
||||
: ' <span class="label label-warning">已推送·文件不在</span>'));
|
||||
@@ -207,7 +207,7 @@ function rpEnsurePolling() {
|
||||
}
|
||||
}
|
||||
|
||||
// ================== 上传:视频 ==================
|
||||
// ================== 上传:素材(视频/图片) ==================
|
||||
// 文件名规则与服务端一致(这里只做**本地预检**,真正的判定永远以后端为准)
|
||||
// `名字_日期_编号`:**右锚定** —— 末尾可省编号 → 日期 → 紧挨日期的那一段就是名字
|
||||
var _RP_DATE = /^\d{8}$/, _RP_SEQ = /^\d{1,3}$/;
|
||||
@@ -251,7 +251,7 @@ function rpPickVideos(input) {
|
||||
}
|
||||
|
||||
function rpShowUploadConfirm(rows) {
|
||||
document.getElementById('modal-title').textContent = '上传视频(' + rows.length + ' 个)';
|
||||
document.getElementById('modal-title').textContent = '上传视频/图片(' + rows.length + ' 个)';
|
||||
document.getElementById('modal-box').classList.add('wide-modal');
|
||||
var body = '<div class="help" style="margin-bottom:8px">'
|
||||
+ '确认下面每个文件解析出的账号与日期对不对(<b>传上去就按这个配</b>)。'
|
||||
@@ -385,7 +385,7 @@ function rpShowTitleConfirm(fname, text) {
|
||||
document.getElementById('modal-box').classList.add('wide-modal');
|
||||
document.getElementById('modal-body').innerHTML =
|
||||
'<div class="help" style="margin-bottom:6px">共 ' + lines.length + ' 行有效标题。'
|
||||
+ '每行 <code>标题 || 正文_名字_日期_编号</code>(<code>||</code> 后面是正文,可省略;编号可省,标题里可以有 <code>#话题</code>);<br>没写编号的按顺序配到该名字当天还没标题的视频上。</div>'
|
||||
+ '每行 <code>标题 || 正文_名字_日期_编号</code>(<code>||</code> 后面是正文,可省略;编号可省,标题里可以有 <code>#话题</code>);<br>没写编号的按顺序配到该名字当天还没标题的素材上。</div>'
|
||||
+ '<div style="max-height:50vh;overflow:auto;font-family:var(--mono);font-size:12px;white-space:pre-wrap">'
|
||||
+ esc(lines.slice(0, 200).join('\n')) + (lines.length > 200 ? '\n…' : '') + '</div>'
|
||||
+ '<div id="rp-title-result"></div>';
|
||||
|
||||
Reference in New Issue
Block a user