简介:这是一份基于n8n构建全自动短视频生产线的项目源码包,适合具备一定n8n基础、希望实现AI文案生成、自动成片并发布到YouTube的内容创作者或开发者。资源将n8n、Gemini API、MoneyPrinterTurbo与YouTube Data API串联为完整工作流,支持Ubuntu/Debian/macOS/WSL2环境,纯CPU即可运行。压缩包共11个文件,包含yml编排文件、sh安装脚本、env环境变量示例、json工作流定义、py辅助脚本及md说明文档等,结构清晰便于快速部署与二次开发。目前已有118人学习参考。通过本包可直接导入n8n工作流、了解Docker环境搭建要点与脚本部署方法,同时获得常见问题解决方案和后续扩展方向,可有效缩短从创意到视频上线的开发周期。
1. 为什么是n8n:短视频工厂的底座选型逻辑
先交代一下背景。我手上同时运营着三个垂直领域的短视频账号,每周要产出15条以上的成片。最开始完全是手工作坊:找素材、写脚本、配音、剪辑、加字幕、发布、定时维护评论,一个团队三个人,每天被流程黏死,产出还不稳定。后来我意识到,这个事儿本质上不是"创作"问题,而是"流水线"问题——短视频的生产链条极其标准化,完全可以拆成独立的环节,用自动化把它们串起来。
当时摆在我面前的有三条路:一是直接用Python写一套调度系统,配合Celery或Airflow;二是用现成的RPA工具,比如按键精灵或某商业自动化平台;三是用n8n这种可视化工作流引擎。第一条路我直接否了,因为纯代码方案意味着以后每个环节的改动都要动代码、重新部署、处理各种依赖,运营同学完全没法参与,一个人扛全部迭代成本。第二条路的问题在于商业RPA对API支持极差,遇到开放平台接口就要写自定义组件,最后一样变成半代码项目。
最后选了n8n,核心逻辑很简单:n8n把"流程编排"和"业务逻辑"解耦了。脚本生成、素材抓取、视频渲染这些重度逻辑我用自定义节点或Python脚本来做,而流程编排、触发条件、数据传递、失败重试、多平台分发这些通用能力直接靠n8n的节点图来实现。运营同学想要调整发布频率、修改分发平台,画流程图就能改,不需要找我写代码。这个取舍在后来的半年里被证明是划算的。
n8n本身是开源的,可以完全自托管,数据不会经过第三方云。这一点对后面接入各平台API、批量发视频很重要——用云服务版我反而会担心凭证和素材安全。
项目落地后,整体架构长这样:
- 数据层:MySQL存账号信息和内容清单,Redis做队列和缓存
- 编排层:n8n主服务负责流程调度、定时触发、条件分支、重试策略
- 执行层:自定义Python脚本节点处理AI文案、素材抓取、视频渲染
- 分发层:通过各平台开放API批量发布,状态回写到数据层
这套架构跑通之后,从选题到发布全程无人值守,人力从三个人缩到一个人,产出量还翻了一倍。下面我把搭建过程中的关键决策和踩坑都写出来。
2. 本地部署到企业级集群:环境准备是第一个大坑
n8n的安装本身不复杂,复杂的是"装完能不能稳定跑生产"。我最初是在一台4核8G的云服务器上直接用Docker跑单机版,结果跑了不到两周就出问题:定时任务一多,节点执行到一半就OOM,n8n主进程直接挂掉。后来我查了日志,发现是执行线程队列堆积,每个视频渲染节点要开一个Python子进程,内存一下就爆了。
所以如果你想跑真正的生产负载,单机Docker只适合开发测试,不太适合直接上线。我的建议是直接从企业级部署方案起步,一步到位。
2.1 生产环境的部署架构
我现在的部署方式是经典的n8n主实例+worker模式:
- 主实例(main):跑Web界面、webhook触发器、负责编排调度,不执行重型任务
- worker节点(worker):执行所有实际业务节点,可以水平扩容
- Redis:作为队列后端,主实例把任务分发给worker
- PostgreSQL:生产数据库,比默认的SQLite更适合高并发
- Nginx:反向代理,配置HTTPS
用Docker Compose可以把这套堆起来,关键配置如下:
version: "3.8" services: n8n-main: image: n8nio/n8n:latest command: start environment: - N8N_MODE=main - N8N_ENCRYPTION_KEY=your-encryption-key - DB_TYPE=postgresdb - DB_POSTGRESDB_DATABASE=n8n - DB_POSTGRESDB_HOST=postgres - DB_POSTGRESDB_PORT=5432 - DB_POSTGRESDB_USER=n8n - DB_POSTGRESDB_PASSWORD=your-db-password - QUEUE_BULL_REDIS_HOST=redis - QUEUE_BULL_REDIS_PORT=6379 - N8N_DIAGNOSTICS_ENABLED=false - N8N_PERSONALIZATION_ENABLED=false ports: - "5678:5678" depends_on: - postgres - redis n8n-worker: image: n8nio/n8n:latest command: worker --concurrency=10 environment: - N8N_MODE=worker - N8N_ENCRYPTION_KEY=your-encryption-key - DB_TYPE=postgresdb - DB_POSTGRESDB_DATABASE=n8n - DB_POSTGRESDB_HOST=postgres - DB_POSTGRESDB_PORT=5432 - DB_POSTGRESDB_USER=n8n - DB_POSTGRESDB_PASSWORD=your-db-password - QUEUE_BULL_REDIS_HOST=redis - QUEUE_BULL_REDIS_PORT=6379 depends_on: - postgres - redis - n8n-main postgres: image: postgres:15 environment: - POSTGRES_USER=n8n - POSTGRES_PASSWORD=your-db-password - POSTGRES_DB=n8n volumes: - postgres_data:/var/lib/postgresql/data redis: image: redis:7-alpine command: redis-server --appendonly yes volumes: - redis_data:/data volumes: postgres_data: redis_data:这里有个非常关键的配置:N8N_ENCRYPTION_KEY。这个值是用来加密保存凭证信息的密钥,如果你不手动指定,n8n首次启动时会自动生成一个。问题在于,当你从单机版迁移到集群模式、或者重新部署容器时,如果加密密钥变了,之前保存的所有credentials都没法解密了。我早期就吃过这个亏,所有平台的API密钥全部重配了一遍。生产环境务必在部署时固定这个环境变量。
2.2 凭证管理的几个细节
紧接着上面的话题,说说credentials。短视频工厂要接的内容平台和AI服务非常多,我维护着十几组凭证:
- 大模型API的Key(文案生成)
- 各短视频平台的开放平台凭证(发布)
- 素材网站的抓取凭证
- 对象存储的AccessKey(存视频文件)
n8n的凭证管理本身做得不错,它会把凭证加密后存入数据库,Web界面上不会明文显示。但有几个坑需要注意:
第一,凭证作用域。n8n里凭证默认是"所有用户共享"的。如果团队多个人都在编辑工作流,任何能编辑工作流的人都能调用但看不到明文,这一点还好。不过我的建议是创建专门的服务账号来做自动化,不要把个人账号的凭证绑进去,防止有人离职导致凭证失效。
第二,凭证轮换机制。很多平台API的token有有效期,比如有的平台access_token是7天过期,需要refresh_token刷新。n8n本身不负责token轮换,我是在工作流里专门做了一个"定时刷新token"子工作流,每天早上跑一次,把新token写回数据库,其他工作流从数据库动态读取。这个子工作流属于整个工厂的"基础设施",一旦挂了所有发布流程都会挂,所以我给它配了独立的失败告警。
第三,不要在凭证内容里用特殊字符。这是我实际遇到过的问题:某个平台的client_secret里带有$符号,在n8n环境变量里被解析成了变量引用,导致鉴权一直失败。排查了很久才定位到是环境变量转义问题。后来我统一把包含特殊字符的凭证改成通过n8n界面的credential管理录入,不再走环境变量注入。
3. 核心流水线的设计:从热点抓取到多平台发布
短视频工厂的整个流程,我把它分成了7个核心环节。如果你要用n8n搭一套类似的系统,这7个环节可以作为你设计工作流的骨架。
这是一个完整的工作流流转:
- 定时触发:每天8点和14点各触发一次
- 热点选题:从各平台热榜抓取关键词
- AI文案生成:基于热点生成3个方向的脚本
- 素材采集:根据脚本关键词自动搜索并下载免费素材
- 字幕与配音:调用TTS服务生成配音,语音识别生成字幕
- 视频渲染:用FFmpeg合成最终成片
- 多平台分发:发布到各短视频平台,并更新内容管理表
在n8n中,我并不是把这7个环节全画在一张巨大的画布里——那样维护成本太高。正确的做法是拆成多个子工作流,用n8n-nodes-base.executeWorkflow来调用,或者用webhook做跨工作流触发。
我是这样拆的:
- 主调度流:定时触发,维护任务状态,按顺序调用下面的子工作流,处理成功/失败分支
- 热点获取流:负责抓取各平台热榜,清洗数据,输出关键词列表
- 文案生成流:接收关键词,调用大模型生成文案,输出结构化脚本
- 素材抓取流:根据关键词搜索素材站,下载素材到本地/NAS
- 渲染发布流:调用FFmpeg合成视频,调用各平台API发布
这样拆的好处是,任何一个环节挂了,只需要重启对应的子工作流就好了,不会把整个工厂拖垮。而且你可以单独给每个子工作流设置重试次数、超时时间、告警策略。
主调度流的逻辑是n8n中比较核心的部分,它有点像一个"状态机"。每个子工作流执行完之后返回一个JSON对象,包含status和data字段。主调度流读取这些字段来做下一步决策:
{ "status": "success", "data": { "videoPath": "/data/videos/20240215_001.mp4", "duration": 58, "fileSize": 23456789 } }如果某一步返回status: "failed",主调度流会执行一个"失败处理"分支,把任务信息写入数据库,同时通过企业微信机器人/钉钉机器人发告警通知。这个失败处理分支很重要,否则某个环节悄悄失败了,你可能要过好几天才能从一堆静默日志里发现。
4. 关键节点的代码级实现:这五个节点撑起整个工厂
画流程节点只是第一步,真正决定工厂产能上限的是那些"自定义逻辑节点"。下面我把五个最核心的节点实现写出来,这些是我在项目里反复打磨过的。
4.1 热点获取节点的实现
热点获取我用的是HTTP Request节点 + 数据清洗的组合。n8n内置的HTTP Request节点可以直接请求各平台热榜API,但返回的数据通常是嵌套JSON,需要做转换。
这里有个实用的技巧:请求热榜API时,很多平台对高频请求有严格限流,而热榜数据其实几分钟内变化不大。我的做法是在n8n里加了一个"缓存判断"逻辑——用Redis节点读取上次请求的时间戳,如果距上次请求小于10分钟,直接用缓存的关键词列表,否则才发起新的HTTP请求。这个优化让我的触发频率可以设得很高,但API调用量被压到了一个非常低的水平。
数据清洗阶段我写了一个Function节点,把返回的JSON标准化为统一格式:
// n8n Function节点代码 const items = $input.all(); const result = []; for (const item of items) { const raw = item.json.data || item.json; const list = raw.list || raw.hotList || raw.data || []; for (const entry of list) { const title = entry.title || entry.word || entry.name; const hotValue = entry.hotValue || entry.heat || entry.num || 0; if (title && hotValue > 10000) { result.push({ json: { title: title.trim(), hotValue: Number(hotValue), platform: item.json.platform || 'unknown', capturedAt: new Date().toISOString() } }); } } } return result;清洗后的数据会写入数据库,同时作为下一个节点的输入。有个细节:关键词去重很重要。不同平台热榜常常会出现同一个热点词,如果不做去重,后面文案生成环节会对同样的话题反复写脚本,浪费模型调用费用。
4.2 AI文案生成:结构化输出是关键
文案生成节点是整条流水线的"大脑"。我用的是OpenAI节点,但在prompt设计上花了很多心思。
最初我试过直接把热点词丢给模型:"帮我就这个话题写一个短视频脚本",返回的内容完全不可控:有时是散文,有时是纯对话,有时带着emoji,根本没法直接进入后面的配音和渲染环节。
后来我改成要求模型返回固定结构的JSON,并且把约束条件写死在系统提示词里:
你是短视频脚本策划专家。请根据给定主题生成一个适合口播的短视频脚本,要求: 1. 字数控制在200字以内,适合35-45秒的语音播报 2. 开头3秒必须抓住注意力,使用疑问句或反常识观点 3. 结构为:钩子-铺垫-核心观点-行动号召 4. 返回格式必须是JSON,包含以下字段: { "title": "视频标题(不超过20字)", "hook": "开头钩子(不超过30字)", "script": "完整口播文案", "suggested_keywords": ["标签1", "标签2", "标签3"], "visual_notes": "画面建议,描述每个段落应配的画面内容" } 5. 只返回JSON,不要有其他文字说明配合n8n OpenAI节点的JSON模式(在节点配置里把responseFormat设置为json_object),返回内容可以直接用JSON.parse解析,再拆成多个字段供下游节点使用。
这个设计让文案质量和生产稳定性都有了保障。因为script字段是纯文本,直接就可以丢给TTS去生成配音,不需要额外清洗。visual_notes则作为素材抓取节点的搜索关键词参考。
4.3 素材抓取的合法性处理
素材是整个流程里最敏感的环节。我的原则是:只用明确提供免费商用授权的素材源,并且把素材的出处信息随视频一起存档,防止日后产生版权纠纷。
素材抓取节点用的是n8n的HTTP Request节点+自定义循环。核心逻辑是:从visual_notes中解析出场景关键词,每个关键词去素材站搜索一次,取前几个结果下载。
这里有个问题:素材站通常会把大文件放在CDN上,重定向URL有时效性,直接下载容易失败。我的方案是先请求搜索API拿到素材ID,再调用专门的文件下载接口获取临时直链,然后交给Execute Command节点用wget或curl下载。
下载完成之后一定要做文件完整性校验。我吃过一次亏:某个素材文件下载了一半,FFmpeg合成时完全没有报错,视频输出就是花屏。后来我在下载节点后面加了一个ffprobe校验步骤,检查每个素材的时长和编码信息,不合格的直接标记为失败并重新下载。
4.4 视频渲染:FFmpeg的工业化封装
视频渲染是整个工厂里计算压力最大的环节。我没有用专门的视频编辑软件(那没法自动化),而是直接用FFmpeg命令拼素材。
把流程简化后,渲染节点做的事情是:
- 把文案转成配音音频文件(TTS生成)
- 把配音音频的时长作为基准,按
visual_notes切分素材片段 - 用FFmpeg的
scale、crop、fps参数统一素材分辨率 - 拼接片段、混入配音、叠加字幕
核心FFmpeg命令大致长这样:
ffmpeg -y \ -f concat -safe 0 -i filelist.txt \ -i audio.mp3 \ -vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2,fps=30,subtitles=subtitle.ass" \ -c:v libx264 -preset medium -crf 23 \ -c:a aac -b:a 192k \ -shortest \ output.mp4这里filelist.txt是需要拼接的素材文件清单,subtitle.ass是用配音音频自动生成的 ASS 字幕文件。整个合成过程在n8n里通过Execute Command节点调用,用exec执行命令并等待返回。
FFmpeg命令没有做"一刀切"的参数统一。我按视频类型分了三个预设:
- 口播类:1080x1920竖屏,30fps,crf 23
- 图文类:1080x1920竖屏,静态图加Ken Burns效果
- 混剪类:1920x1080横屏,25fps,crf 20(画质更高)
不同预设之间的切换,通过n8n的条件节点判断文案的video_type字段来路由。这个设计让同一个工厂能产出不同风格的视频,不是千篇一律的套模板。
4.5 多平台分发:状态回写与幂等性设计
分发节点是直接面对用户的环节,也是出错风险最高的环节。我接入了两个短视频平台的开放API,核心要点是幂等性。
什么是幂等?简单说就是"同一个发布请求,无论执行多少次,结果都一样"。平台的发布接口本质上是创建一个视频资源,如果网络超时导致你重试,就很容易创建出重复视频。为了防止这个问题,我在每条视频生成时都会创建一个全局唯一的videoId(UUID),发布请求中把这个ID作为client_video_id传过去。平台如果收到相同的ID,会返回已创建的视频信息而不是再创建一个新的。
发布成功之后,工作流会把平台的返回信息(视频ID、发布URL、审核状态)写回MySQL内容管理表。这个表是整个工厂的"成果台账",我会基于它做数据统计分析:哪类选题播放量高、哪个时段发布效果好、哪个平台的推荐算法更友好。
平台分发环节还有一个容易被忽略的点:不同平台对视频封面的要求不同,有的要求9:16的JPG,有的要求PNG,还有的要带文字标题的封面层。我在渲染节点就已经把这些变体一次性生成好了,分发节点按平台规则选择对应的封面文件提交即可。
5. 上线半年的踩坑清单与排查链路
任何自动化系统,上线只是开始,真正的挑战都在后续的日常运行里。这半年我记了一堆踩坑记录,挑几个有代表性的分享出来,都是文档里不会告诉你的。
5.1 凭证失效引发的连锁崩溃
最严重的一次事故:某个平台的refresh_token静默过了有效期,导致所有发布任务鉴权失败。由于发布失败会走"失败处理"分支,理论上应该报警,但那个子工作流的报警节点本身因为凭证失效也挂了——告警通道和业务通道绑了同一个凭证体系,一出事全出事。
这次事故之后,我把告警通知改成了完全不依赖第三方平台凭证的方案:直接给运维邮箱发SMTP邮件。SMTP凭证独立保存在服务器环境变量里,和业务凭证完全隔离。从那以后,凡是核心基础设施(告警、健康检查、心跳检测)都走独立凭证,坚决不和业务凭证混用。
5.2 定时任务堆积:时区与触发频率的冲突
n8n的定时触发节点默认使用服务器时区,如果你服务器设的是UTC,定时任务的"每天8点"实际执行时间是北京时间下午4点。这个坑在单机部署时可能不明显,因为很多人会无意识地把服务器时区设成北京时间。但如果你用了容器化部署,基础镜像默认都是UTC,设置定时任务时就要特别注意。
另一个问题是触发频率过高导致的多实例冲突。我最初把主调度流设为每5分钟跑一次,用来检查待处理任务。但n8n的定时触发器在worker模式下,如果多个worker同时在线,同一个定时任务可能被触发多次。这会导致同一个视频被重复生产。
解决方案有两个:一是把定时任务改为只让主实例执行(在worker环境变量里禁用定时触发);二是在任务表里加状态锁,通过数据库原子操作抢占任务,抢不到的实例直接跳过。我用的是第二种方案,更保险。
5.3 大文件传输:n8n数据流的内存瓶颈
n8n的工作流设计里,上一个节点的输出会作为下一个节点的输入在内存中传递。如果你把视频文件本身放进节点间的数据流里,内存会迅速被打爆。比如素材下载节点如果直接返回整个文件内容,后面所有节点都会很卡。
解决方式:文件不要进n8n数据流,只在节点之间传递文件路径。我用的模式是:
- 素材下载节点把文件存到NAS的固定目录,返回文件路径
- 渲染节点通过Execute Command节点访问该路径,输出成片到一个新目录,返回输出路径
- 发布节点从路径读取文件,通过平台的"文件上传"接口发送
这个模式把n8n当成了"指挥中心",而不是"搬运工",内存占用一下就降下来了。
6. 把工作流当代码管理:项目结构重构与版本化方案
n8n项目跑起来不难,难的是持续迭代。等你有了几十个工作流、上百个节点时,如果还在Web界面上手动拖拽修改,迟早会把生产环境改坏。我后来做了一次比较大的重构,把整个项目按照"工程化"的标准来管理,借鉴了很多后端工程的最佳实践。
6.1 工作流的JSON导出与版本管理
n8n的每个工作流本质上是一个JSON文件,n8n内置了导出功能。我的做法是:把每个工作流从n8n界面导出成JSON文件,放进Git仓库管理,和项目代码放在一起。每个工作流的修改,都先在测试环境改完、验证通过,然后导出JSON,提交到Git,再通过n8n的CLI工具导入到生产环境。
仓库结构大概是这样:
n8n-shortvideo-factory/ ├── workflows/ │ ├── main_scheduler.json # 主调度流 │ ├── hot_topic_fetcher.json # 热点获取流 │ ├── script_generator.json # 文案生成流 │ ├── material_downloader.json # 素材抓取流 │ ├── video_renderer.json # 渲染发布流 │ └── token_refresher.json # 凭证刷新流 ├── scripts/ │ ├── deploy.sh # 导入导出脚本 │ ├── render_preset_a.sh # FFmpeg预设A │ ├── render_preset_b.sh # FFmpeg预设B │ └── check_material.sh # 素材完整性校验 ├── docker-compose.yml └── .env.example你可能觉得这有点"杀鸡用牛刀",但经历过一次手滑在生产环境误删节点之后,我发誓再也不用纯Web界面管理生产工作流。
有人说n8n不是有内置的版本历史吗?确实有,但那个版本历史保存在n8n数据库里,没法做代码评审,也没法做多人协作的分支管理。只有放到Git里,才能走diff、review、回滚的完整流程。
6.2 把重复逻辑封装成"子工作流"
在项目管理领域有个说法叫"单一职责",这个原则同样适用于n8n。我在重构前,主调度流里塞了各种业务逻辑:热点清洗、关键词去重、文案解析、素材判断……一个工作流里堆了七八十个节点,改一个条件分支就要小心翼翼翻半天。
重构后的方案是把通用能力沉淀为可复用的子工作流。比如"AI文案解析"这个能力,它接收任意文本,解析成结构化的JSON。这个子工作流被三个上游工作流复用,逻辑只维护一份。再比如"发送告警"子工作流,任何环节失败都可以调用它。
这就像写代码时抽取公共函数,避免了到处复制粘贴。n8n里调用子工作流有两种方式:一种是executeWorkflow节点,直接在当前流程中同步执行;另一种是通过webhook触发,异步调用。对于需要获取返回结果的场景,我用同步方式;对于"通知""记录日志"这类不关心结果的,我用异步方式,避免拖慢主流程。
6.3 环境隔离:开发、测试、生产三套环境
最后一个工程化建议:至少要开两套n8n环境。我自己维护了一个本地Docker测试环境和一台生产服务器。所有工作流的改动先在测试环境验证,数据源用mock数据和真实脱敏数据混合,确认没问题再导入生产。
开多套环境会带来一个额外问题:不同环境下的凭证、webhook URL、数据库连接串都不一样。我通过n8n的"变量"功能解决——在n8n设置里维护了环境级别的变量,测试环境的变量值指向测试数据库和mock服务,生产环境的变量值指向真实服务。工作流里引用变量时用{{$vars.xxx}},这样同一个JSON文件在测试环境和生产环境都能跑得通。
如果你团队有多个人,建议再引入一个"定义即代码"的流程:工作流的变更必须走Git提交加人工review,禁止直接在测试环境上改完就跑,不然很容易出现"测试环境能跑,生产环境跑不了"的玄学问题。
7. 项目上线后的实际效果与可复用经验
最后说一下实际运行数据,给想搭这套系统的人一个参考。目前这套"n8n自动短视频工厂"跑了半年,三个账号稳定更新,每周产出15条成片,人工介入的时间每周不超过两小时。对比搭建之前,产能提升了接近3倍,而且因为AI参与内容生产,选题覆盖的广度比原来人工选题要宽不少。
但我也想说一句实话:自动化解决的是流程效率,不是内容质量。工厂跑出来的视频是"合格品",不是"爆款"。它的定位是帮你省掉重复劳动时间,让你有更多精力去做真正需要创意的那部分——比如优化选题策略、打磨内容差异化、设计更好的开头钩子。
如果你想复刻这套系统,我的建议是从最小闭环开始:先只做"热点获取→文案生成→手动渲染→手动发布"这条半自动链路,跑通之后再逐步加上素材抓取、自动渲染、自动发布。一次到位的大而全是灾难的源头,小步快跑才能及时调整方向。
我后来还做了一些锦上添花的扩展:接入了数据统计看板,每天早上推送前一天的播放数据到企业微信;加了素材库自动分类逻辑,按主题归档素材方便人工作业时快速查找;还做了一套简单的AB文案测试,同一热点自动生成两个版本的标题和封面,发布后对比数据。这些扩展都是用n8n的新工作流完成的,没有改核心代码。
如果你也在用n8n搭内容生产的自动化管道,希望这篇笔记能帮你少走一些弯路。自动化这条路的尽头不是"机器替人",而是"人做更有价值的事"。
本文还有配套的精品资源,点击获取