Skip to content

Commit 1683aae

Browse files
committed
Added support for bili's linear-movement comments. Better support for acfun high level motion comments
1 parent 479209d commit 1683aae

10 files changed

Lines changed: 1399 additions & 137 deletions

File tree

build/CommentCoreLibrary.js

Lines changed: 163 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,12 @@ var CoreComment = (function () {
245245
this.cindex = -1;
246246
this.motion = [];
247247
this.movable = true;
248+
this._alphaMotion = null;
249+
/**
250+
* Absolute coordinates. Use absolute coordinates if true otherwise use percentages.
251+
* @type {boolean} use absolute coordinates or not (default true)
252+
*/
253+
this.absolute = true;
248254
/**
249255
* Alignment
250256
* @type {number} 0=tl, 2=bl, 1=tr, 3=br
@@ -310,6 +316,9 @@ var CoreComment = (function () {
310316
if (init.hasOwnProperty("opacity")) {
311317
this._alpha = init["opacity"];
312318
}
319+
if (init.hasOwnProperty("alpha")) {
320+
this._alphaMotion = init["alpha"];
321+
}
313322
if (init.hasOwnProperty("font")) {
314323
this._font = init["font"];
315324
}
@@ -322,6 +331,14 @@ var CoreComment = (function () {
322331
if (init.hasOwnProperty("shadow")) {
323332
this._shadow = init["shadow"];
324333
}
334+
if (init.hasOwnProperty("position")) {
335+
if (init["position"] === "relative") {
336+
this.absolute = false;
337+
if (this.mode < 7) {
338+
console.warn("Using relative position for CSA comment.");
339+
}
340+
}
341+
}
325342
}
326343
/**
327344
* Initializes the DOM element (or canvas) backing the comment
@@ -369,10 +386,16 @@ var CoreComment = (function () {
369386
this._x = this.parent.width - this.dom.offsetLeft - this.width;
370387
}
371388
}
389+
if (!this.absolute) {
390+
return this._x / this.parent.width;
391+
}
372392
return this._x;
373393
},
374394
set: function (x) {
375395
this._x = x;
396+
if (!this.absolute) {
397+
this._x *= this.parent.width;
398+
}
376399
if (this.align % 2 === 0) {
377400
this.dom.style.left = this._x + "px";
378401
} else {
@@ -392,10 +415,16 @@ var CoreComment = (function () {
392415
this._y = this.parent.height - this.dom.offsetTop - this.height;
393416
}
394417
}
418+
if (!this.absolute) {
419+
return this._y / this.parent.height;
420+
}
395421
return this._y;
396422
},
397423
set: function (y) {
398424
this._y = y;
425+
if (!this.absolute) {
426+
this._y *= this.parent.height;
427+
}
399428
if (this.align < 2) {
400429
this.dom.style.top = this._y + "px";
401430
} else {
@@ -581,27 +610,44 @@ var CoreComment = (function () {
581610
this._y = null;
582611
};
583612

613+
/**
614+
* Executes a motion object
615+
* @param currentMotion - motion object
616+
* @private
617+
*/
618+
CoreComment.prototype._execMotion = function (currentMotion, time) {
619+
for (var prop in currentMotion) {
620+
if (currentMotion.hasOwnProperty(prop)) {
621+
var m = currentMotion[prop];
622+
this[prop] = m.easing(Math.min(Math.max(time - m.delay, 0), m.dur), m.from, m.to - m.from, m.dur);
623+
}
624+
}
625+
};
626+
584627
/**
585628
* Update the comment's position depending on the applied motion
586629
* groups.
587630
*/
588631
CoreComment.prototype.animate = function () {
632+
if (this._alphaMotion) {
633+
this.alpha = (this.dur - this.ttl) * (this._alphaMotion["to"] - this._alphaMotion["from"]) / this.dur + this._alphaMotion["from"];
634+
}
589635
if (this.motion.length === 0) {
590636
return;
591637
}
592-
if (this.dur - this.ttl > this._motionEnd[this._curMotion]) {
638+
var ttl = Math.max(this.ttl, 0);
639+
var time = (this.dur - ttl) - this._motionStart[this._curMotion];
640+
if (this.dur - ttl > this._motionEnd[this._curMotion]) {
641+
var oldMotion = this.motion[this._curMotion];
642+
this._execMotion(oldMotion, time);
593643
this._curMotion++;
594-
this.animate();
644+
if (this._curMotion >= this.motion.length) {
645+
this._curMotion = this.motion.length - 1;
646+
}
595647
return;
596648
} else {
597649
var currentMotion = this.motion[this._curMotion];
598-
var time = (this.dur - Math.max(this.ttl, 0)) - this._motionStart[this._curMotion];
599-
for (var prop in currentMotion) {
600-
if (currentMotion.hasOwnProperty(prop)) {
601-
var m = currentMotion[prop];
602-
this[prop] = m.easing(Math.min(Math.max(time - m.delay, 0), m.dur), m.from, m.to - m.from, m.dur);
603-
}
604-
}
650+
this._execMotion(currentMotion, time);
605651
}
606652
};
607653

@@ -636,6 +682,7 @@ var ScrollComment = (function (_super) {
636682
if (typeof recycle === "undefined") { recycle = null; }
637683
_super.prototype.init.call(this, recycle);
638684
this.x = this.parent.width;
685+
this.absolute = true;
639686
};
640687

641688
ScrollComment.prototype.update = function () {
@@ -929,12 +976,6 @@ Licensed Under MIT License
929976
An alternative format comment parser
930977
**/
931978
function AcfunParser(jsond){
932-
function fillRGB(string){
933-
while(string.length < 6){
934-
string = "0" + string;
935-
}
936-
return string;
937-
}
938979
var list = [];
939980
try{
940981
var jsondt = JSON.parse(jsond);
@@ -948,12 +989,12 @@ function AcfunParser(jsond){
948989
var xc = jsondt[i]['c'].split(',');
949990
if(xc.length > 0){
950991
data.stime = parseFloat(xc[0]) * 1000;
951-
data.color = '#' + fillRGB(parseInt(xc[1]).toString(16));
992+
data.color = parseInt(xc[1])
952993
data.mode = parseInt(xc[2]);
953994
data.size = parseInt(xc[3]);
954995
data.hash = xc[4];
955996
data.date = parseInt(xc[5]);
956-
data.position = "relative";
997+
data.position = "absolute";
957998
if(data.mode != 7){
958999
data.text = jsondt[i].m.replace(/(\/n|\\n|\n|\r\n|\\r)/g,"\n");
9591000
data.text = data.text.replace(/\r/g,"\n");
@@ -970,9 +1011,15 @@ function AcfunParser(jsond){
9701011
console.log('[Dbg] ' + data.text);
9711012
continue;
9721013
}
1014+
data.position = "relative";
9731015
data.text = x.n; /*.replace(/\r/g,"\n");*/
9741016
data.text = data.text.replace(/\ /g,"\u00a0");
9751017
console.log(data.text);
1018+
if(x.a != null){
1019+
data.opacity = x.a;
1020+
}else{
1021+
data.opacity = 1;
1022+
}
9761023
if(x.p != null){
9771024
data.x = x.p.x / 1000; // relative position
9781025
data.y = x.p.y / 1000;
@@ -981,25 +1028,40 @@ function AcfunParser(jsond){
9811028
data.y = 0;
9821029
}
9831030
data.shadow = x.b;
984-
data.duration = 4000;
1031+
data.dur = 4000;
9851032
if(x.l != null)
9861033
data.moveDelay = x.l * 1000;
9871034
if(x.z != null && x.z.length > 0){
9881035
data.movable = true;
989-
data.toX = x.z[0].x / 1000;
990-
data.toY = x.z[0].y / 1000;
991-
data.alphaTo = x.z[0].t;
992-
data.colorTo = x.z[0].c;
993-
data.moveDuration = x.z[0].l != null ? (x.z[0].l * 1000) : 500;
994-
data.duration = data.moveDelay + data.moveDuration;
1036+
data.motion = [];
1037+
var moveDuration = 0;
1038+
var last = {x:data.x, y:data.y, alpha:data.opacity, color:data.color};
1039+
for(var m = 0; m < x.z.length; m++){
1040+
var dur = x.z[m].l != null ? (x.z[m].l * 1000) : 500;
1041+
moveDuration += dur;
1042+
var motion = {
1043+
x:{from:last.x, to:x.z[m].x/1000, dur: dur, delay: 0},
1044+
y:{from:last.y, to:x.z[m].y/1000, dur: dur, delay: 0}
1045+
};
1046+
last.x = motion.x.to;
1047+
last.y = motion.y.to;
1048+
if(x.z[m].t !== last.alpha){
1049+
motion.alpha = {from:last.alpha, to:x.z[m].t, dur: dur, delay: 0};
1050+
last.alpha = motion.alpha.to;
1051+
}
1052+
if(x.z[m].c != null && x.z[m].c !== last.color){
1053+
motion.color = {from:last.color, to:x.z[m].c, dur: dur, delay: 0};
1054+
last.color = motion.color.to;
1055+
}
1056+
data.motion.push(motion);
1057+
}
1058+
data.dur = moveDuration + (data.moveDelay ? data.moveDelay : 0);
9951059
}
9961060
if(x.r != null && x.k != null){
9971061
data.rX = x.r;
9981062
data.rY = x.k;
9991063
}
1000-
if(x.a){
1001-
data.alphaFrom = x.a;
1002-
}
1064+
10031065
}
10041066
list.push(data);
10051067
}
@@ -1013,32 +1075,36 @@ Licensed Under MIT License
10131075
Takes in an XMLDoc/LooseXMLDoc and parses that into a Generic Comment List
10141076
**/
10151077
function BilibiliParser(xmlDoc, text, warn){
1016-
//Format the bili output to be json-valid
10171078
function format(string){
1079+
//Format the bili output to be json-valid
10181080
return string.replace(/\t/,"\\t");
10191081
}
1082+
10201083
if(xmlDoc !== null){
1021-
var elems = xmlDoc.getElementsByTagName('d');
1022-
}else{
1023-
if(warn){
1024-
if(!confirm("XML Parse Error. \n Allow tag soup parsing?\n[WARNING: This is unsafe.]")){
1025-
return [];
1026-
}
1027-
}else{
1028-
// clobber some potentially bad things
1029-
text = text.replace(new RegExp("</([^d])","g"), "</disabled $1");
1030-
text = text.replace(new RegExp("</(\S{2,})","g"), "</disabled $1");
1031-
text = text.replace(new RegExp("<([^d/]\W*?)","g"), "<disabled $1");
1032-
text = text.replace(new RegExp("<([^/ ]{2,}\W*?)","g"), "<disabled $1");
1033-
console.log(text);
1034-
}
1035-
var tmp = document.createElement("div");
1036-
tmp.innerHTML = text;
1037-
console.log(tmp);
1038-
var elems = tmp.getElementsByTagName('d');
1039-
}
1084+
var elems = xmlDoc.getElementsByTagName('d');
1085+
}else{
1086+
if(!document || !document.createElement){
1087+
//Maybe we are in a restricted context
1088+
return [];
1089+
}
1090+
if(warn){
1091+
if(!confirm("XML Parse Error. \n Allow tag soup parsing?\n[WARNING: This is unsafe.]")){
1092+
return [];
1093+
}
1094+
}else{
1095+
// clobber some potentially bad things
1096+
text = text.replace(new RegExp("</([^d])","g"), "</disabled $1");
1097+
text = text.replace(new RegExp("</(\S{2,})","g"), "</disabled $1");
1098+
text = text.replace(new RegExp("<([^d/]\W*?)","g"), "<disabled $1");
1099+
text = text.replace(new RegExp("<([^/ ]{2,}\W*?)","g"), "<disabled $1");
1100+
}
1101+
var tmp = document.createElement("div");
1102+
tmp.innerHTML = text;
1103+
var elems = tmp.getElementsByTagName('d');
1104+
}
1105+
10401106
var tlist = [];
1041-
for(var i=0;i<elems.length;i++){
1107+
for(var i=0;i < elems.length;i++){
10421108
if(elems[i].getAttribute('p') != null){
10431109
var opt = elems[i].getAttribute('p').split(',');
10441110
if(!elems[i].childNodes[0])
@@ -1063,8 +1129,11 @@ function BilibiliParser(xmlDoc, text, warn){
10631129
try{
10641130
adv = JSON.parse(format(text));
10651131
obj.shadow = true;
1066-
obj.x = parseInt(adv[0], 10);
1067-
obj.y = parseInt(adv[1], 10);
1132+
obj.x = parseFloat(adv[0]);
1133+
obj.y = parseFloat(adv[1]);
1134+
if(Math.floor(obj.x) < obj.x || Math.floor(obj.y) < obj.y){
1135+
obj.position = "relative";
1136+
}
10681137
obj.text = adv[4].replace(/(\/n|\\n|\n|\r\n)/g, "\n");
10691138
obj.rZ = 0;
10701139
obj.rY = 0;
@@ -1076,13 +1145,15 @@ function BilibiliParser(xmlDoc, text, warn){
10761145
obj.movable = false;
10771146
if(adv.length >= 11){
10781147
obj.movable = true;
1148+
var singleStepDur = 500;
10791149
var motion = {
1080-
x:{from: obj.x, to:parseInt(adv[7], 10), dur:500, delay:0},
1081-
y:{from: obj.y, to:parseInt(adv[8], 10), dur:500, delay:0},
1082-
}
1150+
x:{from: obj.x, to:parseFloat(adv[7]), dur:singleStepDur, delay:0},
1151+
y:{from: obj.y, to:parseFloat(adv[8]), dur:singleStepDur, delay:0},
1152+
};
10831153
if(adv[9] !== ''){
1084-
motion.x.dur = parseInt(adv[9], 10);
1085-
motion.y.dur = parseInt(adv[9], 10);
1154+
singleStepDur = parseInt(adv[9], 10);
1155+
motion.x.dur = singleStepDur;
1156+
motion.y.dur = singleStepDur;
10861157
}
10871158
if(adv[10] !== ''){
10881159
motion.x.delay = parseInt(adv[10], 10);
@@ -1099,8 +1170,42 @@ function BilibiliParser(xmlDoc, text, warn){
10991170
if(adv[12] != null){
11001171
obj.font = adv[12];
11011172
}
1173+
if(adv.length > 14){
1174+
// Support for Bilibili Advanced Paths
1175+
if(obj.position === "relative"){
1176+
console.log("Cannot mix relative and absolute positioning");
1177+
obj.position = "absolute";
1178+
}
1179+
var path = adv[14];
1180+
var lastPoint = {x:motion.x.from, y:motion.y.from};
1181+
var pathMotion = [];
1182+
var regex = new RegExp("([a-zA-Z])\\s*(\\d+)[, ](\\d+)","g");
1183+
var counts = path.split(/[a-zA-Z]/).length - 1;
1184+
var m = regex.exec(path);
1185+
while(m !== null){
1186+
switch(m[1]){
1187+
case "M":{
1188+
lastPoint.x = parseInt(m[2],10);
1189+
lastPoint.y = parseInt(m[3],10);
1190+
}break;
1191+
case "L":{
1192+
pathMotion.push({
1193+
"x":{"from":lastPoint.x, "to":parseInt(m[2],10), "dur": singleStepDur / counts, "delay": 0},
1194+
"y":{"from":lastPoint.y, "to":parseInt(m[3],10), "dur": singleStepDur / counts, "delay": 0}
1195+
});
1196+
lastPoint.x = parseInt(m[2],10);
1197+
lastPoint.y = parseInt(m[3],10);
1198+
}break;
1199+
}
1200+
m = regex.exec(path);
1201+
}
1202+
motion = null;
1203+
obj.motion = pathMotion;
1204+
}
1205+
}
1206+
if(motion !== null){
1207+
obj.motion.push(motion);
11021208
}
1103-
obj.motion.push(motion);
11041209
}
11051210
obj.dur = 2500;
11061211
if(adv[3] < 12){
@@ -1111,11 +1216,8 @@ function BilibiliParser(xmlDoc, text, warn){
11111216
var alphaFrom = parseFloat(tmp[0]);
11121217
var alphaTo = parseFloat(tmp[1]);
11131218
obj.opacity = alphaFrom;
1114-
var alphaObj = {from:alphaFrom, to:alphaTo, dur:obj.dur, delay:0};
1115-
if(obj.motion.length > 0){
1116-
obj.motion[0]["alpha"] = alphaObj;
1117-
}else{
1118-
obj.motion.push({alpha:alphaObj});
1219+
if(alphaFrom !== alphaTo){
1220+
obj.alpha = {from:alphaFrom, to:alphaTo}
11191221
}
11201222
}
11211223
}catch(e){
@@ -1126,7 +1228,6 @@ function BilibiliParser(xmlDoc, text, warn){
11261228
obj.code = text; //Code comments are special
11271229
}
11281230
}
1129-
//Before we push
11301231
if(obj.text != null)
11311232
obj.text = obj.text.replace(/\u25a0/g,"\u2588");
11321233
tlist.push(obj);

build/CommentCoreLibrary.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

demo/debugger.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ var tests = {
77
"test-5":"tests/unowen.xml",
88
"test-6":"tests/comment.xml",
99
"test-7":"tests/extended.xml",
10-
"test-8":"tests/bilibili.xml",
10+
"test-8":"tests/boss.xml",
1111
"test-9":"tests/utsukushiki_mono.xml",
1212
"test-s":"tests/scripting/kanpai.xml",
1313
"test-ac-1":{"f":'tests/ACFun.json',"p":"acfun"},

0 commit comments

Comments
 (0)