Skip to content

Commit 0c3f430

Browse files
committed
Very basic ASS subtitle parser
1 parent f556404 commit 0c3f430

7 files changed

+663
-1
lines changed

build/CommentCoreLibrary.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/CommentTypes.md

+4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
* 18 - Canvas/SVG定位弹幕(未完成)
1313
* 19 - 绘图弹幕(未完成)
1414
* 20 - 高阶定位混合弹幕组(实验性)
15+
* 21 - 字幕弹幕
1516
默认情况下,弹幕都必须包含:开始时间、字体大小、字体字号、颜色。
1617

1718
## 滚动弹幕
@@ -114,3 +115,6 @@ toScale为形如"[Int]x[Int]"的参数,标记了缩放末位置的大小。缩
114115

115116
## 绘图弹幕
116117
无完整的实现Spec.
118+
119+
## 字幕弹幕
120+
部分兼容 ASS 字幕文件

experimental/extensions/index.htm

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5+
<meta http-equiv="X-UA-Compatible" value="IE=9">
6+
<link rel="stylesheet" href="../../demo/default.css" />
7+
<link rel="stylesheet" href="../../build/base.css" />
8+
<!-- Run 'make' to build the file -->
9+
<script src="../../build/CommentCoreLibrary.js"></script>
10+
11+
<!-- A few helpers to do some decoding/fetching below-->
12+
<script src="player.js"></script>
13+
<script src="../../extend/ass2dm.js"></script>
14+
15+
<title>Testrun Sandbox For ASS Subtitles</title>
16+
</head>
17+
<body>
18+
<div class="m20 abp" id="player" style="width:100%;height:600px;">
19+
<div id="commentCanvas" class="container"></div>
20+
<video id="abpVideo" autobuffer="true" data-setup="{}" width="100%" height="100%" style="z-index:-1;width:100%;height:100%;top:0;left:0;right:0;bottom:0;" autobuffer="true">
21+
<source src="http://tools.kanoha.org/ccltestingvideos/%5bYYDM-11FANS%5d%5bStrike_Witches%5d%5bBDRIP%5d%5b01%5d%5bX264_AAC%5d%5b1280X720%5d.mp4" type="video/mp4">
22+
</video>
23+
</div>
24+
<a onclick="play();" href="javascript:;">Play</a>
25+
<a onclick="stop();" href="javascript:;">Pause</a>
26+
27+
<p>Scripting: <a href="../../demo/">&larr; Back to main test</a> </p>
28+
<script>
29+
var isWindowedFullscreen = false;
30+
function launchFullScreen(element) {
31+
cm.setBounds();
32+
if(element.requestFullscreen) {
33+
element.requestFullscreen();
34+
} else if(element.mozRequestFullscreen) {
35+
element.mozRequestFullscreen();
36+
} else if(element.webkitRequestFullscreen) {
37+
element.webkitRequestFullscreen();
38+
}
39+
}
40+
41+
function launchWindowFull(element){
42+
if(!isWindowedFullscreen){
43+
element.style.position = "fixed";
44+
element.style.top = "0";
45+
element.style.bottom = "0";
46+
element.style.left = "0";
47+
element.style.right = "0";
48+
element.style.width = "auto";
49+
element.style.height = "auto";
50+
}else{
51+
element.style.position = "";
52+
element.style.top = "";
53+
element.style.bottom = "";
54+
element.style.left = "";
55+
element.style.right = "";
56+
}
57+
cm.getBounds();
58+
isWindowedFullscreen = !isWindowedFullscreen;
59+
}
60+
61+
var cm = new CommentManager($('commentCanvas'));
62+
cm.init();
63+
64+
function rescale(){
65+
var aspectRatio = $("abpVideo").videoHeight / $("abpVideo").videoWidth;
66+
var myRatio = $("abpVideo").offsetHeight / $("abpVideo").offsetWidth;
67+
var realVideoHeight = aspectRatio > myRatio ? $("abpVideo").offsetHeight : $("abpVideo").offsetWidth * aspectRatio;
68+
var realVideoWidth = aspectRatio > myRatio ? $("abpVideo").offsetHeight / aspectRatio : $("abpVideo").offsetWidth;
69+
$("commentCanvas").style.bottom = "auto";
70+
$("commentCanvas").style.top = ($("abpVideo").offsetHeight - realVideoHeight)/2 + "px";
71+
$("commentCanvas").style.height = realVideoHeight + "px";
72+
$("commentCanvas").style.left = ($("abpVideo").offsetWidth - realVideoWidth)/2 + "px";
73+
$("commentCanvas").style.right = "auto";
74+
$("commentCanvas").style.width = realVideoWidth + "px";
75+
cm.setBounds();
76+
return {width: realVideoWidth, height: realVideoHeight}
77+
};
78+
79+
function loadASS(file){
80+
load(file, function(text){
81+
var timeline = parseASS(text, rescale());
82+
rescale();
83+
cm.load(timeline);
84+
});
85+
}
86+
87+
function play(){
88+
$("abpVideo").play();
89+
loadASS('../../tests/subtitles/[YYDM-11FANS][Strike_Witches][BDRIP][01][X264_AAC][1280X720].uni_gb.ass');
90+
}
91+
92+
function stop(){
93+
$("abpVideo").pause();
94+
}
95+
96+
window.addEventListener("load", function(){
97+
bind($("abpVideo"),cm);
98+
});
99+
</script>
100+
</body>
101+
</html>

experimental/extensions/player.js

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/** Some loading code **/
2+
function bind(video, cm){
3+
video.addEventListener("timeupdate", function(){
4+
if(cm.display === false) return;
5+
if(video.hasStalled){
6+
cm.startTimer();
7+
video.hasStalled = false;
8+
}
9+
cm.time(Math.floor(video.currentTime * 1000));
10+
});
11+
video.addEventListener("play", function(){
12+
cm.startTimer();
13+
});
14+
video.addEventListener("pause", function(){
15+
cm.stopTimer();
16+
});
17+
video.addEventListener("waiting", function(){
18+
cm.stopTimer();
19+
});
20+
video.addEventListener("playing",function(){
21+
cm.startTimer();
22+
});
23+
};
24+
25+
function load(filename, callback){
26+
var XHR = new XMLHttpRequest();
27+
XHR.onreadystatechange = function(){
28+
if(XHR.readyState === 4 && XHR.status === 200){
29+
callback(XHR.responseText);
30+
}
31+
};
32+
XHR.open("GET", filename, true);
33+
XHR.send();
34+
}

extend/ass2dm.js

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/**
2+
*Subtitles File Parser Unit
3+
*
4+
* Licensed Under MIT License
5+
* Transforms an ASS file into a readable array for the CommentCoreLibrary
6+
*
7+
* With reference from (https://github.com/spiegeleixxl/html5-ass-subtitles/)
8+
***/
9+
10+
function parseASS(input, config) {
11+
var state = 0;
12+
var linecounter = 0;
13+
var resizeFactor = 1;
14+
var captions = {};
15+
// initializing captions array
16+
var info = {};
17+
var styles = {};
18+
var timeline = [];
19+
// split the assfile by newlines.
20+
var assfile = input.split('\n');
21+
var comments="";
22+
23+
for (var linecount=0; linecount < assfile.length; linecount++){
24+
if (assfile[linecount].indexOf('[Script Info]') === 0){
25+
state = 1;
26+
} else if (assfile[linecount].indexOf('[V4+ Styles]')=== 0){
27+
state = 2;
28+
console.log(config);
29+
if ((info['PlayResX'] || info['PlayResY']) && (config.width || config.height)){
30+
resizeFactor = parseInt(info['PlayResY']) / config.height;
31+
console.log(resizeFactor);
32+
}
33+
} else if (assfile[linecount].indexOf('[Events]')=== 0){
34+
state = 3;
35+
} else if (state == 1){
36+
if (assfile[linecount].indexOf(';') !== 0){
37+
if (assfile[linecount].indexOf(':') > -1){
38+
var infoLine = assfile[linecount].split(':');
39+
info[infoLine[0].trim()] = infoLine[1].trim();
40+
}
41+
} else {
42+
comments = comments + assfile[linecount] + "\n";
43+
}
44+
} else if (state == 2){
45+
if (assfile[linecount].indexOf('Style:')=== 0){
46+
var styleparts = assfile[linecount].split(':')[1].split(',');
47+
var stylename = styleparts[0].trim();
48+
49+
var style = {};
50+
style['stylename'] = styleparts[0].trim();
51+
style['fontname'] = styleparts[1];
52+
style['fontsize'] = parseFloat(styleparts[2]) * resizeFactor;
53+
style['color1'] = styleparts[3].replace(/^&H00/, "#");
54+
style['color2'] = styleparts[4].replace(/^&H00/, "#");
55+
style['border-color'] = styleparts[5];
56+
style['shadow-color'] = styleparts[6];
57+
style['bold'] = styleparts[7];
58+
style['italic'] = styleparts[8];
59+
style['underline'] = styleparts[9];
60+
style['strikeout'] = styleparts[10];
61+
style['fontscalex'] = styleparts[11];
62+
style['fontscaley'] = styleparts[12];
63+
style['spacing'] = styleparts[13];
64+
style['angle'] = styleparts[14];
65+
66+
style['borderstyle'] = styleparts[15];
67+
style['outline'] = parseFloat(styleparts[16])*resizeFactor;
68+
style['shadow'] = parseFloat(styleparts[17])*resizeFactor;
69+
style['alignment'] = styleparts[18];
70+
style['marginleft'] = parseFloat(styleparts[19])*resizeFactor;
71+
style['marginright'] = parseFloat(styleparts[20])*resizeFactor;
72+
style['marginvertical'] = parseFloat(styleparts[21])*resizeFactor;
73+
style['encoding'] = styleparts[22];
74+
75+
styles[style.stylename] = style;
76+
}
77+
} else if (state == 3){
78+
if (assfile[linecount].indexOf('Dialogue:')=== 0){
79+
var lineparts = assfile[linecount].split(',');
80+
var st = lineparts[1].trim().split(':');
81+
var et = lineparts[2].trim().split(':');
82+
var stime = st[0]*60*60 + st[1]*60 + parseFloat(st[2]);
83+
var etime = et[0]*60*60 + et[1]*60 + parseFloat(et[2]);
84+
var comment = {
85+
'stime' : Math.round(stime * 1000),
86+
'dur': Math.round((etime - stime) * 1000),
87+
'ttl': Math.round((etime - stime) * 1000),
88+
'mode': 4,
89+
'size': styles[lineparts[3]]['fontsize'] * resizeFactor,
90+
'color': styles[lineparts[3]]['color1'],
91+
'font': styles[lineparts[3]]['fontname'],
92+
'margin': styles[lineparts[3]]['marginleft'] + "px " + styles[lineparts[3]]['marginvertical'] + "px " + styles[lineparts[3]]['marginright'] + "px " + styles[lineparts[3]]['marginvertical'] + "px",
93+
'style' : lineparts[3],
94+
'pool': 15,
95+
'actor' : lineparts[4],
96+
'marginleft' : lineparts[5],
97+
'marginright' : lineparts[6],
98+
'marginvertical' : lineparts[7],
99+
'effect' : lineparts[8]
100+
}
101+
for (var z = 0; z < 9; z++) { lineparts.shift(); }
102+
comment.text = lineparts.join(',');
103+
comment.text = comment.text.replace(/{[^}]+}/gi,"");
104+
/*
105+
captions['lines'][linecounter]['asstags'] = "";
106+
var matches = captions['lines'][linecounter]['text'].match(/{[^}]+}/g);
107+
for (var z in matches){
108+
if (matches[z].startsWith("{\\")){
109+
captions['lines'][linecounter]['asstags'] = captions['lines'][linecounter]['asstags'] + matches[z] + " ";
110+
}
111+
}
112+
captions['lines'][linecounter]['text'] = captions['lines'][linecounter]['text'].replace(/{[^}]+}/gi,"");
113+
*/
114+
timeline.push(comment);
115+
linecounter = linecounter+1;
116+
}
117+
}
118+
}
119+
console.log(styles);
120+
return timeline;
121+
}

src/CommentCoreLibrary.js

+2
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ function CommentManager(stageObject){
8989
cmt.className = 'cmt noshadow';
9090
if(data.color == "#000000" && (data.shadow || data.shadow == null))
9191
cmt.className += ' rshadow';
92+
if(data.margin != null)
93+
cmt.style.margin = data.margin;
9294
if(data.color != null)
9395
cmt.style.color = data.color;
9496
if(this.def.opacity != 1 && data.mode == 1)

0 commit comments

Comments
 (0)