capcut-pro-free

软件下载地址

剪影国际版下载地址

node.js下载地址

字幕工具

剪映国际版字幕导出工具

提示词

https://jy2.mzh.ren/index_61f7cabff92c9fafcd77.js 分析下这段代码的作用

你资深的产品经理,通过提问帮助我理解需求,我需要一个在我电脑上可以使用的版本,我的电脑上有安装nodejs,有什么需要我澄清的请提问?

字幕导出JS代码

const fs = require('fs');
const path = require('path');
const os = require('os');

/**
 * 过滤字幕文本中的 XML 样式标签(如 <color>, <size> 等)
 */
function cleanText(text) {
  if (!text) return '';
  // 正则匹配并移除所有的 XML/HTML 标签
  return text.replace(/<\/?[^>]+(>|$)/g, "").trim();
}

/**
 * 将微秒(microseconds)转换为 SRT 格式的时间戳 (HH:MM:SS,mmm)
 */
function formatTime(us) {
  const msTotal = Math.floor(us / 1000);
  const ms = msTotal % 1000;
  const sTotal = Math.floor(msTotal / 1000);
  const s = sTotal % 60;
  const mTotal = Math.floor(sTotal / 60);
  const m = mTotal % 60;
  const h = Math.floor(mTotal / 60);

  const pad = (num, size) => num.toString().padStart(size, '0');
  return `${pad(h, 2)}:${pad(m, 2)}:${pad(s, 2)},${pad(ms, 3)}`;
}

/**
 * 寻找 Windows 下载文件夹中不冲突的固定文件名
 */
function getUniqueOutputPath(downloadsDir, baseName, ext) {
  let candidate = path.join(downloadsDir, `${baseName}${ext}`);
  if (!fs.existsSync(candidate)) {
    return candidate;
  }
  let counter = 1;
  while (true) {
    candidate = path.join(downloadsDir, `${baseName} (${counter})${ext}`);
    if (!fs.existsSync(candidate)) {
      return candidate;
    }
    counter++;
  }
}

function main() {
  // 1. 校验输入参数
  const inputPathRaw = process.argv[2];
  if (!inputPathRaw) {
    console.error('\x1b[31m[错误] 请提供 draft_content.json 的路径。\x1b[0m');
    console.log('\n使用方法:');
    console.log('  node export.js <文件路径>');
    console.log('\n示例:');
    console.log('  node export.js "C:\\Users\\YourName\\AppData\\Local\\JianyingPro\\User Data\\Projects\\com.lveditor.draft\\Draft_1\\draft_content.json"\n');
    process.exit(1);
  }

  // 去除 Windows 路径可能携带的双引号
  const inputPath = inputPathRaw.replace(/^"|"$/g, '');

  if (!fs.existsSync(inputPath)) {
    console.error(`\x1b[31m[错误] 找不到指定的文件,请检查路径是否正确:\n${inputPath}\x1b[0m`);
    process.exit(1);
  }

  console.log('正在读取并解析文件...');

  try {
    const fileContent = fs.readFileSync(inputPath, 'utf-8');
    const jsonData = JSON.parse(fileContent);

    // 2. 建立 material_id 到字幕文本的映射表
    const contentMap = new Map();
    if (jsonData.materials && Array.isArray(jsonData.materials.texts)) {
      jsonData.materials.texts.forEach(item => {
        let textVal = '';
        try {
          // 剪映新版 content 是一个 JSON 字符串,需要二次解析
          const parsed = JSON.parse(item.content);
          textVal = parsed.text || '';
        } catch (e) {
          // 如果解析失败,则按普通文本处理
          textVal = item.content || '';
        }
        contentMap.set(item.id, cleanText(textVal));
      });
    }

    // 3. 提取所有字幕片段(从文字轨道中匹配时间轴与内容)
    const srtSegments = [];
    if (Array.isArray(jsonData.tracks)) {
      jsonData.tracks.forEach(track => {
        // 筛选文本/字幕轨道
        if (track.type === 'text' || track.type === 'subtitle') {
          if (Array.isArray(track.segments)) {
            track.segments.forEach(seg => {
              const text = contentMap.get(seg.material_id);
              if (text && seg.target_timerange) {
                const start = parseInt(seg.target_timerange.start, 10) || 0;
                const duration = parseInt(seg.target_timerange.duration, 10) || 0;
                const end = start + duration;
                srtSegments.push({ start, end, text });
              }
            });
          }
        }
      });
    }

    if (srtSegments.length === 0) {
      console.warn('\x1b[33m[警告] 未在草稿文件中找到任何有效的字幕内容。\x1b[0m');
      process.exit(0);
    }

    // 4. 按开始时间进行升序排序
    srtSegments.sort((a, b) => a.start - b.start);

    // 5. 格式化为标准 SRT 字幕格式
    let srtContent = '';
    srtSegments.forEach((seg, index) => {
      const num = index + 1;
      const startStr = formatTime(seg.start);
      const endStr = formatTime(seg.end);
      srtContent += `${num}\n${startStr} --> ${endStr}\n${seg.text}\n\n`;
    });

    // 6. 写入“下载”目录
    const homeDir = os.homedir();
    const downloadsDir = path.join(homeDir, 'Downloads');
    
    // 确保下载目录存在
    if (!fs.existsSync(downloadsDir)) {
      fs.mkdirSync(downloadsDir, { recursive: true });
    }

    const finalPath = getUniqueOutputPath(downloadsDir, 'subtitles', '.srt');
    fs.writeFileSync(finalPath, srtContent, 'utf-8');

    console.log(`\n\x1b[32m[成功] 已成功提取 ${srtSegments.length} 条字幕!\x1b[0m`);
    console.log(`\x1b[36m[输出] 文件已保存至:${finalPath}\x1b[0m\n`);

  } catch (error) {
    console.error('\x1b[31m[发生错误] 解析文件时失败,错误信息如下:\x1b[0m');
    console.error(error);
    process.exit(1);
  }
}

main();