对接 Strapi CMS:awesome-seedance-2-prompts cms-client 提示词抓取与去重原理
【免费下载链接】awesome-seedance-2-prompts🎬 2000+ curated Seedance 2.0 video generation prompts — cinematic, anime, UGC, ads, meme styles. Includes Seedance API guides, character consistency tips, and advanced video workflows.项目地址: https://gitcode.com/gh_mirrors/aw/awesome-seedance-2-prompts
awesome-seedance-2-prompts 是一个收录 2000+ 条 Seedance 2.0 视频生成提示词的开源项目,覆盖电影感、动漫、UGC、广告、表情包等多种风格。它的核心能力之一是:通过 Strapi CMS 自动抓取提示词数据,并在"最新列表"与"精选列表"之间做 ID 级去重,最终一键生成 16 种语言的 README。本文将拆解 cms-client.ts 的抓取与去重原理,帮你理解这条自动化内容流水线的运作方式。
一、项目概览:一个会自己"长大"的提示词库
这个项目最聪明的地方,是它不靠人工复制粘贴维护内容,而是一条CMS → 脚本 → 多语言 README的自动化流水线:
- 数据源头:Strapi CMS 中的
video-prompts内容类型,收录原始提示词、作者、出处链接、视频缩略图等 - 抓取层:scripts/utils/cms-client.ts 负责发起 API 请求并清洗数据
- 生成层:scripts/generate-readme.ts 按 16 种语言逐一生成
README.md、README_zh.md等文件 - 媒体层:scripts/download-videos.ts 增量下载视频、压缩后上传,地址记录在 video-urls.json
整条链路只需一条命令即可运行:
pnpm generate二、抓取原理:一次"最新 + 精选"双源查询
核心函数是 fetchSeedancePrompts(),它并不是简单地拉取全量数据,而是拆成两次针对性查询,这是理解整套设计的钥匙。
2.1 为什么需要查两次?
| 查询 | 筛选条件 | 排序 | 数量 | 目的 |
|---|---|---|---|---|
| 最新列表 | model = seedance-2.0 | 按sourcePublishedAt倒序 | 200 条 | 保证新提示词不遗漏 |
| 精选列表 | model = seedance-2.0且featured = true | 按 CMS 的sort字段 | 100 条 | 保证运营手工排序的精选位不失效 |
问题的关键在于:一条提示词可能既是"最新的",又是"精选的",而且精选提示词往往发布时间较老,可能根本不在最新 200 条之内。如果只查最新列表,精选内容就会丢失;如果只查精选列表,新内容就进不来。所以必须双源查询,再合并去重。
2.2 请求细节
每次请求都携带Authorization: users API-Key请求头(密钥来自环境变量CMS_API_KEY),并通过 qs-esm 序列化查询参数。共享的查询参数(见 SHARED_QUERY_PARAMS)做了两点优化:
depth: 2:只展开两级关联字段,避免拉取过深的嵌套数据select: { sourceMeta: false, raw: false }:主动排除原始字段,减小响应体积
三、去重原理:用 Set 按 ID 合并,精选优先
两次查询的结果在 合并逻辑 中处理,思路非常简洁:
const seenIds = new Set<number>(); // 记录已见过的提示词 ID const allDocs: VideoPrompt[] = []; for (const doc of featuredData.docs) { // ① 精选优先入列 seenIds.add(doc.id); allDocs.push(doc); } for (const doc of mainData.docs) { // ② 最新列表跳过重复 ID if (!seenIds.has(doc.id)) { seenIds.add(doc.id); allDocs.push(doc); } }去重的关键就三处:
- 以 CMS 的主键
id作为唯一标识——这是最可靠的去重键,比标题、内容等文本字段更稳定 - 用
Set<number>做 O(1) 查重,万级数据量下依然开销极低 - 精选先入列、最新后入列——当同一条提示词同时出现在两个列表时,保留精选列表中的版本,确保运营方设置的
sort排序和featured标记不被最新列表覆盖
这样合并后,数组的顺序天然就是"精选在前、最新在后",直接决定了最终 README 中提示词的展示顺序。
四、清洗过滤:五级缩略图提取链
去重之后,每条文档还要经过 processDoc() 的标准化处理,其中最核心的"过滤闸门"是没有缩略图的提示词会被直接跳过——因为 README 中的每条提示词都配有一张可点击的视频封面。
extractThumbnail() 定义了五级降级提取链,按优先级依次尝试:
| 优先级 | 数据源 | 说明 |
|---|---|---|
| 1 | videos[] | Cloudflare Stream 缩略图或海报 |
| 2 | results.docs[].video | 关联结果中的视频封面 |
| 3 | sourceVideos[] | 外部源视频自带缩略图 |
| 4 | media[] | 图片型提示词,优先用 CDN 裁切的sizes.thumbnail |
| 5 | sourceMedia[] | 兜底的外部媒体地址 |
这种"逐级降级"的写法让脚本对不同年代、不同字段结构的 CMS 数据都有容错能力——新数据走 Cloudflare Stream,老数据也能靠sourceMedia兜底,保证不会因为字段差异而漏掉内容。
同理,参考图与媒体图也都遵循"结构化字段优先、sourceXxx平铺字段兜底"的双通道策略(见 参考图提取)。
五、增量更新:让每次生成都更便宜
抓取结果并不是每次都从零开始处理,generate-readme.ts 中设计了增量机制:
- 视频增量下载:
video-urls.json记录了"提示词 ID → Release 下载地址"的映射,只处理映射中不存在的新提示词(DOWNLOAD_VIDEOS=auto模式) - README 全量重写:每次对 16 种语言(见 SUPPORTED_LANGUAGES)重新拉取并生成,保证多语言版本始终与 CMS 同步
配合 upload-to-github.ts 把压缩后的视频上传到 Release 并回写 URL,整条流水线实现了"只增量处理新增、全量保证一致"的平衡。
六、小结
| 设计点 | 做法 | 收益 |
|---|---|---|
| 双源查询 | 最新 200 条 + 精选 100 条分开拉 | 新内容与运营精选都不丢失 |
| ID 级去重 | Set<number>+ 精选优先 | 合并后顺序即展示顺序,逻辑极简 |
| 五级缩略图提取 | 结构化字段逐级降级到 source 兜底 | 兼容新旧数据结构,无图才丢弃 |
| 增量视频处理 | video-urls.json映射新 ID | 重复运行成本低、速度快 |
整套原理浓缩在一百多行的 cms-client.ts 中,却支撑起了 2000+ 条提示词、16 种语言 README 的日常自动更新。对于想学习"如何用 CMS 驱动文档生成"的同学,这套双源查询 + ID 去重 + 字段降级兜底的组合拳,是一个可以直接借鉴的轻量级数据管道范例。
【免费下载链接】awesome-seedance-2-prompts🎬 2000+ curated Seedance 2.0 video generation prompts — cinematic, anime, UGC, ads, meme styles. Includes Seedance API guides, character consistency tips, and advanced video workflows.项目地址: https://gitcode.com/gh_mirrors/aw/awesome-seedance-2-prompts
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考