吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 9277|回复: 28
收起左侧

[其他转载] 剪映字幕导出为SRT文件网页版

  [复制链接]
pansong291 发表于 2021-3-11 20:12
本帖最后由 pansong291 于 2022-10-12 22:21 编辑

更新:增加选择文件功能,原来 h5 早就支持读取本地文件了,我居然不知道。



更新:坛友反馈时间不正常,现增加了一个时间单位选择框,如果生成的时间不正常,可尝试自行切换时间单位



我最早是看到了一个python版的和一个易语言版的软件,后面又有人出了Mac版的,小弟不才也想来凑个热闹,写了个网页版的,但这又算不上是一个软件,因此在本版发出来,大家当一个小玩具玩玩便可。纯 Html 与 js 写成,无任何第三方库调用。

截图

截图


代码如下,使用方法,找个记事本新建一个文本文件,将代码复制进去,保存。然后修改后缀名为 .html ,拖到浏览器窗口中即可。
代码也托管在 Gitee 上了,https://gitee.com/pansong291/web
你也可以直接访问这个页面:https://pansong291.github.io/ashe/
<!DOCTYPE html>
<html lang="zh-cmn-Hans">
  <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;
        font-weight: bold;
      }

      div {
        margin: 4px 0;
      }

      .gap-8 {
        gap: 8px;
      }

      .flex {
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
      }

      .flex.row {
        flex-direction: row;
      }

      #main-container {
        align-items: flex-start;
      }

      .hint-span {
        color: red;
        display: none;
        margin-left: 8px;
      }
    </style>
  </head>
  <body>
    <div class="flex">
      <div id="main-container" class="flex">
        <div>Windows 目录:C:\Users\Administrator\AppData\Local\JianyingPro\User Data\Projects\com.lveditor.draft\</div>
        <div>Android 目录:/data/data/com.lemon.lv/files/newdrafts/</div>
        <div>
          <label>
            设置换行符:
            <select>
              <option value="rn">\r\n (Windows)</option>
              <option value="n">\n (Linux)</option>
            </select>
            <span id="rn-hint" class="hint-span">** 修改后需要重新生成</span>
          </label>
        </div>
        <div>
          <label>
            选择时间单位:
            <select>
              <option value="milli">毫秒</option>
              <option value="micro">微秒</option>
            </select>
            <span id="time-unit-hint">一般情况Windows是微秒,安卓是毫秒,如果时间不正常,可根据实际情况自行选择</span>
            <span id="time-unit-reapply-hint" class="hint-span">** 修改后需要重新生成</span>
          </label>
        </div>
        <div><label for="input-text">输入 JSON</label></div>
        <div class="flex row gap-8">
          <input id="input-file" type="file" />
          <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">生成 SRT 文件</button>
          <button type="button">清空</button>
        </div>
        <div><label>输出 SRT</label></div>
      </div>
    </div>
    <script>
      let mainContainer = document.getElementById('main-container')
      // 文件选择
      let inputFile = document.getElementById('input-file')
      // 输入文本域
      let inputText = document.getElementById('input-text')
      // 换行符提示信息
      let rnHintSpan = document.getElementById('rn-hint')
      // 时间单位提示信息
      let timeUnitHintSpan = document.getElementById('time-unit-hint')
      // 时间单位重新应用提示信息
      let timeUnitReapplyHintSpan = document.getElementById('time-unit-reapply-hint')
      // 存储输出的 div 数组
      let outputDivArray = []
      // 换行符
      let RN = '\r\n'
      let timeUnit = 'milli'

      function onRNChange(value) {
        switch (value) {
          case 'rn':
            RN = '\r\n'
            break
          case 'n':
            RN = '\n'
            break
          default:
        }
        if (outputDivArray.length) {
          rnHintSpan.style.display = 'inline-block'
        }
      }

      function onTimeUnitChange(value) {
        timeUnit = value
        if (outputDivArray.length) {
          timeUnitHintSpan.style.display = 'none'
          timeUnitReapplyHintSpan.style.display = 'inline-block'
        }
      }

      function onFileSelected(el) {
        let file = el.files[0]
        if (file) {
          let reader = new FileReader()
          reader.readAsText(file)
          reader.onload = function () {
            inputText.value = this.result
          }
        }
      }

      function onClearClick() {
        inputText.value = ''
        inputFile.value = ''
      }

      function onGenerateClick() {
        try {
          rnHintSpan.style.display = 'none'
          timeUnitHintSpan.style.display = 'inline-block'
          timeUnitReapplyHintSpan.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,
            i = 1
          for (let k in srtFiles) {
            text = srtFiles[k]
            temp = document.createElement('div')
            temp.className = 'flex row gap-8'
            temp.innerHTML = `<textarea cols="60" rows="15" readonly>${text}</textarea>`
            temp.appendChild(getDownloadLink(`下载轨道${i}`, `jy_track${i}_${k}.srt`, text))
            mainContainer.appendChild(temp)
            outputDivArray.push(temp)
            i++
          }
        } catch (e) {
          console.log(e)
          alert('JSON 解析错误')
        }
      }

      function convertJSON2SRT(jy) {
        // 提取文本材料
        // 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)
          if (temp) {
            srtFiles[track.id] = temp
          }
        }
        return srtFiles
      }

      /**
       * 将一条轨道转换为 srt 文本
       * @param track 轨道
       * @param texts 文本材料
       * @return {string}
       */
      function convertTrack2Srt(track, texts) {
        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)
          srt.end = getSrtTimeText(srt.end)
          index++
          srtText += formatSrt(index, srt)
        }
        return srtText
      }

      /**
       * 获取下载地址的标签
       * @param text 文案
       * @param fileName 文件名
       * @param data 数据
       * @returns {HTMLElement}
       */
      function getDownloadLink(text, fileName, data) {
        // 创建 a 标签
        let a = document.createElement('a')
        a.innerText = text
        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版本为微秒数
       * @returns {string}
       */
      function getSrtTimeText(time) {
        // 1h1m1s111ms = 61m1s111ms = 3661s111ms = 3661111ms
        if (timeUnit === 'micro') {
          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)
        minute = formatDigit(minute, 2)
        second = formatDigit(second, 2)
        millisecond = formatDigit(millisecond, 3)
        return `${hour}:${minute}:${second},${millisecond}`
      }

      /**
       * 格式化为 SRT
       * @param index 字幕序号,从 1 开始
       * @param srt 字幕内容等信息
       * @returns {string}
       */
      function formatSrt(index, srt) {
        return `${index}${RN}${srt.start} --> ${srt.end}${RN}${srt.content}${RN}${RN}`
      }

      /**
       * 格式化数字
       * @param digit 数字
       * @param length 长度
       * @returns {string}
       */
      function formatDigit(digit, length) {
        let str = digit.toString()
        while (str.length < length) {
          str = `0${str}`
        }
        return str
      }
    </script>
  </body>
</html>

免费评分

参与人数 5吾爱币 +5 热心值 +3 收起 理由
Ls30 + 1 + 1 我很赞同!
YYSYSS + 1 + 1 谢谢@Thanks!
yemoecom + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
solidajun + 1 + 1 我很赞同!
odeepo + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

sang 发表于 2021-9-8 17:20

楼主已经修复了这个问题,请下载楼主最新版代码,感谢楼主!!

本帖最后由 sang 于 2021-11-19 15:05 编辑

最新版本剪映楼主的这个文件导出的字幕时间上会出问题,我研究了一下代码,和毫秒有关。
找到以下代码
function getSrtTimeText(time, milli) {
        // 1h1m1s111ms = 61m1s111ms = 3661s111ms = 3661111ms
        if (!milli) {
            time = Math.floor(time / 1000);
把if (!milli)这个里面的感叹号删除保存即可
 楼主| pansong291 发表于 2021-3-31 00:08
本帖最后由 pansong291 于 2021-3-31 00:12 编辑
lyjhyjyes 发表于 2021-3-28 20:34
您好,我的剪映装在win10 d盘,非默认地址。导出字幕空白,请问其他人有正常使用的吗

你好,抱歉隔了这么久才看到这条消息,剪映不管装在哪个盘里,数据存储路径都是固定的(目前是这样,以后版本会不会变就不清楚了。需要注意的是用户文件夹需要根据自己电脑用户确定,不一定都是 Administrator。另外,如果其中某个目录找不到,请确认开启了显示隐藏文件)。请麻烦你将问题再描述清楚一点,最后好能附上如下信息:json文件内容,以及一些操作截图等。
tek2y 发表于 2021-3-11 23:11
红蓝黄 发表于 2021-3-11 23:54
感谢分享
长弓邪 发表于 2021-3-14 23:14
能不能反过来呢?把srt文件转为剪映字幕呢?
55168791 发表于 2021-3-16 16:32
mark 一下剪映字幕导出
dada000028 发表于 2021-3-25 11:14
长弓邪 发表于 2021-3-14 23:14
能不能反过来呢?把srt文件转为剪映字幕呢?

没有必要吧,剪映识别率很高的
lyjhyjyes 发表于 2021-3-28 20:34
您好,我的剪映装在win10 d盘,非默认地址。导出字幕空白,请问其他人有正常使用的吗
叶子大人 发表于 2021-3-30 17:23
能不能导出xml格式文件咧,,,
lyjhyjyes 发表于 2021-3-31 21:50
pansong291 发表于 2021-3-31 00:08
你好,抱歉隔了这么久才看到这条消息,剪映不管装在哪个盘里,数据存储路径都是固定的(目前是这样,以后 ...

您好,html文档修改Administrator或者本地用户名,都无法完成转换,可能没找到准确位置。
https://www.52pojie.cn/forum.php?tid=1386435 这个却能准确获取,完成转换。
可能是您的html没能找到子目录
01.png
02.png
03.png
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 09:40

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表