@xpadev-net/niconicomments 0.1.4 → 0.1.8

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 (4) hide show
  1. package/LICENSE +7 -7
  2. package/README.md +24 -24
  3. package/dist/bundle.js +364 -197
  4. package/package.json +31 -33
package/LICENSE CHANGED
@@ -1,7 +1,7 @@
1
- Copyright (c) 2021 xpadev https://xpadev.net
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
-
5
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
-
7
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+ Copyright (c) 2021 xpadev https://xpadev.net
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1,24 +1,24 @@
1
- # [niconicomments](https://xpadev.net/niconicomments/)
2
- [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/xpadev-net/niconicomments/blob/master/LICENSE)
3
- ニコニコ動画の公式プレイヤーに多少の互換性を持つコメント描画ライブラリです
4
- This is a comment drawing library that is somewhat compatible with the official Nico Nico Douga player.
5
- Reference: https://xpadev.net/niconicomments/docs/
6
- Github: https://github.com/xpadev-net/niconicomments
7
-
8
- ## Installation
9
- ```html
10
- <script src="https://cdn.jsdelivr.net/npm/@xpadev-net/niconicomments@latest/dist/bundle.min.js"></script>
11
- ```
12
- or
13
- ```
14
- npm i @xpadev-net/niconicomments
15
- ```
16
-
17
- ## Examples
18
- ```javascript
19
- const niconiComments = new NiconiComments(canvas, comments);
20
- niconiComments.drawCanvas(vpos)
21
- ```
22
-
23
- ## Sample
24
- https://xpadev.net/niconicomments/sample.html
1
+ # [niconicomments](https://xpadev.net/niconicomments/)
2
+ [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/xpadev-net/niconicomments/blob/master/LICENSE)
3
+ ニコニコ動画の公式プレイヤーに多少の互換性を持つコメント描画ライブラリです
4
+ This is a comment drawing library that is somewhat compatible with the official Nico Nico Douga player.
5
+ Reference: https://xpadev.net/niconicomments/docs/
6
+ Github: https://github.com/xpadev-net/niconicomments
7
+
8
+ ## Installation
9
+ ```html
10
+ <script src="https://cdn.jsdelivr.net/npm/@xpadev-net/niconicomments@latest/dist/bundle.min.js"></script>
11
+ ```
12
+ or
13
+ ```
14
+ npm i @xpadev-net/niconicomments
15
+ ```
16
+
17
+ ## Examples
18
+ ```javascript
19
+ const niconiComments = new NiconiComments(canvas, comments);
20
+ niconiComments.drawCanvas(vpos)
21
+ ```
22
+
23
+ ## Sample
24
+ https://xpadev.net/niconicomments/sample.html
package/dist/bundle.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- niconicomments.js v0.1.4
2
+ niconicomments.js v0.1.8
3
3
  (c) 2021 xpadev-net https://xpadevn.et
4
4
  Released under the MIT License.
5
5
  */
@@ -10,42 +10,56 @@
10
10
  })(this, (function () { 'use strict';
11
11
 
12
12
  class NiconiComments {
13
- /**
14
- * NiconiComments Constructor
15
- * @param {HTMLCanvasElement} canvas - 描画対象のキャンバス
16
- * @param {[]} data - 描画用のコメント
17
- * @param {boolean} useLegacy - defontにsans-serifを適用するか(trueでニコニコ公式に準拠)
18
- * @param {boolean} formatted - dataが独自フォーマットに変換されているか
13
+ /**
14
+ * NiconiComments Constructor
15
+ * @param {HTMLCanvasElement} canvas - 描画対象のキャンバス
16
+ * @param {[]} data - 描画用のコメント
17
+ * @param {{useLegacy: boolean, formatted: boolean, video: HTMLVideoElement|null}} options - 細かい設定類
19
18
  */
20
- constructor(canvas, data, useLegacy = false, formatted = false) {
19
+ constructor(canvas, data, options = {
20
+ useLegacy: false,
21
+ formatted: false,
22
+ video: null
23
+ }) {
21
24
  this.canvas = canvas;
22
25
  this.context = canvas.getContext("2d");
23
26
  this.context.strokeStyle = "rgba(0,0,0,0.7)";
24
27
  this.context.textAlign = "left";
25
28
  this.context.textBaseline = "top";
26
- this.context.lineWidth = "6";
29
+ this.context.lineWidth = 4;
27
30
 
28
- if (useLegacy) {
31
+ if (options.useLegacy) {
29
32
  this.commentYOffset = 0.25;
30
33
  } else {
31
- this.commentYOffset = 0.125;
34
+ this.commentYOffset = 0.2;
32
35
  }
33
36
 
34
- this.commentYMarginTop = 10;
37
+ this.commentYMarginTop = 0.08;
35
38
  this.fontSize = {
36
39
  "small": {
37
- "default": 45,
38
- "resized": 18
40
+ "default": 47,
41
+ "resized": 27.5
39
42
  },
40
43
  "medium": {
41
- "default": 85,
42
- "resized": 35
44
+ "default": 76,
45
+ "resized": 39
43
46
  },
44
47
  "big": {
45
- "default": 120,
46
- "resized": 57.5
48
+ "default": 118,
49
+ "resized": 62.5
47
50
  }
48
51
  };
52
+ this.defaultCommandValue = {
53
+ loc: "naka",
54
+ size: "medium",
55
+ fontSize: this.fontSize.medium.default,
56
+ color: "#ffffff",
57
+ font: 'defont',
58
+ full: false,
59
+ ender: false,
60
+ _live: false,
61
+ invisible: false
62
+ };
49
63
  this.doubleResizeMaxWidth = {
50
64
  full: {
51
65
  legacy: 3020,
@@ -57,24 +71,26 @@
57
71
  }
58
72
  };
59
73
 
60
- if (formatted) {
74
+ if (options.formatted) {
61
75
  this.data = data;
62
76
  } else {
63
77
  this.data = this.parseData(data);
64
78
  }
65
79
 
80
+ this.video = options.video ? options.video : null;
66
81
  this.showCollision = false;
67
82
  this.showFPS = false;
68
83
  this.showCommentCount = false;
69
84
  this.timeline = {};
70
85
  this.nicoScripts = {
71
- "reverse": []
86
+ "reverse": [],
87
+ "default": []
72
88
  };
73
89
  this.collision_right = {};
74
90
  this.collision_left = {};
75
91
  this.collision_ue = {};
76
92
  this.collision_shita = {};
77
- this.useLegacy = useLegacy;
93
+ this.useLegacy = options.useLegacy;
78
94
  this.preRendering();
79
95
  this.fpsCount = 0;
80
96
  this.fps = 0;
@@ -83,10 +99,10 @@
83
99
  this.fpsCount = 0;
84
100
  }, 500);
85
101
  }
86
- /**
87
- * ニコニコが吐き出したデータを処理しやすいように変換する
88
- * @param {[]} data - ニコニコが吐き出したコメントデータ
89
- * @returns {*[]} - 独自フォーマットのコメントデータ
102
+ /**
103
+ * ニコニコが吐き出したデータを処理しやすいように変換する
104
+ * @param {[]} data - ニコニコが吐き出したコメントデータ
105
+ * @returns {*[]} - 独自フォーマットのコメントデータ
90
106
  */
91
107
 
92
108
 
@@ -130,8 +146,8 @@
130
146
  });
131
147
  return data_;
132
148
  }
133
- /**
134
- * 事前に当たり判定を考慮してコメントの描画場所を決定する
149
+ /**
150
+ * 事前に当たり判定を考慮してコメントの描画場所を決定する
135
151
  */
136
152
 
137
153
 
@@ -139,16 +155,17 @@
139
155
  this.getFont();
140
156
  this.getCommentSize();
141
157
  this.getCommentPos();
158
+ this.sortComment();
142
159
  }
143
- /**
144
- * コマンドをもとに各コメントに適用するフォントを決定する
160
+ /**
161
+ * コマンドをもとに各コメントに適用するフォントを決定する
145
162
  */
146
163
 
147
164
 
148
165
  getFont() {
149
166
  for (let i in this.data) {
150
167
  let comment = this.data[i];
151
- let command = this.parseCommand(comment);
168
+ let command = this.parseCommandAndNicoscript(comment);
152
169
  this.data[i].loc = command.loc;
153
170
  this.data[i].size = command.size;
154
171
  this.data[i].fontSize = command.fontSize;
@@ -157,11 +174,13 @@
157
174
  this.data[i].full = command.full;
158
175
  this.data[i].ender = command.ender;
159
176
  this.data[i]._live = command._live;
177
+ this.data[i].long = command.long;
178
+ this.data[i].invisible = command.invisible;
160
179
  this.data[i].content = this.data[i].content.replaceAll("\t", " ");
161
180
  }
162
181
  }
163
- /**
164
- * コメントの描画サイズを計算する
182
+ /**
183
+ * コメントの描画サイズを計算する
165
184
  */
166
185
 
167
186
 
@@ -174,6 +193,11 @@
174
193
 
175
194
  for (let k in tmpData[i][j]) {
176
195
  let comment = tmpData[i][j][k];
196
+
197
+ if (comment.invisible) {
198
+ continue;
199
+ }
200
+
177
201
  let measure = this.measureText(comment);
178
202
  this.data[comment.index].height = measure.height;
179
203
  this.data[comment.index].width = measure.width;
@@ -188,8 +212,8 @@
188
212
  }
189
213
  }
190
214
  }
191
- /**
192
- * 計算された描画サイズをもとに各コメントの配置位置を決定する
215
+ /**
216
+ * 計算された描画サイズをもとに各コメントの配置位置を決定する
193
217
  */
194
218
 
195
219
 
@@ -199,6 +223,10 @@
199
223
  for (let i in data) {
200
224
  let comment = data[i];
201
225
 
226
+ if (comment.invisible) {
227
+ continue;
228
+ }
229
+
202
230
  for (let j = 0; j < 500; j++) {
203
231
  if (!this.timeline[comment.vpos + j]) {
204
232
  this.timeline[comment.vpos + j] = [];
@@ -229,73 +257,77 @@
229
257
  is_change = true,
230
258
  count = 0;
231
259
 
232
- while (is_change && count < 10) {
233
- is_change = false;
234
- count++;
235
-
236
- for (let j = 0; j < 500; j++) {
237
- let vpos = comment.vpos + j;
238
- let left_pos = 1920 - (1920 + comment.width_max) * j / 500;
260
+ if (1080 < comment.height) {
261
+ posY = (comment.height - 1080) / -2;
262
+ } else {
263
+ while (is_change && count < 10) {
264
+ is_change = false;
265
+ count++;
266
+
267
+ for (let j = 0; j < 500; j++) {
268
+ let vpos = comment.vpos + j;
269
+ let left_pos = 1920 - (1920 + comment.width_max) * j / 500;
270
+
271
+ if (left_pos + comment.width_max >= 1880) {
272
+ for (let k in this.collision_right[vpos]) {
273
+ let l = this.collision_right[vpos][k];
274
+
275
+ if (posY < data[l].posY + data[l].height && posY + comment.height > data[l].posY && data[l].owner === comment.owner) {
276
+ if (data[l].posY + data[l].height > posY) {
277
+ posY = data[l].posY + data[l].height;
278
+ is_change = true;
279
+ }
239
280
 
240
- if (left_pos + comment.width_max >= 1880) {
241
- for (let k in this.collision_right[vpos]) {
242
- let l = this.collision_right[vpos][k];
281
+ if (posY + comment.height > 1080) {
282
+ if (1080 < comment.height) {
283
+ posY = (comment.height - 1080) / -2;
284
+ } else {
285
+ posY = Math.floor(Math.random() * (1080 - comment.height));
286
+ }
243
287
 
244
- if (posY < data[l].posY + data[l].height && posY + comment.height > data[l].posY && data[l].owner === comment.owner) {
245
- if (data[l].posY + data[l].height > posY) {
246
- posY = data[l].posY + data[l].height;
247
- is_change = true;
248
- }
249
-
250
- if (posY + comment.height > 1080) {
251
- if (1080 < comment.height) {
252
- posY = (comment.height - 1080) / -2;
253
- } else {
254
- posY = Math.floor(Math.random() * (1080 - comment.height));
288
+ is_break = true;
289
+ break;
255
290
  }
256
-
257
- is_break = true;
258
- break;
259
291
  }
260
292
  }
261
- }
262
293
 
263
- if (is_break) {
264
- break;
294
+ if (is_break) {
295
+ break;
296
+ }
265
297
  }
266
- }
267
298
 
268
- if (left_pos <= 40 && is_break === false) {
269
- for (let k in this.collision_left[vpos]) {
270
- let l = this.collision_left[vpos][k];
299
+ if (left_pos <= 40 && is_break === false) {
300
+ for (let k in this.collision_left[vpos]) {
301
+ let l = this.collision_left[vpos][k];
271
302
 
272
- if (posY < data[l].posY + data[l].height && posY + comment.height > data[l].posY && data[l].owner === comment.owner) {
273
- if (data[l].posY + data[l].height > posY) {
274
- posY = data[l].posY + data[l].height;
275
- is_change = true;
276
- }
277
-
278
- if (posY + comment.height > 1080) {
279
- if (1080 < comment.height) {
280
- posY = 0;
281
- } else {
282
- posY = Math.random() * (1080 - comment.height);
303
+ if (posY < data[l].posY + data[l].height && posY + comment.height > data[l].posY && data[l].owner === comment.owner) {
304
+ if (data[l].posY + data[l].height > posY) {
305
+ posY = data[l].posY + data[l].height;
306
+ is_change = true;
283
307
  }
284
308
 
285
- is_break = true;
286
- break;
309
+ if (posY + comment.height > 1080) {
310
+ if (1080 < comment.height) {
311
+ posY = 0;
312
+ } else {
313
+ posY = Math.random() * (1080 - comment.height);
314
+ }
315
+
316
+ is_break = true;
317
+ break;
318
+ }
287
319
  }
288
320
  }
321
+
322
+ if (is_break) {
323
+ break;
324
+ }
289
325
  }
290
326
 
291
327
  if (is_break) {
292
328
  break;
293
329
  }
294
330
  }
295
-
296
- if (is_break) {
297
- break;
298
- }
299
331
  }
300
332
  }
301
333
 
@@ -362,7 +394,7 @@
362
394
  }
363
395
  }
364
396
 
365
- for (let j = 0; j < 300; j++) {
397
+ for (let j = 0; j < comment.long; j++) {
366
398
  let vpos = comment.vpos + j;
367
399
  arrayPush(this.timeline, vpos, i);
368
400
 
@@ -377,11 +409,28 @@
377
409
  }
378
410
  }
379
411
  }
380
- /**
381
- * context.measureTextの複数行対応版
382
- * 画面外にはみ出すコメントの縮小も行う
383
- * @param comment - 独自フォーマットのコメントデータ
384
- * @returns {{resized: boolean, width: number, width_max: number, fontSize: number, width_min: number, height: number}} - 描画サイズとリサイズの情報
412
+
413
+ sortComment() {
414
+ for (let vpos in this.timeline) {
415
+ this.timeline[vpos].sort((a, b) => {
416
+ const A = this.data[a];
417
+ const B = this.data[b];
418
+
419
+ if (!A.owner && B.owner) {
420
+ return -1;
421
+ } else if (A.owner && !B.owner) {
422
+ return 1;
423
+ } else {
424
+ return 0;
425
+ }
426
+ });
427
+ }
428
+ }
429
+ /**
430
+ * context.measureTextの複数行対応版
431
+ * 画面外にはみ出すコメントの縮小も行う
432
+ * @param comment - 独自フォーマットのコメントデータ
433
+ * @returns {{resized: boolean, width: number, width_max: number, fontSize: number, width_min: number, height: number}} - 描画サイズとリサイズの情報
385
434
  */
386
435
 
387
436
 
@@ -420,7 +469,7 @@
420
469
  width = width_arr.reduce((p, c) => p + c, 0) / width_arr.length;
421
470
  width_max = Math.max(...width_arr);
422
471
  width_min = Math.min(...width_arr);
423
- height = (comment.fontSize + this.commentYMarginTop) * lines.length;
472
+ height = (comment.fontSize + this.commentYMarginTop * comment.fontSize) * lines.length;
424
473
 
425
474
  if (comment.loc !== "naka" && !comment.tateRisized) {
426
475
  if (comment.full && width_max > 1920) {
@@ -463,10 +512,10 @@
463
512
  "fontSize": comment.fontSize
464
513
  };
465
514
  }
466
- /**
467
- * コマンドをもとに所定の位置にコメントを表示する
468
- * @param comment - 独自フォーマットのコメントデータ
469
- * @param {number} vpos - 動画の現在位置の100倍 ニコニコから吐き出されるコメントの位置情報は主にこれ
515
+ /**
516
+ * コマンドをもとに所定の位置にコメントを表示する
517
+ * @param comment - 独自フォーマットのコメントデータ
518
+ * @param {number} vpos - 動画の現在位置の100倍 ニコニコから吐き出されるコメントの位置情報は主にこれ
470
519
  */
471
520
 
472
521
 
@@ -488,32 +537,16 @@
488
537
  let lines = comment.content.split("\n"),
489
538
  posX = (1920 - comment.width_max) / 2;
490
539
 
491
- if (comment.loc === "shita") {
492
- for (let i in lines) {
493
- let line = lines[i];
494
- let posY = 1080 - comment.posY + i * (comment.fontSize + this.commentYMarginTop) - comment.height + this.commentYOffset * comment.fontSize;
495
- this.context.strokeText(line, posX, posY);
496
- this.context.fillText(line, posX, posY);
497
- }
498
- } else {
499
- if (comment.loc === "naka") {
500
- if (reverse) {
501
- posX = (1920 + comment.width_max) * (vpos - comment.vpos) / 500 - comment.width_max;
502
- } else {
503
- posX = 1920 - (1920 + comment.width_max) * (vpos - comment.vpos) / 500;
504
- }
505
- }
506
-
507
- for (let i in lines) {
508
- let line = lines[i];
509
- let posY = comment.posY + i * (comment.fontSize + this.commentYMarginTop) + this.commentYOffset * comment.fontSize;
510
- this.context.strokeText(line, posX, posY);
511
- this.context.fillText(line, posX, posY);
540
+ if (comment.loc === "naka") {
541
+ if (reverse) {
542
+ posX = (1920 + comment.width_max) * (vpos - comment.vpos) / 500 - comment.width_max;
543
+ } else {
544
+ posX = 1920 - (1920 + comment.width_max) * (vpos - comment.vpos) / 500;
512
545
  }
513
546
  }
514
547
 
515
548
  if (this.showCollision) {
516
- this.context.strokeStyle = "rgba(255,255,0,1)";
549
+ this.context.strokeStyle = "rgba(0,255,255,1)";
517
550
 
518
551
  if (comment.loc === "shita") {
519
552
  this.context.strokeRect(posX, 1080 - comment.posY - comment.height, comment.width_max, comment.height);
@@ -521,60 +554,67 @@
521
554
  this.context.strokeRect(posX, comment.posY, comment.width_max, comment.height);
522
555
  }
523
556
 
524
- this.context.strokeStyle = "rgba(0,0,0,0.7)";
557
+ if (comment.color === "#000000") {
558
+ this.context.strokeStyle = "rgba(255,255,255,0.7)";
559
+ } else {
560
+ this.context.strokeStyle = "rgba(0,0,0,0.7)";
561
+ }
525
562
  }
526
- }
527
- /**
528
- * コメントに含まれるコマンドを解釈する
529
- * @param comment- 独自フォーマットのコメントデータ
530
- * @returns {{loc: string, size: string, color: string, fontSize: number, ender: boolean, font: string, full: boolean, _live: boolean}}
531
- */
532
563
 
564
+ for (let i in lines) {
565
+ let line = lines[i],
566
+ posY;
533
567
 
534
- parseCommand(comment) {
535
- let metadata = comment.mail,
536
- loc = "naka",
537
- size = "medium",
538
- fontSize = this.fontSize.medium.default,
539
- color = "#ffffff",
540
- font = 'defont',
541
- full = false,
542
- ender = false,
543
- reverse = comment.content.match(/@逆 ?(全|コメ|投コメ)?/),
544
- _live = false;
545
-
546
- if (reverse) {
547
- if (!reverse[1]) {
548
- reverse[1] = "全";
568
+ if (comment.loc === "shita") {
569
+ posY = 1080 - comment.posY + i * (comment.fontSize + this.commentYMarginTop * comment.fontSize) - comment.height + this.commentYOffset * comment.fontSize;
570
+ } else {
571
+ posY = comment.posY + i * (comment.fontSize + this.commentYMarginTop * comment.fontSize) + this.commentYOffset * comment.fontSize;
549
572
  }
550
573
 
551
- let length = false;
574
+ this.context.strokeText(line, posX, posY);
575
+ this.context.fillText(line, posX, posY);
552
576
 
553
- for (let i in metadata) {
554
- let match = metadata[i].match(/@([0-9]+)/);
577
+ if (this.showCollision) {
578
+ this.context.strokeStyle = "rgba(255,255,0,0.5)";
579
+ this.context.strokeRect(posX, posY, comment.width_max, comment.fontSize);
555
580
 
556
- if (match) {
557
- length = match[1];
558
- break;
581
+ if (comment.color === "#000000") {
582
+ this.context.strokeStyle = "rgba(255,255,255,0.7)";
583
+ } else {
584
+ this.context.strokeStyle = "rgba(0,0,0,0.7)";
559
585
  }
560
586
  }
587
+ }
588
+ }
589
+ /**
590
+ * コメントに含まれるコマンドを解釈する
591
+ * @param comment- 独自フォーマットのコメントデータ
592
+ * @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}}
593
+ */
561
594
 
562
- if (!length) {
563
- length = 30;
564
- }
565
595
 
566
- this.nicoScripts.reverse.push({
567
- "start": comment.vpos,
568
- "end": comment.vpos + length * 100,
569
- "target": reverse[1]
570
- });
571
- fontSize = 0;
572
- }
596
+ parseCommand(comment) {
597
+ let metadata = comment.mail,
598
+ loc = null,
599
+ size = null,
600
+ fontSize = null,
601
+ color = null,
602
+ font = null,
603
+ full = false,
604
+ ender = false,
605
+ _live = false,
606
+ invisible = false,
607
+ long = null;
573
608
 
574
609
  for (let i in metadata) {
575
610
  let command = metadata[i].toLowerCase();
611
+ const match = command.match(/^@([0-9.]+)/);
612
+
613
+ if (match) {
614
+ long = match[1];
615
+ }
576
616
 
577
- if (loc === "naka") {
617
+ if (loc === null) {
578
618
  switch (command) {
579
619
  case "ue":
580
620
  loc = "ue";
@@ -586,7 +626,7 @@
586
626
  }
587
627
  }
588
628
 
589
- if (size === "medium") {
629
+ if (size === null) {
590
630
  switch (command) {
591
631
  case "big":
592
632
  size = "big";
@@ -600,7 +640,7 @@
600
640
  }
601
641
  }
602
642
 
603
- if (color === "#ffffff") {
643
+ if (color === null) {
604
644
  switch (command) {
605
645
  case "white":
606
646
  color = "#FFFFFF";
@@ -700,7 +740,7 @@
700
740
  }
701
741
  }
702
742
 
703
- if (font === 'defont') {
743
+ if (font === null) {
704
744
  switch (command) {
705
745
  case "gothic":
706
746
  font = "gothic";
@@ -723,6 +763,11 @@
723
763
 
724
764
  case "_live":
725
765
  _live = true;
766
+ break;
767
+
768
+ case "invisible":
769
+ invisible = true;
770
+ break;
726
771
  }
727
772
  }
728
773
 
@@ -734,12 +779,109 @@
734
779
  font,
735
780
  full,
736
781
  ender,
737
- _live
782
+ _live,
783
+ invisible,
784
+ long
738
785
  };
739
786
  }
740
- /**
741
- * キャンバスを描画する
742
- * @param vpos - 動画の現在位置の100倍 ニコニコから吐き出されるコメントの位置情報は主にこれ
787
+
788
+ parseCommandAndNicoscript(comment) {
789
+ let data = this.parseCommand(comment),
790
+ nicoscript = comment.content.match(/^@(デフォルト|置換|逆|コメント禁止|シーク禁止|ジャンプ)/);
791
+
792
+ if (nicoscript) {
793
+ switch (nicoscript[1]) {
794
+ case "デフォルト":
795
+ this.nicoScripts.default.push({
796
+ start: comment.vpos,
797
+ long: data.long === null ? null : Math.floor(data.long * 100),
798
+ color: data.color,
799
+ size: data.size,
800
+ font: data.font,
801
+ loc: data.loc
802
+ });
803
+ break;
804
+
805
+ case "逆":
806
+ let reverse = comment.content.match(/^@逆 ?(全|コメ|投コメ)?/);
807
+
808
+ if (!reverse[1]) {
809
+ reverse[1] = "全";
810
+ }
811
+
812
+ if (data.long === null) {
813
+ data.long = 30;
814
+ }
815
+
816
+ this.nicoScripts.reverse.push({
817
+ "start": comment.vpos,
818
+ "end": comment.vpos + data.long * 100,
819
+ "target": reverse[1]
820
+ });
821
+ break;
822
+ }
823
+
824
+ data.invisible = true;
825
+ }
826
+
827
+ let color = "#FFFFFF",
828
+ size = "medium",
829
+ font = "defont",
830
+ loc = "naka";
831
+
832
+ for (let i in this.nicoScripts.default) {
833
+ if (this.nicoScripts.default[i].long !== null && this.nicoScripts.default[i].start + this.nicoScripts.default[i].long < comment.vpos) {
834
+ this.nicoScripts.default = this.nicoScripts.default.splice(Number(i), 1);
835
+ continue;
836
+ }
837
+
838
+ if (this.nicoScripts.default[i].loc) {
839
+ loc = this.nicoScripts.default[i].loc;
840
+ }
841
+
842
+ if (this.nicoScripts.default[i].color) {
843
+ color = this.nicoScripts.default[i].color;
844
+ }
845
+
846
+ if (this.nicoScripts.default[i].size) {
847
+ size = this.nicoScripts.default[i].size;
848
+ }
849
+
850
+ if (this.nicoScripts.default[i].font) {
851
+ font = this.nicoScripts.default[i].font;
852
+ }
853
+ }
854
+
855
+ if (!data.loc) {
856
+ data.loc = loc;
857
+ }
858
+
859
+ if (!data.color) {
860
+ data.color = color;
861
+ }
862
+
863
+ if (!data.size) {
864
+ data.size = size;
865
+ data.fontSize = this.fontSize[data.size].default;
866
+ }
867
+
868
+ if (!data.font) {
869
+ data.font = font;
870
+ }
871
+
872
+ if (data.loc !== "naka") {
873
+ if (!data.long) {
874
+ data.long = 300;
875
+ } else {
876
+ data.long = Math.floor(data.long * 100);
877
+ }
878
+ }
879
+
880
+ return data;
881
+ }
882
+ /**
883
+ * キャンバスを描画する
884
+ * @param vpos - 動画の現在位置の100倍 ニコニコから吐き出されるコメントの位置情報は主にこれ
743
885
  */
744
886
 
745
887
 
@@ -747,25 +889,50 @@
747
889
  this.fpsCount++;
748
890
  this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
749
891
 
750
- for (let index in this.timeline[vpos]) {
751
- let comment = this.data[this.timeline[vpos][index]];
752
- this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
892
+ if (this.video) {
893
+ let offsetX,
894
+ offsetY,
895
+ scale,
896
+ height = this.canvas.height / this.video.videoHeight,
897
+ width = this.canvas.width / this.video.videoWidth;
753
898
 
754
- if (comment._live) {
755
- let rgb = hex2rgb(comment.color);
756
- this.context.fillStyle = `rgba(${rgb[0]},${rgb[1]},${rgb[2]},0.5)`;
899
+ if (height > width) {
900
+ scale = width;
757
901
  } else {
758
- this.context.fillStyle = comment.color;
902
+ scale = height;
759
903
  }
760
904
 
761
- if (comment.color === "#000000") {
762
- this.context.strokeStyle = "rgba(255,255,255,0.7)";
763
- }
905
+ offsetX = (this.canvas.width - this.video.videoWidth * scale) * 0.5;
906
+ offsetY = (this.canvas.height - this.video.videoHeight * scale) * 0.5;
907
+ this.context.drawImage(this.video, offsetX, offsetY, this.video.videoWidth * scale, this.video.videoHeight * scale);
908
+ }
764
909
 
765
- this.drawText(comment, vpos);
910
+ if (this.timeline[vpos]) {
911
+ for (let index in this.timeline[vpos]) {
912
+ let comment = this.data[this.timeline[vpos][index]];
766
913
 
767
- if (comment.color === "#000000") {
768
- this.context.strokeStyle = "rgba(0,0,0,0.7)";
914
+ if (comment.invisible) {
915
+ continue;
916
+ }
917
+
918
+ this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
919
+
920
+ if (comment._live) {
921
+ let rgb = hex2rgb(comment.color);
922
+ this.context.fillStyle = `rgba(${rgb[0]},${rgb[1]},${rgb[2]},0.5)`;
923
+ } else {
924
+ this.context.fillStyle = comment.color;
925
+ }
926
+
927
+ if (comment.color === "#000000") {
928
+ this.context.strokeStyle = "rgba(255,255,255,0.7)";
929
+ }
930
+
931
+ this.drawText(comment, vpos);
932
+
933
+ if (comment.color === "#000000") {
934
+ this.context.strokeStyle = "rgba(0,0,0,0.7)";
935
+ }
769
936
  }
770
937
  }
771
938
 
@@ -783,8 +950,8 @@
783
950
  this.context.fillText("Count:" + this.timeline[vpos].length, 100, 200);
784
951
  }
785
952
  }
786
- /**
787
- * キャンバスを消去する
953
+ /**
954
+ * キャンバスを消去する
788
955
  */
789
956
 
790
957
 
@@ -793,12 +960,12 @@
793
960
  }
794
961
 
795
962
  }
796
- /**
797
- * 配列を複数のキーでグループ化する
798
- * @param {{}} array
799
- * @param {string} key
800
- * @param {string} key2
801
- * @returns {{}}
963
+ /**
964
+ * 配列を複数のキーでグループ化する
965
+ * @param {{}} array
966
+ * @param {string} key
967
+ * @param {string} key2
968
+ * @returns {{}}
802
969
  */
803
970
 
804
971
 
@@ -820,12 +987,12 @@
820
987
 
821
988
  return data;
822
989
  };
823
- /**
824
- * フォント名とサイズをもとにcontextで使えるフォントを生成する
825
- * @param {string} font
826
- * @param {number} size
827
- * @param {boolean} useLegacy
828
- * @returns {string}
990
+ /**
991
+ * フォント名とサイズをもとにcontextで使えるフォントを生成する
992
+ * @param {string} font
993
+ * @param {number} size
994
+ * @param {boolean} useLegacy
995
+ * @returns {string}
829
996
  */
830
997
 
831
998
 
@@ -846,11 +1013,11 @@
846
1013
 
847
1014
  }
848
1015
  };
849
- /**
850
- * phpのarray_push的なあれ
851
- * @param array
852
- * @param {string} key
853
- * @param push
1016
+ /**
1017
+ * phpのarray_push的なあれ
1018
+ * @param array
1019
+ * @param {string} key
1020
+ * @param push
854
1021
  */
855
1022
 
856
1023
 
@@ -865,10 +1032,10 @@
865
1032
 
866
1033
  array[key].push(push);
867
1034
  };
868
- /**
869
- * Hexからrgbに変換する(_live用)
870
- * @param {string} hex
871
- * @return {array} RGB
1035
+ /**
1036
+ * Hexからrgbに変換する(_live用)
1037
+ * @param {string} hex
1038
+ * @return {array} RGB
872
1039
  */
873
1040
 
874
1041
 
package/package.json CHANGED
@@ -1,33 +1,31 @@
1
- {
2
- "name": "@xpadev-net/niconicomments",
3
- "version": "0.1.4",
4
- "description": "NiconiComments is a comment drawing library that is somewhat compatible with the official Nico Nico Douga player.",
5
- "main": "dist/bundle.js",
6
- "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1",
8
- "build": "rollup -c rollup.config.js",
9
- "prepublishOnly": "rollup -c rollup.config.js"
10
- },
11
- "repository": {
12
- "type": "git",
13
- "url": "git+https://github.com/xpadev-net/niconicomments.git"
14
- },
15
- "keywords": [
16
- "niconico"
17
- ],
18
- "author": "xpadev(xpadev.net)",
19
- "bugs": {
20
- "url": "https://github.com/xpadev-net/niconicomments/issues"
21
- },
22
- "files": [
23
- "dist/bundle.js"
24
- ],
25
- "homepage": "https://xpadev.net/niconicomments/docs/",
26
- "license": "MIT",
27
- "devDependencies": {
28
- "rollup": "^2.61.1"
29
- },
30
- "dependencies": {
31
- "@rollup/plugin-babel": "^5.3.0"
32
- }
33
- }
1
+ {
2
+ "name": "@xpadev-net/niconicomments",
3
+ "version": "0.1.8",
4
+ "description": "NiconiComments is a comment drawing library that is somewhat compatible with the official Nico Nico Douga player.",
5
+ "main": "dist/bundle.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1",
8
+ "build": "rollup -c rollup.config.js",
9
+ "prepublishOnly": "rollup -c rollup.config.js"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/xpadev-net/niconicomments.git"
14
+ },
15
+ "keywords": [
16
+ "niconico"
17
+ ],
18
+ "author": "xpadev(xpadev.net)",
19
+ "bugs": {
20
+ "url": "https://github.com/xpadev-net/niconicomments/issues"
21
+ },
22
+ "files": [
23
+ "dist/bundle.js"
24
+ ],
25
+ "homepage": "https://xpadev.net/niconicomments/docs/",
26
+ "license": "MIT",
27
+ "devDependencies": {
28
+ "rollup": "^2.61.1",
29
+ "@rollup/plugin-babel": "^5.3.0"
30
+ }
31
+ }