@dan-uni/dan-any 0.9.4 → 0.9.6
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 +129 -79
- package/dist/index.min.js +138 -93
- package/dist/index.umd.min.js +373 -232
- 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/dist/src/index.d.ts +68 -1
- package/dist/src/utils/dm-gen.d.ts +3 -0
- 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.test.ts +0 -1
- package/src/index.ts +120 -12
- 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 +38 -28
- 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/dist/src/index.d.ts
CHANGED
|
@@ -25,8 +25,74 @@ export interface DM_XML_Bili {
|
|
|
25
25
|
}[];
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
+
export interface DM_JSON_BiliUp {
|
|
29
|
+
/** 接口状态码,0 表示成功 */
|
|
30
|
+
code: number;
|
|
31
|
+
/** 文本形式的状态码,约定为字符串 "0" */
|
|
32
|
+
message: string;
|
|
33
|
+
/** TTL(time to live) 标识,本接口常量为 1 */
|
|
34
|
+
ttl: number;
|
|
35
|
+
data: {
|
|
36
|
+
/** 分页元信息 */
|
|
37
|
+
page: {
|
|
38
|
+
/** 当前页序号,从 1 开始 */
|
|
39
|
+
num: number;
|
|
40
|
+
/** 每页返回的弹幕条数 */
|
|
41
|
+
size: number;
|
|
42
|
+
/** 总页数 */
|
|
43
|
+
total: number;
|
|
44
|
+
};
|
|
45
|
+
result: {
|
|
46
|
+
/** 弹幕 ID,int64 */
|
|
47
|
+
id: number;
|
|
48
|
+
/** 弹幕 ID 字符串形式 */
|
|
49
|
+
id_str: string;
|
|
50
|
+
/** 弹幕类型:1 表示视频弹幕(当前接口恒为 1) */
|
|
51
|
+
type: number;
|
|
52
|
+
aid: number;
|
|
53
|
+
bvid: string;
|
|
54
|
+
oid: number;
|
|
55
|
+
mid: number;
|
|
56
|
+
/** 发送者 mid 的 CRC 哈希(正常接口里用的是这个,保护隐私) */
|
|
57
|
+
mid_hash: string;
|
|
58
|
+
/** 弹幕池 */
|
|
59
|
+
pool: number;
|
|
60
|
+
/** 属性位字符串,逗号分隔的数字列表,对应 attr 二进制位 */
|
|
61
|
+
attrs: string;
|
|
62
|
+
/** 弹幕出现时间,单位毫秒(注意,此处与protobuf接口保持一致,但xml中progress是秒) */
|
|
63
|
+
progress: number;
|
|
64
|
+
mode: number;
|
|
65
|
+
/** 弹幕内容, content */
|
|
66
|
+
msg: string;
|
|
67
|
+
state: number;
|
|
68
|
+
fontsize: number;
|
|
69
|
+
/** 弹幕颜色,需将16进制转化为普通弹幕的10进制,示例:"ffffff" */
|
|
70
|
+
color: string;
|
|
71
|
+
/** 发送时间戳,单位秒 */
|
|
72
|
+
ctime: number;
|
|
73
|
+
/** 发送者昵称 */
|
|
74
|
+
uname: string;
|
|
75
|
+
/** 发送者头像链接 */
|
|
76
|
+
uface: string;
|
|
77
|
+
/** 视频主标题 */
|
|
78
|
+
title: string;
|
|
79
|
+
self_seen: boolean;
|
|
80
|
+
/** 弹幕点赞数 */
|
|
81
|
+
like_count: number;
|
|
82
|
+
user_like: number;
|
|
83
|
+
/** 分 P 标题 */
|
|
84
|
+
p_title: string;
|
|
85
|
+
/** 视频封面链接 */
|
|
86
|
+
cover: string;
|
|
87
|
+
is_charge: boolean;
|
|
88
|
+
is_charge_plus: boolean;
|
|
89
|
+
following: boolean;
|
|
90
|
+
extra_cps: null;
|
|
91
|
+
}[];
|
|
92
|
+
};
|
|
93
|
+
}
|
|
28
94
|
export interface DM_JSON_Dplayer {
|
|
29
|
-
code:
|
|
95
|
+
code: number;
|
|
30
96
|
/**
|
|
31
97
|
* progress,mode,color,midHash,content
|
|
32
98
|
*/
|
|
@@ -151,6 +217,7 @@ export declare class UniPool {
|
|
|
151
217
|
* @param bin 符合`DmWebViewReplySchema`(bili视频meta)的protobuf二进制
|
|
152
218
|
*/
|
|
153
219
|
static fromBiliCommandGrpc(bin: Uint8Array | ArrayBuffer, options?: Options): UniPool;
|
|
220
|
+
static fromBiliUp(json: DM_JSON_BiliUp, options?: Options): UniPool;
|
|
154
221
|
static fromDplayer(json: DM_JSON_Dplayer & {
|
|
155
222
|
danuni?: DanUniConvertTip;
|
|
156
223
|
}, playerID: string, domain?: string, options?: Options): UniPool;
|
|
@@ -18,6 +18,7 @@ interface DMBili {
|
|
|
18
18
|
mode: number;
|
|
19
19
|
fontsize: number;
|
|
20
20
|
color: number;
|
|
21
|
+
mid?: number;
|
|
21
22
|
midHash: string;
|
|
22
23
|
/**
|
|
23
24
|
* 特殊类型解析:
|
|
@@ -97,6 +98,8 @@ interface ExtraBili {
|
|
|
97
98
|
mode?: number;
|
|
98
99
|
pool?: number;
|
|
99
100
|
dmid?: bigint;
|
|
101
|
+
attr?: number;
|
|
102
|
+
mid?: number;
|
|
100
103
|
adv?: string;
|
|
101
104
|
code?: string;
|
|
102
105
|
bas?: 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.6",
|
|
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.test.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -59,8 +59,74 @@ export interface DM_XML_Bili {
|
|
|
59
59
|
}[]
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
+
export interface DM_JSON_BiliUp {
|
|
63
|
+
/** 接口状态码,0 表示成功 */
|
|
64
|
+
code: number
|
|
65
|
+
/** 文本形式的状态码,约定为字符串 "0" */
|
|
66
|
+
message: string
|
|
67
|
+
/** TTL(time to live) 标识,本接口常量为 1 */
|
|
68
|
+
ttl: number
|
|
69
|
+
data: {
|
|
70
|
+
/** 分页元信息 */
|
|
71
|
+
page: {
|
|
72
|
+
/** 当前页序号,从 1 开始 */
|
|
73
|
+
num: number
|
|
74
|
+
/** 每页返回的弹幕条数 */
|
|
75
|
+
size: number
|
|
76
|
+
/** 总页数 */
|
|
77
|
+
total: number
|
|
78
|
+
}
|
|
79
|
+
result: {
|
|
80
|
+
/** 弹幕 ID,int64 */
|
|
81
|
+
id: number
|
|
82
|
+
/** 弹幕 ID 字符串形式 */
|
|
83
|
+
id_str: string
|
|
84
|
+
/** 弹幕类型:1 表示视频弹幕(当前接口恒为 1) */
|
|
85
|
+
type: number
|
|
86
|
+
aid: number
|
|
87
|
+
bvid: string
|
|
88
|
+
oid: number
|
|
89
|
+
mid: number
|
|
90
|
+
/** 发送者 mid 的 CRC 哈希(正常接口里用的是这个,保护隐私) */
|
|
91
|
+
mid_hash: string
|
|
92
|
+
/** 弹幕池 */
|
|
93
|
+
pool: number
|
|
94
|
+
/** 属性位字符串,逗号分隔的数字列表,对应 attr 二进制位 */
|
|
95
|
+
attrs: string
|
|
96
|
+
/** 弹幕出现时间,单位毫秒(注意,此处与protobuf接口保持一致,但xml中progress是秒) */
|
|
97
|
+
progress: number
|
|
98
|
+
mode: number
|
|
99
|
+
/** 弹幕内容, content */
|
|
100
|
+
msg: string
|
|
101
|
+
state: number // ?
|
|
102
|
+
fontsize: number
|
|
103
|
+
/** 弹幕颜色,需将16进制转化为普通弹幕的10进制,示例:"ffffff" */
|
|
104
|
+
color: string
|
|
105
|
+
/** 发送时间戳,单位秒 */
|
|
106
|
+
ctime: number
|
|
107
|
+
/** 发送者昵称 */
|
|
108
|
+
uname: string
|
|
109
|
+
/** 发送者头像链接 */
|
|
110
|
+
uface: string
|
|
111
|
+
/** 视频主标题 */
|
|
112
|
+
title: string
|
|
113
|
+
self_seen: boolean // 尽自己可见?
|
|
114
|
+
/** 弹幕点赞数 */
|
|
115
|
+
like_count: number
|
|
116
|
+
user_like: number // ?
|
|
117
|
+
/** 分 P 标题 */
|
|
118
|
+
p_title: string
|
|
119
|
+
/** 视频封面链接 */
|
|
120
|
+
cover: string
|
|
121
|
+
is_charge: boolean // 该up是否开通充电计划?
|
|
122
|
+
is_charge_plus: boolean // 该up是否开通高级充电计划?
|
|
123
|
+
following: boolean // 当前登录用户是否关注该发送者?
|
|
124
|
+
extra_cps: null // ?
|
|
125
|
+
}[]
|
|
126
|
+
}
|
|
127
|
+
}
|
|
62
128
|
export interface DM_JSON_Dplayer {
|
|
63
|
-
code:
|
|
129
|
+
code: number
|
|
64
130
|
/**
|
|
65
131
|
* progress,mode,color,midHash,content
|
|
66
132
|
*/
|
|
@@ -172,17 +238,17 @@ export class UniPool {
|
|
|
172
238
|
const default_stat: Stat[] = []
|
|
173
239
|
const stats = this.dans.reduce((stat, dan) => {
|
|
174
240
|
const valWithCount = stat.find((i) => i.val === dan[key])
|
|
175
|
-
if (
|
|
176
|
-
stat.push({ val: dan[key], count: 1 })
|
|
177
|
-
} else {
|
|
241
|
+
if (valWithCount) {
|
|
178
242
|
valWithCount.count++
|
|
243
|
+
} else {
|
|
244
|
+
stat.push({ val: dan[key], count: 1 })
|
|
179
245
|
}
|
|
180
246
|
return stat
|
|
181
247
|
}, default_stat)
|
|
182
248
|
return stats
|
|
183
249
|
}
|
|
184
250
|
getMost(key: keyof statItems) {
|
|
185
|
-
return this.getStat(key).
|
|
251
|
+
return this.getStat(key).toSorted((a, b) => b.count - a.count)[0]
|
|
186
252
|
}
|
|
187
253
|
get most() {
|
|
188
254
|
return {
|
|
@@ -449,8 +515,11 @@ export class UniPool {
|
|
|
449
515
|
try {
|
|
450
516
|
const fileStr = new TextDecoder().decode(file)
|
|
451
517
|
const prStr = parseStr(fileStr)
|
|
452
|
-
if (
|
|
453
|
-
|
|
518
|
+
if (prStr) {
|
|
519
|
+
return prStr
|
|
520
|
+
} else {
|
|
521
|
+
errmesg = `${err}(定位: bin->string)`
|
|
522
|
+
}
|
|
454
523
|
} catch {}
|
|
455
524
|
} else if (mod.includes('json')) {
|
|
456
525
|
// pure-json
|
|
@@ -611,6 +680,7 @@ export class UniPool {
|
|
|
611
680
|
return builder.build({
|
|
612
681
|
'?xml': {
|
|
613
682
|
'@_version': '1.0',
|
|
683
|
+
// eslint-disable-next-line unicorn/text-encoding-identifier-case
|
|
614
684
|
'@_encoding': 'UTF-8',
|
|
615
685
|
},
|
|
616
686
|
danuni: { ...DanUniConvertTipTemplate, data: this.shared.SOID },
|
|
@@ -653,6 +723,41 @@ export class UniPool {
|
|
|
653
723
|
options,
|
|
654
724
|
)
|
|
655
725
|
}
|
|
726
|
+
static fromBiliUp(json: DM_JSON_BiliUp, options?: Options) {
|
|
727
|
+
return new UniPool(
|
|
728
|
+
json.data.result.map((d) => {
|
|
729
|
+
// 处理 attrs 字符串转换为 attr 二进制
|
|
730
|
+
// attrs 格式如 "1,13,21",每个数字对应二进制位
|
|
731
|
+
const attrBin = d.attrs
|
|
732
|
+
? d.attrs
|
|
733
|
+
.split(',')
|
|
734
|
+
.map(Number)
|
|
735
|
+
.reduce((bin, bitPosition) => bin | (1 << (bitPosition - 1)), 0)
|
|
736
|
+
: 0
|
|
737
|
+
|
|
738
|
+
return UniDM.fromBili(
|
|
739
|
+
{
|
|
740
|
+
id: BigInt(d.id_str || d.id),
|
|
741
|
+
progress: d.progress / 1000, // 毫秒转秒
|
|
742
|
+
mode: d.mode,
|
|
743
|
+
fontsize: d.fontsize,
|
|
744
|
+
color: Number.parseInt(d.color, 16),
|
|
745
|
+
mid: d.mid,
|
|
746
|
+
midHash: d.mid_hash,
|
|
747
|
+
content: d.msg,
|
|
748
|
+
ctime: BigInt(d.ctime),
|
|
749
|
+
pool: d.pool,
|
|
750
|
+
// idStr: d.id_str,
|
|
751
|
+
attr: attrBin,
|
|
752
|
+
oid: BigInt(d.oid),
|
|
753
|
+
},
|
|
754
|
+
BigInt(d.oid),
|
|
755
|
+
options,
|
|
756
|
+
)
|
|
757
|
+
}),
|
|
758
|
+
options,
|
|
759
|
+
)
|
|
760
|
+
}
|
|
656
761
|
static fromDplayer(
|
|
657
762
|
json: DM_JSON_Dplayer & { danuni?: DanUniConvertTip },
|
|
658
763
|
playerID: string,
|
|
@@ -785,12 +890,15 @@ export class UniPool {
|
|
|
785
890
|
/**
|
|
786
891
|
* 转换为ASS字幕格式的弹幕,需播放器支持多行ASS渲染
|
|
787
892
|
*/
|
|
788
|
-
toASS(
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
): string {
|
|
893
|
+
toASS(canvasCtx: CanvasCtx, options?: AssGenOptions): string {
|
|
894
|
+
const defaultOptions: AssGenOptions = { substyle: {} }
|
|
895
|
+
const finalOptions = options ?? defaultOptions
|
|
792
896
|
const fn = this.shared.SOID
|
|
793
|
-
return generateASS(
|
|
897
|
+
return generateASS(
|
|
898
|
+
this,
|
|
899
|
+
{ filename: fn, title: fn, ...finalOptions },
|
|
900
|
+
canvasCtx,
|
|
901
|
+
)
|
|
794
902
|
}
|
|
795
903
|
}
|
|
796
904
|
|