拓冰建站拓冰建站
首页 / 资讯中心 / 正文

LosslessCut 表达式(JavaScript Expressions)完全指南:按表达式选择、批量编辑分段与文件名模板

LosslessCut 表达式JavaScript Expressions完全指南按表达式选择、批量编辑分段与文件名模板【免费下载链接】lossless-cutThe swiss army knife of lossless video/audio editing项目地址: https://gitcode.com/gh_mirrors/lo/lossless-cut导读LosslessCut无损音视频剪切工具内置了一套 JavaScript 表达式引擎允许你在特定对话框中编写 JS 表达式实现按条件批量选择分段批量修改分段属性在导出文件名模板中做动态计算按条件过滤音视频轨道等高级操作。本文以官方文档 docs/expressions.md 为主线结合仓库源码深入讲解表达式的可用变量、求值机制、安全沙箱实现与实战示例读完你即可用一行表达式完成原本需要手动逐条处理的批量编辑任务。一、表达式系统总览一个轻量 JS 求值环境LosslessCut 在若干对话框对话框中提供 JavaScript 表达式支持本质上是一个基于浏览器 Web Worker 的基础 JavaScript 环境内置了 核心 JavaScript 功能也就是说你日常使用的Math、String、Array、RegExp、JSON等内置对象与语法三元表达式、箭头函数、模板字符串、展开运算符等都可以直接使用。从源码结构看整个表达式求值链路由两个文件支撑主线程侧的封装 src/renderer/src/worker/eval.ts暴露safeishEval(code, context)异步函数它把表达式代码和以 JSON 序列化的上下文对象context通过postMessage发送给 Web Worker并按请求id匹配返回结果出错时以error字段回传并reject。Worker 侧的实际执行器 src/renderer/src/worker/evalWorker.ts收到消息后执行Function(with (this) { return ( code ); }).call(context)把上下文对象作为this暴露给表达式随后将postMessage的结果data或error返回主线程。因此表达式本质上是一条返回值即结果的 JS 语句用圆括号包裹后求值上下文变量通过with (this)注入为可直接访问的全局名字。注意表达式是一条语句不是一段脚本你不能在其中声明多条语句或使用return而是直接写成一个有值的表达式对象字面量需要加括号如({ start: 1 })。二、按表达式选择分段Select segments by expression2.1 用法与核心变量官方文档 docs/expressions.md 说明在按表达式选择分段对话框中你会拿到一个全局变量segment类型为Segment并编写一个返回true或false的表达式对所有分段逐一求值结果为true的分段将被选中。最经典的示例——选中所有时长小于 5 秒的分段segment.duration 5Segment的完整类型定义见 docs/generated/types.mdinterface Segment { index: number; // 分段在分段列表中的下标从 0 开始 label: string; // 分段名称label start: number; // 分段开始时间秒 end?: number | undefined; // 分段结束时间秒marker标记点为 undefined duration: number; // 时长秒等于 end - startmarker 为 0 tags: Recordstring, string; // 与该分段关联的标签tag }2.2 官方对话框内置示例在 src/renderer/src/hooks/useSegments.tsx 的selectSegmentsByExpr实现中可以看到对话框内置的完整示例清单均可一键填入直接对应源码中的examples数组功能点表达式时长小于 5 秒segment.duration 5开始时间在 01:00 之后segment.start 60名称精确匹配segment.label My label名称以某前缀开头segment.label.startsWith(My lab)名称用正则匹配/^My label/.test(segment.label)某个 tag 的值匹配segment.tags.myTag tag value标记点markersegment.end null对话框底部还会列出可用变量segment.index、segment.label、segment.start、segment.end、segment.duration、segment.tags.*其渲染组件为 src/renderer/src/components/ExpressionDialog.tsx。2.3 求值细节与边界行为从源码可以看出几个重要的行为边界表达式返回严格等于true true才选中返回其他真值不会选中见matchSegment(await safeishEval(expr, { segment })) true。求值是并发的使用pMap(..., { concurrency: 5 })对全部分段并行求值。空表达式会报错 Please enter a JavaScript expression.。没有分段匹配时提示 No segments match this expression.全部匹配时提示 All segments match this expression.防止无意义操作。表达式抛错时会提示 Expression failed: ...不会影响已有选中状态。三、按表达式编辑分段Edit segments by expression3.1 用法说明官方文档 docs/expressions.md 说明该功能对每一个已选中的分段给出segment变量你返回一个包含被修改属性的新对象返回对象中出现的属性会被写回分段。文档同时提示更多示例见应用内。源码实现位于 src/renderer/src/hooks/useSegments.tsx 的mutateSegmentsByExpr它通过mutateSegment校验返回结果表达式必须返回对象否则报错 The expression must return an object。返回对象中可识别并写回的属性是label字符串写回分段名称、start、end数字以及tags对象。其中start/end会经过有效性校验例如开始时间必须小于结束时间否则提示 Segment start time must be less than end time 之类错误。tags会合并写回返回tags时将新标签合并进原分段标签。由于segment对象在求值前被克隆见getScopeSegmenttags: { ...tags }你在表达式中修改segment.tags不会污染原始数据只有返回的对象才会真正生效。3.2 官方内置示例可直接套用以下示例均来自源码中的examples数组覆盖了最常见的批量编辑场景功能点表达式前后各扩展 5 秒{ start: segment.start - 5, end: segment.end 5 }前后各收缩 5 秒{ start: segment.start 5, end: segment.end - 5 }以 start 为中心对称 5 秒{ start: segment.start - 5, end: segment.start 5 }给名称追加编号后缀{ label: ${segment.label} ${segment.index 1} }给偶数下标分段加 tag{ tags: (segment.index 1) % 2 0 ? { ...segment.tags, even: true } : segment.tags }全转成标记点marker{ end: undefined }标记点转成 5 秒分段{ ...(segment.end null { end: segment.start 5 }) }注意第三组示例利用对象展开...(segment.end null { end: ... })在end存在时不展开任何键保证已有分段不被破坏——这是条件更新的常用写法。3.3 触发入口该功能与按表达式选择分段一样位于分段列表的右键上下文菜单中见 src/renderer/src/SegmentList.tsx分别对应菜单项 Select segments by expression 与 Edit segments by expression。四、在导出文件名模板中使用表达式4.1 基础用法官方文档 docs/expressions.md 说明在导出文件名模板中${}内部支持完整的 JavaScript 表达式例如${FILENAME.toLowerCase()}模板整体会作为一个 JavaScript 模板字符串 的interpolateOutFileNameawait safeishEval(${template}, context)。因此凡是 JS 能做的字符串处理大小写转换、正则替换、字符串补零、数组 join 等都能用在这里。4.2 模板中的全部变量以下变量在模板求值时的上下文类型为FileNameTemplateContext中可用完整说明见 docs/file-name-template.md变量类型说明${FILENAME}string原文件名不含扩展名合并导出时为第一个源文件名${FILES}SourceFile[]源文件信息数组可用表达式查询例如${new Date(FILES[0].ctime).toISOString()}${EXT}string输出扩展名如.mp4${EPOCH_MS}number自纪元起的毫秒数用于生成唯一文件名${EXPORT_COUNT}number本次启动 LosslessCut 以来的导出次数从 1 开始${FILE_EXPORT_COUNT}number打开当前文件以来的导出次数${SEG_LABEL}string/string[]分段名称合并模式下为数组可用${SEG_LABEL.filter(l l).join(,)}拼接${SEG_NUM}string分段序号补零字符串如01${SEG_NUM_INT}number分段序号整数可做算术如${SEG_NUM_INT100}${SELECTED_SEG_NUM}/${SELECTED_SEG_NUM_INT}string/number仅统计已选中分段的序号${SEG_SUFFIX}string有名称时形如-Getting_Lunch无名称时形如-seg1${CUT_FROM}/${CUT_TO}/${CUT_DURATION}string起止/时长格式hh.mm.ss.sss${CUT_FROM_NUM}/${CUT_TO_NUM}number起止时间的数值版可参与算术${SEG_TAGS.XX}object按名取分段标签标签不存在时输出undefined可用${SEG_TAGS.foo ?? }兜底4.3 实战技巧与约束数字补零${String(FILE_EXPORT_COUNT).padStart(2, 0)}先把数字转String再padStart。必须包含唯一标识模板至少要含一个唯一标识如${SEG_NUM}、${CUT_FROM}且以${EXT}结尾否则播放器可能无法识别文件。重名自动回退若模板为两个及以上分段生成相同文件名LosslessCut 会自动回退到默认模板相关校验在 src/renderer/src/util/outputNameTemplate.ts 中实现并给出中文提示。源码中定义的默认模板见同文件defaultCutFileTemplate 为${FILENAME}-${CUT_FROM}-${CUT_TO}${SEG_SUFFIX}${EXT}合并类模板则带有-merged-与${EPOCH_MS}。五、按表达式过滤轨道Select tracks by expression官方文档 docs/expressions.md 说明在Tracks轨道对话框中对每条轨道打开Track info轨道信息即可看到全部可用变量你可以据此编写过滤器filter表达式实现按条件批量启用/禁用要复制的音视频轨道。源码实现位于 src/renderer/src/hooks/useStreamsMeta.tsxfilterEnabledStreams对每一条轨道以{ track: stream }作为上下文调用safeishEval true的轨道会被保留并写入复制轨道集合进而影响导出时 ffmpeg 的轨道选择。这里的track即FFprobeStream类型含index、codec_type、codec_name、width、height、language等 ffprobe 探测出的字段例如可以用track.codec_type audio之类的表达式批量选中全部音频轨。六、表达式安全沙箱求值是怎么被保护的由于表达式是用户可控代码LosslessCut 将其放在 Web Worker 中执行并在 src/renderer/src/worker/evalWorker.ts 中做了多层防护可以将其视为安全求值safeish eval白名单隔离Worker 内定义了wl白名单仅放行Array、Math、JSON、String、RegExp等基础全局对象对白名单之外的全局属性通过Object.defineProperty覆盖为抛Security Exception的 getter从根上阻止访问window、process等敏感对象。禁用网络能力显式将fetch置为undefined并禁止 XHR 等网络访问表达式无法发起外部请求。防内存炸弹覆写Array.prototype.join当数组长度超过 500 时直接抛异常防止类似Array(5000000000).join(...)拖垮浏览器标签页。错误回传表达式抛出的任何错误都会以字符串形式回传主线程并展示在对话框中见 src/renderer/src/worker/eval.ts。需要说明的是这套机制旨在防误操作与基本隔离从注释safeishEval的命名与 TODO 注释todo terminate() and recreate in case of error?可以推断它并非严格的完全沙箱因此请只运行你自己信任的表达式。七、小结LosslessCut 的 JavaScript 表达式功能把批量选择—批量编辑—导出命名—轨道过滤四个高频操作统一到了同一种能力模型下在对话框里输入一条返回值的 JS 表达式配合文档级docs/expressions.md与类型级docs/generated/types.md的变量说明即可对分段、文件与轨道做精细化批处理。其底层求值由 src/renderer/src/worker/eval.ts 与 src/renderer/src/worker/evalWorker.ts 组成的 Worker 沙箱完成各功能入口与内置示例可在 src/renderer/src/hooks/useSegments.tsx、src/renderer/src/hooks/useStreamsMeta.tsx 和 src/renderer/src/util/outputNameTemplate.ts 中进一步查阅。【免费下载链接】lossless-cutThe swiss army knife of lossless video/audio editing项目地址: https://gitcode.com/gh_mirrors/lo/lossless-cut创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门