diff --git a/.workbuddy/memory/2026-09-03.md b/.workbuddy/memory/2026-09-03.md index a92e04d..494591a 100644 --- a/.workbuddy/memory/2026-09-03.md +++ b/.workbuddy/memory/2026-09-03.md @@ -275,4 +275,18 @@ - **junction 重建**:node `unlinkSync` 删旧链(rmdir 对 junction 报 Not a directory)→ PowerShell New-Item Junction `短视频工作台`→`D:\...\project\短视频脚本创作\V1.0\`;验证 isSymbolicLink:true/children:7/frontmatter name=短视频工作台/md5 一致 - **残留核查**:全仓剩 35 行全部可保留分类(产品叙事 13/流程术语 4/能力描述+变更记录 4/历史审计 4/repo 路径字面量 9/失误记录 1),技能名指称清零 - 版本 ?v=20260903r;commit 057522c -- **待办**:dsh 副本 short-video-script name 仍「短视频脚本创作」待授权同步;用户环境安装包技能名=短视频工作台 +- **待办**:用户环境安装包技能名=短视频工作台(仅剩此项,dsh 已同步见下) +- **R32 补完:dsh 副本同步改名(09-03 16:5x,commit 5bc1f49)**:用户「按方案 B 完整档修改」授权 → 同步 `C:\Users\maidou\.dsh\skills\short-video-script\`:SKILL.md name→短视频工作台 + description 前缀「短视频工作台(短视频脚本创作全流程技能):」+ 标题 `# 短视频工作台 Skill` + last_change 前缀照源 V1.0 写法追加改名记录;帮助文档 L1→`# 短视频工作台 — 使用指南`(源格式无「技能」字样);deployment:"dsh"/deployed_at 保留;残留 5 处全保留(description 括号能力描述/last_change/L22 能力描述/references 创作师角色 2)与源处理一致;git add 精确两文件,不混入 .dsh 仓库其他未提交变更(mcn-data-insight 等仍在工作区) + +## R33 工作台榜单页「更新」按钮(09-03 晚间) +- **需求**:热点数据三榜页加更新图标(用户中途改纯图标去文字),点击确认后后台任务重抓三榜最新一期并落盘;执行前检查上次更新防重复 +- **后端 server.js 顶层新增**:`RANK_UPDATE_NAME='更新榜单数据'`(固定任务名=防重识别键)+ `RANK_UPDATE_COOLDOWN_MS=30min` + `wbDb()`(宿主库 `~/.workbuddy/workbuddy.db`)+ `createOnceAutomation(name,prompt,skillsArr)`(自 /api/run 抽公共一次性任务创建:once+next_run_at +5s/owner 取最近会话/model 动态跟随/skills 参数级挂载)+ `rankLastTaskState()`(按固定任务名查最近状态,running/queued/pending=进行中) +- **接口**:`GET /api/dsh/ranking-update` 返回新鲜度(exists/files/latestMtime→lastUpdateAgeMin/lastUpdateDate/cooldownMin/task);`POST {prompt,force}` 双层防重:①任务进行中直接拦截 ②距上次落盘 <30min 且未 force → `needForce:true`;通过则 createOnceAutomation(name, prompt, ['mcn-data-insight']) +- **数据层 dsh-data.js `rankingFreshness()`**:递归扫 RANKING_DIR(三榜子目录 账号周榜/视频热榜/点赞榜 + 根旧平铺回退)全部 .json → latestMtime/latestFile/latestDate/files(=最近成功落盘时刻) +- **前端 data-pages.js**:`SKILL_HINT_RANKING` 常量(mcn-data-insight 更新语义:fetch_week_ranks.py --board both 全品类单次 + douyin-top-account 5 赛道 + 幂等铁律 ls 跳过跳 API + 环境落盘目录)+ toolbar 标题行右 `.toolbar-right` 加 `#rankUpdate`(**纯图标**:`.btn-icon` + svgIcon('refresh',16) + title 悬停说明全链路)+ `updateRankingData()`:GET 状态→running 拦截 toast→确认 modal(上次更新时间/三榜范围;冷却窗口内黄字警示 `#b7791f` 按钮变「仍要更新」=force)→ POST→轮询 15min 上限→完成 `view._reload=null; router()` **整页重建**(meta 缓存闭包内,不重建拉不到新数据期);busy 态**不动 innerHTML**,改 title='榜单更新中…' + `.btn-busy` 类图标旋转 +- **style.css**:`.btn-icon`(padding 5px 9px inline-flex center)+ `.btn-busy .ic`(animation: req-spin 1s linear infinite,复用弹窗 spinner) +- **成本铁律**:modal 明示约 7 次红狐 API(2 作品榜调用 + 5 赛道账号榜),用户确认即豁免;抓取器幂等 ls 命中跳 API 防重复花钱 +- **版本**:index.html ?v=20260903r→s→t(style.css+data-pages.js 均到 t) +- **验证**:node --check 3 JS ✓;curl --noproxy GET 状态正常(files=73/lastUpdateAgeMin=124/task=null);POST 空 prompt 400;CDP 冒烟 `tmp/cdp-rank-update-smoke.mjs`(9225)纯图标版 9 项全 PASS(text='' + svg + title + modal 标题/三榜范围/上次更新/按钮文案/取消) +- **服务/工具坑(重踩)**:nohup+& 后台 node 随 bash 退出被回收 → 须 Bash run_in_background 直接托管前台;taskkill //PID Git Bash 语法错 → PowerShell Stop-Process -Force(返回 exit 1 但端口已释放);curl 全局 socks 代理 502 → 必须 --noproxy '*' +- **待实测**:首次真实点击任务链路(调度拾取→技能会话→抓取执行→落盘→页面重建出最新期) diff --git a/project/短视频脚本创作/V1.0/mcn-work-shop/dsh-data.js b/project/短视频脚本创作/V1.0/mcn-work-shop/dsh-data.js index 291b8df..6c4de3c 100644 --- a/project/短视频脚本创作/V1.0/mcn-work-shop/dsh-data.js +++ b/project/短视频脚本创作/V1.0/mcn-work-shop/dsh-data.js @@ -409,6 +409,32 @@ function rankingMeta(board = 'week') { return { dates, categories: collectCategories(board, files) }; } +// 榜单数据新鲜度(更新防重依据,09-03 新增):递归扫描 RANKING_DIR(三榜子目录 + 根目录旧平铺)全部 .json, +// 返回最新落盘文件的 mtime(=最近一次成功抓取完成时刻,任务落盘即刷新) +function rankingFreshness() { + const out = { exists: fs.existsSync(RANKING_DIR), latestMtime: 0, latestFile: '', latestDate: '', files: 0 }; + if (!out.exists) return out; + const walk = (dir) => { + let entries = []; + try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch (e) { return; } + for (const en of entries) { + const full = path.join(dir, en.name); + if (en.isDirectory()) walk(full); + else if (/\.json$/i.test(en.name)) { + out.files++; + try { + const st = fs.statSync(full); + if (st.mtimeMs > out.latestMtime) { out.latestMtime = st.mtimeMs; out.latestFile = full; } + } catch (e) {} + } + } + }; + walk(RANKING_DIR); + const m = String(out.latestFile).match(/(\d{4}-\d{2}-\d{2})\.json$/); + if (m) out.latestDate = m[1]; + return out; +} + function parseNum(v) { const s = String(v ?? ''); const m = s.match(/^([\d.]+)\s*(w|万)?$/i); @@ -541,6 +567,6 @@ function getRewriteStats(account = '') { module.exports = { dbAvailable, setFavorite, batchDelete, listTracks, listAccounts, listAccountVideos, getPersona, getAccountAnalysis, listVideos, getVideoDetail, getVideoScript, listRewrites, listStoryboards, listRecentScripts, - getReviewDetail, getReviewFull, getStats, rankingMeta, getRanking, DSH_DB, RANKING_DIR, + getReviewDetail, getReviewFull, getStats, rankingMeta, getRanking, rankingFreshness, DSH_DB, RANKING_DIR, listCustomScripts, getCustomScript, saveScript, getRewriteStats, }; diff --git a/project/短视频脚本创作/V1.0/mcn-work-shop/public/data-pages.js b/project/短视频脚本创作/V1.0/mcn-work-shop/public/data-pages.js index 685e62b..f1b8281 100644 --- a/project/短视频脚本创作/V1.0/mcn-work-shop/public/data-pages.js +++ b/project/短视频脚本创作/V1.0/mcn-work-shop/public/data-pages.js @@ -21,6 +21,10 @@ const SKILL_HINT_VIDEO_PARSE = '请调用 Skill 工具加载「mcn-dou-analysis 参考选题创作(有原视频,如视频行 AI创作):传 videoId/awemeId → rewrite_log.video_id 关联原视频; 自定义选题创作(无原视频,如账号列表 AI创作 弹窗):不传 videoId → video_id 留空,归「自定义选题创作」tab。 保存走本地服务 /api/dsh/script-save:server 自行解析 mcn-plugin.db 路径(跨开发机/dsh 环境最可靠),勿让 agent 猜库路径 */ +/* 榜单数据更新技能声明(09-03 新增:热点数据页「更新榜单」按钮 → 后台任务按 mcn-data-insight 落盘规范抓取三榜最新一期。 + 范围与调用次数已在点击确认弹窗中向用户明示并获授权(账号周榜 5 赛道 + 视频热榜/点赞榜,约 7 次红狐 API); + prompt 内保留「查询幂等铁律」与「落盘目录按环境解析」,禁止模型逐赛道/逐日循环浪费 API 配额 */ +const SKILL_HINT_RANKING = '请调用 Skill 工具加载「mcn-data-insight」技能(技能根目录 = 用户技能目录 ~/.workbuddy/skills/短视频工作台/subskills/mcn-data-insight/,先读取其 SKILL.md 及 references 规范;若 Skill 工具无法加载,请直接读取该目录下的 SKILL.md 文件)。本任务为「榜单数据更新」(工作台热点数据页更新按钮触发,用户已确认本次调用范围与次数):按 SKILL.md「榜单数据落盘规范」将热点数据三榜最新一期数据落盘到本地 抖音榜单/ 目录:① 视频热榜 + 点赞榜:运行 scripts/fetch_week_ranks.py --board both(全品类单次调用,禁止逐赛道/逐日循环);② 账号周榜:按 subskills/douyin-top-account 技能流程抓取保留 5 赛道(生活vlog/小剧场/亲子/美食/旅行)最新一期账号周榜,逐赛道写入 账号周榜/抖音周榜_{赛道}_{周一}.json;③ 落盘目录按技能规范按环境解析(开发机/用户环境 = 桌面 MCNSkill项目\\三方数据\\红狐数据\\抖音榜单\\;dsh 环境 = D:\\dshworkspace\\抖音榜单\\),新产物入 账号周榜/视频热榜/点赞榜 三个子目录,文件名保持 抖音周榜_ 前缀;④ 查询幂等铁律:每次调用前先 ls 目标目录,同榜名+赛道+数据日期文件已存在则直接跳过对应 API 调用(红狐 API 按次计费);⑤ 数据日期取 API 返回的榜单对应日期(最新一期),非获取时刻。完成后汇报:三榜各写入的文件路径与数据期、缓存命中跳过项、实际 API 调用次数。技能边界:只做榜单数据抓取与落盘,不做账号分析/脚本创作等其他能力。'; const saveHintOf = (ctx) => { const ref = Number(ctx.videoId) > 0; const lines = []; @@ -519,10 +523,14 @@ async function renderRanking(view) { let tab = 'week'; const tabLabel = () => { const t = RANK_TABS.find(([k]) => k === tab); return t ? t[1] : ''; }; // tab 切换 + 赛道选择 + 时间切换 同一行(标题行只放 返回 | 标题,tab + 筛选放标题下一行 .rank-toolbar) + // 09-03 更新榜单按钮放标题行最右(.toolbar-right):三榜 tab 切换与空态(无本地数据文件)均可见,便于首次抓取 const toolbar = (s, withFilters) => `
${withFilters ? `