--- 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""></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&bvid=BV16G4y1S7Hp&cid=985575449&page=1&as_wide=1&high_quality=1&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 %}