<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>剪映 - 字幕导出工具</title>
    <style type="text/css" rel="stylesheet">
        label {
            user-select: none;
        }
    </style>
</head>
<body>
<p>Windows 目录:C:\Users\Administrator\AppData\Local\JianyingPro\User Data\Projects\com.lveditor.draft\</p>
<p>Android 目录:/data/data/com.lemon.lv/files/newdrafts/</p>
<label>设置换行符:
    <select onchange="onChange(this.value)">
        <option value="rn">\r\n (Windows)</option>
        <option value="n">\n (Linux)</option>
    </select>
    <span id="rn-hint" style="color: red;display: none">  **  修改后需要重新生成</span>
</label>
<p><label for="input-text">输入 JSON</label></p>
<div>
    <textarea id="input-text" cols="60" rows="15">{"platform": {"os": ""},"materials":{"texts":[{"content":"轨道一文本","id":
"28824EDA-D841-4c81-B264-DC268957660B","type":"text"},{"content":"轨道二文本","id":"A4637647-EF07-418c-B2A4-6781EC9B6003",
"type":"text"}]},"tracks":[{"id":"A891C42E-A9F6-41fa-89E4-5DD250F2D7D1","segments":[{"id":"624A1A67-15F8-499b-BDF4-0C949FFB383A",
"material_id":"28824EDA-D841-4c81-B264-DC268957660B","target_timerange":{"duration":3000000,"start":0}}],"type":"text"},
{"id":"45336909-80D9-4320-93C2-1737989C45FC","segments":[{"id":"7729B6F5-8C3D-46ee-A0F4-3D3FC5B82823","material_id":
"A4637647-EF07-418c-B2A4-6781EC9B6003","target_timerange":{"duration":3000000,"start":2652233000}}],"type":"text"}]}</textarea>
    <button type="button" onclick="onGenerateClick()">生成 srt 文件</button>
    <button type="button" onclick="onClearClick()">清空</button>
</div>
<p><label>输出 SRT</label></p>
<script>
    // 输入文本域
    let inputText = document.getElementById('input-text');
    // 提示信息
    let hintSpan = document.getElementById('rn-hint');
    // 存储输出的 div 数组
    let outputDivArray = [];
    // 换行符
    let RN = '\r\n';
    function onChange(value) {
        switch (value) {
            case 'rn':
                RN = '\r\n';
                break;
            case 'n':
                RN = '\n';
                break;
            default:
        }
        if (outputDivArray.length) {
            hintSpan.style.display = 'inline-block';
        }
    }
    function onClearClick() {
        inputText.value = '';
    }
    function onGenerateClick() {
        try {
            hintSpan.style.display = 'none';
            // 如果上一次生成的 div 标签存在就移除掉
            let temp;
            while (outputDivArray.length) {
                temp = outputDivArray.pop();
                temp.parentNode.removeChild(temp);
            }
            // 剪映 json 对象
            temp = JSON.parse(inputText.value);
            let srtFiles = convertJSON2SRT(temp);
            let text;
            for (let k in srtFiles) {
                text = srtFiles[k];
                temp = document.createElement('div');
                temp.innerHTML = '<textarea cols="60" rows="15" readonly>' + text + '</textarea>';
                temp.appendChild(getDownloadLink('jy_' + k + '.srt', text));
                document.body.appendChild(temp);
                outputDivArray.push(temp);
            }
            alert('生成完毕');
        } catch (e) {
            console.log(e);
            alert('JSON 解析错误');
        }
    }
    function convertJSON2SRT(jy) {
        // 平台系统
        let os = jy.platform.os;
        // 提取文本材料
        // Map 结构 = {id1: text1, id2: text2, ...}
        let texts = {}, temp = jy.materials.texts;
        for (let i in temp) {
            texts[temp[i].id] = temp[i].content;
        }
        // 轨道列表
        let tracks = jy.tracks, track;
        // SRT 文件 Map
        let srtFiles = {};
        for (let i in tracks) {
            track = tracks[i];
            temp = convertTrack2Srt(track, texts, os);
            if (temp) {
                srtFiles[track.id] = temp;
            }
        }
        return srtFiles;
    }
    /**
     * 将一条轨道转换为 srt 文本
     * @param track 轨道
     * @param texts 文本材料
     * @param milli 是否是毫秒单位
     * @return {string}
     */
    function convertTrack2Srt(track, texts, milli) {
        let segments = track.segments, segment;
        let srt = {content: null, start: null, end: null};
        let srtText = '', index = 0;
        for (let i in segments) {
            segment = segments[i];
            srt.content = texts[segment.material_id];
            if (!srt.content) continue;
            srt.start = segment.target_timerange.start;
            srt.end = srt.start + segment.target_timerange.duration;
            srt.start = getSrtTimeText(srt.start, milli);
            srt.end = getSrtTimeText(srt.end, milli);
            index++;
            srtText += formatSrt(index, srt);
        }
        return srtText;
    }
    /**
     * 获取下载地址的标签
     * @param fileName 文件名
     * @param data 数据
     * @returns {HTMLElement}
     */
    function getDownloadLink(fileName, data) {
        // 创建 a 标签
        let a = document.createElement('a');
        a.innerText = '保存到本地';
        a.download = fileName;
        //生成一个 blob 二进制数据,内容为数据
        let blob = new Blob([data], {type: 'application/octet-stream'});
        //生成一个指向 blob 的 URL 地址,并赋值给 a 标签的 href 属性
        a.href = URL.createObjectURL(blob);
        return a;
    }
    /**
     * 获取 SRT 格式的时间文本
     * @param time 时间,windows版本为微秒数
     * @param milli 是否是毫秒单位
     * @returns {string}
     */
    function getSrtTimeText(time, milli) {
        // 1h1m1s111ms = 61m1s111ms = 3661s111ms = 3661111ms
        if (!milli) {
            time = Math.floor(time / 1000);
        }
        // 余出的毫秒
        let millisecond = time % 1000;
        time = Math.floor(time / 1000);
        // 余出秒
        let second = time % 60;
        time = Math.floor(time / 60);
        // 余出分钟
        let minute = time % 60;
        time = Math.floor(time / 60);
        // 剩余时数
        let hour = time;
        hour = formatDigit(hour, 2);
Back to home | 
File page
Subscribe | 
Register |
Login
| N