通过扣子官方语音合成开发的速推版剪映小助手时间线插件

2026-04-07 11:47:17 9 分享链接 开发笔记 扣子插件

扣子工作流javascript代码

// 类型定义(扣子环境已内置,仅作提示)
interface Args {
    params: {
        durations: number[];    // 各音频时长(秒)
        links: string[];        // 音频链接列表
        medias: Array<{         // 媒体索引映射
            index: number;
            start: number;
            end: number;
        }>;
    };
}

interface TimeLineItem {
    start: number; // 起始时间(微秒)
    end: number;   // 结束时间(微秒)
}

interface Output {
    all_timelines: TimeLineItem[];    // 总时长时间线
    timelines: TimeLineItem[];        // 单个音频时间线
    media_timelines: TimeLineItem[];  // 按medias分组的时间线
}

async function main({ params }: Args): Promise<Output> {
    // 1. 获取输入参数并兜底处理
    const durations = params.durations || [];
    const links = params.links || [];
    const medias = params.medias || [];

    // 2. 核心验证:durations与links长度必须一致
    if (durations.length !== links.length) {
        throw new Error(`参数验证失败:durations长度(${durations.length})与links长度(${links.length})不一致`);
    }

    // 3. 常量定义:秒转微秒(1秒 = 1000000 微秒)
    const SEC_TO_US = 1000000;

    // 4. 计算单个音频的时间线(timelines)
    const timelines: TimeLineItem[] = [];
    let currentStart = 0; // 累计起始时间(微秒)
    
    durations.forEach((durationSec) => {
        // 转换时长为微秒(避免浮点精度问题,先乘1000000再取整)
        const durationUs = Math.round(durationSec * SEC_TO_US);
        const end = currentStart + durationUs;
        
        timelines.push({
            start: currentStart,
            end: end
        });
        
        // 更新下一个音频的起始时间
        currentStart = end;
    });

    // 5. 计算总时长时间线(all_timelines)
    const allTimelines: TimeLineItem[] = [];
    if (timelines.length > 0) {
        allTimelines.push({
            start: 0,
            end: timelines[timelines.length - 1].end // 总结束时间 = 最后一个音频的结束时间
        });
    } else {
        allTimelines.push({ start: 0, end: 0 }); // 空数据兜底
    }

    // 6. 计算按medias分组的时间线(media_timelines)
    const mediaTimelines: TimeLineItem[] = [];
    
    medias.forEach((media) => {
        const { start: linkStartIdx, end: linkEndIdx } = media;
        
        // 边界校验:确保medias的start/end在links索引范围内
        if (linkStartIdx < 0 || linkEndIdx >= links.length || linkStartIdx > linkEndIdx) {
            throw new Error(`medias索引越界:index=${media.index} 的start(${linkStartIdx})/end(${linkEndIdx})超出links范围`);
        }

        // 取分组第一个音频的start作为media的start
        const mediaStart = timelines[linkStartIdx].start;
        // 取分组最后一个音频的end作为media的end
        const mediaEnd = timelines[linkEndIdx].end;
        
        mediaTimelines.push({
            start: mediaStart,
            end: mediaEnd
        });
    });

    // 7. 构建最终输出
    const ret: Output = {
        all_timelines: allTimelines,
        timelines: timelines,
        media_timelines: mediaTimelines
    };

    return ret;
}

输入(input)

{
  "durations": [
    0.525,
    0.778,
    1.085,
    0.665,
    0.865,
    0.865,
    0.685,
    1.078,
    0.738,
    1.151,
    0.985,
    1.631,
    2.418,
    0.551,
    1.365,
    0.931,
    0.771
  ],
  "links": [
    "https://lf3-appstore-sign.oceancloudapi.com/ocean-cloud-tos/VolcanoUserVoice/speech_7481299960424759350_d042d4cd-30cf-4230-afd0-43798f246c2f.mp3?lk3s=da27ec82&x-expires=1775640956&x-signature=DowjhJ3RpP47Zs%2FBDIgmxhd7NKk%3D",
    "https://lf9-appstore-sign.oceancloudapi.com/ocean-cloud-tos/VolcanoUserVoice/speech_7481299960424759350_339e3ede-07e8-4fb5-b83f-b1ab53082dd9.mp3?lk3s=da27ec82&x-expires=1775640956&x-signature=YWEWUNZkYUC%2FfO0Txl4dCrC7orM%3D",
    "https://lf26-appstore-sign.oceancloudapi.com/ocean-cloud-tos/VolcanoUserVoice/speech_7481299960424759350_533384b9-7503-438b-ad06-fadef1be4932.mp3?lk3s=da27ec82&x-expires=1775640956&x-signature=%2F%2BiYuE3Di%2F382iUQYMmO%2BNsQUdQ%3D",
    "https://lf6-appstore-sign.oceancloudapi.com/ocean-cloud-tos/VolcanoUserVoice/speech_7481299960424759350_020acb28-0295-409a-8447-1e5a93cc32e0.mp3?lk3s=da27ec82&x-expires=1775640957&x-signature=wxNiEWbQgrwSTnS1Vg0zOzFfzwU%3D",
    "https://lf3-appstore-sign.oceancloudapi.com/ocean-cloud-tos/VolcanoUserVoice/speech_7481299960424759350_d6d00e0a-2c8b-4852-9b9e-c0082a579fcf.mp3?lk3s=da27ec82&x-expires=1775640957&x-signature=0TbZXeTH9tL3mIKv3b44uHRGTPA%3D",
    "https://lf26-appstore-sign.oceancloudapi.com/ocean-cloud-tos/VolcanoUserVoice/speech_7481299960424759350_391e021d-8ed9-4864-b1ff-3f45a4751816.mp3?lk3s=da27ec82&x-expires=1775640957&x-signature=ZvrO2kPJ8dZ8XCKdcoBHS4VWbXw%3D",
    "https://lf6-appstore-sign.oceancloudapi.com/ocean-cloud-tos/VolcanoUserVoice/speech_7481299960424759350_720efc5e-64c8-4faa-9c9a-a50e352757b4.mp3?lk3s=da27ec82&x-expires=1775640957&x-signature=2W1jhRMzAYttZFk8IzZx%2B1tzgUY%3D",
    "https://lf9-appstore-sign.oceancloudapi.com/ocean-cloud-tos/VolcanoUserVoice/speech_7481299960424759350_fb20945c-b7a3-4e8e-92c0-2aaec62eca7c.mp3?lk3s=da27ec82&x-expires=1775640958&x-signature=RURiqbqYU%2B1S0l9gexvp24CqeyU%3D",
    "https://lf6-appstore-sign.oceancloudapi.com/ocean-cloud-tos/VolcanoUserVoice/speech_7481299960424759350_acd40bef-166a-43c8-9a79-40e90c78483c.mp3?lk3s=da27ec82&x-expires=1775640958&x-signature=jUVAJsYgPQg2nmnlmaDEuOBLtD4%3D",
    "https://lf6-appstore-sign.oceancloudapi.com/ocean-cloud-tos/VolcanoUserVoice/speech_7481299960424759350_164b54d2-db1e-4c66-9271-7f14ce1b675c.mp3?lk3s=da27ec82&x-expires=1775640958&x-signature=vZrcziKx91EwI0comDVneW8heQA%3D",
    "https://lf26-appstore-sign.oceancloudapi.com/ocean-cloud-tos/VolcanoUserVoice/speech_7481299960424759350_078634b3-1dad-4fb5-98a2-58cc41c15b20.mp3?lk3s=da27ec82&x-expires=1775640959&x-signature=YR%2Fm7235kIm%2FIFS07fjZg%2BJO1yc%3D",
    "https://lf9-appstore-sign.oceancloudapi.com/ocean-cloud-tos/VolcanoUserVoice/speech_7481299960424759350_98d041e1-c8fe-46d9-aa6d-89e865102efb.mp3?lk3s=da27ec82&x-expires=1775640959&x-signature=vmIMPc87KcZxBIAX9D5gS6Kw4yE%3D",
    "https://lf26-appstore-sign.oceancloudapi.com/ocean-cloud-tos/VolcanoUserVoice/speech_7481299960424759350_fe23dcf8-7088-4156-8ef7-a5fb1395595f.mp3?lk3s=da27ec82&x-expires=1775640960&x-signature=hnBP7VQmDD6ljTITQM4lMRlsDts%3D",
    "https://lf3-appstore-sign.oceancloudapi.com/ocean-cloud-tos/VolcanoUserVoice/speech_7481299960424759350_aa4ac4d8-343e-4123-ab66-6c6e3758fa22.mp3?lk3s=da27ec82&x-expires=1775640960&x-signature=SrJfa8v8qp4SlCanmMhcmNdkJno%3D",
    "https://lf9-appstore-sign.oceancloudapi.com/ocean-cloud-tos/VolcanoUserVoice/speech_7481299960424759350_a3772140-2e47-4620-907a-c29c95eebdeb.mp3?lk3s=da27ec82&x-expires=1775640960&x-signature=9h1ZoDG9bnfswsbnuCL6FYDLCO8%3D",
    "https://lf3-appstore-sign.oceancloudapi.com/ocean-cloud-tos/VolcanoUserVoice/speech_7481299960424759350_e81b91bd-c95c-4024-939d-926a78d03c04.mp3?lk3s=da27ec82&x-expires=1775640960&x-signature=ghRF3Cl790jv%2BYIo6siC4aJwnHY%3D",
    "https://lf6-appstore-sign.oceancloudapi.com/ocean-cloud-tos/VolcanoUserVoice/speech_7481299960424759350_6d804e9c-1f85-40a8-8a26-9b76dc396b62.mp3?lk3s=da27ec82&x-expires=1775640962&x-signature=Rupknj8zFcndYDvEjHybn%2F32rDs%3D"
  ],
  "medias": [
    {
      "end": 5,
      "index": 0,
      "start": 0
    },
    {
      "end": 11,
      "index": 1,
      "start": 6
    },
    {
      "end": 12,
      "index": 2,
      "start": 12
    },
    {
      "end": 16,
      "index": 3,
      "start": 13
    }
  ]
}

输出(output)

{
  "all_timelines": [
    {
      "end": 17087000,
      "start": 0
    }
  ],
  "media_timelines": [
    {
      "end": 4783000,
      "start": 0
    },
    {
      "end": 11051000,
      "start": 4783000
    },
    {
      "end": 13469000,
      "start": 11051000
    },
    {
      "end": 17087000,
      "start": 13469000
    }
  ],
  "timelines": [
    {
      "end": 525000,
      "start": 0
    },
    {
      "end": 1303000,
      "start": 525000
    },
    {
      "end": 2388000,
      "start": 1303000
    },
    {
      "end": 3053000,
      "start": 2388000
    },
    {
      "end": 3918000,
      "start": 3053000
    },
    {
      "end": 4783000,
      "start": 3918000
    },
    {
      "end": 5468000,
      "start": 4783000
    },
    {
      "end": 6546000,
      "start": 5468000
    },
    {
      "end": 7284000,
      "start": 6546000
    },
    {
      "end": 8435000,
      "start": 7284000
    },
    {
      "end": 9420000,
      "start": 8435000
    },
    {
      "end": 11051000,
      "start": 9420000
    },
    {
      "end": 13469000,
      "start": 11051000
    },
    {
      "end": 14020000,
      "start": 13469000
    },
    {
      "end": 15385000,
      "start": 14020000
    },
    {
      "end": 16316000,
      "start": 15385000
    },
    {
      "end": 17087000,
      "start": 16316000
    }
  ]
}

通过扣子官方语音合成开发的速推版剪映小助手时间线插件