@xpadev-net/niconicomments 0.2.13 → 0.2.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bundle.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- niconicomments.js v0.2.13
2
+ niconicomments.js v0.2.16
3
3
  (c) 2021 xpadev-net https://xpadev.net
4
4
  Released under the MIT License.
5
5
  */
@@ -25,952 +25,954 @@
25
25
  return _assign.apply(this, arguments);
26
26
  };
27
27
 
28
- var isDebug = false;
29
- var NiconiComments = (function () {
30
- function NiconiComments(canvas, data, options) {
31
- if (options === void 0) { options = {
32
- useLegacy: false,
33
- formatted: false,
34
- video: null,
35
- showCollision: false,
36
- showFPS: false,
37
- showCommentCount: false,
38
- drawAllImageOnLoad: false,
39
- debug: false
40
- }; }
41
- var _this = this;
42
- isDebug = options.debug;
43
- var constructorStart = performance.now();
44
- this.canvas = canvas;
45
- var context = canvas.getContext("2d");
46
- if (!context)
47
- throw new Error("Fail to get CanvasRenderingContext2D");
48
- this.context = context;
49
- this.context.strokeStyle = "rgba(0,0,0,0.7)";
50
- this.context.textAlign = "start";
51
- this.context.textBaseline = "alphabetic";
52
- this.context.lineWidth = 4;
53
- this.commentYPaddingTop = 0.08;
54
- this.commentYMarginBottom = 0.24;
55
- this.fontSize = {
56
- "small": {
57
- "default": 47,
58
- "resized": 26.1
59
- },
60
- "medium": {
61
- "default": 74,
62
- "resized": 38.7
63
- },
64
- "big": {
65
- "default": 110,
66
- "resized": 61
67
- }
68
- };
69
- this.lineHeight = {
70
- "small": {
71
- "default": 1,
72
- "resized": 1
73
- },
74
- "medium": {
75
- "default": 1,
76
- "resized": 1
77
- },
78
- "big": {
79
- "default": 1.03,
80
- "resized": 1.01
81
- }
82
- };
83
- this.doubleResizeMaxWidth = {
84
- full: {
85
- legacy: 3020,
86
- default: 3220
87
- },
88
- normal: {
89
- legacy: 2540,
90
- default: 2740
91
- }
92
- };
93
- var parsedData = options.formatted ? data : this.parseData(data);
94
- this.video = options.video ? options.video : null;
95
- this.showCollision = options.showCollision;
96
- this.showFPS = options.showFPS;
97
- this.showCommentCount = options.showCommentCount;
98
- this.timeline = {};
99
- this.nicoScripts = { reverse: [], default: [], replace: [], ban: [] };
100
- this.collision_right = {};
101
- this.collision_left = {};
102
- this.collision_ue = {};
103
- this.collision_shita = {};
104
- this.data = [];
105
- this.lastVpos = -1;
106
- this.useLegacy = options.useLegacy;
107
- this.preRendering(parsedData, options.drawAllImageOnLoad);
108
- this.fpsCount = 0;
109
- this.fps = 0;
110
- window.setInterval(function () {
111
- _this.fps = _this.fpsCount * 2;
112
- _this.fpsCount = 0;
113
- }, 500);
114
- logger("constructor complete: ".concat(performance.now() - constructorStart, "ms"));
115
- }
116
- NiconiComments.prototype.parseData = function (data) {
117
- var parseDataStart = performance.now();
118
- var data_ = [];
119
- for (var i = 0; i < data.length; i++) {
120
- for (var key in data[i]) {
121
- var val = data[i];
122
- if (!val)
123
- continue;
124
- var value = val[key];
125
- if (isApiChat(value) && value["deleted"] !== 1) {
126
- var tmpParam = {
127
- "id": value["no"],
128
- "vpos": value["vpos"],
129
- "content": value["content"],
130
- "date": value["date"],
131
- "date_usec": value["date_usec"],
132
- "owner": !value["user_id"],
133
- "premium": value["premium"] === 1,
134
- "mail": []
135
- };
136
- if (value["mail"]) {
137
- tmpParam["mail"] = value["mail"].split(/[\s ]/g);
138
- }
139
- if (value["content"].startsWith("/") && !value["user_id"]) {
140
- tmpParam["mail"].push("invisible");
141
- }
142
- data_.push(tmpParam);
143
- }
144
- }
145
- }
146
- data_.sort(function (a, b) {
147
- if (a.vpos < b.vpos)
148
- return -1;
149
- if (a.vpos > b.vpos)
150
- return 1;
151
- if (a.date < b.date)
152
- return -1;
153
- if (a.date > b.date)
154
- return 1;
155
- if (a.date_usec < b.date_usec)
156
- return -1;
157
- if (a.date_usec > b.date_usec)
158
- return 1;
159
- return 0;
160
- });
161
- logger("parseData complete: ".concat(performance.now() - parseDataStart, "ms"));
162
- return data_;
163
- };
164
- NiconiComments.prototype.preRendering = function (rawData, drawAll) {
165
- var preRenderingStart = performance.now();
166
- var parsedData = this.getCommentPos(this.getCommentSize(this.getFont(rawData)));
167
- this.data = this.sortComment(parsedData);
168
- if (drawAll) {
169
- for (var i in parsedData) {
170
- this.getTextImage(Number(i));
171
- }
172
- }
173
- logger("preRendering complete: ".concat(performance.now() - preRenderingStart, "ms"));
174
- };
175
- NiconiComments.prototype.getFont = function (parsedData) {
176
- var getFontStart = performance.now();
177
- var result = [];
178
- for (var i in parsedData) {
179
- var value = parsedData[i];
180
- if (!value)
181
- continue;
182
- value.content = value.content.replace(/\t/g, "\u2003\u2003");
183
- result[i] = this.parseCommandAndNicoscript(value);
184
- }
185
- logger("getFont complete: ".concat(performance.now() - getFontStart, "ms"));
186
- return result;
187
- };
188
- NiconiComments.prototype.getCommentSize = function (parsedData) {
189
- var getCommentSizeStart = performance.now();
190
- var tmpData = groupBy(parsedData, "font", "fontSize");
191
- var result = [];
192
- for (var i in tmpData) {
193
- for (var j in tmpData[i]) {
194
- this.context.font = parseFont(i, j, this.useLegacy);
195
- for (var k in tmpData[i][j]) {
196
- var comment = tmpData[i][j][k];
197
- if (comment.invisible) {
198
- continue;
199
- }
200
- var measure = this.measureText(comment);
201
- var size = parsedData[comment.index];
202
- size.height = measure.height;
203
- size.width = measure.width;
204
- size.width_max = measure.width_max;
205
- size.width_min = measure.width_min;
206
- size.lineHeight = measure.lineHeight;
207
- if (measure.resized) {
208
- size.fontSize = measure.fontSize;
209
- this.context.font = parseFont(i, j, this.useLegacy);
210
- }
211
- result[comment.index] = size;
212
- }
213
- }
214
- }
215
- logger("getCommentSize complete: ".concat(performance.now() - getCommentSizeStart, "ms"));
216
- return result;
217
- };
218
- NiconiComments.prototype.getCommentPos = function (parsedData) {
219
- var getCommentPosStart = performance.now();
220
- var data = parsedData;
221
- for (var i in data) {
222
- var comment = data[i];
223
- if (!comment || comment.invisible) {
224
- continue;
225
- }
226
- for (var j = 0; j < 500; j++) {
227
- if (!this.timeline[comment.vpos + j]) {
228
- this.timeline[comment.vpos + j] = [];
229
- }
230
- if (!this.collision_right[comment.vpos + j]) {
231
- this.collision_right[comment.vpos + j] = [];
232
- }
233
- if (!this.collision_left[comment.vpos + j]) {
234
- this.collision_left[comment.vpos + j] = [];
235
- }
236
- if (!this.collision_ue[comment.vpos + j]) {
237
- this.collision_ue[comment.vpos + j] = [];
238
- }
239
- if (!this.collision_shita[comment.vpos + j]) {
240
- this.collision_shita[comment.vpos + j] = [];
241
- }
242
- }
243
- if (comment.loc === "naka") {
244
- comment.vpos -= 70;
245
- parsedData[i].vpos -= 70;
246
- var posY = 0, is_break = false, is_change = true, count = 0;
247
- if (1080 < comment.height) {
248
- posY = (comment.height - 1080) / -2;
249
- }
250
- else {
251
- while (is_change && count < 10) {
252
- is_change = false;
253
- count++;
254
- for (var j = 0; j < 500; j++) {
255
- var vpos = comment.vpos + j;
256
- var left_pos = 1920 - ((1920 + comment.width_max) * j / 500);
257
- if (left_pos + comment.width_max >= 1880) {
258
- for (var k in this.collision_right[vpos]) {
259
- var l = this.collision_right[vpos][k];
260
- if ((posY < data[l].posY + data[l].height && posY + comment.height > data[l].posY) && data[l].owner === comment.owner) {
261
- if (data[l].posY + data[l].height > posY) {
262
- posY = data[l].posY + data[l].height;
263
- is_change = true;
264
- }
265
- if (posY + comment.height > 1080) {
266
- if (1080 < comment.height) {
267
- posY = (comment.height - 1080) / -2;
268
- }
269
- else {
270
- posY = Math.floor(Math.random() * (1080 - comment.height));
271
- }
272
- is_break = true;
273
- break;
274
- }
275
- }
276
- }
277
- if (is_break) {
278
- break;
279
- }
280
- }
281
- if (left_pos <= 40) {
282
- for (var k in this.collision_left[vpos]) {
283
- var l = this.collision_left[vpos][k];
284
- if ((posY < data[l].posY + data[l].height && posY + comment.height > data[l].posY) && data[l].owner === comment.owner) {
285
- if (data[l].posY + data[l].height > posY) {
286
- posY = data[l].posY + data[l].height;
287
- is_change = true;
288
- }
289
- if (posY + comment.height > 1080) {
290
- if (1080 < comment.height) {
291
- posY = 0;
292
- }
293
- else {
294
- posY = Math.random() * (1080 - comment.height);
295
- }
296
- is_break = true;
297
- break;
298
- }
299
- }
300
- }
301
- if (is_break) {
302
- break;
303
- }
304
- }
305
- }
306
- if (is_break) {
307
- break;
308
- }
309
- }
310
- }
311
- for (var j = 0; j < 500; j++) {
312
- var vpos = comment.vpos + j;
313
- var left_pos = 1920 - ((1920 + comment.width_max) * j / 500);
314
- arrayPush(this.timeline, vpos, i);
315
- if (left_pos + comment.width_max >= 1880) {
316
- arrayPush(this.collision_right, vpos, i);
317
- }
318
- if (left_pos <= 40) {
319
- arrayPush(this.collision_left, vpos, i);
320
- }
321
- }
322
- parsedData[i].posY = posY;
323
- }
324
- else {
325
- var posY = 0, is_break = false, is_change = true, count = 0, collision = void 0;
326
- if (comment.loc === "ue") {
327
- collision = this.collision_ue;
328
- }
329
- else if (comment.loc === "shita") {
330
- collision = this.collision_shita;
331
- }
332
- while (is_change && count < 10) {
333
- is_change = false;
334
- count++;
335
- for (var j = 0; j < 300; j++) {
336
- var vpos = comment.vpos + j;
337
- for (var k in collision[vpos]) {
338
- var l = collision[vpos][k];
339
- if ((posY < data[l].posY + data[l].height && posY + comment.height > data[l].posY) && data[l].owner === comment.owner) {
340
- if (data[l].posY + data[l].height > posY) {
341
- posY = data[l].posY + data[l].height;
342
- is_change = true;
343
- }
344
- if (posY + comment.height > 1080) {
345
- if (1000 <= comment.height) {
346
- posY = 0;
347
- }
348
- else {
349
- posY = Math.floor(Math.random() * (1080 - comment.height));
350
- }
351
- is_break = true;
352
- break;
353
- }
354
- }
355
- }
356
- if (is_break) {
357
- break;
358
- }
359
- }
360
- }
361
- for (var j = 0; j < comment.long; j++) {
362
- var vpos = comment.vpos + j;
363
- arrayPush(this.timeline, vpos, i);
364
- if (comment.loc === "ue") {
365
- arrayPush(this.collision_ue, vpos, i);
366
- }
367
- else {
368
- arrayPush(this.collision_shita, vpos, i);
369
- }
370
- }
371
- parsedData[i].posY = posY;
372
- }
373
- }
374
- logger("getCommentPos complete: ".concat(performance.now() - getCommentPosStart, "ms"));
375
- return parsedData;
376
- };
377
- NiconiComments.prototype.sortComment = function (parsedData) {
378
- var sortCommentStart = performance.now();
379
- for (var vpos in this.timeline) {
380
- if (!this.timeline[vpos])
381
- continue;
382
- var owner = [], user = [];
383
- for (var _i = 0, _a = this.timeline[vpos]; _i < _a.length; _i++) {
384
- var i = _a[_i];
385
- if (parsedData[i].owner) {
386
- owner.push(i);
387
- }
388
- else {
389
- user.push(i);
390
- }
391
- }
392
- this.timeline[vpos] = owner.concat(user);
393
- }
394
- logger("parseData complete: ".concat(performance.now() - sortCommentStart, "ms"));
395
- return parsedData;
396
- };
397
- NiconiComments.prototype.measureText = function (comment) {
398
- var width, width_max, width_min, height, width_arr = [], lines = comment.content.split("\n");
399
- if (!comment.lineHeight)
400
- comment.lineHeight = this.lineHeight[comment.size].default;
401
- if (!comment.resized && !comment.ender) {
402
- if (comment.size === "big" && lines.length > 2) {
403
- comment.fontSize = this.fontSize.big.resized;
404
- comment.lineHeight = this.lineHeight.big.resized;
405
- comment.resized = true;
406
- comment.tateresized = true;
407
- this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
408
- }
409
- else if (comment.size === "medium" && lines.length > 4) {
410
- comment.fontSize = this.fontSize.medium.resized;
411
- comment.lineHeight = this.lineHeight.medium.resized;
412
- comment.resized = true;
413
- comment.tateresized = true;
414
- this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
415
- }
416
- else if (comment.size === "small" && lines.length > 6) {
417
- comment.fontSize = this.fontSize.small.resized;
418
- comment.lineHeight = this.lineHeight.small.resized;
419
- comment.resized = true;
420
- comment.tateresized = true;
421
- this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
422
- }
423
- }
424
- for (var i = 0; i < lines.length; i++) {
425
- var measure = this.context.measureText(lines[i]);
426
- width_arr.push(measure.width);
427
- }
428
- width = width_arr.reduce(function (p, c) { return p + c; }, 0) / width_arr.length;
429
- width_max = Math.max.apply(Math, width_arr);
430
- width_min = Math.min.apply(Math, width_arr);
431
- height = (comment.fontSize * comment.lineHeight * (1 + this.commentYPaddingTop) * lines.length) + (this.commentYMarginBottom * comment.fontSize);
432
- if (comment.loc !== "naka" && !comment.tateresized) {
433
- if (comment.full && width_max > 1930) {
434
- comment.fontSize -= 2;
435
- comment.resized = true;
436
- comment.yokoResized = true;
437
- this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
438
- return this.measureText(comment);
439
- }
440
- else if (!comment.full && width_max > 1440) {
441
- comment.fontSize -= 1;
442
- comment.resized = true;
443
- comment.yokoResized = true;
444
- this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
445
- return this.measureText(comment);
446
- }
447
- }
448
- else if (comment.loc !== "naka" && comment.tateresized && (comment.full && width_max > 2120 || !comment.full && width_max > 1440) && !comment.yokoResized) {
449
- comment.fontSize = this.fontSize[comment.size].default;
450
- comment.resized = true;
451
- comment.yokoResized = true;
452
- this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
453
- return this.measureText(comment);
454
- }
455
- else if (comment.loc !== "naka" && comment.tateresized && comment.yokoResized) {
456
- if (comment.full && width_max > this.doubleResizeMaxWidth.full[this.useLegacy ? "legacy" : "default"]) {
457
- comment.fontSize -= 1;
458
- this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
459
- return this.measureText(comment);
460
- }
461
- else if (!comment.full && width_max > this.doubleResizeMaxWidth.normal[this.useLegacy ? "legacy" : "default"]) {
462
- comment.fontSize -= 1;
463
- this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
464
- return this.measureText(comment);
465
- }
466
- }
467
- return {
468
- "width": width,
469
- "width_max": width_max,
470
- "width_min": width_min,
471
- "height": height,
472
- "resized": comment.resized,
473
- "fontSize": comment.fontSize,
474
- "lineHeight": comment.lineHeight
475
- };
476
- };
477
- NiconiComments.prototype.drawText = function (comment, vpos) {
478
- var reverse = false;
479
- for (var i in this.nicoScripts.reverse) {
480
- var range = this.nicoScripts.reverse[i];
481
- if ((range.target === "コメ" && comment.owner) || (range.target === "投コメ" && !comment.owner)) {
482
- break;
483
- }
484
- if (range.start < vpos && vpos < range.end) {
485
- reverse = true;
486
- }
487
- }
488
- for (var i in this.nicoScripts.ban) {
489
- var range = this.nicoScripts.ban[i];
490
- if (range.start < vpos && vpos < range.end) {
491
- return;
492
- }
493
- }
494
- var posX = (1920 - comment.width_max) / 2, posY = comment.posY;
495
- if (comment.loc === "naka") {
496
- if (reverse) {
497
- posX = ((1920 + comment.width_max) * (vpos - comment.vpos) / 500) - comment.width_max;
498
- }
499
- else {
500
- posX = 1920 - ((1920 + comment.width_max) * (vpos - comment.vpos) / 500);
501
- }
502
- }
503
- else if (comment.loc === "shita") {
504
- posY = 1080 - comment.posY - comment.height;
505
- }
506
- if (comment.image && comment.image !== true) {
507
- this.context.drawImage(comment.image, posX, posY);
508
- }
509
- if (this.showCollision) {
510
- this.context.strokeStyle = "rgba(0,255,255,1)";
511
- this.context.strokeRect(posX, posY, comment.width_max, comment.height);
512
- var lines = comment.content.split("\n");
513
- for (var i in lines) {
514
- var linePosY = (Number(i) + 1) * (comment.fontSize * comment.lineHeight) * (1 + this.commentYPaddingTop);
515
- this.context.strokeStyle = "rgba(255,255,0,0.5)";
516
- this.context.strokeRect(posX, posY + linePosY, comment.width_max, comment.fontSize * comment.lineHeight * -1);
517
- }
518
- }
519
- };
520
- NiconiComments.prototype.getTextImage = function (i) {
521
- var _this = this;
522
- var value = this.data[i];
523
- if (!value || value.invisible)
524
- return;
525
- var image = document.createElement("canvas");
526
- image.width = value.width_max;
527
- image.height = value.height;
528
- var context = image.getContext("2d");
529
- if (!context)
530
- throw new Error("Fail to get CanvasRenderingContext2D");
531
- context.strokeStyle = "rgba(0,0,0,0.7)";
532
- context.textAlign = "start";
533
- context.textBaseline = "alphabetic";
534
- context.lineWidth = 4;
535
- context.font = parseFont(value.font, value.fontSize, this.useLegacy);
536
- if (value._live) {
537
- var rgb = hex2rgb(value.color);
538
- context.fillStyle = "rgba(".concat(rgb[0], ",").concat(rgb[1], ",").concat(rgb[2], ",0.5)");
539
- }
540
- else {
541
- context.fillStyle = value.color;
542
- }
543
- if (value.color === "#000000") {
544
- context.strokeStyle = "rgba(255,255,255,0.7)";
545
- }
546
- var lines = value.content.split("\n");
547
- for (var i_1 in lines) {
548
- var line = lines[i_1], posY = void 0;
549
- posY = (Number(i_1) + 1) * (value.fontSize * value.lineHeight) * (1 + this.commentYPaddingTop);
550
- context.strokeText(line, 0, posY);
551
- context.fillText(line, 0, posY);
552
- }
553
- this.data[i].image = image;
554
- setTimeout(function () {
555
- if (_this.data[i].image)
556
- delete _this.data[i].image;
557
- }, 5000);
558
- };
559
- NiconiComments.prototype.parseCommand = function (comment) {
560
- var metadata = comment.mail, loc = null, size = null, fontSize = null, color = null, font = null, full = false, ender = false, _live = false, invisible = false, long = null;
561
- for (var i in metadata) {
562
- var command = metadata[i].toLowerCase();
563
- var match = command.match(/^@([0-9.]+)/);
564
- if (match) {
565
- long = match[1];
566
- }
567
- if (loc === null) {
568
- switch (command) {
569
- case "ue":
570
- loc = "ue";
571
- break;
572
- case "shita":
573
- loc = "shita";
574
- break;
575
- }
576
- }
577
- if (size === null) {
578
- switch (command) {
579
- case "big":
580
- size = "big";
581
- fontSize = this.fontSize.big.default;
582
- break;
583
- case "small":
584
- size = "small";
585
- fontSize = this.fontSize.small.default;
586
- break;
587
- }
588
- }
589
- if (color === null) {
590
- switch (command) {
591
- case "white":
592
- color = "#FFFFFF";
593
- break;
594
- case "red":
595
- color = "#FF0000";
596
- break;
597
- case "pink":
598
- color = "#FF8080";
599
- break;
600
- case "orange":
601
- color = "#FFC000";
602
- break;
603
- case "yellow":
604
- color = "#FFFF00";
605
- break;
606
- case "green":
607
- color = "#00FF00";
608
- break;
609
- case "cyan":
610
- color = "#00FFFF";
611
- break;
612
- case "blue":
613
- color = "#0000FF";
614
- break;
615
- case "purple":
616
- color = "#C000FF";
617
- break;
618
- case "black":
619
- color = "#000000";
620
- break;
621
- case "white2":
622
- case "niconicowhite":
623
- color = "#CCCC99";
624
- break;
625
- case "red2":
626
- case "truered":
627
- color = "#CC0033";
628
- break;
629
- case "pink2":
630
- color = "#FF33CC";
631
- break;
632
- case "orange2":
633
- case "passionorange":
634
- color = "#FF6600";
635
- break;
636
- case "yellow2":
637
- case "madyellow":
638
- color = "#999900";
639
- break;
640
- case "green2":
641
- case "elementalgreen":
642
- color = "#00CC66";
643
- break;
644
- case "cyan2":
645
- color = "#00CCCC";
646
- break;
647
- case "blue2":
648
- case "marineblue":
649
- color = "#3399FF";
650
- break;
651
- case "purple2":
652
- case "nobleviolet":
653
- color = "#6633CC";
654
- break;
655
- case "black2":
656
- color = "#666666";
657
- break;
658
- default:
659
- var match_1 = command.match(/#[0-9a-z]{3,6}/);
660
- if (match_1 && comment.premium) {
661
- color = match_1[0].toUpperCase();
662
- }
663
- break;
664
- }
665
- }
666
- if (font === null) {
667
- switch (command) {
668
- case "gothic":
669
- font = "gothic";
670
- break;
671
- case "mincho":
672
- font = "mincho";
673
- break;
674
- }
675
- }
676
- switch (command) {
677
- case "full":
678
- full = true;
679
- break;
680
- case "ender":
681
- ender = true;
682
- break;
683
- case "_live":
684
- _live = true;
685
- break;
686
- case "invisible":
687
- invisible = true;
688
- break;
689
- }
690
- }
691
- return { loc: loc, size: size, fontSize: fontSize, color: color, font: font, full: full, ender: ender, _live: _live, invisible: invisible, long: long };
692
- };
693
- NiconiComments.prototype.parseCommandAndNicoscript = function (comment) {
694
- var data = this.parseCommand(comment), nicoscript = comment.content.match(/^@(デフォルト|置換|逆|コメント禁止|シーク禁止|ジャンプ)/);
695
- if (nicoscript) {
696
- switch (nicoscript[1]) {
697
- case "デフォルト":
698
- this.nicoScripts.default.push({
699
- start: comment.vpos,
700
- long: data.long === null ? null : Math.floor(data.long * 100),
701
- color: data.color,
702
- size: data.size,
703
- font: data.font,
704
- loc: data.loc
705
- });
706
- break;
707
- case "逆":
708
- var reverse = comment.content.match(/^@逆 ?(全|コメ|投コメ)?/);
709
- if (!reverse)
710
- reverse = [];
711
- if (!reverse[1]) {
712
- reverse[1] = "全";
713
- }
714
- if (data.long === null) {
715
- data.long = 30;
716
- }
717
- this.nicoScripts.reverse.push({
718
- start: comment.vpos,
719
- end: comment.vpos + (data.long * 100),
720
- target: reverse[1]
721
- });
722
- break;
723
- case "コメント禁止":
724
- if (data.long === null) {
725
- data.long = 30;
726
- }
727
- this.nicoScripts.reverse.push({
728
- start: comment.vpos,
729
- end: comment.vpos + (data.long * 100),
730
- });
731
- break;
732
- case "置換":
733
- var content = comment.content.split(""), quote = "", last_i = "", string = "", result = [];
734
- for (var _i = 0, _a = content.slice(4); _i < _a.length; _i++) {
735
- var i = _a[_i];
736
- if (i.match(/["'「]/) && quote === "") {
737
- quote = i;
738
- }
739
- else if (i.match(/["']/) && quote === i && last_i !== "\\") {
740
- result.push(replaceAll(string, "\\n", "\n"));
741
- quote = "";
742
- string = "";
743
- }
744
- else if (i.match(/」/) && quote === "") {
745
- result.push(string);
746
- quote = "";
747
- string = "";
748
- }
749
- else if (quote === "" && i.match(/[\s ]/)) {
750
- if (string) {
751
- result.push(string);
752
- string = "";
753
- }
754
- }
755
- else {
756
- string += i;
757
- }
758
- last_i = i;
759
- }
760
- result.push(string);
761
- this.nicoScripts.replace.push({
762
- start: comment.vpos,
763
- long: data.long === null ? null : Math.floor(data.long * 100),
764
- keyword: result[0],
765
- replace: result[1] || "",
766
- range: result[2] || "単",
767
- target: result[3] || "コメ",
768
- condition: result[4] || "部分一致",
769
- color: data.color,
770
- size: data.size,
771
- font: data.font,
772
- loc: data.loc
773
- });
774
- break;
775
- }
776
- data.invisible = true;
777
- }
778
- var color = "#FFFFFF", size = "medium", font = "defont", loc = "naka";
779
- for (var i in this.nicoScripts.default) {
780
- if (this.nicoScripts.default[i].long !== null && this.nicoScripts.default[i].start + this.nicoScripts.default[i].long < comment.vpos) {
781
- this.nicoScripts.default = this.nicoScripts.default.splice(Number(i), 1);
782
- continue;
783
- }
784
- if (this.nicoScripts.default[i].loc) {
785
- loc = this.nicoScripts.default[i].loc;
786
- }
787
- if (this.nicoScripts.default[i].color) {
788
- color = this.nicoScripts.default[i].color;
789
- }
790
- if (this.nicoScripts.default[i].size) {
791
- size = this.nicoScripts.default[i].size;
792
- }
793
- if (this.nicoScripts.default[i].font) {
794
- font = this.nicoScripts.default[i].font;
795
- }
796
- }
797
- for (var i in this.nicoScripts.replace) {
798
- if (this.nicoScripts.replace[i].long !== null && this.nicoScripts.replace[i].start + this.nicoScripts.replace[i].long < comment.vpos) {
799
- this.nicoScripts.default = this.nicoScripts.default.splice(Number(i), 1);
800
- continue;
801
- }
802
- var item = this.nicoScripts.replace[i];
803
- if ((item.target === "コメ" && comment.owner) || (item.target === "投コメ" && !comment.owner) || (item.target === "含まない" && comment.owner))
804
- continue;
805
- if ((item.condition === "完全一致" && comment.content === item.keyword) || (item.condition === "部分一致" && comment.content.indexOf(item.keyword) !== -1)) {
806
- if (item.range === "単") {
807
- comment.content = replaceAll(comment.content, item.keyword, item.replace);
808
- }
809
- else {
810
- comment.content = item.replace;
811
- }
812
- if (item.loc) {
813
- loc = item.loc;
814
- }
815
- if (item.color) {
816
- color = item.color;
817
- }
818
- if (item.size) {
819
- size = item.size;
820
- }
821
- if (item.font) {
822
- font = item.font;
823
- }
824
- }
825
- }
826
- if (!data.loc) {
827
- data.loc = loc;
828
- }
829
- if (!data.color) {
830
- data.color = color;
831
- }
832
- if (!data.size) {
833
- data.size = size;
834
- data.fontSize = this.fontSize[data.size].default;
835
- }
836
- if (!data.font) {
837
- data.font = font;
838
- }
839
- if (data.loc !== "naka") {
840
- if (!data.long) {
841
- data.long = 300;
842
- }
843
- else {
844
- data.long = Math.floor(data.long * 100);
845
- }
846
- }
847
- return _assign(_assign({}, comment), data);
848
- };
849
- NiconiComments.prototype.drawCanvas = function (vpos) {
850
- var drawCanvasStart = performance.now();
851
- if (this.lastVpos === vpos)
852
- return;
853
- this.lastVpos = vpos;
854
- this.fpsCount++;
855
- this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
856
- if (this.video) {
857
- var offsetX = void 0, offsetY = void 0, scale = void 0, height = this.canvas.height / this.video.videoHeight, width = this.canvas.width / this.video.videoWidth;
858
- if (height < width) {
859
- scale = width;
860
- }
861
- else {
862
- scale = height;
863
- }
864
- offsetX = (this.canvas.width - this.video.videoWidth * scale) * 0.5;
865
- offsetY = (this.canvas.height - this.video.videoHeight * scale) * 0.5;
866
- this.context.drawImage(this.video, offsetX, offsetY, this.video.videoWidth * scale, this.video.videoHeight * scale);
867
- }
868
- if (this.timeline[vpos]) {
869
- for (var i in this.timeline[vpos]) {
870
- var index = this.timeline[vpos][Number(i)];
871
- var comment = this.data[index];
872
- if (!comment || comment.invisible) {
873
- continue;
874
- }
875
- if (comment.image === undefined) {
876
- this.getTextImage(index);
877
- }
878
- try {
879
- this.drawText(comment, vpos);
880
- }
881
- catch (e) {
882
- comment.image = false;
883
- }
884
- }
885
- }
886
- if (this.showFPS) {
887
- this.context.font = parseFont("defont", 60, this.useLegacy);
888
- this.context.fillStyle = "#00FF00";
889
- this.context.strokeStyle = "rgba(0,0,0,0.7)";
890
- this.context.strokeText("FPS:" + this.fps, 100, 100);
891
- this.context.fillText("FPS:" + this.fps, 100, 100);
892
- }
893
- if (this.showCommentCount) {
894
- this.context.font = parseFont("defont", 60, this.useLegacy);
895
- this.context.fillStyle = "#00FF00";
896
- this.context.strokeStyle = "rgba(0,0,0,0.7)";
897
- if (this.timeline[vpos]) {
898
- this.context.strokeText("Count:" + this.timeline[vpos].length, 100, 200);
899
- this.context.fillText("Count:" + this.timeline[vpos].length, 100, 200);
900
- }
901
- else {
902
- this.context.strokeText("Count:0", 100, 200);
903
- this.context.fillText("Count:0", 100, 200);
904
- }
905
- }
906
- logger("drawCanvas complete: ".concat(performance.now() - drawCanvasStart, "ms"));
907
- };
908
- NiconiComments.prototype.clear = function () {
909
- this.context.clearRect(0, 0, 1920, 1080);
910
- };
911
- return NiconiComments;
912
- }());
913
- var groupBy = function (array, key, key2) {
914
- var data = {};
915
- for (var i in array) {
916
- if (!data[array[i][key]]) {
917
- data[array[i][key]] = {};
918
- }
919
- if (!data[array[i][key]][array[i][key2]]) {
920
- data[array[i][key]][array[i][key2]] = [];
921
- }
922
- array[i].index = i;
923
- data[array[i][key]][array[i][key2]].push(array[i]);
924
- }
925
- return data;
926
- };
927
- var parseFont = function (font, size, useLegacy) {
928
- switch (font) {
929
- case "gothic":
930
- return "normal 400 ".concat(size, "px \"\u6E38\u30B4\u30B7\u30C3\u30AF\u4F53\", \"\u6E38\u30B4\u30B7\u30C3\u30AF\", \"Yu Gothic\", YuGothic, yugothic, YuGo-Medium");
931
- case "mincho":
932
- return "normal 400 ".concat(size, "px \"\u6E38\u660E\u671D\u4F53\", \"\u6E38\u660E\u671D\", \"Yu Mincho\", YuMincho, yumincho, YuMin-Medium");
933
- default:
934
- if (useLegacy) {
935
- return "normal 600 ".concat(size, "px Arial, \"\uFF2D\uFF33 \uFF30\u30B4\u30B7\u30C3\u30AF\", \"MS PGothic\", MSPGothic, MS-PGothic");
936
- }
937
- else {
938
- return "normal 600 ".concat(size, "px sans-serif, Arial, \"\uFF2D\uFF33 \uFF30\u30B4\u30B7\u30C3\u30AF\", \"MS PGothic\", MSPGothic, MS-PGothic");
939
- }
940
- }
941
- };
942
- var arrayPush = function (array, key, push) {
943
- if (!array) {
944
- array = {};
945
- }
946
- if (!array[key]) {
947
- array[key] = [];
948
- }
949
- array[key].push(push);
950
- };
951
- var hex2rgb = function (hex) {
952
- if (hex.slice(0, 1) === "#")
953
- hex = hex.slice(1);
954
- if (hex.length === 3)
955
- hex = hex.slice(0, 1) + hex.slice(0, 1) + hex.slice(1, 2) + hex.slice(1, 2) + hex.slice(2, 3) + hex.slice(2, 3);
956
- return [hex.slice(0, 2), hex.slice(2, 4), hex.slice(4, 6)].map(function (str) {
957
- return parseInt(str, 16);
958
- });
959
- };
960
- var replaceAll = function (string, target, replace) {
961
- var count = 0;
962
- while (string.indexOf(target) !== -1 && count < 100) {
963
- string = string.replace(target, replace);
964
- count++;
965
- }
966
- return string;
967
- };
968
- var isApiChat = function (item) {
969
- return !!item.chat;
970
- };
971
- var logger = function (msg) {
972
- if (isDebug)
973
- console.debug(msg);
28
+ var isDebug = false;
29
+ var NiconiComments = (function () {
30
+ function NiconiComments(canvas, data, options) {
31
+ if (options === void 0) { options = {
32
+ useLegacy: false,
33
+ formatted: false,
34
+ video: null,
35
+ showCollision: false,
36
+ showFPS: false,
37
+ showCommentCount: false,
38
+ drawAllImageOnLoad: false,
39
+ debug: false,
40
+ enableLegacyPiP: false
41
+ }; }
42
+ var _this = this;
43
+ isDebug = options.debug;
44
+ var constructorStart = performance.now();
45
+ this.canvas = canvas;
46
+ var context = canvas.getContext("2d");
47
+ if (!context)
48
+ throw new Error("Fail to get CanvasRenderingContext2D");
49
+ this.context = context;
50
+ this.context.strokeStyle = "rgba(0,0,0,0.7)";
51
+ this.context.textAlign = "start";
52
+ this.context.textBaseline = "alphabetic";
53
+ this.context.lineWidth = 4;
54
+ this.commentYPaddingTop = 0.08;
55
+ this.commentYMarginBottom = 0.24;
56
+ this.fontSize = {
57
+ "small": {
58
+ "default": 47,
59
+ "resized": 26.1
60
+ },
61
+ "medium": {
62
+ "default": 74,
63
+ "resized": 38.7
64
+ },
65
+ "big": {
66
+ "default": 110,
67
+ "resized": 61
68
+ }
69
+ };
70
+ this.lineHeight = {
71
+ "small": {
72
+ "default": 1,
73
+ "resized": 1
74
+ },
75
+ "medium": {
76
+ "default": 1,
77
+ "resized": 1
78
+ },
79
+ "big": {
80
+ "default": 1.03,
81
+ "resized": 1.01
82
+ }
83
+ };
84
+ this.doubleResizeMaxWidth = {
85
+ full: {
86
+ legacy: 3020,
87
+ default: 3220
88
+ },
89
+ normal: {
90
+ legacy: 2540,
91
+ default: 2740
92
+ }
93
+ };
94
+ var parsedData = options.formatted ? data : this.parseData(data);
95
+ this.video = options.video ? options.video : null;
96
+ this.showCollision = options.showCollision;
97
+ this.showFPS = options.showFPS;
98
+ this.showCommentCount = options.showCommentCount;
99
+ this.enableLegacyPiP = options.enableLegacyPiP;
100
+ this.timeline = {};
101
+ this.nicoScripts = { reverse: [], default: [], replace: [], ban: [] };
102
+ this.collision_right = {};
103
+ this.collision_left = {};
104
+ this.collision_ue = {};
105
+ this.collision_shita = {};
106
+ this.data = [];
107
+ this.lastVpos = -1;
108
+ this.useLegacy = options.useLegacy;
109
+ this.preRendering(parsedData, options.drawAllImageOnLoad);
110
+ this.fpsCount = 0;
111
+ this.fps = 0;
112
+ window.setInterval(function () {
113
+ _this.fps = _this.fpsCount * 2;
114
+ _this.fpsCount = 0;
115
+ }, 500);
116
+ logger("constructor complete: ".concat(performance.now() - constructorStart, "ms"));
117
+ }
118
+ NiconiComments.prototype.parseData = function (data) {
119
+ var parseDataStart = performance.now();
120
+ var data_ = [];
121
+ for (var i = 0; i < data.length; i++) {
122
+ var val = data[i];
123
+ if (!val)
124
+ continue;
125
+ for (var key in val) {
126
+ var value = val[key];
127
+ if (isApiChat(value) && value["deleted"] !== 1) {
128
+ var tmpParam = {
129
+ "id": value["no"],
130
+ "vpos": value["vpos"],
131
+ "content": value["content"],
132
+ "date": value["date"],
133
+ "date_usec": value["date_usec"],
134
+ "owner": !value["user_id"],
135
+ "premium": value["premium"] === 1,
136
+ "mail": []
137
+ };
138
+ if (value["mail"]) {
139
+ tmpParam["mail"] = value["mail"].split(/[\s ]/g);
140
+ }
141
+ if (value["content"].startsWith("/") && !value["user_id"]) {
142
+ tmpParam["mail"].push("invisible");
143
+ }
144
+ data_.push(tmpParam);
145
+ }
146
+ }
147
+ }
148
+ data_.sort(function (a, b) {
149
+ if (a.vpos < b.vpos)
150
+ return -1;
151
+ if (a.vpos > b.vpos)
152
+ return 1;
153
+ if (a.date < b.date)
154
+ return -1;
155
+ if (a.date > b.date)
156
+ return 1;
157
+ if (a.date_usec < b.date_usec)
158
+ return -1;
159
+ if (a.date_usec > b.date_usec)
160
+ return 1;
161
+ return 0;
162
+ });
163
+ logger("parseData complete: ".concat(performance.now() - parseDataStart, "ms"));
164
+ return data_;
165
+ };
166
+ NiconiComments.prototype.preRendering = function (rawData, drawAll) {
167
+ var preRenderingStart = performance.now();
168
+ var parsedData = this.getCommentPos(this.getCommentSize(this.getFont(rawData)));
169
+ this.data = this.sortComment(parsedData);
170
+ if (drawAll) {
171
+ for (var i in parsedData) {
172
+ this.getTextImage(Number(i));
173
+ }
174
+ }
175
+ logger("preRendering complete: ".concat(performance.now() - preRenderingStart, "ms"));
176
+ };
177
+ NiconiComments.prototype.getFont = function (parsedData) {
178
+ var getFontStart = performance.now();
179
+ var result = [];
180
+ for (var i in parsedData) {
181
+ var value = parsedData[i];
182
+ if (!value)
183
+ continue;
184
+ value.content = value.content.replace(/\t/g, "\u2003\u2003");
185
+ result[i] = this.parseCommandAndNicoscript(value);
186
+ }
187
+ logger("getFont complete: ".concat(performance.now() - getFontStart, "ms"));
188
+ return result;
189
+ };
190
+ NiconiComments.prototype.getCommentSize = function (parsedData) {
191
+ var getCommentSizeStart = performance.now();
192
+ var tmpData = groupBy(parsedData, "font", "fontSize");
193
+ var result = [];
194
+ for (var i in tmpData) {
195
+ for (var j in tmpData[i]) {
196
+ this.context.font = parseFont(i, j, this.useLegacy);
197
+ for (var k in tmpData[i][j]) {
198
+ var comment = tmpData[i][j][k];
199
+ if (comment.invisible) {
200
+ continue;
201
+ }
202
+ var measure = this.measureText(comment);
203
+ var size = parsedData[comment.index];
204
+ size.height = measure.height;
205
+ size.width = measure.width;
206
+ size.width_max = measure.width_max;
207
+ size.width_min = measure.width_min;
208
+ size.lineHeight = measure.lineHeight;
209
+ if (measure.resized) {
210
+ size.fontSize = measure.fontSize;
211
+ this.context.font = parseFont(i, j, this.useLegacy);
212
+ }
213
+ result[comment.index] = size;
214
+ }
215
+ }
216
+ }
217
+ logger("getCommentSize complete: ".concat(performance.now() - getCommentSizeStart, "ms"));
218
+ return result;
219
+ };
220
+ NiconiComments.prototype.getCommentPos = function (parsedData) {
221
+ var getCommentPosStart = performance.now();
222
+ var data = parsedData;
223
+ for (var i in data) {
224
+ var comment = data[i];
225
+ if (!comment || comment.invisible) {
226
+ continue;
227
+ }
228
+ for (var j = 0; j < 500; j++) {
229
+ if (!this.timeline[comment.vpos + j]) {
230
+ this.timeline[comment.vpos + j] = [];
231
+ }
232
+ if (!this.collision_right[comment.vpos + j]) {
233
+ this.collision_right[comment.vpos + j] = [];
234
+ }
235
+ if (!this.collision_left[comment.vpos + j]) {
236
+ this.collision_left[comment.vpos + j] = [];
237
+ }
238
+ if (!this.collision_ue[comment.vpos + j]) {
239
+ this.collision_ue[comment.vpos + j] = [];
240
+ }
241
+ if (!this.collision_shita[comment.vpos + j]) {
242
+ this.collision_shita[comment.vpos + j] = [];
243
+ }
244
+ }
245
+ if (comment.loc === "naka") {
246
+ comment.vpos -= 70;
247
+ parsedData[i].vpos -= 70;
248
+ var posY = 0, is_break = false, is_change = true, count = 0;
249
+ if (1080 < comment.height) {
250
+ posY = (comment.height - 1080) / -2;
251
+ }
252
+ else {
253
+ while (is_change && count < 10) {
254
+ is_change = false;
255
+ count++;
256
+ for (var j = 0; j < 500; j++) {
257
+ var vpos = comment.vpos + j;
258
+ var left_pos = 1920 - ((1920 + comment.width_max) * j / 500);
259
+ if (left_pos + comment.width_max >= 1880) {
260
+ for (var k in this.collision_right[vpos]) {
261
+ var l = this.collision_right[vpos][k];
262
+ if ((posY < data[l].posY + data[l].height && posY + comment.height > data[l].posY) && data[l].owner === comment.owner) {
263
+ if (data[l].posY + data[l].height > posY) {
264
+ posY = data[l].posY + data[l].height;
265
+ is_change = true;
266
+ }
267
+ if (posY + comment.height > 1080) {
268
+ if (1080 < comment.height) {
269
+ posY = (comment.height - 1080) / -2;
270
+ }
271
+ else {
272
+ posY = Math.floor(Math.random() * (1080 - comment.height));
273
+ }
274
+ is_break = true;
275
+ break;
276
+ }
277
+ }
278
+ }
279
+ if (is_break) {
280
+ break;
281
+ }
282
+ }
283
+ if (left_pos <= 40) {
284
+ for (var k in this.collision_left[vpos]) {
285
+ var l = this.collision_left[vpos][k];
286
+ if ((posY < data[l].posY + data[l].height && posY + comment.height > data[l].posY) && data[l].owner === comment.owner) {
287
+ if (data[l].posY + data[l].height > posY) {
288
+ posY = data[l].posY + data[l].height;
289
+ is_change = true;
290
+ }
291
+ if (posY + comment.height > 1080) {
292
+ if (1080 < comment.height) {
293
+ posY = 0;
294
+ }
295
+ else {
296
+ posY = Math.random() * (1080 - comment.height);
297
+ }
298
+ is_break = true;
299
+ break;
300
+ }
301
+ }
302
+ }
303
+ if (is_break) {
304
+ break;
305
+ }
306
+ }
307
+ }
308
+ if (is_break) {
309
+ break;
310
+ }
311
+ }
312
+ }
313
+ for (var j = 0; j < 500; j++) {
314
+ var vpos = comment.vpos + j;
315
+ var left_pos = 1920 - ((1920 + comment.width_max) * j / 500);
316
+ arrayPush(this.timeline, vpos, i);
317
+ if (left_pos + comment.width_max >= 1880) {
318
+ arrayPush(this.collision_right, vpos, i);
319
+ }
320
+ if (left_pos <= 40) {
321
+ arrayPush(this.collision_left, vpos, i);
322
+ }
323
+ }
324
+ parsedData[i].posY = posY;
325
+ }
326
+ else {
327
+ var posY = 0, is_break = false, is_change = true, count = 0, collision = void 0;
328
+ if (comment.loc === "ue") {
329
+ collision = this.collision_ue;
330
+ }
331
+ else if (comment.loc === "shita") {
332
+ collision = this.collision_shita;
333
+ }
334
+ while (is_change && count < 10) {
335
+ is_change = false;
336
+ count++;
337
+ for (var j = 0; j < 300; j++) {
338
+ var vpos = comment.vpos + j;
339
+ for (var k in collision[vpos]) {
340
+ var l = collision[vpos][k];
341
+ if ((posY < data[l].posY + data[l].height && posY + comment.height > data[l].posY) && data[l].owner === comment.owner) {
342
+ if (data[l].posY + data[l].height > posY) {
343
+ posY = data[l].posY + data[l].height;
344
+ is_change = true;
345
+ }
346
+ if (posY + comment.height > 1080) {
347
+ if (1000 <= comment.height) {
348
+ posY = 0;
349
+ }
350
+ else {
351
+ posY = Math.floor(Math.random() * (1080 - comment.height));
352
+ }
353
+ is_break = true;
354
+ break;
355
+ }
356
+ }
357
+ }
358
+ if (is_break) {
359
+ break;
360
+ }
361
+ }
362
+ }
363
+ for (var j = 0; j < comment.long; j++) {
364
+ var vpos = comment.vpos + j;
365
+ arrayPush(this.timeline, vpos, i);
366
+ if (comment.loc === "ue") {
367
+ arrayPush(this.collision_ue, vpos, i);
368
+ }
369
+ else {
370
+ arrayPush(this.collision_shita, vpos, i);
371
+ }
372
+ }
373
+ parsedData[i].posY = posY;
374
+ }
375
+ }
376
+ logger("getCommentPos complete: ".concat(performance.now() - getCommentPosStart, "ms"));
377
+ return parsedData;
378
+ };
379
+ NiconiComments.prototype.sortComment = function (parsedData) {
380
+ var sortCommentStart = performance.now();
381
+ for (var vpos in this.timeline) {
382
+ if (!this.timeline[vpos])
383
+ continue;
384
+ var owner = [], user = [];
385
+ for (var _i = 0, _a = this.timeline[vpos]; _i < _a.length; _i++) {
386
+ var i = _a[_i];
387
+ if (parsedData[i].owner) {
388
+ owner.push(i);
389
+ }
390
+ else {
391
+ user.push(i);
392
+ }
393
+ }
394
+ this.timeline[vpos] = owner.concat(user);
395
+ }
396
+ logger("parseData complete: ".concat(performance.now() - sortCommentStart, "ms"));
397
+ return parsedData;
398
+ };
399
+ NiconiComments.prototype.measureText = function (comment) {
400
+ var width, width_max, width_min, height, width_arr = [], lines = comment.content.split("\n");
401
+ if (!comment.lineHeight)
402
+ comment.lineHeight = this.lineHeight[comment.size].default;
403
+ if (!comment.resized && !comment.ender) {
404
+ if (comment.size === "big" && lines.length > 2) {
405
+ comment.fontSize = this.fontSize.big.resized;
406
+ comment.lineHeight = this.lineHeight.big.resized;
407
+ comment.resized = true;
408
+ comment.tateresized = true;
409
+ this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
410
+ }
411
+ else if (comment.size === "medium" && lines.length > 4) {
412
+ comment.fontSize = this.fontSize.medium.resized;
413
+ comment.lineHeight = this.lineHeight.medium.resized;
414
+ comment.resized = true;
415
+ comment.tateresized = true;
416
+ this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
417
+ }
418
+ else if (comment.size === "small" && lines.length > 6) {
419
+ comment.fontSize = this.fontSize.small.resized;
420
+ comment.lineHeight = this.lineHeight.small.resized;
421
+ comment.resized = true;
422
+ comment.tateresized = true;
423
+ this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
424
+ }
425
+ }
426
+ for (var i = 0; i < lines.length; i++) {
427
+ var measure = this.context.measureText(lines[i]);
428
+ width_arr.push(measure.width);
429
+ }
430
+ width = width_arr.reduce(function (p, c) { return p + c; }, 0) / width_arr.length;
431
+ width_max = Math.max.apply(Math, width_arr);
432
+ width_min = Math.min.apply(Math, width_arr);
433
+ height = (comment.fontSize * comment.lineHeight * (1 + this.commentYPaddingTop) * lines.length) + (this.commentYMarginBottom * comment.fontSize);
434
+ if (comment.loc !== "naka" && !comment.tateresized) {
435
+ if (comment.full && width_max > 1930) {
436
+ comment.fontSize -= 2;
437
+ comment.resized = true;
438
+ comment.yokoResized = true;
439
+ this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
440
+ return this.measureText(comment);
441
+ }
442
+ else if (!comment.full && width_max > 1440) {
443
+ comment.fontSize -= 1;
444
+ comment.resized = true;
445
+ comment.yokoResized = true;
446
+ this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
447
+ return this.measureText(comment);
448
+ }
449
+ }
450
+ else if (comment.loc !== "naka" && comment.tateresized && (comment.full && width_max > 2120 || !comment.full && width_max > 1440) && !comment.yokoResized) {
451
+ comment.fontSize = this.fontSize[comment.size].default;
452
+ comment.resized = true;
453
+ comment.yokoResized = true;
454
+ this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
455
+ return this.measureText(comment);
456
+ }
457
+ else if (comment.loc !== "naka" && comment.tateresized && comment.yokoResized) {
458
+ if (comment.full && width_max > this.doubleResizeMaxWidth.full[this.useLegacy ? "legacy" : "default"]) {
459
+ comment.fontSize -= 1;
460
+ this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
461
+ return this.measureText(comment);
462
+ }
463
+ else if (!comment.full && width_max > this.doubleResizeMaxWidth.normal[this.useLegacy ? "legacy" : "default"]) {
464
+ comment.fontSize -= 1;
465
+ this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
466
+ return this.measureText(comment);
467
+ }
468
+ }
469
+ return {
470
+ "width": width,
471
+ "width_max": width_max,
472
+ "width_min": width_min,
473
+ "height": height,
474
+ "resized": comment.resized,
475
+ "fontSize": comment.fontSize,
476
+ "lineHeight": comment.lineHeight
477
+ };
478
+ };
479
+ NiconiComments.prototype.drawText = function (comment, vpos) {
480
+ var reverse = false;
481
+ for (var i in this.nicoScripts.reverse) {
482
+ var range = this.nicoScripts.reverse[i];
483
+ if ((range.target === "コメ" && comment.owner) || (range.target === "投コメ" && !comment.owner)) {
484
+ break;
485
+ }
486
+ if (range.start < vpos && vpos < range.end) {
487
+ reverse = true;
488
+ }
489
+ }
490
+ for (var i in this.nicoScripts.ban) {
491
+ var range = this.nicoScripts.ban[i];
492
+ if (range.start < vpos && vpos < range.end) {
493
+ return;
494
+ }
495
+ }
496
+ var posX = (1920 - comment.width_max) / 2, posY = comment.posY;
497
+ if (comment.loc === "naka") {
498
+ if (reverse) {
499
+ posX = ((1920 + comment.width_max) * (vpos - comment.vpos) / 500) - comment.width_max;
500
+ }
501
+ else {
502
+ posX = 1920 - ((1920 + comment.width_max) * (vpos - comment.vpos) / 500);
503
+ }
504
+ }
505
+ else if (comment.loc === "shita") {
506
+ posY = 1080 - comment.posY - comment.height;
507
+ }
508
+ if (comment.image && comment.image !== true) {
509
+ this.context.drawImage(comment.image, posX, posY);
510
+ }
511
+ if (this.showCollision) {
512
+ this.context.strokeStyle = "rgba(0,255,255,1)";
513
+ this.context.strokeRect(posX, posY, comment.width_max, comment.height);
514
+ var lines = comment.content.split("\n");
515
+ for (var i in lines) {
516
+ var linePosY = (Number(i) + 1) * (comment.fontSize * comment.lineHeight) * (1 + this.commentYPaddingTop);
517
+ this.context.strokeStyle = "rgba(255,255,0,0.5)";
518
+ this.context.strokeRect(posX, posY + linePosY, comment.width_max, comment.fontSize * comment.lineHeight * -1);
519
+ }
520
+ }
521
+ };
522
+ NiconiComments.prototype.getTextImage = function (i) {
523
+ var _this = this;
524
+ var value = this.data[i];
525
+ if (!value || value.invisible)
526
+ return;
527
+ var image = document.createElement("canvas");
528
+ image.width = value.width_max;
529
+ image.height = value.height;
530
+ var context = image.getContext("2d");
531
+ if (!context)
532
+ throw new Error("Fail to get CanvasRenderingContext2D");
533
+ context.strokeStyle = "rgba(0,0,0,0.7)";
534
+ context.textAlign = "start";
535
+ context.textBaseline = "alphabetic";
536
+ context.lineWidth = 4;
537
+ context.font = parseFont(value.font, value.fontSize, this.useLegacy);
538
+ if (value._live) {
539
+ var rgb = hex2rgb(value.color);
540
+ context.fillStyle = "rgba(".concat(rgb[0], ",").concat(rgb[1], ",").concat(rgb[2], ",0.5)");
541
+ }
542
+ else {
543
+ context.fillStyle = value.color;
544
+ }
545
+ if (value.color === "#000000") {
546
+ context.strokeStyle = "rgba(255,255,255,0.7)";
547
+ }
548
+ var lines = value.content.split("\n");
549
+ for (var i_1 in lines) {
550
+ var line = lines[i_1], posY = void 0;
551
+ posY = (Number(i_1) + 1) * (value.fontSize * value.lineHeight) * (1 + this.commentYPaddingTop);
552
+ context.strokeText(line, 0, posY);
553
+ context.fillText(line, 0, posY);
554
+ }
555
+ this.data[i].image = image;
556
+ setTimeout(function () {
557
+ if (_this.data[i].image)
558
+ delete _this.data[i].image;
559
+ }, 5000);
560
+ };
561
+ NiconiComments.prototype.parseCommand = function (comment) {
562
+ var metadata = comment.mail, loc = null, size = null, fontSize = null, color = null, font = null, full = false, ender = false, _live = false, invisible = false, long = null;
563
+ for (var i in metadata) {
564
+ var command = metadata[i].toLowerCase();
565
+ var match = command.match(/^@([0-9.]+)/);
566
+ if (match) {
567
+ long = match[1];
568
+ }
569
+ if (loc === null) {
570
+ switch (command) {
571
+ case "ue":
572
+ loc = "ue";
573
+ break;
574
+ case "shita":
575
+ loc = "shita";
576
+ break;
577
+ }
578
+ }
579
+ if (size === null) {
580
+ switch (command) {
581
+ case "big":
582
+ size = "big";
583
+ fontSize = this.fontSize.big.default;
584
+ break;
585
+ case "small":
586
+ size = "small";
587
+ fontSize = this.fontSize.small.default;
588
+ break;
589
+ }
590
+ }
591
+ if (color === null) {
592
+ switch (command) {
593
+ case "white":
594
+ color = "#FFFFFF";
595
+ break;
596
+ case "red":
597
+ color = "#FF0000";
598
+ break;
599
+ case "pink":
600
+ color = "#FF8080";
601
+ break;
602
+ case "orange":
603
+ color = "#FFC000";
604
+ break;
605
+ case "yellow":
606
+ color = "#FFFF00";
607
+ break;
608
+ case "green":
609
+ color = "#00FF00";
610
+ break;
611
+ case "cyan":
612
+ color = "#00FFFF";
613
+ break;
614
+ case "blue":
615
+ color = "#0000FF";
616
+ break;
617
+ case "purple":
618
+ color = "#C000FF";
619
+ break;
620
+ case "black":
621
+ color = "#000000";
622
+ break;
623
+ case "white2":
624
+ case "niconicowhite":
625
+ color = "#CCCC99";
626
+ break;
627
+ case "red2":
628
+ case "truered":
629
+ color = "#CC0033";
630
+ break;
631
+ case "pink2":
632
+ color = "#FF33CC";
633
+ break;
634
+ case "orange2":
635
+ case "passionorange":
636
+ color = "#FF6600";
637
+ break;
638
+ case "yellow2":
639
+ case "madyellow":
640
+ color = "#999900";
641
+ break;
642
+ case "green2":
643
+ case "elementalgreen":
644
+ color = "#00CC66";
645
+ break;
646
+ case "cyan2":
647
+ color = "#00CCCC";
648
+ break;
649
+ case "blue2":
650
+ case "marineblue":
651
+ color = "#3399FF";
652
+ break;
653
+ case "purple2":
654
+ case "nobleviolet":
655
+ color = "#6633CC";
656
+ break;
657
+ case "black2":
658
+ color = "#666666";
659
+ break;
660
+ default:
661
+ var match_1 = command.match(/#[0-9a-z]{3,6}/);
662
+ if (match_1 && comment.premium) {
663
+ color = match_1[0].toUpperCase();
664
+ }
665
+ break;
666
+ }
667
+ }
668
+ if (font === null) {
669
+ switch (command) {
670
+ case "gothic":
671
+ font = "gothic";
672
+ break;
673
+ case "mincho":
674
+ font = "mincho";
675
+ break;
676
+ }
677
+ }
678
+ switch (command) {
679
+ case "full":
680
+ full = true;
681
+ break;
682
+ case "ender":
683
+ ender = true;
684
+ break;
685
+ case "_live":
686
+ _live = true;
687
+ break;
688
+ case "invisible":
689
+ invisible = true;
690
+ break;
691
+ }
692
+ }
693
+ return { loc: loc, size: size, fontSize: fontSize, color: color, font: font, full: full, ender: ender, _live: _live, invisible: invisible, long: long };
694
+ };
695
+ NiconiComments.prototype.parseCommandAndNicoscript = function (comment) {
696
+ var data = this.parseCommand(comment), nicoscript = comment.content.match(/^@(デフォルト|置換|逆|コメント禁止|シーク禁止|ジャンプ)/);
697
+ if (nicoscript) {
698
+ switch (nicoscript[1]) {
699
+ case "デフォルト":
700
+ this.nicoScripts.default.push({
701
+ start: comment.vpos,
702
+ long: data.long === null ? null : Math.floor(data.long * 100),
703
+ color: data.color,
704
+ size: data.size,
705
+ font: data.font,
706
+ loc: data.loc
707
+ });
708
+ break;
709
+ case "逆":
710
+ var reverse = comment.content.match(/^@逆 ?(全|コメ|投コメ)?/);
711
+ if (!reverse)
712
+ reverse = [];
713
+ if (!reverse[1]) {
714
+ reverse[1] = "全";
715
+ }
716
+ if (data.long === null) {
717
+ data.long = 30;
718
+ }
719
+ this.nicoScripts.reverse.push({
720
+ start: comment.vpos,
721
+ end: comment.vpos + (data.long * 100),
722
+ target: reverse[1]
723
+ });
724
+ break;
725
+ case "コメント禁止":
726
+ if (data.long === null) {
727
+ data.long = 30;
728
+ }
729
+ this.nicoScripts.reverse.push({
730
+ start: comment.vpos,
731
+ end: comment.vpos + (data.long * 100),
732
+ });
733
+ break;
734
+ case "置換":
735
+ var content = comment.content.split(""), quote = "", last_i = "", string = "", result = [];
736
+ for (var _i = 0, _a = content.slice(4); _i < _a.length; _i++) {
737
+ var i = _a[_i];
738
+ if (i.match(/["'「]/) && quote === "") {
739
+ quote = i;
740
+ }
741
+ else if (i.match(/["']/) && quote === i && last_i !== "\\") {
742
+ result.push(replaceAll(string, "\\n", "\n"));
743
+ quote = "";
744
+ string = "";
745
+ }
746
+ else if (i.match(/」/) && quote === "") {
747
+ result.push(string);
748
+ quote = "";
749
+ string = "";
750
+ }
751
+ else if (quote === "" && i.match(/[\s ]/)) {
752
+ if (string) {
753
+ result.push(string);
754
+ string = "";
755
+ }
756
+ }
757
+ else {
758
+ string += i;
759
+ }
760
+ last_i = i;
761
+ }
762
+ result.push(string);
763
+ this.nicoScripts.replace.push({
764
+ start: comment.vpos,
765
+ long: data.long === null ? null : Math.floor(data.long * 100),
766
+ keyword: result[0],
767
+ replace: result[1] || "",
768
+ range: result[2] || "",
769
+ target: result[3] || "コメ",
770
+ condition: result[4] || "部分一致",
771
+ color: data.color,
772
+ size: data.size,
773
+ font: data.font,
774
+ loc: data.loc
775
+ });
776
+ break;
777
+ }
778
+ data.invisible = true;
779
+ }
780
+ var color = "#FFFFFF", size = "medium", font = "defont", loc = "naka";
781
+ for (var i in this.nicoScripts.default) {
782
+ if (this.nicoScripts.default[i].long !== null && this.nicoScripts.default[i].start + this.nicoScripts.default[i].long < comment.vpos) {
783
+ this.nicoScripts.default = this.nicoScripts.default.splice(Number(i), 1);
784
+ continue;
785
+ }
786
+ if (this.nicoScripts.default[i].loc) {
787
+ loc = this.nicoScripts.default[i].loc;
788
+ }
789
+ if (this.nicoScripts.default[i].color) {
790
+ color = this.nicoScripts.default[i].color;
791
+ }
792
+ if (this.nicoScripts.default[i].size) {
793
+ size = this.nicoScripts.default[i].size;
794
+ }
795
+ if (this.nicoScripts.default[i].font) {
796
+ font = this.nicoScripts.default[i].font;
797
+ }
798
+ }
799
+ for (var i in this.nicoScripts.replace) {
800
+ if (this.nicoScripts.replace[i].long !== null && this.nicoScripts.replace[i].start + this.nicoScripts.replace[i].long < comment.vpos) {
801
+ this.nicoScripts.default = this.nicoScripts.default.splice(Number(i), 1);
802
+ continue;
803
+ }
804
+ var item = this.nicoScripts.replace[i];
805
+ if ((item.target === "コメ" && comment.owner) || (item.target === "投コメ" && !comment.owner) || (item.target === "含まない" && comment.owner))
806
+ continue;
807
+ if ((item.condition === "完全一致" && comment.content === item.keyword) || (item.condition === "部分一致" && comment.content.indexOf(item.keyword) !== -1)) {
808
+ if (item.range === "単") {
809
+ comment.content = replaceAll(comment.content, item.keyword, item.replace);
810
+ }
811
+ else {
812
+ comment.content = item.replace;
813
+ }
814
+ if (item.loc) {
815
+ loc = item.loc;
816
+ }
817
+ if (item.color) {
818
+ color = item.color;
819
+ }
820
+ if (item.size) {
821
+ size = item.size;
822
+ }
823
+ if (item.font) {
824
+ font = item.font;
825
+ }
826
+ }
827
+ }
828
+ if (!data.loc) {
829
+ data.loc = loc;
830
+ }
831
+ if (!data.color) {
832
+ data.color = color;
833
+ }
834
+ if (!data.size) {
835
+ data.size = size;
836
+ data.fontSize = this.fontSize[data.size].default;
837
+ }
838
+ if (!data.font) {
839
+ data.font = font;
840
+ }
841
+ if (data.loc !== "naka") {
842
+ if (!data.long) {
843
+ data.long = 300;
844
+ }
845
+ else {
846
+ data.long = Math.floor(data.long * 100);
847
+ }
848
+ }
849
+ return _assign(_assign({}, comment), data);
850
+ };
851
+ NiconiComments.prototype.drawCanvas = function (vpos) {
852
+ var drawCanvasStart = performance.now();
853
+ if (this.lastVpos === vpos)
854
+ return;
855
+ this.lastVpos = vpos;
856
+ this.fpsCount++;
857
+ this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
858
+ if (this.video) {
859
+ var offsetX = void 0, offsetY = void 0, scale = void 0, height = this.canvas.height / this.video.videoHeight, width = this.canvas.width / this.video.videoWidth;
860
+ if (this.enableLegacyPiP ? height > width : height < width) {
861
+ scale = width;
862
+ }
863
+ else {
864
+ scale = height;
865
+ }
866
+ offsetX = (this.canvas.width - this.video.videoWidth * scale) * 0.5;
867
+ offsetY = (this.canvas.height - this.video.videoHeight * scale) * 0.5;
868
+ this.context.drawImage(this.video, offsetX, offsetY, this.video.videoWidth * scale, this.video.videoHeight * scale);
869
+ }
870
+ if (this.timeline[vpos]) {
871
+ for (var i in this.timeline[vpos]) {
872
+ var index = this.timeline[vpos][Number(i)];
873
+ var comment = this.data[index];
874
+ if (!comment || comment.invisible) {
875
+ continue;
876
+ }
877
+ if (comment.image === undefined) {
878
+ this.getTextImage(index);
879
+ }
880
+ try {
881
+ this.drawText(comment, vpos);
882
+ }
883
+ catch (e) {
884
+ comment.image = false;
885
+ }
886
+ }
887
+ }
888
+ if (this.showFPS) {
889
+ this.context.font = parseFont("defont", 60, this.useLegacy);
890
+ this.context.fillStyle = "#00FF00";
891
+ this.context.strokeStyle = "rgba(0,0,0,0.7)";
892
+ this.context.strokeText("FPS:" + this.fps, 100, 100);
893
+ this.context.fillText("FPS:" + this.fps, 100, 100);
894
+ }
895
+ if (this.showCommentCount) {
896
+ this.context.font = parseFont("defont", 60, this.useLegacy);
897
+ this.context.fillStyle = "#00FF00";
898
+ this.context.strokeStyle = "rgba(0,0,0,0.7)";
899
+ if (this.timeline[vpos]) {
900
+ this.context.strokeText("Count:" + this.timeline[vpos].length, 100, 200);
901
+ this.context.fillText("Count:" + this.timeline[vpos].length, 100, 200);
902
+ }
903
+ else {
904
+ this.context.strokeText("Count:0", 100, 200);
905
+ this.context.fillText("Count:0", 100, 200);
906
+ }
907
+ }
908
+ logger("drawCanvas complete: ".concat(performance.now() - drawCanvasStart, "ms"));
909
+ };
910
+ NiconiComments.prototype.clear = function () {
911
+ this.context.clearRect(0, 0, 1920, 1080);
912
+ };
913
+ return NiconiComments;
914
+ }());
915
+ var groupBy = function (array, key, key2) {
916
+ var data = {};
917
+ for (var i in array) {
918
+ if (!data[array[i][key]]) {
919
+ data[array[i][key]] = {};
920
+ }
921
+ if (!data[array[i][key]][array[i][key2]]) {
922
+ data[array[i][key]][array[i][key2]] = [];
923
+ }
924
+ array[i].index = i;
925
+ data[array[i][key]][array[i][key2]].push(array[i]);
926
+ }
927
+ return data;
928
+ };
929
+ var parseFont = function (font, size, useLegacy) {
930
+ switch (font) {
931
+ case "gothic":
932
+ return "normal 400 ".concat(size, "px \"\u6E38\u30B4\u30B7\u30C3\u30AF\u4F53\", \"\u6E38\u30B4\u30B7\u30C3\u30AF\", \"Yu Gothic\", YuGothic, yugothic, YuGo-Medium");
933
+ case "mincho":
934
+ return "normal 400 ".concat(size, "px \"\u6E38\u660E\u671D\u4F53\", \"\u6E38\u660E\u671D\", \"Yu Mincho\", YuMincho, yumincho, YuMin-Medium");
935
+ default:
936
+ if (useLegacy) {
937
+ return "normal 600 ".concat(size, "px Arial, \"\uFF2D\uFF33 \uFF30\u30B4\u30B7\u30C3\u30AF\", \"MS PGothic\", MSPGothic, MS-PGothic");
938
+ }
939
+ else {
940
+ return "normal 600 ".concat(size, "px sans-serif, Arial, \"\uFF2D\uFF33 \uFF30\u30B4\u30B7\u30C3\u30AF\", \"MS PGothic\", MSPGothic, MS-PGothic");
941
+ }
942
+ }
943
+ };
944
+ var arrayPush = function (array, key, push) {
945
+ if (!array) {
946
+ array = {};
947
+ }
948
+ if (!array[key]) {
949
+ array[key] = [];
950
+ }
951
+ array[key].push(push);
952
+ };
953
+ var hex2rgb = function (hex) {
954
+ if (hex.slice(0, 1) === "#")
955
+ hex = hex.slice(1);
956
+ if (hex.length === 3)
957
+ hex = hex.slice(0, 1) + hex.slice(0, 1) + hex.slice(1, 2) + hex.slice(1, 2) + hex.slice(2, 3) + hex.slice(2, 3);
958
+ return [hex.slice(0, 2), hex.slice(2, 4), hex.slice(4, 6)].map(function (str) {
959
+ return parseInt(str, 16);
960
+ });
961
+ };
962
+ var replaceAll = function (string, target, replace) {
963
+ var count = 0;
964
+ while (string.indexOf(target) !== -1 && count < 100) {
965
+ string = string.replace(target, replace);
966
+ count++;
967
+ }
968
+ return string;
969
+ };
970
+ var isApiChat = function (item) {
971
+ return item.id && item.vpos && item.vpos;
972
+ };
973
+ var logger = function (msg) {
974
+ if (isDebug)
975
+ console.debug(msg);
974
976
  };
975
977
 
976
978
  return NiconiComments;