@dan-uni/dan-any 0.9.3 → 0.9.5

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,5 +1,4 @@
1
1
  import type { UniPool } from '../..';
2
2
  import type { Context, SubtitleStyle } from '../types';
3
3
  import type { RawConfig } from './raw';
4
- declare const _default: (list: UniPool, rawList: UniPool, config: SubtitleStyle, context?: Context, rawConfig?: RawConfig) => string;
5
- export default _default;
4
+ export declare const ass: (list: UniPool, rawList: UniPool, config: SubtitleStyle, context?: Context, rawConfig?: RawConfig) => string;
@@ -1,6 +1,6 @@
1
1
  import type { RGB } from '../types';
2
2
  import { DanmakuType } from '../types';
3
- declare const _default: (danmaku: {
3
+ export declare const dialogue: (danmaku: {
4
4
  type: (typeof DanmakuType)[keyof typeof DanmakuType];
5
5
  color: RGB;
6
6
  fontSizeType: number;
@@ -14,4 +14,3 @@ declare const _default: (danmaku: {
14
14
  scrollTime: number;
15
15
  fixTime: number;
16
16
  }) => string;
17
- export default _default;
@@ -1,3 +1,2 @@
1
1
  import type { Danmaku, SubtitleStyle } from '../types';
2
- declare const _default: (list: Danmaku[], config: SubtitleStyle) => string;
3
- export default _default;
2
+ export declare const event: (list: Danmaku[], config: SubtitleStyle) => string;
@@ -4,5 +4,5 @@ type Resolution = {
4
4
  playResX: number;
5
5
  playResY: number;
6
6
  };
7
- declare const _default: ({ playResX, playResY }: Resolution, { filename, title }: ExtraInfo) => string;
8
- export default _default;
7
+ export declare const info: ({ playResX, playResY }: Resolution, { filename, title }: ExtraInfo) => string;
8
+ export {};
@@ -1,3 +1,2 @@
1
1
  import type { SubtitleStyle } from '../types';
2
- declare const _default: ({ fontName, fontSize, color: configColor, outlineColor, backColor, bold, outline, shadow, opacity, }: SubtitleStyle) => string;
3
- export default _default;
2
+ export declare const style: ({ fontName, fontSize, color: configColor, outlineColor, backColor, bold, outline, shadow, opacity, }: SubtitleStyle) => string;
@@ -1,3 +1,2 @@
1
1
  import type { SubtitleStyle } from './types';
2
- declare const _default: (overrides?: {}) => SubtitleStyle;
3
- export default _default;
2
+ export declare const getConfig: (overrides?: {}) => SubtitleStyle;
@@ -113,7 +113,11 @@ export declare class UniPool {
113
113
  */
114
114
  merge(lifetime?: number): UniPool;
115
115
  minify(): (Partial<UniDMTools.UniDMObj> & Pick<UniDMTools.UniDMObj, "SOID">)[];
116
- static import(file: unknown, options?: Options): {
116
+ static import(file: unknown, options?: Options,
117
+ /**
118
+ * 加载指定解析模块,为空则全选
119
+ */
120
+ mod?: ('json' | 'str' | 'bin')[]): {
117
121
  pool: UniPool;
118
122
  fmt: DM_format;
119
123
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dan-uni/dan-any",
3
- "version": "0.9.3",
3
+ "version": "0.9.5",
4
4
  "description": "A danmaku transformer lib, supporting danmaku from different platforms.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -32,20 +32,20 @@
32
32
  "buf": "buf generate"
33
33
  },
34
34
  "dependencies": {
35
- "@bufbuild/protobuf": "^2.7.0",
35
+ "@bufbuild/protobuf": "^2.9.0",
36
36
  "base16384": "^1.0.0",
37
37
  "class-transformer": "^0.5.1",
38
38
  "class-validator": "^0.14.2",
39
- "fast-xml-parser": "^5.2.5",
40
- "fs-extra": "^11.3.1",
39
+ "fast-xml-parser": "^5.3.0",
40
+ "fs-extra": "^11.3.2",
41
41
  "hh-mm-ss": "^1.2.0",
42
42
  "json-bigint": "^1.0.0",
43
43
  "jssha": "^3.3.1",
44
44
  "reflect-metadata": "^0.2.2"
45
45
  },
46
46
  "devDependencies": {
47
- "@bufbuild/buf": "^1.56.0",
48
- "@bufbuild/protoc-gen-es": "^2.7.0",
47
+ "@bufbuild/buf": "^1.57.2",
48
+ "@bufbuild/protoc-gen-es": "^2.9.0",
49
49
  "@types/fs-extra": "^11.0.4",
50
50
  "@types/hh-mm-ss": "^1.2.3",
51
51
  "@types/json-bigint": "^1.0.4",
@@ -12,7 +12,7 @@ const __dirname = dirname(fileURLToPath(import.meta.url))
12
12
  it('generate ass from xml', () => {
13
13
  const filename = '898651903.xml'
14
14
  const xmlPath = path.join(__dirname, filename)
15
- const xmlText = fs.readFileSync(xmlPath, 'utf-8')
15
+ const xmlText = fs.readFileSync(xmlPath, 'utf8')
16
16
  const canvas = createCanvas(50, 50)
17
17
  const assText = generateASS(
18
18
  UniPool.fromBiliXML(xmlText),
@@ -22,5 +22,5 @@ it('generate ass from xml', () => {
22
22
  },
23
23
  canvas.getContext('2d') as unknown as CanvasRenderingContext2D,
24
24
  )
25
- fs.writeFileSync(path.join(__dirname, `${filename}.ass`), assText, 'utf-8')
25
+ fs.writeFileSync(path.join(__dirname, `${filename}.ass`), assText, 'utf8')
26
26
  })
@@ -3,17 +3,18 @@ import type { Context, SubtitleStyle } from '../types'
3
3
  import type { RawConfig } from './raw'
4
4
 
5
5
  import { UniPool2DanmakuLists } from '../util'
6
- import event from './event'
7
- import info from './info'
6
+ import { event } from './event'
7
+ import { info } from './info'
8
8
  import { raw } from './raw'
9
- import style from './style'
9
+ import { style } from './style'
10
10
 
11
- // eslint-disable-next-line import/no-default-export
12
- export default (
11
+ const default_context = { filename: 'unknown', title: 'unknown' }
12
+
13
+ export const ass = (
13
14
  list: UniPool,
14
15
  rawList: UniPool,
15
16
  config: SubtitleStyle,
16
- context: Context = { filename: 'unknown', title: 'unknown' },
17
+ context: Context = default_context,
17
18
  rawConfig?: RawConfig,
18
19
  ) => {
19
20
  const Elist = UniPool2DanmakuLists(list)
@@ -40,8 +40,7 @@ const fixCommand = ({ top, left }: { top: number; left: number }) =>
40
40
  const colorCommand = (color: RGB) => `\\c${formatColor(color)}`
41
41
  const borderColorCommand = (color: RGB) => `\\3c${formatColor(color)}`
42
42
 
43
- // eslint-disable-next-line import/no-default-export
44
- export default (
43
+ export const dialogue = (
45
44
  danmaku: {
46
45
  type: (typeof DanmakuType)[keyof typeof DanmakuType]
47
46
  color: RGB
@@ -1,7 +1,7 @@
1
1
  import type { Danmaku, SubtitleStyle } from '../types'
2
2
 
3
3
  import { DanmakuType } from '../types'
4
- import dialogue from './dialogue'
4
+ import { dialogue } from './dialogue'
5
5
 
6
6
  const calculateDanmakuPosition = (danmaku: Danmaku, config: SubtitleStyle) => {
7
7
  const { playResX, playResY, scrollTime, fixTime } = config
@@ -43,8 +43,7 @@ const calculateDanmakuPosition = (danmaku: Danmaku, config: SubtitleStyle) => {
43
43
  }
44
44
  }
45
45
 
46
- // eslint-disable-next-line import/no-default-export
47
- export default (list: Danmaku[], config: SubtitleStyle) => {
46
+ export const event = (list: Danmaku[], config: SubtitleStyle) => {
48
47
  const content = [
49
48
  '[Events]',
50
49
  'Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text',
@@ -9,8 +9,7 @@ type Resolution = {
9
9
  playResY: number
10
10
  }
11
11
 
12
- // eslint-disable-next-line import/no-default-export
13
- export default (
12
+ export const info = (
14
13
  { playResX, playResY }: Resolution,
15
14
  { filename, title }: ExtraInfo,
16
15
  ) => {
@@ -9,8 +9,8 @@ import type { Context, Danmaku, SubtitleStyle } from '../types'
9
9
 
10
10
  type compressType = 'brotli' | 'gzip'
11
11
  type baseType = 'base64' | 'base18384'
12
- const compressTypes = ['brotli', 'gzip']
13
- const baseTypes = ['base64', 'base18384']
12
+ const compressTypes = new Set(['brotli', 'gzip'])
13
+ const baseTypes = new Set(['base64', 'base18384'])
14
14
 
15
15
  export interface RawConfig {
16
16
  compressType: compressType
@@ -20,7 +20,7 @@ export interface RawConfig {
20
20
  function fromUint16Array(array: Uint16Array): string {
21
21
  let result = ''
22
22
  for (const element of array) {
23
- result += String.fromCharCode(element)
23
+ result += String.fromCodePoint(element)
24
24
  }
25
25
  return result
26
26
  }
@@ -57,20 +57,20 @@ export function deRaw(ass: string):
57
57
  else {
58
58
  let compressType = lineCompressType.replace(';RawCompressType: ', '').trim()
59
59
  let baseType = lineBaseType.replace(';RawBaseType: ', '').trim()
60
- if (!compressTypes.includes(compressType)) compressType = 'gzip'
61
- if (!baseTypes.includes(baseType)) baseType = 'base64'
60
+ if (!compressTypes.has(compressType)) compressType = 'gzip'
61
+ if (!baseTypes.has(baseType)) baseType = 'base64'
62
62
  const text = lineRaw.replace(';Raw: ', '').trim()
63
63
  const buffer =
64
64
  baseType === 'base64'
65
65
  ? Buffer.from(text, 'base64')
66
66
  : Buffer.from(
67
- base16384.decode(Buffer.from(text, 'utf-8').toString('utf-8')),
67
+ base16384.decode(Buffer.from(text, 'utf8').toString('utf8')),
68
68
  )
69
69
  let decompress: Buffer
70
70
  if (compressType === 'brotli') decompress = brotliDecompressSync(buffer)
71
71
  else decompress = gunzipSync(buffer)
72
72
  try {
73
- return JSON.parse(decompress.toString('utf-8'))
73
+ return JSON.parse(decompress.toString('utf8'))
74
74
  } catch {
75
75
  return undefined
76
76
  }
@@ -2,8 +2,7 @@ import type { SubtitleStyle } from '../types'
2
2
 
3
3
  import { formatColor, getDecoratingColor, hexColorToRGB } from '../util'
4
4
 
5
- // eslint-disable-next-line import/no-default-export
6
- export default ({
5
+ export const style = ({
7
6
  fontName,
8
7
  fontSize,
9
8
  color: configColor,
@@ -11,7 +11,7 @@ import { assign, formatColor, hexColorToRGB } from './util'
11
11
  // const convertBlockRule = (rule: string) =>
12
12
  // builtinRules[rule] ? rule : new RegExp(rule)
13
13
 
14
- export default (overrides = {}): SubtitleStyle => {
14
+ export const getConfig = (overrides = {}): SubtitleStyle => {
15
15
  const defaults = {
16
16
  fontSize: [25, 25, 36],
17
17
  fontName: 'SimHei',
@@ -4,9 +4,9 @@ import type { RawConfig } from './ass/raw'
4
4
  import type { CanvasCtx, SubtitleStyle } from './types'
5
5
 
6
6
  import { UniPool } from '..'
7
- import ass from './ass/create'
7
+ import { ass } from './ass/create'
8
8
  import { deRaw } from './ass/raw'
9
- import getConfig from './config'
9
+ import { getConfig } from './config'
10
10
  import { DanmakuList2UniPool, layoutDanmaku } from './util'
11
11
 
12
12
  export { CanvasCtx }
@@ -65,6 +65,9 @@ export function parseAssRawField(
65
65
  options?: UniPoolOptions,
66
66
  ): UniPool {
67
67
  const raw = deRaw(ass)
68
- if (!raw) return UniPool.create()
69
- else return DanmakuList2UniPool(raw.list, options)
68
+ if (raw) {
69
+ return DanmakuList2UniPool(raw.list, options)
70
+ } else {
71
+ return UniPool.create()
72
+ }
70
73
  }
@@ -233,7 +233,7 @@ export const layoutDanmaku = (
233
233
  config: SubtitleStyle,
234
234
  canvasCtx: CanvasCtx,
235
235
  ): UniPool => {
236
- const list = [...UniPool2DanmakuLists(inputList)].sort(
236
+ const list = [...UniPool2DanmakuLists(inputList)].toSorted(
237
237
  (x, y) => x.time - y.time,
238
238
  )
239
239
  const layout = initializeLayout(config, canvasCtx)
package/src/index.ts CHANGED
@@ -172,17 +172,17 @@ export class UniPool {
172
172
  const default_stat: Stat[] = []
173
173
  const stats = this.dans.reduce((stat, dan) => {
174
174
  const valWithCount = stat.find((i) => i.val === dan[key])
175
- if (!valWithCount) {
176
- stat.push({ val: dan[key], count: 1 })
177
- } else {
175
+ if (valWithCount) {
178
176
  valWithCount.count++
177
+ } else {
178
+ stat.push({ val: dan[key], count: 1 })
179
179
  }
180
180
  return stat
181
181
  }, default_stat)
182
182
  return stats
183
183
  }
184
184
  getMost(key: keyof statItems) {
185
- return this.getStat(key).sort((a, b) => b.count - a.count)[0]
185
+ return this.getStat(key).toSorted((a, b) => b.count - a.count)[0]
186
186
  }
187
187
  get most() {
188
188
  return {
@@ -351,7 +351,12 @@ export class UniPool {
351
351
  static import(
352
352
  file: unknown,
353
353
  options?: Options,
354
+ /**
355
+ * 加载指定解析模块,为空则全选
356
+ */
357
+ mod?: ('json' | 'str' | 'bin')[],
354
358
  ): { pool: UniPool; fmt: DM_format } {
359
+ if (!mod) mod = ['json', 'str', 'bin']
355
360
  const err = '无法识别该文件,请手动指定格式!'
356
361
  const parseJSON = (
357
362
  json: DM_JSON_Artplayer &
@@ -400,49 +405,64 @@ export class UniPool {
400
405
  const parseStr = (
401
406
  file: string,
402
407
  ): { pool: UniPool; fmt: DM_format } | undefined => {
403
- try {
404
- if (isJSON(file)) {
405
- const json = JSON.parse(file)
406
- return parseJSON(json)
407
- }
408
- } catch {}
409
- try {
410
- const xmlParser = new XMLParser({ ignoreAttributes: false })
411
- const xml = xmlParser.parse(file)
412
- if (xml?.i?.d)
413
- return { pool: this.fromBiliXML(file, options), fmt: 'bili.xml' }
414
- } catch {}
415
- try {
416
- return { pool: this.fromASS(file, options), fmt: 'common.ass' }
417
- } catch {}
418
- }
419
- let errmesg
420
- if (isObject(file)) {
421
- if (file instanceof ArrayBuffer || file instanceof Uint8Array) {
408
+ // json-str
409
+ if (mod.includes('json'))
422
410
  try {
423
- return { pool: this.fromPb(file), fmt: 'danuni.pb.bin' }
411
+ if (isJSON(file)) {
412
+ const json = JSON.parse(file)
413
+ return parseJSON(json)
414
+ }
424
415
  } catch {}
416
+ // pure-str (xml/ass)
417
+ if (mod.includes('str')) {
425
418
  try {
426
- return { pool: this.fromBiliGrpc(file), fmt: 'bili.pb.bin' }
419
+ const xmlParser = new XMLParser({ ignoreAttributes: false })
420
+ const xml = xmlParser.parse(file)
421
+ if (xml?.i?.d)
422
+ return { pool: this.fromBiliXML(file, options), fmt: 'bili.xml' }
427
423
  } catch {}
428
424
  try {
429
- return {
430
- pool: this.fromBiliCommandGrpc(file),
431
- fmt: 'bili.cmd.pb.bin',
432
- }
425
+ return { pool: this.fromASS(file, options), fmt: 'common.ass' }
433
426
  } catch {}
427
+ }
428
+ }
429
+ let errmesg
430
+ if (isObject(file)) {
431
+ if (file instanceof ArrayBuffer || file instanceof Uint8Array) {
432
+ // pure-bin (pb)
433
+ if (mod.includes('bin')) {
434
+ try {
435
+ return { pool: this.fromPb(file), fmt: 'danuni.pb.bin' }
436
+ } catch {}
437
+ try {
438
+ return { pool: this.fromBiliGrpc(file), fmt: 'bili.pb.bin' }
439
+ } catch {}
440
+ try {
441
+ return {
442
+ pool: this.fromBiliCommandGrpc(file),
443
+ fmt: 'bili.cmd.pb.bin',
444
+ }
445
+ } catch {}
446
+ }
447
+ // str-bin (pure-str + json-str)
448
+
434
449
  try {
435
450
  const fileStr = new TextDecoder().decode(file)
436
451
  const prStr = parseStr(fileStr)
437
- if (!prStr) errmesg = `${err}(定位: bin->string)`
438
- else return prStr
452
+ if (prStr) {
453
+ return prStr
454
+ } else {
455
+ errmesg = `${err}(定位: bin->string)`
456
+ }
439
457
  } catch {}
440
- } else {
458
+ } else if (mod.includes('json')) {
459
+ // pure-json
441
460
  const prJSON = parseJSON(file as any)
442
461
  if (!prJSON) throw new Error(`${err}(定位: json)`)
443
462
  return prJSON
444
463
  }
445
464
  } else if (isString(file)) {
465
+ // pure-str + json-str
446
466
  const prStr = parseStr(file)
447
467
  if (!prStr) throw new Error(`${err}(定位: string)`)
448
468
  return prStr
@@ -594,6 +614,7 @@ export class UniPool {
594
614
  return builder.build({
595
615
  '?xml': {
596
616
  '@_version': '1.0',
617
+ // eslint-disable-next-line unicorn/text-encoding-identifier-case
597
618
  '@_encoding': 'UTF-8',
598
619
  },
599
620
  danuni: { ...DanUniConvertTipTemplate, data: this.shared.SOID },
@@ -768,12 +789,15 @@ export class UniPool {
768
789
  /**
769
790
  * 转换为ASS字幕格式的弹幕,需播放器支持多行ASS渲染
770
791
  */
771
- toASS(
772
- canvasCtx: CanvasCtx,
773
- options: AssGenOptions = { substyle: {} },
774
- ): string {
792
+ toASS(canvasCtx: CanvasCtx, options?: AssGenOptions): string {
793
+ const defaultOptions: AssGenOptions = { substyle: {} }
794
+ const finalOptions = options ?? defaultOptions
775
795
  const fn = this.shared.SOID
776
- return generateASS(this, { filename: fn, title: fn, ...options }, canvasCtx)
796
+ return generateASS(
797
+ this,
798
+ { filename: fn, title: fn, ...finalOptions },
799
+ canvasCtx,
800
+ )
777
801
  }
778
802
  }
779
803
 
@@ -1,4 +1,4 @@
1
- // @generated by protoc-gen-es v2.7.0 with parameter "target=ts"
1
+ // @generated by protoc-gen-es v2.9.0 with parameter "target=ts"
2
2
  // @generated from file bili/dm.proto (package bilibili.community.service.dm.v1, syntax proto3)
3
3
  /* eslint-disable */
4
4
 
@@ -1,4 +1,4 @@
1
- // @generated by protoc-gen-es v2.7.0 with parameter "target=ts"
1
+ // @generated by protoc-gen-es v2.9.0 with parameter "target=ts"
2
2
  // @generated from file danuni.proto (package danuni.danmaku.v1, syntax proto3)
3
3
  /* eslint-disable */
4
4
 
@@ -585,35 +585,36 @@ export class UniDM {
585
585
  type UObj = Partial<UniDMObj> & Pick<UniDMObj, 'SOID'>
586
586
  const def: UObj = UniDM.create()
587
587
  const dan: UObj = UniDM.create(this)
588
- // const prototypes = Object.getOwnPropertyNames(this)
589
- for (const key in dan) {
590
- const k = key as keyof UObj
591
- const v = dan[k]
592
- // if (key in prototypes) continue
593
- if (key === 'SOID') continue
594
- else if (!v) delete dan[k]
595
- else if (v === def[k]) delete dan[k]
596
- else {
597
- if (k === 'attr' && Array.isArray(v) && v.length === 0) delete dan[k]
598
- if (k === 'extraStr' && v === '{}') delete dan[k]
588
+ const shouldKeep = (key: keyof UObj, value: UObj[keyof UObj]) => {
589
+ if (key === 'SOID') return true
590
+ if (value === undefined || value === null) return false
591
+ if (value === def[key]) return false
592
+ if (key === 'attr' && Array.isArray(value) && value.length === 0)
593
+ return false
594
+ if (key === 'extraStr' && value === '{}') return false
595
+ return true
596
+ }
597
+ const result: UObj = { SOID: dan.SOID }
598
+ for (const key of Object.keys(dan) as (keyof UObj)[]) {
599
+ const value = dan[key]
600
+ if (shouldKeep(key, value)) {
601
+ if (key === 'SOID') continue
602
+ Reflect.set(result, key, value)
599
603
  }
600
604
  }
601
- return JSON.parse(JSON.stringify(dan)) as UObj
605
+ return result
602
606
  }
603
607
  @Expose()
604
- downgradeAdvcancedDan(
605
- {
606
- include,
607
- exclude,
608
- cleanExtra = false,
609
- }: {
610
- include?: (keyof Extra)[]
611
- exclude?: (keyof Extra)[]
612
- cleanExtra?: boolean
613
- } = { include: [], exclude: [] },
614
- ) {
615
- if (!this.extra) return this
616
- else {
608
+ downgradeAdvcancedDan({
609
+ include,
610
+ exclude,
611
+ cleanExtra = false,
612
+ }: {
613
+ include?: (keyof Extra)[]
614
+ exclude?: (keyof Extra)[]
615
+ cleanExtra?: boolean
616
+ } = {}) {
617
+ if (this.extra) {
617
618
  if (!include) include = []
618
619
  if (!exclude) exclude = []
619
620
  const check = (k: keyof Extra) =>
@@ -649,7 +650,7 @@ export class UniDM {
649
650
  clone.attr.push(DMAttr.Compatible)
650
651
  if (cleanExtra) clone.extraStr = undefined
651
652
  return clone
652
- }
653
+ } else return this
653
654
  }
654
655
  /**
655
656
  * 将各种类型的时间进行格式化
@@ -794,7 +795,7 @@ export class UniDM {
794
795
  senderID: senderID.toString(),
795
796
  // content: args.content,
796
797
  ctime: this.transCtime(args.ctime, 's'),
797
- weight: args.weight ? args.weight : pool === Pools.Ix ? 1 : 0,
798
+ weight: args.weight || (pool === Pools.Ix ? 1 : 0),
798
799
  pool,
799
800
  attr: DMAttrUtils.fromBin(args.attr, PlatformVideoSource.Bilibili),
800
801
  platform: PlatformVideoSource.Bilibili,
@@ -1 +1 @@
1
- {"version":"5.9.2"}
1
+ {"version":"5.9.3"}