---
title: B站字幕转换
date: 2022-02-22 10:34:50
toc: false
---
{% raw %}
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="Pragma" content="no-cache">
    <meta http-equiv="Cache-Control" content="no-cache">
    <meta http-equiv="Expires" content="0">
    <link rel="stylesheet" href="/html/assets/element-ui.css">
    <!-- import Vue before Element -->
    <script src="/html/assets/vue.min.js"></script>
    <!-- import JavaScript -->
    <script src="/html/assets/element-ui.js"></script>
</head>
<body>
<div id="app">
    <div class="tools-upload">
        <el-upload action="#" :http-request="requestUpload" :show-file-list="false">
            <el-button size="mini" type="primary">上传</el-button>
        </el-upload>
        <div class="tools-right">
            <div class="tool-item">
                文件编码:
                <el-select size="mini" v-model="fileEncoder" placeholder="文件编码">
                    <el-option label="GBK" value="GBK"></el-option>
                    <el-option label="UTF-8" value="UTF-8"></el-option>
                    <el-option label="GB2312" value="GB2312&quot;"></el-option>
                </el-select>
            </div>
            <div class="tool-item">
                换行符:
                <el-select size="mini" v-model="newline" placeholder="换行符">
                    <el-option label="\r\n (Windows)" value="windows"></el-option>
                    <el-option label="\n (Linux)" value="linux"></el-option>
                </el-select>
            </div>
        </div>
    </div>
    <el-input type="textarea" placeholder="请上传或输入字幕文件" v-model="originText" rows="15" show-word-limit="">
    </el-input>
    <div class="tools-btn">
        <el-button size="mini" @click="generateSrt">生成SRT文件</el-button>
        <el-button size="mini" @click="generateTXT">生成TXT文件</el-button>
        <el-button size="mini" @click="clear">清空</el-button>
    </div>
    <el-input type="textarea" placeholder="等待生成SRT文件" v-model="srtText" rows="15" show-word-limit="">
    </el-input>
    <el-button type="text" @click="saveSrt">保存到本地</el-button>

    <h3>字幕提取方法参考下面的视频</h3>

    <div style="position: relative; padding: 30% 50%;">
        <iframe src="//player.bilibili.com/player.html?aid=863543343&amp;bvid=BV16G4y1S7Hp&amp;cid=985575449&amp;page=1&amp;as_wide=1&amp;high_quality=1&amp;danmaku=1"
                scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"
                style="position: absolute; width: 100%; height: 100%; left: 0; top: 0;"></iframe>
    </div>
    <div class="post-reward">
        <div class="reward-button">
            <i class="fas fa-qrcode"></i>
            打赏
        </div>
        <div class="reward-main">
            <ul class="reward-all">
                <li class="reward-item">
                    <a href="/img/wechat.jpg" target="_blank">
                        <img class="post-qr-code-img" src="/img/wechat.jpg" alt="微信"/>
                    </a>
                    <div class="post-qr-code-desc">微信</div>
                </li>
            </ul>
        </div>
    </div>
</div>
</body>
<script>

    new Vue({
        el: '#app',
        data: function () {
            return {
                fileEncoder: "UTF-8",
                newline: "windows",
                originText: "",
                srtText: "",
                fileName: ""
            }
        },
        methods: {
            // 覆盖默认的上传行为
            requestUpload(content) {
                let file = content.file
                let index = file.name.lastIndexOf('.')
                this.fileName = file.name.substring(0, index)
                // 新建一个FileReader
                const reader = new FileReader()
                // 读取文件
                reader.readAsText(file, this.fileEncoder)
                // 读取完文件之后会回来这里
                reader.onload = (e) => {
                    // 读取文件内容
                    const fileString = e.target.result
                    // 接下来可对文件内容进行处理
                    this.originText = fileString
                }
            },
            generateSrt() {
                this.srtText = ""
                let originObj = JSON.parse(this.originText)
                let body = originObj.body
                let lastTo = null
                for (let index = 0; index < body.length; index++) {
                    let line = body[index]
                    this.srtText += (index + (this.newline == 'windows' ? '\r\n' : '\n'))
                    let from = line.from
                    if (lastTo) {
                        let timeA = (from + '').split(".");
                        let timeB = (lastTo + '').split("."); //上次的时间
                        if (parseInt(timeB[0]) >= parseInt(timeA[0])) {
                            timeA[0] = timeB[0];
                            if (timeB[1]) {
                                if (parseInt(timeB[1]) >= parseInt(timeA[1])) {
                                    timeA[1] = timeB[1];
                                }
                            }
                            from = (timeA[1] ? (timeA[0] + '.' + timeA[1]) : timeA[0])
                        }
                    }
                    this.srtText += (this.deelTime(from) + " --> ")
                    let to = line.to
                    lastTo = to
                    this.srtText += (this.deelTime(to) + (this.newline == 'windows' ? '\r\n' : '\n'))
                    this.srtText += line.content
                    this.srtText += (this.newline == 'windows' ? '\r\n' : '\n')
                    this.srtText += (this.newline == 'windows' ? '\r\n' : '\n')
                }
            },
            generateTXT() {
                this.srtText = ""
                let originObj = JSON.parse(this.originText)
                let body = originObj.body
                let lastTo = null
                for (let index = 0; index < body.length; index++) {
                    let line = body[index]
                    let content = line.content
                    this.srtText += content
                    this.srtText += (this.newline == 'windows' ? '\r\n' : '\n')
                }
            },
            deelTime(origin) {
                let timeA = (origin + '').split(".");
                let tranTime = this.sumSecondToTime(timeA[0]);
                return tranTime + "," + (timeA.length < 2 ? '000' : timeA[1].padStart(3, '0'));
            },

            sumSecondToTime(sumSecond) {
                if (sumSecond <= 0) {
                    return "00:00:00";
                }
                let h = parseInt(sumSecond / 3600);
                let m = parseInt((sumSecond - h * 3600) / 60);
                let s = sumSecond - h * 3600 - m * 60;
                let time = (h + '').padStart(2, '0') + ':' + (m + '').padStart(2, '0') + ':' + (s + '').padStart(2,
                    '0');
                return time;
            },
            clear() {
                this.originText = ""
            },
            saveSrt() {
                // const file = new Blob(this.srtText, {
                //   type: 'text/plain'
                // });
                // a.href = URL.createObjectURL(file);
                // a.download = name;

                var element = document.createElement('a');
                element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(this.srtText));
                if (this.fileName != '') {
                    element.setAttribute('download', this.fileName + '.srt');
                } else {
                    element.setAttribute('download', 'translated.srt');
                }

                element.style.display = 'none';
                document.body.appendChild(element);
                element.click();
                document.body.removeChild(element);
            }
        }
    })

</script>
<style>
    .tools-upload {
        margin: 10px 0;
        display: flex;
        flex-direction: row;
        justify-content: space-between;
        align-items: center;
    }

    .tools-right {
        display: flex;
        flex-direction: row;
        align-items: center;
        font-size: 15px;
    }

    .tool-item {
        margin-left: 10px;
    }

    .tools-btn {
        margin: 10px 0;
    }
</style>
</html>
{% endraw %}