@dan-uni/dan-any 0.8.7 → 0.9.1

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.
@@ -1,3 +1,4 @@
1
+ import type { Options as UniPoolOptions } from '..';
1
2
  import type { RawConfig } from './ass/raw';
2
3
  import type { CanvasCtx, SubtitleStyle } from './types';
3
4
  import { UniPool } from '..';
@@ -26,4 +27,4 @@ fs.writeFileSync(`${filename}.ass`, assText, 'utf-8')
26
27
  ```
27
28
  */
28
29
  export declare function generateASS(danmaku: UniPool, options: Options, canvasCtx: CanvasCtx): string;
29
- export declare function parseAssRawField(ass: string): UniPool;
30
+ export declare function parseAssRawField(ass: string, options?: UniPoolOptions): UniPool;
@@ -1,4 +1,5 @@
1
+ import type { Options as UniPoolOptions } from '../..';
1
2
  import type { Danmaku } from '../types';
2
3
  import { UniPool } from '../..';
3
4
  export declare function UniPool2DanmakuLists(UP: UniPool): Danmaku[];
4
- export declare function DanmakuList2UniPool(d: Danmaku[]): UniPool;
5
+ export declare function DanmakuList2UniPool(d: Danmaku[], options?: UniPoolOptions): UniPool;
@@ -50,11 +50,11 @@ export interface DM_JSON_DDPlay {
50
50
  m: string;
51
51
  }[];
52
52
  }
53
- export type DM_format = 'danuni.json' | 'danuni.bin' | 'danuni.pb.zst' | 'bili.xml' | 'bili.bin' | 'bili.cmd.bin' | 'dplayer.json' | 'artplayer.json' | 'ddplay.json' | 'common.ass';
53
+ export type DM_format = 'danuni.json' | 'danuni.pb.bin' | 'bili.xml' | 'bili.pb.bin' | 'bili.cmd.pb.bin' | 'dplayer.json' | 'artplayer.json' | 'ddplay.json' | 'common.ass';
54
54
  type shareItems = Partial<Pick<UniDMTools.UniDMObj, 'SOID' | 'senderID' | 'platform' | 'SOID' | 'pool' | 'mode' | 'color'>>;
55
55
  type UniPoolPipe = (that: UniPool) => Promise<UniPool>;
56
56
  type UniPoolPipeSync = (that: UniPool) => UniPool;
57
- interface Options {
57
+ export interface Options {
58
58
  dedupe?: boolean;
59
59
  dmid?: boolean | number | UniIDTools.DMIDGenerator;
60
60
  }
@@ -143,6 +143,10 @@ export declare class UniPool {
143
143
  */
144
144
  merge(lifetime?: number): UniPool;
145
145
  minify(): (Partial<UniDMTools.UniDMObj> & Pick<UniDMTools.UniDMObj, "SOID">)[];
146
+ static import(file: unknown, options?: Options): {
147
+ pool: UniPool;
148
+ fmt: DM_format;
149
+ };
146
150
  convert2(format: DM_format, continue_on_error?: boolean): string | Uint8Array<ArrayBufferLike> | UniDM[] | (DM_JSON_Dplayer & {
147
151
  danuni?: DanUniConvertTip;
148
152
  }) | (DM_JSON_Artplayer & {
@@ -191,7 +195,7 @@ export declare class UniPool {
191
195
  toDDplay(): DM_JSON_DDPlay & {
192
196
  danuni?: DanUniConvertTip;
193
197
  };
194
- static fromASS(ass: string): UniPool;
198
+ static fromASS(ass: string, options?: Options): UniPool;
195
199
  /**
196
200
  * 转换为ASS字幕格式的弹幕,需播放器支持多行ASS渲染
197
201
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dan-uni/dan-any",
3
- "version": "0.8.7",
3
+ "version": "0.9.1",
4
4
  "description": "A danmaku transformer lib, supporting danmaku from different platforms.",
5
5
  "keywords": [
6
6
  "bangumi",
@@ -1,4 +1,5 @@
1
1
  // import parse from './parse/bilibili'
2
+ import type { Options as UniPoolOptions } from '..'
2
3
  import type { RawConfig } from './ass/raw'
3
4
  import type { CanvasCtx, SubtitleStyle } from './types'
4
5
 
@@ -59,8 +60,11 @@ export function generateASS(
59
60
  return content
60
61
  }
61
62
 
62
- export function parseAssRawField(ass: string): UniPool {
63
+ export function parseAssRawField(
64
+ ass: string,
65
+ options?: UniPoolOptions,
66
+ ): UniPool {
63
67
  const raw = deRaw(ass)
64
68
  if (!raw) return UniPool.create()
65
- else return DanmakuList2UniPool(raw.list)
69
+ else return DanmakuList2UniPool(raw.list, options)
66
70
  }
@@ -1,3 +1,4 @@
1
+ import type { Options as UniPoolOptions } from '../..'
1
2
  import type { Danmaku, RGB } from '../types'
2
3
 
3
4
  import { UniPool } from '../..'
@@ -31,6 +32,12 @@ export function UniPool2DanmakuLists(UP: UniPool): Danmaku[] {
31
32
  } satisfies Danmaku
32
33
  })
33
34
  }
34
- export function DanmakuList2UniPool(d: Danmaku[]): UniPool {
35
- return new UniPool(d.map((d) => UniDM.create(d.extra)))
35
+ export function DanmakuList2UniPool(
36
+ d: Danmaku[],
37
+ options?: UniPoolOptions,
38
+ ): UniPool {
39
+ return new UniPool(
40
+ d.map((d) => UniDM.create(d.extra)),
41
+ options,
42
+ )
36
43
  }
package/src/index.test.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  //基于以下注释,根据vitest生成测试用例
2
2
  import { createCanvas } from 'canvas'
3
- import { describe, it } from 'vitest'
3
+ import { describe, expect, it } from 'vitest'
4
4
 
5
5
  import { UniPool } from './index'
6
6
 
@@ -35,6 +35,9 @@ describe('转化自', () => {
35
35
  console.info(pool)
36
36
  console.info(pool.toBiliXML())
37
37
  console.info(pool.toBiliXML({ avoidSenderIDWithAt: true }))
38
+ const imp = UniPool.import(xml)
39
+ expect(imp.fmt).toBe('bili.xml')
40
+ expect(imp.pool).toEqual(pool)
38
41
  })
39
42
  it('artplayer(json)', () => {
40
43
  const json = {
@@ -52,6 +55,9 @@ describe('转化自', () => {
52
55
  pool = UniPool.fromArtplayer(json, 'playerid-test', 'acfun')
53
56
  console.info(json)
54
57
  console.info(pool)
58
+ const imp = UniPool.import(json)
59
+ expect(imp.fmt).toBe('artplayer.json')
60
+ // expect(imp.pool).toEqual(pool)
55
61
  })
56
62
  it('ass[双向]', () => {
57
63
  const canvas = createCanvas(50, 50)
@@ -59,16 +65,25 @@ describe('转化自', () => {
59
65
  const ass = pool.toASS(canvas.getContext('2d'))
60
66
  console.info(ass)
61
67
  console.info(UniPool.fromASS(ass))
68
+ const imp = UniPool.import(ass)
69
+ expect(imp.fmt).toBe('common.ass')
70
+ expect(imp.pool).toEqual(pool)
62
71
  })
63
72
  it('pb[双向]', () => {
64
73
  const pool = UniPool.fromBiliXML(xml)
65
74
  const pb = pool.toPb()
66
75
  console.info(UniPool.fromPb(pb))
76
+ const imp = UniPool.import(pb)
77
+ expect(imp.fmt).toBe('danuni.pb.bin')
78
+ expect(imp.pool).toEqual(pool)
67
79
  })
68
80
  it('DDplay[双向]', () => {
69
81
  const pool = UniPool.fromBiliXML(xml)
70
82
  const ddplay = pool.toDDplay()
71
83
  console.info(UniPool.fromDDPlay(ddplay, '1'))
84
+ const imp = UniPool.import(ddplay)
85
+ expect(imp.fmt).toBe('ddplay.json')
86
+ // expect(imp.pool).toEqual(pool)
72
87
  })
73
88
  })
74
89
 
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import 'reflect-metadata/lite'
2
2
 
3
+ import { isJSON, isObject, isString } from 'class-validator'
3
4
  import { XMLBuilder, XMLParser } from 'fast-xml-parser'
4
5
  import JSONbig from 'json-bigint'
5
6
  import type { Options as AssGenOptions, CanvasCtx } from './ass-gen'
@@ -86,11 +87,10 @@ export interface DM_JSON_DDPlay {
86
87
 
87
88
  export type DM_format =
88
89
  | 'danuni.json'
89
- | 'danuni.bin'
90
- | 'danuni.pb.zst'
90
+ | 'danuni.pb.bin'
91
91
  | 'bili.xml'
92
- | 'bili.bin'
93
- | 'bili.cmd.bin'
92
+ | 'bili.pb.bin'
93
+ | 'bili.cmd.pb.bin'
94
94
  | 'dplayer.json'
95
95
  | 'artplayer.json'
96
96
  | 'ddplay.json'
@@ -106,7 +106,7 @@ type shareItems = Partial<
106
106
  type UniPoolPipe = (that: UniPool) => Promise<UniPool>
107
107
  type UniPoolPipeSync = (that: UniPool) => UniPool
108
108
 
109
- interface Options {
109
+ export interface Options {
110
110
  dedupe?: boolean
111
111
  dmid?: boolean | number | UniIDTools.DMIDGenerator
112
112
  }
@@ -396,11 +396,112 @@ export class UniPool {
396
396
  minify() {
397
397
  return this.dans.map((d) => d.minify())
398
398
  }
399
+ static import(
400
+ file: unknown,
401
+ options?: Options,
402
+ ): { pool: UniPool; fmt: DM_format } {
403
+ const err = '无法识别该文件,请手动指定格式!'
404
+ const parseJSON = (
405
+ json: DM_JSON_Artplayer &
406
+ DM_JSON_DDPlay &
407
+ DM_JSON_Dplayer & { danuni?: DanUniConvertTip },
408
+ ): { pool: UniPool; fmt: DM_format } | undefined => {
409
+ try {
410
+ if (Array.isArray(json) && json.every((d) => d.SOID)) {
411
+ return { pool: new UniPool(json, options), fmt: 'danuni.json' }
412
+ } else if (json.danmuku && json.danmuku.every((d) => d.text)) {
413
+ return {
414
+ pool: this.fromArtplayer(
415
+ json,
416
+ json.danuni?.data ?? '',
417
+ undefined,
418
+ options,
419
+ ),
420
+ fmt: 'artplayer.json',
421
+ }
422
+ } else if (
423
+ json.count &&
424
+ json.comments &&
425
+ json.comments.every((d) => d.m)
426
+ ) {
427
+ return {
428
+ pool: this.fromDDPlay(json, json.danuni?.data ?? '', options),
429
+ fmt: 'ddplay.json',
430
+ }
431
+ } else if (
432
+ json?.code == 0 &&
433
+ json.data &&
434
+ json.data.every((d) => Array.isArray(d))
435
+ ) {
436
+ return {
437
+ pool: this.fromDplayer(
438
+ json,
439
+ json.danuni?.data ?? '',
440
+ undefined,
441
+ options,
442
+ ),
443
+ fmt: 'dplayer.json',
444
+ }
445
+ }
446
+ } catch {}
447
+ }
448
+ const parseStr = (
449
+ file: string,
450
+ ): { pool: UniPool; fmt: DM_format } | undefined => {
451
+ try {
452
+ if (isJSON(file)) {
453
+ const json = JSON.parse(file)
454
+ return parseJSON(json)
455
+ }
456
+ } catch {}
457
+ try {
458
+ const xmlParser = new XMLParser({ ignoreAttributes: false })
459
+ const xml = xmlParser.parse(file)
460
+ if (xml?.i?.d)
461
+ return { pool: this.fromBiliXML(file, options), fmt: 'bili.xml' }
462
+ } catch {}
463
+ try {
464
+ return { pool: this.fromASS(file, options), fmt: 'common.ass' }
465
+ } catch {}
466
+ }
467
+ let errmesg
468
+ if (isObject(file)) {
469
+ if (file instanceof ArrayBuffer || file instanceof Uint8Array) {
470
+ try {
471
+ return { pool: this.fromPb(file), fmt: 'danuni.pb.bin' }
472
+ } catch {}
473
+ try {
474
+ return { pool: this.fromBiliGrpc(file), fmt: 'bili.pb.bin' }
475
+ } catch {}
476
+ try {
477
+ return {
478
+ pool: this.fromBiliCommandGrpc(file),
479
+ fmt: 'bili.cmd.pb.bin',
480
+ }
481
+ } catch {}
482
+ try {
483
+ const fileStr = new TextDecoder().decode(file)
484
+ const prStr = parseStr(fileStr)
485
+ if (!prStr) errmesg = `${err}(定位: bin->string)`
486
+ else return prStr
487
+ } catch {}
488
+ } else {
489
+ const prJSON = parseJSON(file as any)
490
+ if (!prJSON) throw new Error(`${err}(定位: json)`)
491
+ return prJSON
492
+ }
493
+ } else if (isString(file)) {
494
+ const prStr = parseStr(file)
495
+ if (!prStr) throw new Error(`${err}(定位: string)`)
496
+ return prStr
497
+ }
498
+ throw new Error(errmesg ?? err)
499
+ }
399
500
  convert2(format: DM_format, continue_on_error = false) {
400
501
  switch (format) {
401
502
  case 'danuni.json':
402
503
  return this.dans
403
- case 'danuni.bin':
504
+ case 'danuni.pb.bin':
404
505
  return this.toPb()
405
506
  case 'bili.xml':
406
507
  return this.toBiliXML()
@@ -435,6 +536,8 @@ export class UniPool {
435
536
  ctime: timestampDate(d.ctime || timestampNow()),
436
537
  pool: d.pool as number,
437
538
  attr: d.attr as UniDMTools.DMAttr[],
539
+ extra: undefined,
540
+ extraStr: d.extra,
438
541
  },
439
542
  options,
440
543
  ),
@@ -588,9 +691,6 @@ export class UniPool {
588
691
  ) {
589
692
  return new UniPool(
590
693
  json.data.map((d) => {
591
- // let TYPE = 0
592
- // if (d[1] === 1) TYPE = 5
593
- // else if (d[1] === 2) TYPE = 4
594
694
  return UniDM.fromDplayer(
595
695
  {
596
696
  content: d[4],
@@ -611,7 +711,10 @@ export class UniPool {
611
711
  toDplayer(): DM_JSON_Dplayer & { danuni?: DanUniConvertTip } {
612
712
  return {
613
713
  code: 0,
614
- danuni: DanUniConvertTipTemplate,
714
+ danuni: {
715
+ ...DanUniConvertTipTemplate,
716
+ data: this.dans[0].SOID.split('@')[0],
717
+ },
615
718
  data: this.dans.map((dan) => {
616
719
  const d = dan.toDplayer()
617
720
  return [d.progress, d.mode, d.color, d.midHash, d.content]
@@ -626,9 +729,6 @@ export class UniPool {
626
729
  ) {
627
730
  return new UniPool(
628
731
  json.danmuku.map((d) => {
629
- // let TYPE = 0
630
- // if (d.mode === 1) TYPE = 5
631
- // else if (d.mode === 2) TYPE = 4
632
732
  return UniDM.fromArtplayer(
633
733
  {
634
734
  content: d.text,
@@ -648,7 +748,10 @@ export class UniPool {
648
748
  }
649
749
  toArtplayer(): DM_JSON_Artplayer & { danuni?: DanUniConvertTip } {
650
750
  return {
651
- danuni: DanUniConvertTipTemplate,
751
+ danuni: {
752
+ ...DanUniConvertTipTemplate,
753
+ data: this.dans[0].SOID.split('@')[0],
754
+ },
652
755
  danmuku: this.dans.map((dan) => {
653
756
  const d = dan.toArtplayer()
654
757
  return {
@@ -689,8 +792,12 @@ export class UniPool {
689
792
  )
690
793
  }
691
794
  toDDplay(): DM_JSON_DDPlay & { danuni?: DanUniConvertTip } {
795
+ const episodeId = this.dans[0].SOID.split('@')[0].replaceAll(
796
+ `def_${platform.PlatformDanmakuOnlySource.DanDanPlay}+`,
797
+ '',
798
+ )
692
799
  return {
693
- danuni: DanUniConvertTipTemplate,
800
+ danuni: { ...DanUniConvertTipTemplate, data: episodeId },
694
801
  count: this.dans.length,
695
802
  comments: this.dans.map((dan) => {
696
803
  const d = dan.toDDplay()
@@ -702,8 +809,8 @@ export class UniPool {
702
809
  }),
703
810
  }
704
811
  }
705
- static fromASS(ass: string) {
706
- return parseAssRawField(ass)
812
+ static fromASS(ass: string, options?: Options) {
813
+ return parseAssRawField(ass, options)
707
814
  }
708
815
  /**
709
816
  * 转换为ASS字幕格式的弹幕,需播放器支持多行ASS渲染
@@ -471,6 +471,7 @@ export class UniDM {
471
471
  this.options.dmid = createDMID
472
472
 
473
473
  this.content = String(this.content)
474
+ this.ctime = UniDM.transCtime(this.ctime)
474
475
 
475
476
  if (!this.SOID) this.SOID = def.SOID
476
477
  if (!this.progress) this.progress = def.progress