news 2026/6/10 17:12:39

实战:从零构建一个支持屏幕录制与片段合并的视频管理系统 (Node.js + FFmpeg)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
实战:从零构建一个支持屏幕录制与片段合并的视频管理系统 (Node.js + FFmpeg)

1. 背景 (Background)

作为开发者,我们每天都会浏览大量的技术教程(YouTube, Bilibili)。收藏夹往往乱作一团,而且很多时候,我们只需要长视频中的某几个关键片段

单纯的书签管理已经无法满足需求,我想要一个工具:

  1. 美观管理:像 Netflix 一样展示我的视频收藏。
  2. 随手记录:看到重点时,能直接录制屏幕片段。
  3. 自动归档:录制的片段自动关联到当前视频条目下,不丢失。
  4. 整理输出:能把零散的片段合并成一个完整的笔记视频。

于是,VideoHub Pro诞生了。
C:\myApp\myvideo-manager

2. 目标 (Goal)

我们需要构建一个B/S 架构的全栈应用,无需繁重的数据库安装,开箱即用。

  • 前端:原生 HTML/CSS/JS(极致轻量),实现卡片式展示、剪贴板截图粘贴、Web 录屏 API 调用。
  • 后端:Node.js (Express),负责数据存储(JSON)、文件上传(Multer)以及视频处理(FFmpeg)。
  • 核心痛点解决:解决 Web 端录屏的持久化存储,以及多段视频的后端合并下载。

3. 方法 (Method)

  • 技术栈

    • Server: Node.js + Express
    • Media Processing:fluent-ffmpeg(调用系统安装的 FFmpeg)
    • Uploads:multer
    • Frontend: HTML5, CSS3 (Grid + Glassmorphism), Native JavaScript (ES6+)
    • Database: 本地data.json文件 (模拟 NoSQL)
  • 数据模型设计
    一个视频对象(Video)包含基本信息和一个片段(Clips)数组:

    {"id":"uuid-...","title":"Node.js 教程","url":"https://...","thumbnail":"base64...","clips":[{"filename":"17000.webm","createdAt":"...","size":1024}]}

4. 过程与核心代码解析 (Process)

4.1 前端交互与视觉设计

我们采用了深色模式 (Dark Mode)毛玻璃 (Glassmorphism)风格,利用 CSS Grid 实现响应式的卡片布局。

关键点在于粘贴上传缩略图。为了提升体验,我们监听了粘贴事件:

// 监听粘贴事件,自动读取剪贴板中的图片流并转为 Base64document.getElementById('paste-area').addEventListener('paste',e=>{constitems=e.clipboardData.items;for(letitemofitems){if(item.type.startsWith('image')){constblob=item.getAsFile();constreader=newFileReader();reader.onload=ev=>{// 直接展示并赋值给隐藏域document.getElementById('v-thumb').value=ev.target.result;// ...预览逻辑};reader.readAsDataURL(blob);}}});

4.2 核心难点一:Web 录屏与自动上传

这是本项目的核心功能。传统的 Web 录屏往往只保存在浏览器内存中,刷新即丢失。我们的改进方案是:录制停止 -> 自动上传 -> 服务器持久化

前端实现 (index.html):
使用navigator.mediaDevices.getDisplayMedia获取屏幕流,通过MediaRecorder录制。

asyncfunctionstartRec(){// 1. 唤起浏览器原生屏幕分享弹窗conststream=awaitnavigator.mediaDevices.getDisplayMedia({video:true,audio:true});// 2. 创建录制器,指定 MIME 类型constmediaRecorder=newMediaRecorder(stream,{mimeType:'video/webm; codecs=vp9'});letchunks=[];// 临时存储二进制块mediaRecorder.ondataavailable=e=>{if(e.data.size>0)chunks.push(e.data);};// 3. 监听停止事件mediaRecorder.onstop=async()=>{// 将 chunks 转为 Blob 对象constblob=newBlob(chunks,{type:'video/webm'});// 4. 构建 FormData,准备上传constfd=newFormData();fd.append('clip',blob,`rec_${Date.now()}.webm`);fd.append('videoId',currentVideoId);// 关键:带上当前视频的 ID// 5. 立即上传服务器awaitfetch(`${API}/upload-clip`,{method:'POST',body:fd});// 停止流,释放资源stream.getTracks().forEach(t=>t.stop());refreshClipsPanel();// 刷新 UI};mediaRecorder.start();}

后端处理 (server.js):
后端接收文件,保存到uploads目录,并更新data.json中的对应记录。

app.post('/api/upload-clip',upload.single('clip'),(req,res)=>{const{videoId}=req.body;// ...读取 JSON 数据constidx=videos.findIndex(v=>v.id===videoId);if(idx!==-1){// 构建片段元数据对象constclipInfo={filename:req.file.filename,// Multer 生成的物理文件名originalName:req.file.originalname,size:req.file.size,createdAt:newDate()};// 关联数据:将片段信息 push 到该视频的 clips 数组中videos[idx].clips.push(clipInfo);writeDB(videos);// 写入磁盘res.json({success:true});}});

分析:这种“ID关联法”使得录屏文件不再是孤立的,而是永远从属于某个具体的视频条目。


4.3 核心难点二:多片段合并 (FFmpeg)

当用户录制了片段 A、片段 B、片段 C 后,可能只想把 A 和 C 合并下载。

策略变化
早期版本是前端把 Blob 传给后端合并,这很浪费流量。现在的策略是:文件已经在服务器上了,前端只需要传“文件名列表”,后端在本地进行合并

前端逻辑
用户勾选复选框,获取文件名数组:

constcbs=document.querySelectorAll('.clip-cb:checked');constfilenames=Array.from(cbs).map(cb=>cb.value);// ['file1.webm', 'file3.webm']awaitfetch(`${API}/merge-files`,{body:JSON.stringify({filenames})// 只发文件名,极快});

后端逻辑 (server.js):
使用fluent-ffmpeg链式调用。

app.post('/api/merge-files',(req,res)=>{const{filenames}=req.body;constoutputFilename=`merged-${Date.now()}.mp4`;constoutputPath=path.join(UPLOAD_DIR,outputFilename);constcommand=ffmpeg();// 1. 遍历添加输入源 (Input)filenames.forEach(name=>{// 拼接服务器的绝对路径command.input(path.join(UPLOAD_DIR,name));});// 2. 执行合并 (Merge)command.on('error',(err)=>res.status(500).send('Merge failed')).on('end',()=>{// 3. 返回合并后的文件 URLres.json({url:`/uploads/${outputFilename}`});}).mergeToFile(outputPath,UPLOAD_DIR);// 输出});

分析:这个设计将繁重的视频处理工作全部交给了服务器(Node.js 调用底层 FFmpeg),前端只需要发送轻量级的指令,体验非常流畅。


5. 结果展示 (Result)

最终,我们得到了一个功能闭环的系统:

  1. 卡片墙:首页展示所有视频,缩略图清晰,支持分类过滤。
  2. 播放详情页
    • 左侧:智能解析 URL(YouTube/Bilibili 自动嵌入 iframe),下方有“录制”按钮。
    • 右侧:显示所有关联的录屏片段历史。
  3. 工作流
    • 点击“录制” -> 选择区域 -> 录制结束 ->自动出现在右侧列表
    • 在右侧列表中勾选第1条和第3条 -> 点击“合并下载” -> 浏览器弹出合并后的 MP4 下载。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 13:13:58

基于AI智能名片链动2+1模式S2B2C商城小程序的流量运营策略研究

摘要:在零售行业竞争日益激烈的背景下,流量获取与转化成为企业发展的关键。本文聚焦AI智能名片链动21模式S2B2C商城小程序这一创新商业模式,深入探讨其在推广产品定位、归集渠道现有流量以及拓展内外部流量方面的作用机制与实践路径。通过理论…

作者头像 李华
网站建设 2026/6/10 9:04:33

8个降AI率工具推荐!自考党速看

8个降AI率工具推荐!自考党速看 AI降重工具:自考论文的“隐形助手” 随着人工智能技术在学术领域的广泛应用,越来越多的自考学生发现自己的论文中出现了明显的AI痕迹,导致AIGC率过高,影响了最终成绩。为了应对这一挑战…

作者头像 李华
网站建设 2026/6/10 9:05:04

Python+vue3+django的社区桶装饮用水预购管理系统的设计与实现

目录社区桶装饮用水预购管理系统的设计与实现摘要开发技术路线相关技术介绍核心代码参考示例结论源码lw获取/同行可拿货,招校园代理 :文章底部获取博主联系方式!社区桶装饮用水预购管理系统的设计与实现摘要 该系统基于PythonDjangoVue3技术栈开发&…

作者头像 李华
网站建设 2026/6/9 13:19:54

RAG增强与RAG系统技术报告

文章大纲 从架构设计到企业级实践 摘要 第1章 引言 1.1 传统RAG的核心痛点 1.2 PowerRAG的定位 第2章 PowerRAG增强型框架核心能力 2.1 核心技术亮点 2.2 落地效果提升 2.3 与OceanBase一体化融合 第3章 RAG系统全链路技术架构 3.1 两大核心支柱:文档解析 + 检索策略 3.2 嵌入…

作者头像 李华
网站建设 2026/6/10 8:59:42

基于YOLOv8的恶性疟原虫智能检测系统工程实践 [目标检测完整源码]

文章目录基于YOLOv8的恶性疟原虫智能检测系统工程实践 [目标检测完整源码]一、应用背景与问题定义源码下载与效果演示二、整体技术方案设计三、数据集构建与训练策略四、模型推理与系统部署五、工程实现亮点六、应用前景与拓展方向七、结语基于YOLOv8的恶性疟原虫智能检测系统工…

作者头像 李华
网站建设 2026/6/10 9:02:44

写论文软件哪个好?实测揭秘!宏智树 AI 凭 “真研究” 实力出圈

毕业季的论文焦虑,几乎是每一位学子的必经之路:选题太泛被导师打回、文献堆砌逻辑混乱、数据分析无从下手、查重率居高不下、AI 生成痕迹被系统标红…… 面对五花八门的论文写作工具,“写论文软件哪个好” 成了无数学子的灵魂拷问。 作为深耕…

作者头像 李华