@xpadev-net/niconicomments 0.1.3 → 0.1.7

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.
Files changed (2) hide show
  1. package/dist/bundle.js +305 -148
  2. package/package.json +2 -4
package/dist/bundle.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- niconicomments.js v0.1.3
2
+ niconicomments.js v0.1.7
3
3
  (c) 2021 xpadev-net https://xpadevn.et
4
4
  Released under the MIT License.
5
5
  */
@@ -23,21 +23,48 @@
23
23
  this.context.strokeStyle = "rgba(0,0,0,0.7)";
24
24
  this.context.textAlign = "left";
25
25
  this.context.textBaseline = "top";
26
- this.context.lineWidth = "6";
27
- this.commentYOffset = 0.25;
28
- this.commentYMarginTop = 10;
26
+ this.context.lineWidth = 4;
27
+
28
+ if (useLegacy) {
29
+ this.commentYOffset = 0.25;
30
+ } else {
31
+ this.commentYOffset = 0.2;
32
+ }
33
+
34
+ this.commentYMarginTop = 0.08;
29
35
  this.fontSize = {
30
36
  "small": {
31
- "default": 45,
32
- "resized": 18
37
+ "default": 47,
38
+ "resized": 27.5
33
39
  },
34
40
  "medium": {
35
- "default": 85,
36
- "resized": 35
41
+ "default": 76,
42
+ "resized": 39
37
43
  },
38
44
  "big": {
39
- "default": 120,
40
- "resized": 57.5
45
+ "default": 118,
46
+ "resized": 62.5
47
+ }
48
+ };
49
+ this.defaultCommandValue = {
50
+ loc: "naka",
51
+ size: "medium",
52
+ fontSize: this.fontSize.medium.default,
53
+ color: "#ffffff",
54
+ font: 'defont',
55
+ full: false,
56
+ ender: false,
57
+ _live: false,
58
+ invisible: false
59
+ };
60
+ this.doubleResizeMaxWidth = {
61
+ full: {
62
+ legacy: 3020,
63
+ default: 3220
64
+ },
65
+ normal: {
66
+ legacy: 2540,
67
+ default: 2740
41
68
  }
42
69
  };
43
70
 
@@ -52,7 +79,8 @@
52
79
  this.showCommentCount = false;
53
80
  this.timeline = {};
54
81
  this.nicoScripts = {
55
- "reverse": []
82
+ "reverse": [],
83
+ "default": []
56
84
  };
57
85
  this.collision_right = {};
58
86
  this.collision_left = {};
@@ -123,6 +151,7 @@
123
151
  this.getFont();
124
152
  this.getCommentSize();
125
153
  this.getCommentPos();
154
+ this.sortComment();
126
155
  }
127
156
  /**
128
157
  * コマンドをもとに各コメントに適用するフォントを決定する
@@ -132,7 +161,7 @@
132
161
  getFont() {
133
162
  for (let i in this.data) {
134
163
  let comment = this.data[i];
135
- let command = this.parseCommand(comment);
164
+ let command = this.parseCommandAndNicoscript(comment);
136
165
  this.data[i].loc = command.loc;
137
166
  this.data[i].size = command.size;
138
167
  this.data[i].fontSize = command.fontSize;
@@ -141,6 +170,8 @@
141
170
  this.data[i].full = command.full;
142
171
  this.data[i].ender = command.ender;
143
172
  this.data[i]._live = command._live;
173
+ this.data[i].long = command.long;
174
+ this.data[i].invisible = command.invisible;
144
175
  this.data[i].content = this.data[i].content.replaceAll("\t", " ");
145
176
  }
146
177
  }
@@ -158,6 +189,11 @@
158
189
 
159
190
  for (let k in tmpData[i][j]) {
160
191
  let comment = tmpData[i][j][k];
192
+
193
+ if (comment.invisible) {
194
+ continue;
195
+ }
196
+
161
197
  let measure = this.measureText(comment);
162
198
  this.data[comment.index].height = measure.height;
163
199
  this.data[comment.index].width = measure.width;
@@ -183,6 +219,10 @@
183
219
  for (let i in data) {
184
220
  let comment = data[i];
185
221
 
222
+ if (comment.invisible) {
223
+ continue;
224
+ }
225
+
186
226
  for (let j = 0; j < 500; j++) {
187
227
  if (!this.timeline[comment.vpos + j]) {
188
228
  this.timeline[comment.vpos + j] = [];
@@ -213,73 +253,77 @@
213
253
  is_change = true,
214
254
  count = 0;
215
255
 
216
- while (is_change && count < 10) {
217
- is_change = false;
218
- count++;
219
-
220
- for (let j = 0; j < 500; j++) {
221
- let vpos = comment.vpos + j;
222
- let left_pos = 1920 - (1920 + comment.width_max) * j / 500;
223
-
224
- if (left_pos + comment.width_max >= 1880) {
225
- for (let k in this.collision_right[vpos]) {
226
- let l = this.collision_right[vpos][k];
256
+ if (1080 < comment.height) {
257
+ posY = (comment.height - 1080) / -2;
258
+ } else {
259
+ while (is_change && count < 10) {
260
+ is_change = false;
261
+ count++;
262
+
263
+ for (let j = 0; j < 500; j++) {
264
+ let vpos = comment.vpos + j;
265
+ let left_pos = 1920 - (1920 + comment.width_max) * j / 500;
266
+
267
+ if (left_pos + comment.width_max >= 1880) {
268
+ for (let k in this.collision_right[vpos]) {
269
+ let l = this.collision_right[vpos][k];
270
+
271
+ if (posY < data[l].posY + data[l].height && posY + comment.height > data[l].posY && data[l].owner === comment.owner) {
272
+ if (data[l].posY + data[l].height > posY) {
273
+ posY = data[l].posY + data[l].height;
274
+ is_change = true;
275
+ }
227
276
 
228
- if (posY < data[l].posY + data[l].height && posY + comment.height > data[l].posY && data[l].owner === comment.owner) {
229
- if (data[l].posY + data[l].height > posY) {
230
- posY = data[l].posY + data[l].height;
231
- is_change = true;
232
- }
277
+ if (posY + comment.height > 1080) {
278
+ if (1080 < comment.height) {
279
+ posY = (comment.height - 1080) / -2;
280
+ } else {
281
+ posY = Math.floor(Math.random() * (1080 - comment.height));
282
+ }
233
283
 
234
- if (posY + comment.height > 1080) {
235
- if (1080 < comment.height) {
236
- posY = (comment.height - 1080) / -2;
237
- } else {
238
- posY = Math.floor(Math.random() * (1080 - comment.height));
284
+ is_break = true;
285
+ break;
239
286
  }
240
-
241
- is_break = true;
242
- break;
243
287
  }
244
288
  }
245
- }
246
289
 
247
- if (is_break) {
248
- break;
290
+ if (is_break) {
291
+ break;
292
+ }
249
293
  }
250
- }
251
294
 
252
- if (left_pos <= 40 && is_break === false) {
253
- for (let k in this.collision_left[vpos]) {
254
- let l = this.collision_left[vpos][k];
295
+ if (left_pos <= 40 && is_break === false) {
296
+ for (let k in this.collision_left[vpos]) {
297
+ let l = this.collision_left[vpos][k];
255
298
 
256
- if (posY < data[l].posY + data[l].height && posY + comment.height > data[l].posY && data[l].owner === comment.owner) {
257
- if (data[l].posY + data[l].height > posY) {
258
- posY = data[l].posY + data[l].height;
259
- is_change = true;
260
- }
261
-
262
- if (posY + comment.height > 1080) {
263
- if (1080 < comment.height) {
264
- posY = 0;
265
- } else {
266
- posY = Math.random() * (1080 - comment.height);
299
+ if (posY < data[l].posY + data[l].height && posY + comment.height > data[l].posY && data[l].owner === comment.owner) {
300
+ if (data[l].posY + data[l].height > posY) {
301
+ posY = data[l].posY + data[l].height;
302
+ is_change = true;
267
303
  }
268
304
 
269
- is_break = true;
270
- break;
305
+ if (posY + comment.height > 1080) {
306
+ if (1080 < comment.height) {
307
+ posY = 0;
308
+ } else {
309
+ posY = Math.random() * (1080 - comment.height);
310
+ }
311
+
312
+ is_break = true;
313
+ break;
314
+ }
271
315
  }
272
316
  }
317
+
318
+ if (is_break) {
319
+ break;
320
+ }
273
321
  }
274
322
 
275
323
  if (is_break) {
276
324
  break;
277
325
  }
278
326
  }
279
-
280
- if (is_break) {
281
- break;
282
- }
283
327
  }
284
328
  }
285
329
 
@@ -346,7 +390,7 @@
346
390
  }
347
391
  }
348
392
 
349
- for (let j = 0; j < 300; j++) {
393
+ for (let j = 0; j < comment.long; j++) {
350
394
  let vpos = comment.vpos + j;
351
395
  arrayPush(this.timeline, vpos, i);
352
396
 
@@ -361,6 +405,23 @@
361
405
  }
362
406
  }
363
407
  }
408
+
409
+ sortComment() {
410
+ for (let vpos in this.timeline) {
411
+ this.timeline[vpos].sort((a, b) => {
412
+ const A = this.data[a];
413
+ const B = this.data[b];
414
+
415
+ if (!A.owner && B.owner) {
416
+ return -1;
417
+ } else if (A.owner && !B.owner) {
418
+ return 1;
419
+ } else {
420
+ return 0;
421
+ }
422
+ });
423
+ }
424
+ }
364
425
  /**
365
426
  * context.measureTextの複数行対応版
366
427
  * 画面外にはみ出すコメントの縮小も行う
@@ -404,7 +465,7 @@
404
465
  width = width_arr.reduce((p, c) => p + c, 0) / width_arr.length;
405
466
  width_max = Math.max(...width_arr);
406
467
  width_min = Math.min(...width_arr);
407
- height = (comment.fontSize + this.commentYMarginTop) * lines.length;
468
+ height = (comment.fontSize + this.commentYMarginTop * comment.fontSize) * lines.length;
408
469
 
409
470
  if (comment.loc !== "naka" && !comment.tateRisized) {
410
471
  if (comment.full && width_max > 1920) {
@@ -427,16 +488,12 @@
427
488
  this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
428
489
  return this.measureText(comment);
429
490
  } else if (comment.loc !== "naka" && comment.tateRisized && comment.yokoResized) {
430
- if (comment.full && width_max > 3420) {
491
+ if (comment.full && width_max > this.doubleResizeMaxWidth.full[this.useLegacy ? "legacy" : "default"]) {
431
492
  comment.fontSize -= 1;
432
- comment.resized = true;
433
- comment.yokoResized = true;
434
493
  this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
435
494
  return this.measureText(comment);
436
- } else if (!comment.full && width_max > 2940) {
437
- comment.fontSize -= 1;
438
- comment.resized = true;
439
- comment.yokoResized = true;
495
+ } else if (!comment.full && width_max > this.doubleResizeMaxWidth.normal[this.useLegacy ? "legacy" : "default"]) {
496
+ comment.fontSize -= 1.;
440
497
  this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
441
498
  return this.measureText(comment);
442
499
  }
@@ -476,32 +533,16 @@
476
533
  let lines = comment.content.split("\n"),
477
534
  posX = (1920 - comment.width_max) / 2;
478
535
 
479
- if (comment.loc === "shita") {
480
- for (let i in lines) {
481
- let line = lines[i];
482
- let posY = 1080 - comment.posY + i * (comment.fontSize + this.commentYMarginTop) - comment.height + this.commentYOffset * comment.fontSize;
483
- this.context.strokeText(line, posX, posY);
484
- this.context.fillText(line, posX, posY);
485
- }
486
- } else {
487
- if (comment.loc === "naka") {
488
- if (reverse) {
489
- posX = (1920 + comment.width_max) * (vpos - comment.vpos) / 500 - comment.width_max;
490
- } else {
491
- posX = 1920 - (1920 + comment.width_max) * (vpos - comment.vpos) / 500;
492
- }
493
- }
494
-
495
- for (let i in lines) {
496
- let line = lines[i];
497
- let posY = comment.posY + i * (comment.fontSize + this.commentYMarginTop) + this.commentYOffset * comment.fontSize;
498
- this.context.strokeText(line, posX, posY);
499
- this.context.fillText(line, posX, posY);
536
+ if (comment.loc === "naka") {
537
+ if (reverse) {
538
+ posX = (1920 + comment.width_max) * (vpos - comment.vpos) / 500 - comment.width_max;
539
+ } else {
540
+ posX = 1920 - (1920 + comment.width_max) * (vpos - comment.vpos) / 500;
500
541
  }
501
542
  }
502
543
 
503
544
  if (this.showCollision) {
504
- this.context.strokeStyle = "rgba(255,255,0,1)";
545
+ this.context.strokeStyle = "rgba(0,255,255,1)";
505
546
 
506
547
  if (comment.loc === "shita") {
507
548
  this.context.strokeRect(posX, 1080 - comment.posY - comment.height, comment.width_max, comment.height);
@@ -509,60 +550,67 @@
509
550
  this.context.strokeRect(posX, comment.posY, comment.width_max, comment.height);
510
551
  }
511
552
 
512
- this.context.strokeStyle = "rgba(0,0,0,0.7)";
553
+ if (comment.color === "#000000") {
554
+ this.context.strokeStyle = "rgba(255,255,255,0.7)";
555
+ } else {
556
+ this.context.strokeStyle = "rgba(0,0,0,0.7)";
557
+ }
558
+ }
559
+
560
+ for (let i in lines) {
561
+ let line = lines[i],
562
+ posY;
563
+
564
+ if (comment.loc === "shita") {
565
+ posY = 1080 - comment.posY + i * (comment.fontSize + this.commentYMarginTop * comment.fontSize) - comment.height + this.commentYOffset * comment.fontSize;
566
+ } else {
567
+ posY = comment.posY + i * (comment.fontSize + this.commentYMarginTop * comment.fontSize) + this.commentYOffset * comment.fontSize;
568
+ }
569
+
570
+ this.context.strokeText(line, posX, posY);
571
+ this.context.fillText(line, posX, posY);
572
+
573
+ if (this.showCollision) {
574
+ this.context.strokeStyle = "rgba(255,255,0,0.5)";
575
+ this.context.strokeRect(posX, posY, comment.width_max, comment.fontSize);
576
+
577
+ if (comment.color === "#000000") {
578
+ this.context.strokeStyle = "rgba(255,255,255,0.7)";
579
+ } else {
580
+ this.context.strokeStyle = "rgba(0,0,0,0.7)";
581
+ }
582
+ }
513
583
  }
514
584
  }
515
585
  /**
516
586
  * コメントに含まれるコマンドを解釈する
517
587
  * @param comment- 独自フォーマットのコメントデータ
518
- * @returns {{loc: string, size: string, color: string, fontSize: number, ender: boolean, font: string, full: boolean, _live: boolean}}
588
+ * @returns {{loc: string|null, size: string|null, color: string|null, fontSize: number|null, ender: boolean, font: string|null, full: boolean, _live: boolean, invisible: boolean, long:number|null}}
519
589
  */
520
590
 
521
591
 
522
592
  parseCommand(comment) {
523
593
  let metadata = comment.mail,
524
- loc = "naka",
525
- size = "medium",
526
- fontSize = this.fontSize.medium.default,
527
- color = "#ffffff",
528
- font = 'defont',
594
+ loc = null,
595
+ size = null,
596
+ fontSize = null,
597
+ color = null,
598
+ font = null,
529
599
  full = false,
530
600
  ender = false,
531
- reverse = comment.content.match(/@逆 ?(全|コメ|投コメ)?/),
532
- _live = false;
533
-
534
- if (reverse) {
535
- if (!reverse[1]) {
536
- reverse[1] = "全";
537
- }
538
-
539
- let length = false;
540
-
541
- for (let i in metadata) {
542
- let match = metadata[i].match(/@([0-9]+)/);
543
-
544
- if (match) {
545
- length = match[1];
546
- break;
547
- }
548
- }
549
-
550
- if (!length) {
551
- length = 30;
552
- }
553
-
554
- this.nicoScripts.reverse.push({
555
- "start": comment.vpos,
556
- "end": comment.vpos + length * 100,
557
- "target": reverse[1]
558
- });
559
- fontSize = 0;
560
- }
601
+ _live = false,
602
+ invisible = false,
603
+ long = null;
561
604
 
562
605
  for (let i in metadata) {
563
606
  let command = metadata[i].toLowerCase();
607
+ const match = command.match(/^@([0-9.]+)/);
564
608
 
565
- if (loc === "naka") {
609
+ if (match) {
610
+ long = match[1];
611
+ }
612
+
613
+ if (loc === null) {
566
614
  switch (command) {
567
615
  case "ue":
568
616
  loc = "ue";
@@ -574,7 +622,7 @@
574
622
  }
575
623
  }
576
624
 
577
- if (size === "medium") {
625
+ if (size === null) {
578
626
  switch (command) {
579
627
  case "big":
580
628
  size = "big";
@@ -588,7 +636,7 @@
588
636
  }
589
637
  }
590
638
 
591
- if (color === "#ffffff") {
639
+ if (color === null) {
592
640
  switch (command) {
593
641
  case "white":
594
642
  color = "#FFFFFF";
@@ -688,7 +736,7 @@
688
736
  }
689
737
  }
690
738
 
691
- if (font === 'defont') {
739
+ if (font === null) {
692
740
  switch (command) {
693
741
  case "gothic":
694
742
  font = "gothic";
@@ -711,6 +759,11 @@
711
759
 
712
760
  case "_live":
713
761
  _live = true;
762
+ break;
763
+
764
+ case "invisible":
765
+ invisible = true;
766
+ break;
714
767
  }
715
768
  }
716
769
 
@@ -722,9 +775,106 @@
722
775
  font,
723
776
  full,
724
777
  ender,
725
- _live
778
+ _live,
779
+ invisible,
780
+ long
726
781
  };
727
782
  }
783
+
784
+ parseCommandAndNicoscript(comment) {
785
+ let data = this.parseCommand(comment),
786
+ nicoscript = comment.content.match(/^@(デフォルト|置換|逆|コメント禁止|シーク禁止|ジャンプ)/);
787
+
788
+ if (nicoscript) {
789
+ switch (nicoscript[1]) {
790
+ case "デフォルト":
791
+ this.nicoScripts.default.push({
792
+ start: comment.vpos,
793
+ long: data.long === null ? null : Math.floor(data.long * 100),
794
+ color: data.color,
795
+ size: data.size,
796
+ font: data.font,
797
+ loc: data.loc
798
+ });
799
+ break;
800
+
801
+ case "逆":
802
+ let reverse = comment.content.match(/^@逆 ?(全|コメ|投コメ)?/);
803
+
804
+ if (!reverse[1]) {
805
+ reverse[1] = "全";
806
+ }
807
+
808
+ if (data.long === null) {
809
+ data.long = 30;
810
+ }
811
+
812
+ this.nicoScripts.reverse.push({
813
+ "start": comment.vpos,
814
+ "end": comment.vpos + data.long * 100,
815
+ "target": reverse[1]
816
+ });
817
+ break;
818
+ }
819
+
820
+ data.invisible = true;
821
+ }
822
+
823
+ let color = "#FFFFFF",
824
+ size = "medium",
825
+ font = "defont",
826
+ loc = "naka";
827
+
828
+ for (let i in this.nicoScripts.default) {
829
+ if (this.nicoScripts.default[i].long !== null && this.nicoScripts.default[i].start + this.nicoScripts.default[i].long < comment.vpos) {
830
+ this.nicoScripts.default = this.nicoScripts.default.splice(Number(i), 1);
831
+ continue;
832
+ }
833
+
834
+ if (this.nicoScripts.default[i].loc) {
835
+ loc = this.nicoScripts.default[i].loc;
836
+ }
837
+
838
+ if (this.nicoScripts.default[i].color) {
839
+ color = this.nicoScripts.default[i].color;
840
+ }
841
+
842
+ if (this.nicoScripts.default[i].size) {
843
+ size = this.nicoScripts.default[i].size;
844
+ }
845
+
846
+ if (this.nicoScripts.default[i].font) {
847
+ font = this.nicoScripts.default[i].font;
848
+ }
849
+ }
850
+
851
+ if (!data.loc) {
852
+ data.loc = loc;
853
+ }
854
+
855
+ if (!data.color) {
856
+ data.color = color;
857
+ }
858
+
859
+ if (!data.size) {
860
+ data.size = size;
861
+ data.fontSize = this.fontSize[data.size].default;
862
+ }
863
+
864
+ if (!data.font) {
865
+ data.font = font;
866
+ }
867
+
868
+ if (data.loc !== "naka") {
869
+ if (!data.long) {
870
+ data.long = 300;
871
+ } else {
872
+ data.long = Math.floor(data.long * 100);
873
+ }
874
+ }
875
+
876
+ return data;
877
+ }
728
878
  /**
729
879
  * キャンバスを描画する
730
880
  * @param vpos - 動画の現在位置の100倍 ニコニコから吐き出されるコメントの位置情報は主にこれ
@@ -735,25 +885,32 @@
735
885
  this.fpsCount++;
736
886
  this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
737
887
 
738
- for (let index in this.timeline[vpos]) {
739
- let comment = this.data[this.timeline[vpos][index]];
740
- this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
888
+ if (this.timeline[vpos]) {
889
+ for (let index in this.timeline[vpos]) {
890
+ let comment = this.data[this.timeline[vpos][index]];
741
891
 
742
- if (comment._live) {
743
- let rgb = hex2rgb(comment.color);
744
- this.context.fillStyle = `rgba(${rgb[0]},${rgb[1]},${rgb[2]},0.5)`;
745
- } else {
746
- this.context.fillStyle = comment.color;
747
- }
892
+ if (comment.invisible) {
893
+ continue;
894
+ }
748
895
 
749
- if (comment.color === "#000000") {
750
- this.context.strokeStyle = "rgba(255,255,255,0.7)";
751
- }
896
+ this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
752
897
 
753
- this.drawText(comment, vpos);
898
+ if (comment._live) {
899
+ let rgb = hex2rgb(comment.color);
900
+ this.context.fillStyle = `rgba(${rgb[0]},${rgb[1]},${rgb[2]},0.5)`;
901
+ } else {
902
+ this.context.fillStyle = comment.color;
903
+ }
754
904
 
755
- if (comment.color === "#000000") {
756
- this.context.strokeStyle = "rgba(0,0,0,0.7)";
905
+ if (comment.color === "#000000") {
906
+ this.context.strokeStyle = "rgba(255,255,255,0.7)";
907
+ }
908
+
909
+ this.drawText(comment, vpos);
910
+
911
+ if (comment.color === "#000000") {
912
+ this.context.strokeStyle = "rgba(0,0,0,0.7)";
913
+ }
757
914
  }
758
915
  }
759
916
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xpadev-net/niconicomments",
3
- "version": "0.1.3",
3
+ "version": "0.1.7",
4
4
  "description": "NiconiComments is a comment drawing library that is somewhat compatible with the official Nico Nico Douga player.",
5
5
  "main": "dist/bundle.js",
6
6
  "scripts": {
@@ -25,9 +25,7 @@
25
25
  "homepage": "https://xpadev.net/niconicomments/docs/",
26
26
  "license": "MIT",
27
27
  "devDependencies": {
28
- "rollup": "^2.61.1"
29
- },
30
- "dependencies": {
28
+ "rollup": "^2.61.1",
31
29
  "@rollup/plugin-babel": "^5.3.0"
32
30
  }
33
31
  }