LosslessCut 导出文件名模板完整指南:变量、JavaScript 表达式与实战配置
2026/9/19 0:42:25 网站建设 项目流程

LosslessCut 导出文件名模板完整指南:变量、JavaScript 表达式与实战配置

【免费下载链接】lossless-cutThe swiss army knife of lossless video/audio editing项目地址: https://gitcode.com/gh_mirrors/lo/lossless-cut

LosslessCut 在导出片段(segments)为文件时,允许用户通过**文件名模板(file name template)**精确控制输出文件的命名规则。本文基于 docs/file-name-template.md 系统讲解模板的全部内置变量、JavaScript 表达式能力、数字补零技巧与回退机制,并结合 src/renderer/src/util/outputNameTemplate.ts 等源码剖析其底层实现。读完本文,你将能编写出可复制的模板,实现「Beach Trip - 1.mp4」式的序列命名、带时间码的命名、基于标签的命名以及防覆盖的唯一命名。

一、模板是什么:JavaScript 模板字符串

当导出片段为文件时,LosslessCut 允许你通过一个**模板(template)**来规定输出文件如何按顺序命名。模板本质上是一个 JavaScript 模板字符串(template literal),也就是说,你可以在模板内部直接使用 JavaScript 语法,例如${...}插值、方法调用、三元运算、数组方法等。

从实现上看,模板字符串在运行时会被构造为`...`代码,并交由一个独立的 Web Worker 执行。入口位于 src/renderer/src/worker/eval.ts 的safeishEval函数:它把代码与序列化后的上下文一起 postMessage 给 Worker,Worker 端(src/renderer/src/worker/evalWorker.ts)通过Function('\nwith (this) { return (${code}); }').call(context)在受限的with作用域中求值。为了安全,Worker 对全局对象做了白名单隔离,只暴露ArrayDateMathStringJSONRegExp等基础对象,其余属性一律抛出Security Exception,因此你无法在模板中访问文件系统或网络。

所有可用变量的类型定义(TypeScript 接口)位于 src/common/userTypes.ts 的FileNameTemplateContext,其 JSDoc 注释会同步生成到 docs/generated/types.md,是理解每个变量类型与可选性的权威依据。模板中这些变量之所以可用,是因为 interpolateOutFileName 在求值前构建了一个包含上述全部变量的上下文对象。

二、全部内置变量速查表

下表完整列出了模板中可用的变量。其中「合并文件」指 Merge 模式(将多个文件合并导出为一个文件),「剪切+合并」指 Cut + Merge 模式(将多个片段合并导出一个文件);带 ✅ 表示该模式下可用。

合并文件可用剪切+合并可用变量类型输出说明
${FILENAME}string原始文件名不含扩展名(例如文件Beach Trip.mp4得到Beach Trip)。合并文件时取第一个原始文件名。
${FILES}SourceFile[]🤓🧪 原始文件对象数组,每个元素是SourceFile,可用 JavaScript 表达式查询属性。示例:${new Date(FILES[0].ctime).toISOString().replaceAll(':', '.').replaceAll('T', ' ')}
${EXT}string文件扩展名(如.mp4.mkv)。
${EPOCH_MS}number自 Unix 纪元起的毫秒数(如1680852771465),每次导出生成唯一名,可防止意外覆盖。
${EXPORT_COUNT}number自本次 LosslessCut 启动以来完成的导出次数(从 1 开始)。
${FILE_EXPORT_COUNT}number自当前文件打开以来完成的导出次数(从 1 开始)。
${SEG_LABEL}string/string[]片段的标签(如Getting Lunch)。Cut + Merge 模式下为数组,可用${SEG_LABEL.filter(label => label).join(',')}合并所有标签;合并文件时是每个被合并原始文件的名称。
${SEG_NUM}string片段序号,零填充字符串(如010242)。
${SEG_NUM_INT}number🤓 片段序号整数(如1242),可用于数值运算,如${SEG_NUM_INT+100}
${SELECTED_SEG_NUM}stringSEG_NUM,但仅对选中的片段计数。
${SELECTED_SEG_NUM_INT}number🤓 同SEG_NUM_INT,但仅对选中的片段计数。
${SEG_SUFFIX}string若该片段有标签,则用标签并前置-;否则用序号前置-seg(例如-Getting_Lunch-seg1)。
${CUT_FROM}string片段起始时间戳,格式hh.mm.ss.sss(如00.00.27.184)。
${CUT_FROM_NUM}number🤓 同${CUT_FROM},但为数值,可用于算术运算。
${CUT_TO}string片段结束时间戳,格式hh.mm.ss.sss(如00.00.28.000)。
${CUT_TO_NUM}number🤓 同${CUT_FROM_NUM}
${CUT_DURATION}string片段时长(CUT_TO - CUT_FROM),格式hh.mm.ss.sss(如00.00.28.000)。
${SEG_TAGS.XX}object按名称取片段的标签。标签名为 foo 时写作${SEG_TAGS.foo};标签不存在时输出文本undefined,可用${SEG_TAGS.foo ?? ''}规避。

🤓 = 高级变量(进阶用户),涉及 JavaScript 表达式;🧪 = 实验性功能。

值得注意的实现细节:SEG_TAGS在上下文中同时保留了原始大小写大写两种键名(见 interpolateOutFileName 中Object.fromEntries的处理),因此${SEG_TAGS.foo}${SEG_TAGS.FOO}均可命中,容错性更好。而标签值在进入模板前会经过净化处理,确保不会引入目标文件系统不支持的字符。

三、变量可用性与默认模板

不同导出模式下变量的可用范围并不相同。从上表可以看出:SEG_NUMCUT_FROMSEG_TAGS等片段级变量只在普通剪切导出(Cut,逐段导出为独立文件)时可用;合并与剪切+合并模式更依赖FILENAMEFILESEXTEPOCH_MSEXPORT_COUNTSEG_LABEL这类文件级变量。

模板必须满足两个硬性要求:

  1. 至少包含一个唯一标识符,例如${SEG_NUM}${CUT_FROM},否则多个输出文件可能重名;
  2. 应以${EXT}结尾,否则播放器可能无法识别文件类型。

若模板生成的文件名至少出现两个重复,LosslessCut 会自动回退到默认模板。源码中定义了三个默认模板(见 outputNameTemplate.ts):

// 普通剪切导出(逐段导出为独立文件) export const defaultCutFileTemplate = '${FILENAME}-${CUT_FROM}-${CUT_TO}${SEG_SUFFIX}${EXT}'; // 剪切+合并导出 export const defaultCutMergedFileTemplate = '${FILENAME}-cut-merged-${EPOCH_MS}${EXT}'; // 合并导出 export const defaultMergedFileTemplate = '${FILENAME}-merged-${EPOCH_MS}${EXT}';

注意默认模板刻意加入了CUT_FROMCUT_TOEPOCH_MS等保证唯一性的元素,注释也写明"fallback 模板必须始终生成唯一文件名"。回退逻辑位于generateWithFallback(outputNameTemplate.ts):当自定义模板求值抛错或getTemplateProblems检测到重复命名、非法字符等问题时,如果自定义模板与默认模板不同,就改用默认模板重试,并返回originalFileNamesproblems供界面提示。

典型示例:要实现Beach Trip - 1.mp4Beach Trip - 2.mp4Beach Trip - 3.mp4这样的序列命名,模板应写为:

${FILENAME} - ${SEG_NUM}${EXT}

四、模板校验规则:什么样的模板会被拒绝

在文件名生成后、写盘之前,getTemplateProblems(outputNameTemplate.ts)会对每个结果逐一校验,任一文件不满足即触发回退。校验项包括:

  • 非法字符:Windows 下禁止< > : " | ? *;macOS 下禁止:;启用安全文件名(safeOutputFileName)时还会把路径分隔符加入黑名单(Windows 为/\,其他平台为系统分隔符),防止模板注入目录结构。
  • 与输入路径相同:生成路径与源文件路径一致时拒绝,避免覆盖原文件。
  • 结尾字符:Windows 下文件名不允许以空格或点结尾。
  • 路径过长:Windows 或开发模式下,完整输出路径达到 259 字符即拒绝(Windows 最大路径限制为 256/259 字符,macOS 为 255)。
  • 空文件名:结果为空字符串时报错。
  • 重复文件名:多个输出同名时拒绝,并提示可加入${SEG_NUM}修复。

此外,模板中的标签、后缀等"非来自源文件名的部分"会先经过filenamify净化(src/renderer/src/util.ts):将不属于 Unicode 字母、数字、空格、点、下划线、连字符的字符替换为_。片段级文件名还会被截断到 250 字符(maxFileNameLength)以内,见maybeTruncatePath

五、数字补零(Padding)

如果需要对数字进行补零,可以在变量外包裹 JavaScript 代码。例如将FILE_EXPORT_COUNT补零到 2 位:先把数字转为String,再调用字符串的padStart

${String(FILE_EXPORT_COUNT).padStart(2, '0')}

其原理与SEG_NUM的实现一致——源码中的formatSegNum(src/renderer/src/segments.ts)正是通过`${segIndex + 1}`.padStart(Math.max(numDigits, minLength), '0')来生成零填充序号:SEG_NUM的填充宽度由全部片段数决定(片段 9 的两位数位数),也可以进一步由设置中的最小零填充位数控制。因此当你需要SEG_NUM固定 3 位时,可以自行用padStart(3, '0')包装(注意SEG_NUM本身已是字符串,无需再String())。

如果需要更多补零技巧,可以求助于 AI,例如提问:"How to pad a number with JavaScript?"(如何用 JavaScript 给数字补零?)。

六、实战模板示例合集

结合变量表与源码行为,下面给出可直接粘贴使用的模板:

1. 序号命名(最常用,保证唯一)

${FILENAME} - ${SEG_NUM}${EXT}

2. 片段时间范围命名(默认模板风格,适合想从文件名看出剪切点)

${FILENAME}-${CUT_FROM}-${CUT_TO}${SEG_SUFFIX}${EXT}

3. 带标签的命名(片段有标签时显示标签,无标签时退化为-segN

${FILENAME}${SEG_SUFFIX}${EXT}

4. 防覆盖唯一命名(每次导出时间戳不同,适合反复导出)

${FILENAME}-${EPOCH_MS}${EXT}

5. 标签合并(Cut + Merge 模式)

${FILENAME}-${SEG_LABEL.filter(label => label).join(',')}${EXT}

6. 数值运算与时间码

${FILENAME}-seg${SEG_NUM_INT+100}-from${CUT_FROM}${EXT}

7. 缺失标签安全处理

${FILENAME}${SEG_SUFFIX}-${SEG_TAGS.scene ?? ''}${EXT}

8. 基于源文件属性的高级用法(🤓🧪):例如把文件的创建时间转成可读日期并替换掉:T字符,使其成为合法文件名:

${new Date(FILES[0].ctime).toISOString().replaceAll(':', '.').replaceAll('T', ' ')} ${FILENAME}${EXT}

需要说明的是:FILES[0]的各时间属性(atimemtimectimebirthtime)单位是毫秒级时间戳(见 SourceFile 定义),size为字节数;该功能标记为实验性,跨平台时间字段行为可能略有差异。

七、底层执行链路与注意事项

一次模板求值的完整链路为:界面读取用户模板 →generateCutFileNames/generateCutMergedFileNames/generateMergedFileNames(对应三种导出模式)组装上下文并调用interpolateOutFileName→ 构造`模板`代码交给safeishEval→ Worker 沙箱内with (context)求值返回字符串 →getTemplateProblems校验 → 出错则回退默认模板。这解释了为什么模板必须"以 JavaScript 模板字符串语法书写",也解释了为什么表达式中能使用ArrayDateMathString等内置对象。

实际使用时请注意:

  • 模板求值结果必须是字符串,否则会抛出Expression did not lead to a string(见 outputNameTemplate.ts)。
  • 语法错误、非法字符、重复文件名都会触发回退到默认模板,界面会同时给出错误原因提示。
  • 由于求值在受限 Worker 中进行,不要尝试访问windowdocumentfetch或任意未列入白名单的全局对象,它们会抛出Security Exception
  • 标签名大小写均可访问,但请记得用?? ''处理缺失标签,避免文件名中出现字面量undefined

掌握上述变量与规则后,你可以在 LosslessCut 的导出设置中直接粘贴模板,实现完全自主控制的批量输出命名。若希望获得更具体的模板写法,也可以把本文档作为提示词交给 AI,让它帮你按需求生成模板字符串。

【免费下载链接】lossless-cutThe swiss army knife of lossless video/audio editing项目地址: https://gitcode.com/gh_mirrors/lo/lossless-cut

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询