SubJSON —可搜索电影的多语言字幕

字幕是电影数据中被低估的部分,但是却导致效率低下。 最有趣的部分是音频信息的文学转录,提供了一种使电影可搜索的方法。

对于不耐烦的人,可以在这里找到示例:
https://github.com/azcoppen/subtitle-json/tree/master/json

现有标准

至少有8种不同的字幕格式经常使用。 SubRip(.srt)是迄今为止下载文件使用最广泛的方法。

  • VOB(DVD)
  • PGS(蓝光)
  • SubRip(.srt)
  • WebVTT(.vtt)
  • 变电站Alpha(.ass)
  • YouTube字幕(.sbv)
  • JSON(TED.com)字幕(.json)
  • TTML(.dfxp)

“ The Shawshank Redemption”中的示例.srt条目:

119 
00:08:51,565 --> 00:08:54,943
So, when Andy Dufresne came to me in 1949

120
00:08:55,027 --> 00:08:58,363
and asked me to smuggle Rita Hayworth
into the prison for him,

121
00:08:58,447 --> 00:09:00,532
I told him, "No problem."

值得注意的问题

很少或没有编程访问数据

为了挖掘或搜索字幕转录内容,访问必须采用易于反序列化为简单且可用的对象模型的格式。 字幕(如剧本)以标记的格式进行格式化,该标记描述了重叠的时间,但其中的内容没有任何变化。 作为数据访问它可以在程序和平台之间进行更复杂的交换,并可以动态生成/操作文档。

每个国家一个文件?

同一部电影有多个国家档案完全没有意义。 尽管翻译发生在不同地方的不同时间,但每个设备或发行版只有一个文件似乎更加实用。

不同版本的数量令人困惑:

http://www.yifysubtitles.com/movie-imdb/tt0111161

版本中的内容不一致

在法国发行的电影可能与在美国发行的电影有所不同。 蓝光特别版可能与美国DVD不同。 “导演剪辑”的长度可能完全不同。

版本中的时间不一致

每个翻译的文件都以毫秒为单位存储其提示 。 不幸的是,每个语言文件都以一种不到司法鉴定的方式注释了相同的对话和/或屏幕文本,这意味着条目在各个国家之间并不一致,通常相差100-400毫秒。 时间码“开始”事件根本不同步。

文件定义对象

主文档容器是一个简单的标头,它提供有关文档的元数据以及有关视觉表示的信息(模板,各个样式)。

定时的叠加项将作为数组存储在data属性中。

  { 
“ id”:“ 33834784375375”,
“ title”:“肖申克的救赎”,
“ format”:“ SubRip”,
“模板”:{
“ default”:“ __CONTENT__”,
“斜体”:“ __ CONTENT __ ”
},
“样式”:{
“ default”:“字体样式:10px;行高:1;颜色:#FFF;”
},
“数据”:[]
}

重叠对象

屏幕事件是一组覆盖对象,按其开始时间码(以毫秒为单位)对ASC进行排序。

时间编码的字幕覆盖表示为常见的JSON对象:

  • 触发器 :发生屏幕事件提示的时间(以毫秒为单位)。
  • lang :要显示的内容的ISO语言代码。
  • styles :播放设备应将哪些样式类应用于内容。
  • 模板 :播放设备应将哪些显示模板应用于内容(排队)。
  • start :屏幕事件触发时间的数学细分。
  • end :屏幕事件应结束且不再显示的时间的数学细分。
  • 持续时间 :屏幕事件生命周期的数学分解。
  • content :应显示的LTR / RTL字符串。
  • meta :任何可以添加到overlay事件中以使播放设备受益的自定义数据,
  { 
“触发器”:4736088,
“ lang”:“ en”,
“样式”:[
“默认”
],
“模板”:[
“默认”
],
“开始”:{
“时间”:4736088,
“小时”:1
“分钟”:18,
“秒”:56
“毫秒”:88
},
“结束”: {
“时间”:4739256,
“小时”:1
“分钟”:18,
“秒”:59,
“ ms”:256
},
“持续时间”:{
“秒”:3.168,
“ ms”:3168
},
“ content”:“有一百种不同的方法可以使您脱颖而出。”,
“元”:{
“原版的”: {
“ start”:“ 01:18:56,088”,
“ end”:“ 01:18:59,256”
}
}
}

用Java显示

假设我们在显示环境中有JQuery的示例(例如,基于节点的程序(如Electron)或网络播放器(如Video.js)。

从EN字幕文件中提取所有字幕并将其打印到有序HTML列表的示例:

  $(video_player_object).load(function(){ 
$ .getJSON(“ subtitles / zh-CN / RAW_en_the_shawshank_redemption.json”,function(file_contents){
var items = [];

$ .each(file_contents.data,function(key,val){
items.push(“
  • ” + val +“
  • ”);
    });

    $(“
      ”,{
      “ class”:“ my-new-list”,
      html:items.join(“”)
      })。appendTo(“ body”);

      });
      });

    从具有EN,FR,PT和IT条目的多语言文件中提取所有西班牙语覆盖数据的示例。

      $(video_player_object).load(function(){ 
    $ .getJSON(“字幕/多语言/RAW_multi_the_shawshank_redemption.json”,function(file_contents){
    var items = [];

    $ .each(file_contents.data,function(key,val){
    call_some_function_when_time_hits(val.trigger,val.content);
    //等
    });

    });
    });

    在NoSQL存储中搜索

    一旦存储在后端NoSQL数据库(如MongoDB,CouchDB,Neo4j甚至HTML5 localStorage)中,我们突然就有了一种搜索电影的方法。

    用MongoDB查询

    从多语言字幕文件中获取所有FR字幕

    (假设我们已经知道文档ID为4ecc05e55dd98a436ddcc47c )。

      db.subtitles.find({“ _ id”:ObjectId(“ 4ecc05e55dd98a436ddcc47c”),'data.lang':'fr'}) 

    电影何时提到“脱脂”一词?

      db.subtitles.ensureIndex({content:1}); 
    db.subtitles.find(content:“ skim”);

    字幕显示的平均持续时间是多少?

      db.subtitles.find({“ _ id”:ObjectId(“ 4ecc05e55dd98a436ddcc47c”)})。aggregate( 
    [
    {
    $ group:
    {
    _id:“ $ item”,
    avgDuration:{$ avg:“ $ duration”}
    }
    }
    ]

    有人说“操”多少次?

    使用Mongo的MapReduce功能(https://docs.mongodb.com/manual/core/map-reduce/)查看所有出现的关键字:

      db.subtitles.mapReduce(map,reduce,{out:“ word_count”}) 

    结果示例:

      db.word_count.find()。sort({value:-1}) 
    {“ _id”:“是”,“值”:3}
    {“ _id”:“坏”,“值”:2}
    {“ _id”:“好”,“值”:2}
    {“ _id”:“ this”,“ value”:2}
    {“ _id”:“都不”,“值”:1}
    {“ _id”:“ or”,“ value”:1}
    {“ _id”:“ something”,“ value”:1}
    {“ _id”:“ that”,“ value”:1}

    SubJSON在Attribution-ShareAlike(CC BY-SA)创用CC许可下可在Github上使用,任何人均可自由使用。

    https://github.com/azcoppen/subtitle-json