@dan-uni/dan-any 0.9.4 → 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.
- package/README.md +4 -0
- package/dist/index.js +88 -78
- package/dist/index.min.js +97 -92
- package/dist/index.umd.min.js +332 -231
- package/dist/src/ass-gen/ass/create.d.ts +1 -2
- package/dist/src/ass-gen/ass/dialogue.d.ts +1 -2
- package/dist/src/ass-gen/ass/event.d.ts +1 -2
- package/dist/src/ass-gen/ass/info.d.ts +2 -2
- package/dist/src/ass-gen/ass/style.d.ts +1 -2
- package/dist/src/ass-gen/config.d.ts +1 -2
- package/package.json +6 -6
- package/src/ass-gen/__tests__/generate.test.ts +2 -2
- package/src/ass-gen/ass/create.ts +7 -6
- package/src/ass-gen/ass/dialogue.ts +1 -2
- package/src/ass-gen/ass/event.ts +2 -3
- package/src/ass-gen/ass/info.ts +1 -2
- package/src/ass-gen/ass/raw.ts +7 -7
- package/src/ass-gen/ass/style.ts +1 -2
- package/src/ass-gen/config.ts +1 -1
- package/src/ass-gen/index.ts +7 -4
- package/src/ass-gen/util/layout.ts +1 -1
- package/src/index.ts +18 -11
- package/src/proto/gen/bili/dm_pb.ts +1 -1
- package/src/proto/gen/danuni_pb.ts +1 -1
- package/src/utils/dm-gen.ts +28 -27
- package/types/tsconfig.tsbuildinfo +1 -1
|
@@ -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
|
|
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
|
|
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;
|
|
@@ -4,5 +4,5 @@ type Resolution = {
|
|
|
4
4
|
playResX: number;
|
|
5
5
|
playResY: number;
|
|
6
6
|
};
|
|
7
|
-
declare const
|
|
8
|
-
export
|
|
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
|
|
3
|
-
export default _default;
|
|
2
|
+
export declare const style: ({ fontName, fontSize, color: configColor, outlineColor, backColor, bold, outline, shadow, opacity, }: SubtitleStyle) => string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dan-uni/dan-any",
|
|
3
|
-
"version": "0.9.
|
|
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.
|
|
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.
|
|
40
|
-
"fs-extra": "^11.3.
|
|
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.
|
|
48
|
-
"@bufbuild/protoc-gen-es": "^2.
|
|
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, '
|
|
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, '
|
|
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
|
-
|
|
12
|
-
|
|
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 =
|
|
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
|
-
|
|
44
|
-
export default (
|
|
43
|
+
export const dialogue = (
|
|
45
44
|
danmaku: {
|
|
46
45
|
type: (typeof DanmakuType)[keyof typeof DanmakuType]
|
|
47
46
|
color: RGB
|
package/src/ass-gen/ass/event.ts
CHANGED
|
@@ -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
|
-
|
|
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',
|
package/src/ass-gen/ass/info.ts
CHANGED
package/src/ass-gen/ass/raw.ts
CHANGED
|
@@ -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.
|
|
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.
|
|
61
|
-
if (!baseTypes.
|
|
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, '
|
|
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('
|
|
73
|
+
return JSON.parse(decompress.toString('utf8'))
|
|
74
74
|
} catch {
|
|
75
75
|
return undefined
|
|
76
76
|
}
|
package/src/ass-gen/ass/style.ts
CHANGED
|
@@ -2,8 +2,7 @@ import type { SubtitleStyle } from '../types'
|
|
|
2
2
|
|
|
3
3
|
import { formatColor, getDecoratingColor, hexColorToRGB } from '../util'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
export default ({
|
|
5
|
+
export const style = ({
|
|
7
6
|
fontName,
|
|
8
7
|
fontSize,
|
|
9
8
|
color: configColor,
|
package/src/ass-gen/config.ts
CHANGED
|
@@ -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
|
|
14
|
+
export const getConfig = (overrides = {}): SubtitleStyle => {
|
|
15
15
|
const defaults = {
|
|
16
16
|
fontSize: [25, 25, 36],
|
|
17
17
|
fontName: 'SimHei',
|
package/src/ass-gen/index.ts
CHANGED
|
@@ -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 (
|
|
69
|
-
|
|
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)].
|
|
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 (
|
|
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).
|
|
185
|
+
return this.getStat(key).toSorted((a, b) => b.count - a.count)[0]
|
|
186
186
|
}
|
|
187
187
|
get most() {
|
|
188
188
|
return {
|
|
@@ -449,8 +449,11 @@ export class UniPool {
|
|
|
449
449
|
try {
|
|
450
450
|
const fileStr = new TextDecoder().decode(file)
|
|
451
451
|
const prStr = parseStr(fileStr)
|
|
452
|
-
if (
|
|
453
|
-
|
|
452
|
+
if (prStr) {
|
|
453
|
+
return prStr
|
|
454
|
+
} else {
|
|
455
|
+
errmesg = `${err}(定位: bin->string)`
|
|
456
|
+
}
|
|
454
457
|
} catch {}
|
|
455
458
|
} else if (mod.includes('json')) {
|
|
456
459
|
// pure-json
|
|
@@ -611,6 +614,7 @@ export class UniPool {
|
|
|
611
614
|
return builder.build({
|
|
612
615
|
'?xml': {
|
|
613
616
|
'@_version': '1.0',
|
|
617
|
+
// eslint-disable-next-line unicorn/text-encoding-identifier-case
|
|
614
618
|
'@_encoding': 'UTF-8',
|
|
615
619
|
},
|
|
616
620
|
danuni: { ...DanUniConvertTipTemplate, data: this.shared.SOID },
|
|
@@ -785,12 +789,15 @@ export class UniPool {
|
|
|
785
789
|
/**
|
|
786
790
|
* 转换为ASS字幕格式的弹幕,需播放器支持多行ASS渲染
|
|
787
791
|
*/
|
|
788
|
-
toASS(
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
): string {
|
|
792
|
+
toASS(canvasCtx: CanvasCtx, options?: AssGenOptions): string {
|
|
793
|
+
const defaultOptions: AssGenOptions = { substyle: {} }
|
|
794
|
+
const finalOptions = options ?? defaultOptions
|
|
792
795
|
const fn = this.shared.SOID
|
|
793
|
-
return generateASS(
|
|
796
|
+
return generateASS(
|
|
797
|
+
this,
|
|
798
|
+
{ filename: fn, title: fn, ...finalOptions },
|
|
799
|
+
canvasCtx,
|
|
800
|
+
)
|
|
794
801
|
}
|
|
795
802
|
}
|
|
796
803
|
|
package/src/utils/dm-gen.ts
CHANGED
|
@@ -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
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
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
|
|
605
|
+
return result
|
|
602
606
|
}
|
|
603
607
|
@Expose()
|
|
604
|
-
downgradeAdvcancedDan(
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
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
|
|
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.
|
|
1
|
+
{"version":"5.9.3"}
|