@dan-uni/dan-any 1.4.8 → 2.0.0
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 +87 -43
- package/dist/adapters.d.mts +2 -0
- package/dist/adapters.mjs +1 -0
- package/dist/chunk-0Lt9GpW0.mjs +1 -0
- package/dist/core/db/schema.d.mts +2 -0
- package/dist/core/db/schema.mjs +2 -0
- package/dist/core/db/schema.mjs.map +1 -0
- package/dist/core/db/utils.d.mts +1707 -0
- package/dist/core/db/utils.d.mts.map +1 -0
- package/dist/core/db/utils.mjs +1 -0
- package/dist/core-D7LMAB5h.mjs +2 -0
- package/dist/core-D7LMAB5h.mjs.map +1 -0
- package/dist/core.d.mts +2 -0
- package/dist/core.mjs +1 -0
- package/dist/db-DWWzkRBb.mjs +41 -0
- package/dist/db-DWWzkRBb.mjs.map +1 -0
- package/dist/dm-extra-DrAQCrFv.d.mts +135 -0
- package/dist/dm-extra-DrAQCrFv.d.mts.map +1 -0
- package/dist/dm-tkTdR_W6.mjs +2 -0
- package/dist/dm-tkTdR_W6.mjs.map +1 -0
- package/dist/index-vAs4qV9A.d.mts +6195 -0
- package/dist/index-vAs4qV9A.d.mts.map +1 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.mjs +1 -0
- package/dist/isSame-D4G9eoE4.mjs +2 -0
- package/dist/isSame-D4G9eoE4.mjs.map +1 -0
- package/dist/plugins.d.mts +105 -0
- package/dist/plugins.d.mts.map +1 -0
- package/dist/plugins.mjs +2 -0
- package/dist/plugins.mjs.map +1 -0
- package/dist/schema-BuenbDx9.d.mts +1619 -0
- package/dist/schema-BuenbDx9.d.mts.map +1 -0
- package/dist/utils.d.mts +25 -0
- package/dist/utils.d.mts.map +1 -0
- package/dist/utils.mjs +2 -0
- package/dist/utils.mjs.map +1 -0
- package/package.json +65 -37
- package/.babelrc.json +0 -12
- package/buf.gen.yaml +0 -10
- package/buf.yaml +0 -12
- package/dist/browser/1~rslib-runtime.min.js +0 -49
- package/dist/browser/index.min.js +0 -13523
- package/dist/browser/index.min.js.LICENSE.txt +0 -17
- package/dist/browser/plugins/bili.min.js +0 -1
- package/dist/browser/plugins/index.min.js +0 -2
- package/dist/browser/plugins/stats.min.js +0 -10
- package/dist/browser/src/ass-gen/__tests__/canvas.test.d.ts +0 -1
- package/dist/browser/src/ass-gen/__tests__/generate.test.d.ts +0 -1
- package/dist/browser/src/ass-gen/ass/create.d.ts +0 -4
- package/dist/browser/src/ass-gen/ass/dialogue.d.ts +0 -16
- package/dist/browser/src/ass-gen/ass/event.d.ts +0 -2
- package/dist/browser/src/ass-gen/ass/info.d.ts +0 -8
- package/dist/browser/src/ass-gen/ass/raw.d.ts +0 -14
- package/dist/browser/src/ass-gen/ass/style.d.ts +0 -2
- package/dist/browser/src/ass-gen/config.d.ts +0 -2
- package/dist/browser/src/ass-gen/index.d.ts +0 -30
- package/dist/browser/src/ass-gen/types.d.ts +0 -71
- package/dist/browser/src/ass-gen/util/color.d.ts +0 -18
- package/dist/browser/src/ass-gen/util/danconvert.d.ts +0 -5
- package/dist/browser/src/ass-gen/util/index.d.ts +0 -4
- package/dist/browser/src/ass-gen/util/lang.d.ts +0 -3
- package/dist/browser/src/ass-gen/util/layout.d.ts +0 -4
- package/dist/browser/src/index.d.ts +0 -283
- package/dist/browser/src/index.test.d.ts +0 -1
- package/dist/browser/src/plugins/bili/dedupe.d.ts +0 -3
- package/dist/browser/src/plugins/bili/history-danmaku-fast-forward.d.ts +0 -18
- package/dist/browser/src/plugins/bili/index.d.ts +0 -2
- package/dist/browser/src/plugins/bili/index.test.d.ts +0 -1
- package/dist/browser/src/plugins/index.d.ts +0 -2
- package/dist/browser/src/plugins/stats/getLatestDan.d.ts +0 -6
- package/dist/browser/src/plugins/stats/index.d.ts +0 -1
- package/dist/browser/src/plugins/stats/index.test.d.ts +0 -1
- package/dist/browser/src/proto/gen/bilibili/community/service/dm/v1/dm_pb.d.ts +0 -3426
- package/dist/browser/src/proto/gen/danuni/danmaku/v1/danmaku_pb.d.ts +0 -176
- package/dist/browser/src/utils/dm-gen.d.ts +0 -309
- package/dist/browser/src/utils/dm-gen.test.d.ts +0 -1
- package/dist/browser/src/utils/fileParser.d.ts +0 -3
- package/dist/browser/src/utils/id-gen.d.ts +0 -50
- package/dist/browser/src/utils/platform.d.ts +0 -24
- package/dist/node/0~rslib-runtime.js +0 -23
- package/dist/node/index.js +0 -2099
- package/dist/node/plugins/bili.js +0 -1
- package/dist/node/plugins/index.js +0 -2
- package/dist/node/plugins/stats.js +0 -10
- package/dist/node/src/ass-gen/__tests__/canvas.test.d.ts +0 -1
- package/dist/node/src/ass-gen/__tests__/generate.test.d.ts +0 -1
- package/dist/node/src/ass-gen/ass/create.d.ts +0 -4
- package/dist/node/src/ass-gen/ass/dialogue.d.ts +0 -16
- package/dist/node/src/ass-gen/ass/event.d.ts +0 -2
- package/dist/node/src/ass-gen/ass/info.d.ts +0 -8
- package/dist/node/src/ass-gen/ass/raw.d.ts +0 -14
- package/dist/node/src/ass-gen/ass/style.d.ts +0 -2
- package/dist/node/src/ass-gen/config.d.ts +0 -2
- package/dist/node/src/ass-gen/index.d.ts +0 -30
- package/dist/node/src/ass-gen/types.d.ts +0 -71
- package/dist/node/src/ass-gen/util/color.d.ts +0 -18
- package/dist/node/src/ass-gen/util/danconvert.d.ts +0 -5
- package/dist/node/src/ass-gen/util/index.d.ts +0 -4
- package/dist/node/src/ass-gen/util/lang.d.ts +0 -3
- package/dist/node/src/ass-gen/util/layout.d.ts +0 -4
- package/dist/node/src/index.d.ts +0 -283
- package/dist/node/src/index.test.d.ts +0 -1
- package/dist/node/src/plugins/bili/dedupe.d.ts +0 -3
- package/dist/node/src/plugins/bili/history-danmaku-fast-forward.d.ts +0 -18
- package/dist/node/src/plugins/bili/index.d.ts +0 -2
- package/dist/node/src/plugins/bili/index.test.d.ts +0 -1
- package/dist/node/src/plugins/index.d.ts +0 -2
- package/dist/node/src/plugins/stats/getLatestDan.d.ts +0 -6
- package/dist/node/src/plugins/stats/index.d.ts +0 -1
- package/dist/node/src/plugins/stats/index.test.d.ts +0 -1
- package/dist/node/src/proto/gen/bilibili/community/service/dm/v1/dm_pb.d.ts +0 -3426
- package/dist/node/src/proto/gen/danuni/danmaku/v1/danmaku_pb.d.ts +0 -176
- package/dist/node/src/utils/dm-gen.d.ts +0 -309
- package/dist/node/src/utils/dm-gen.test.d.ts +0 -1
- package/dist/node/src/utils/fileParser.d.ts +0 -3
- package/dist/node/src/utils/id-gen.d.ts +0 -50
- package/dist/node/src/utils/platform.d.ts +0 -24
- package/dist/umd/index.umd.min.js +0 -32093
- package/dist/umd/index.umd.min.js.LICENSE.txt +0 -34
- package/dist/umd/plugins/bili.umd.min.js +0 -32004
- package/dist/umd/plugins/bili.umd.min.js.LICENSE.txt +0 -34
- package/dist/umd/plugins/index.umd.min.js +0 -32020
- package/dist/umd/plugins/index.umd.min.js.LICENSE.txt +0 -34
- package/dist/umd/plugins/stats.umd.min.js +0 -39
- package/dist/umd/src/ass-gen/__tests__/canvas.test.d.ts +0 -1
- package/dist/umd/src/ass-gen/__tests__/generate.test.d.ts +0 -1
- package/dist/umd/src/ass-gen/ass/create.d.ts +0 -4
- package/dist/umd/src/ass-gen/ass/dialogue.d.ts +0 -16
- package/dist/umd/src/ass-gen/ass/event.d.ts +0 -2
- package/dist/umd/src/ass-gen/ass/info.d.ts +0 -8
- package/dist/umd/src/ass-gen/ass/raw.d.ts +0 -14
- package/dist/umd/src/ass-gen/ass/style.d.ts +0 -2
- package/dist/umd/src/ass-gen/config.d.ts +0 -2
- package/dist/umd/src/ass-gen/index.d.ts +0 -30
- package/dist/umd/src/ass-gen/types.d.ts +0 -71
- package/dist/umd/src/ass-gen/util/color.d.ts +0 -18
- package/dist/umd/src/ass-gen/util/danconvert.d.ts +0 -5
- package/dist/umd/src/ass-gen/util/index.d.ts +0 -4
- package/dist/umd/src/ass-gen/util/lang.d.ts +0 -3
- package/dist/umd/src/ass-gen/util/layout.d.ts +0 -4
- package/dist/umd/src/index.d.ts +0 -283
- package/dist/umd/src/index.test.d.ts +0 -1
- package/dist/umd/src/plugins/bili/dedupe.d.ts +0 -3
- package/dist/umd/src/plugins/bili/history-danmaku-fast-forward.d.ts +0 -18
- package/dist/umd/src/plugins/bili/index.d.ts +0 -2
- package/dist/umd/src/plugins/bili/index.test.d.ts +0 -1
- package/dist/umd/src/plugins/index.d.ts +0 -2
- package/dist/umd/src/plugins/stats/getLatestDan.d.ts +0 -6
- package/dist/umd/src/plugins/stats/index.d.ts +0 -1
- package/dist/umd/src/plugins/stats/index.test.d.ts +0 -1
- package/dist/umd/src/proto/gen/bilibili/community/service/dm/v1/dm_pb.d.ts +0 -3426
- package/dist/umd/src/proto/gen/danuni/danmaku/v1/danmaku_pb.d.ts +0 -176
- package/dist/umd/src/utils/dm-gen.d.ts +0 -309
- package/dist/umd/src/utils/dm-gen.test.d.ts +0 -1
- package/dist/umd/src/utils/fileParser.d.ts +0 -3
- package/dist/umd/src/utils/id-gen.d.ts +0 -50
- package/dist/umd/src/utils/platform.d.ts +0 -24
- package/plugins/package.json +0 -6
- package/rslib.config.ts +0 -101
- package/src/ass-gen/__tests__/898651903.xml +0 -1619
- package/src/ass-gen/__tests__/898651903.xml.ass +0 -1516
- package/src/ass-gen/__tests__/canvas.test.ts +0 -15
- package/src/ass-gen/__tests__/generate.test.ts +0 -26
- package/src/ass-gen/ass/create.ts +0 -37
- package/src/ass-gen/ass/dialogue.ts +0 -90
- package/src/ass-gen/ass/event.ts +0 -57
- package/src/ass-gen/ass/info.ts +0 -27
- package/src/ass-gen/ass/raw.ts +0 -78
- package/src/ass-gen/ass/style.ts +0 -66
- package/src/ass-gen/config.ts +0 -45
- package/src/ass-gen/index.ts +0 -73
- package/src/ass-gen/types.ts +0 -76
- package/src/ass-gen/util/color.ts +0 -55
- package/src/ass-gen/util/danconvert.ts +0 -43
- package/src/ass-gen/util/index.ts +0 -10
- package/src/ass-gen/util/lang.ts +0 -35
- package/src/ass-gen/util/layout.ts +0 -242
- package/src/index.test.ts +0 -157
- package/src/index.ts +0 -1144
- package/src/plugins/bili/README.md +0 -87
- package/src/plugins/bili/dedupe.ts +0 -29
- package/src/plugins/bili/history-danmaku-fast-forward.ts +0 -86
- package/src/plugins/bili/index.test.ts +0 -129
- package/src/plugins/bili/index.ts +0 -2
- package/src/plugins/index.ts +0 -2
- package/src/plugins/stats/README.md +0 -44
- package/src/plugins/stats/getLatestDan.ts +0 -13
- package/src/plugins/stats/index.test.ts +0 -39
- package/src/plugins/stats/index.ts +0 -1
- package/src/proto/gen/bilibili/community/service/dm/v1/dm_pb.ts +0 -4072
- package/src/proto/gen/danuni/danmaku/v1/danmaku_pb.ts +0 -223
- package/src/proto/src/bilibili/community/service/dm/v1/dm.proto +0 -1095
- package/src/proto/src/danuni/danmaku/v1/danmaku.proto +0 -52
- package/src/utils/dm-gen.test.ts +0 -129
- package/src/utils/dm-gen.ts +0 -1082
- package/src/utils/fileParser.ts +0 -37
- package/src/utils/id-gen.ts +0 -73
- package/src/utils/platform.ts +0 -38
- package/tsconfig.json +0 -108
- package/types/tsconfig.tsbuildinfo +0 -1
package/src/utils/dm-gen.ts
DELETED
|
@@ -1,1082 +0,0 @@
|
|
|
1
|
-
import { Expose, plainToInstance } from 'class-transformer'
|
|
2
|
-
import {
|
|
3
|
-
IsDate,
|
|
4
|
-
IsEmail,
|
|
5
|
-
isEmail,
|
|
6
|
-
IsEnum,
|
|
7
|
-
IsInt,
|
|
8
|
-
IsNotEmpty,
|
|
9
|
-
IsNumber,
|
|
10
|
-
IsOptional,
|
|
11
|
-
IsString,
|
|
12
|
-
Max,
|
|
13
|
-
Min,
|
|
14
|
-
validateOrReject,
|
|
15
|
-
} from 'class-validator'
|
|
16
|
-
import TimeFormat from 'hh-mm-ss'
|
|
17
|
-
import JSONbig from 'json-bigint'
|
|
18
|
-
import type { DM_JSON_BiliCommandGrpc } from '..'
|
|
19
|
-
import type { PlatformDanmakuSource } from './platform'
|
|
20
|
-
|
|
21
|
-
import { createDMID, DMIDGenerator, UniID as ID } from './id-gen'
|
|
22
|
-
import {
|
|
23
|
-
PlatformDanmakuOnlySource,
|
|
24
|
-
PlatformDanmakuSources,
|
|
25
|
-
PlatformVideoSource,
|
|
26
|
-
} from './platform'
|
|
27
|
-
|
|
28
|
-
const JSON = JSONbig({ useNativeBigInt: true })
|
|
29
|
-
|
|
30
|
-
function cleanEmptyObjects(obj: object): object {
|
|
31
|
-
if (obj === null || typeof obj !== 'object') {
|
|
32
|
-
return obj
|
|
33
|
-
}
|
|
34
|
-
if (Array.isArray(obj)) {
|
|
35
|
-
return obj
|
|
36
|
-
}
|
|
37
|
-
const cleaned: any = {}
|
|
38
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
39
|
-
const cleanedValue = cleanEmptyObjects(value)
|
|
40
|
-
if (
|
|
41
|
-
cleanedValue !== undefined &&
|
|
42
|
-
(typeof cleanedValue !== 'object' ||
|
|
43
|
-
Object.keys(cleanedValue).length !== 0)
|
|
44
|
-
) {
|
|
45
|
-
cleaned[key] = cleanedValue
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
return Object.keys(cleaned).length > 0 ? cleaned : {}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
class SetBin {
|
|
52
|
-
constructor(public bin: number) {}
|
|
53
|
-
set1(bit: number) {
|
|
54
|
-
this.bin |= 1 << bit
|
|
55
|
-
}
|
|
56
|
-
set0(bit: number) {
|
|
57
|
-
this.bin &= ~(1 << bit)
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* 获得数字的二进制,每位以boolean(true/false)表示1/0,从低位向高位
|
|
63
|
-
* @param number 任意进制数字
|
|
64
|
-
*/
|
|
65
|
-
const toBits = (number: number) => {
|
|
66
|
-
// 低速方案
|
|
67
|
-
// return [...number.toString(2)].map(Number)
|
|
68
|
-
// 高速方案,位运算允许范围内更快
|
|
69
|
-
const bits: boolean[] = []
|
|
70
|
-
do {
|
|
71
|
-
bits.unshift(!!(number & 1)) // boolean[]
|
|
72
|
-
// bits.unshift(number & 1) // (0|1)[]
|
|
73
|
-
number >>= 1
|
|
74
|
-
} while (number)
|
|
75
|
-
return bits.toReversed()
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export enum DMAttr {
|
|
79
|
-
Protect = 'Protect',
|
|
80
|
-
FromLive = 'FromLive',
|
|
81
|
-
HighLike = 'HighLike',
|
|
82
|
-
Compatible = 'Compatible', // 由dan-any进行过兼容处理的弹幕,可能丢失部分信息
|
|
83
|
-
Reported = 'Reported', // 在DanUni上被多人举报过的弹幕
|
|
84
|
-
Unchecked = 'Unchecked', // 在DanUni上未被审核过的弹幕
|
|
85
|
-
HasEvent = 'HasEvent', // 该弹幕当前在DanUni上存在事件(如点赞/举报等)
|
|
86
|
-
Hide = 'Hide', // 由于其它原因需要隐藏的弹幕(建议在server端不返回该类弹幕)
|
|
87
|
-
}
|
|
88
|
-
const DMAttrUtils = {
|
|
89
|
-
fromBin(bin: number = 0, format?: PlatformDanmakuSource) {
|
|
90
|
-
const array = toBits(bin)
|
|
91
|
-
const attr: DMAttr[] = []
|
|
92
|
-
if (format === 'bili') {
|
|
93
|
-
if (array[0]) attr.push(DMAttr.Protect)
|
|
94
|
-
if (array[1]) attr.push(DMAttr.FromLive)
|
|
95
|
-
if (array[2]) attr.push(DMAttr.HighLike)
|
|
96
|
-
}
|
|
97
|
-
return attr
|
|
98
|
-
},
|
|
99
|
-
toBin(
|
|
100
|
-
attr: DMAttr[] = [],
|
|
101
|
-
/**
|
|
102
|
-
* 对于二进制格式的读取,应该分别读取各位,
|
|
103
|
-
* 但由于不知道B站及其它使用该参数程序的读取逻辑,
|
|
104
|
-
* 所以单独提供 bili 格式
|
|
105
|
-
*/
|
|
106
|
-
format?: PlatformDanmakuSource,
|
|
107
|
-
) {
|
|
108
|
-
const bin = new SetBin(0)
|
|
109
|
-
if (format === 'bili') {
|
|
110
|
-
if (attr.includes(DMAttr.Protect)) bin.set1(0)
|
|
111
|
-
if (attr.includes(DMAttr.FromLive)) bin.set1(1)
|
|
112
|
-
if (attr.includes(DMAttr.HighLike)) bin.set1(2)
|
|
113
|
-
}
|
|
114
|
-
return bin.bin
|
|
115
|
-
},
|
|
116
|
-
}
|
|
117
|
-
// class DMAttr {
|
|
118
|
-
// constructor(
|
|
119
|
-
// /**
|
|
120
|
-
// * 保护
|
|
121
|
-
// */
|
|
122
|
-
// public protect: boolean = false,
|
|
123
|
-
// /**
|
|
124
|
-
// * 直播
|
|
125
|
-
// */
|
|
126
|
-
// public live: boolean = false,
|
|
127
|
-
// /**
|
|
128
|
-
// * 高赞
|
|
129
|
-
// */
|
|
130
|
-
// public highpraise: boolean = false,
|
|
131
|
-
// ) {}
|
|
132
|
-
// toBin(
|
|
133
|
-
// /**
|
|
134
|
-
// * 对于二进制格式的读取,应该分别读取各位,
|
|
135
|
-
// * 但由于不知道B站及其它使用该参数程序的读取逻辑,
|
|
136
|
-
// * 所以单独提供 bili 格式
|
|
137
|
-
// */
|
|
138
|
-
// format?: platfrom,
|
|
139
|
-
// ) {
|
|
140
|
-
// const bin = new SetBin(0)
|
|
141
|
-
// if (this.protect) bin.set1(0)
|
|
142
|
-
// if (this.live) bin.set1(1)
|
|
143
|
-
// if (this.highpraise) bin.set1(2)
|
|
144
|
-
// if (format === 'bili') return bin.bin
|
|
145
|
-
// return bin.bin
|
|
146
|
-
// }
|
|
147
|
-
// static fromBin(bin: number = 0, format?: platfrom) {
|
|
148
|
-
// const array = toBits(bin)
|
|
149
|
-
// if (format === 'bili') {
|
|
150
|
-
// return new DMAttr(array[0], array[1], array[2])
|
|
151
|
-
// } else {
|
|
152
|
-
// return new DMAttr(array[0], array[1], array[2])
|
|
153
|
-
// }
|
|
154
|
-
// }
|
|
155
|
-
// }
|
|
156
|
-
|
|
157
|
-
interface DMBili {
|
|
158
|
-
id: bigint // xml 7
|
|
159
|
-
progress: number // xml 0 ; xml s, protobuf ms
|
|
160
|
-
mode: number // xml 1
|
|
161
|
-
fontsize: number // xml 2
|
|
162
|
-
color: number // xml 3
|
|
163
|
-
mid?: bigint // 仅创作中心源
|
|
164
|
-
midHash: string // xml 6
|
|
165
|
-
/**
|
|
166
|
-
* 特殊类型解析:
|
|
167
|
-
* - [ohh] : /oh{2,}/gi
|
|
168
|
-
* - [前方高能]
|
|
169
|
-
* - [...] (JS数组) : 高级弹幕
|
|
170
|
-
*/
|
|
171
|
-
content: string // xml content
|
|
172
|
-
ctime: bigint // xml 4
|
|
173
|
-
pool: number // xml 5
|
|
174
|
-
weight?: number // xml 8
|
|
175
|
-
action?: string
|
|
176
|
-
idStr?: string
|
|
177
|
-
attr?: number
|
|
178
|
-
animation?: string
|
|
179
|
-
extra?: string
|
|
180
|
-
colorful?: number
|
|
181
|
-
type?: number
|
|
182
|
-
oid?: bigint
|
|
183
|
-
}
|
|
184
|
-
interface DMBiliCommand extends DM_JSON_BiliCommandGrpc {}
|
|
185
|
-
interface DMDplayer {
|
|
186
|
-
/**
|
|
187
|
-
* 进度(秒)
|
|
188
|
-
*/
|
|
189
|
-
progress: number
|
|
190
|
-
mode: number
|
|
191
|
-
color: number
|
|
192
|
-
midHash: string
|
|
193
|
-
content: string
|
|
194
|
-
}
|
|
195
|
-
interface DMArtplayer {
|
|
196
|
-
/**
|
|
197
|
-
* 进度(秒)
|
|
198
|
-
*/
|
|
199
|
-
progress: number
|
|
200
|
-
mode: number
|
|
201
|
-
color: number
|
|
202
|
-
content: string
|
|
203
|
-
border?: boolean
|
|
204
|
-
style?: object
|
|
205
|
-
}
|
|
206
|
-
interface DMDDPlay {
|
|
207
|
-
cid: bigint
|
|
208
|
-
/**
|
|
209
|
-
* content
|
|
210
|
-
*/
|
|
211
|
-
m: string
|
|
212
|
-
/**
|
|
213
|
-
* p[0]
|
|
214
|
-
*/
|
|
215
|
-
progress: number
|
|
216
|
-
/**
|
|
217
|
-
* p[1]
|
|
218
|
-
*/
|
|
219
|
-
mode: number
|
|
220
|
-
/**
|
|
221
|
-
* p[2]
|
|
222
|
-
*/
|
|
223
|
-
color: number
|
|
224
|
-
/**
|
|
225
|
-
* p[3]
|
|
226
|
-
*/
|
|
227
|
-
uid: string
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
export interface Extra {
|
|
231
|
-
artplayer?: ExtraArtplayer
|
|
232
|
-
bili?: ExtraBili
|
|
233
|
-
danuni?: ExtraDanUni
|
|
234
|
-
}
|
|
235
|
-
interface ExtraArtplayer {
|
|
236
|
-
style?: object
|
|
237
|
-
border?: boolean
|
|
238
|
-
}
|
|
239
|
-
interface ExtraBili {
|
|
240
|
-
mode?: number //原弹幕类型
|
|
241
|
-
pool?: number //原弹幕池
|
|
242
|
-
dmid?: bigint //原弹幕ID
|
|
243
|
-
attr?: number //原弹幕属性
|
|
244
|
-
mid?: bigint //发送者mid(仅创作中心源、command弹幕)
|
|
245
|
-
adv?: string
|
|
246
|
-
code?: string
|
|
247
|
-
bas?: string
|
|
248
|
-
command?: DMBiliCommand
|
|
249
|
-
}
|
|
250
|
-
export interface ExtraDanUni {
|
|
251
|
-
chapter?: ExtraDanUniChapter
|
|
252
|
-
merge?: ExtraDanUniMerge
|
|
253
|
-
}
|
|
254
|
-
export interface ExtraDanUniChapter {
|
|
255
|
-
// seg: {
|
|
256
|
-
// st: number //开始时刻
|
|
257
|
-
// } //起止时间(ms)
|
|
258
|
-
duration: number //持续时间
|
|
259
|
-
type: ExtraDanUniChapterType
|
|
260
|
-
// action: ExtraDanUniChapterAction
|
|
261
|
-
}
|
|
262
|
-
export interface ExtraDanUniMerge {
|
|
263
|
-
duration: number //持续时间(重复内容第一次出现时间开始到合并了的弹幕中最后一次出现的时间)
|
|
264
|
-
count: number //重复次数
|
|
265
|
-
senders: string[] //发送者
|
|
266
|
-
taolu_count: number //类似弹幕数量
|
|
267
|
-
taolu_senders: string[] //类似弹幕发送者
|
|
268
|
-
}
|
|
269
|
-
export enum ExtraDanUniChapterType {
|
|
270
|
-
Chapter = 'ch', //其它片段(用于标记章节)
|
|
271
|
-
Review = 'rev', //回顾
|
|
272
|
-
OP = 'op', //片头
|
|
273
|
-
Intermission = 'int', //中场
|
|
274
|
-
ED = 'ed', //片尾
|
|
275
|
-
Preview = 'prvw', //预告
|
|
276
|
-
Cut = 'cut', //删减(删减版中提供删减说明,提供开始位置、长度)
|
|
277
|
-
Duplicate = 'dup', //补档(完整版中指明其它平台中删减位置)
|
|
278
|
-
AdBiz = 'biz', //商业广告
|
|
279
|
-
AdUnpaid = 'promo', //推广(无偿/公益)广告
|
|
280
|
-
}
|
|
281
|
-
const ExtraDanUniChapterTypeDict = {
|
|
282
|
-
chs: {
|
|
283
|
-
ch: '其它片段',
|
|
284
|
-
rev: '回顾',
|
|
285
|
-
op: '片头',
|
|
286
|
-
int: '中场',
|
|
287
|
-
ed: '片尾',
|
|
288
|
-
prvw: '预告',
|
|
289
|
-
cut: '删减',
|
|
290
|
-
dup: '补档',
|
|
291
|
-
biz: '商业广告',
|
|
292
|
-
promo: '推广',
|
|
293
|
-
},
|
|
294
|
-
}
|
|
295
|
-
export enum ExtraDanUniChapterAction {
|
|
296
|
-
Disabled = -1,
|
|
297
|
-
ShowOverlay,
|
|
298
|
-
ManualSkip,
|
|
299
|
-
AutoSkip,
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
export enum Modes {
|
|
303
|
-
Normal,
|
|
304
|
-
Bottom,
|
|
305
|
-
Top,
|
|
306
|
-
Reverse, //逆向弹幕
|
|
307
|
-
Ext, //需要读取extra的弹幕,用于兼容bili等复杂弹幕
|
|
308
|
-
}
|
|
309
|
-
export enum Pools {
|
|
310
|
-
Def, //默认池
|
|
311
|
-
Sub, //重要池,建议强制加载,含字幕、科普、空降等
|
|
312
|
-
Adv, //高级弹幕专用池,均需读取extra
|
|
313
|
-
Ix, //互动池
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
export type ctime = string | number | bigint | Date
|
|
317
|
-
// enum ctimeFmt {
|
|
318
|
-
// bigintStr = 'bigintStr',
|
|
319
|
-
// dateObj = 'dateObj',
|
|
320
|
-
// dateStr = 'dateStr',
|
|
321
|
-
// }
|
|
322
|
-
|
|
323
|
-
export interface UniDMObj {
|
|
324
|
-
SOID: string
|
|
325
|
-
progress: number
|
|
326
|
-
mode: Modes
|
|
327
|
-
fontsize: number
|
|
328
|
-
color: number
|
|
329
|
-
senderID: string
|
|
330
|
-
content: string
|
|
331
|
-
ctime: Date
|
|
332
|
-
weight: number
|
|
333
|
-
pool: Pools
|
|
334
|
-
attr: DMAttr[]
|
|
335
|
-
platform: PlatformDanmakuSource | string
|
|
336
|
-
extra: string | Extra
|
|
337
|
-
extraStr: string
|
|
338
|
-
DMID: string
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
interface Options {
|
|
342
|
-
dmid?: boolean | number | DMIDGenerator
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
export class UniDM {
|
|
346
|
-
/**
|
|
347
|
-
* 资源ID
|
|
348
|
-
* @description 由某一danuni服务确定的某一剧集下不同资源(不同视频站/字幕组具有细节差异)的ID
|
|
349
|
-
*/
|
|
350
|
-
@IsEmail({ require_tld: false })
|
|
351
|
-
@IsString()
|
|
352
|
-
@IsNotEmpty()
|
|
353
|
-
@Expose()
|
|
354
|
-
public SOID: string = ID.fromNull().toString()
|
|
355
|
-
/**
|
|
356
|
-
* 弹幕出现位置(单位s;精度为ms,即保留三位小数)
|
|
357
|
-
*/
|
|
358
|
-
@Min(0)
|
|
359
|
-
@IsNumber()
|
|
360
|
-
@IsNotEmpty()
|
|
361
|
-
@Expose()
|
|
362
|
-
public progress: number = 0
|
|
363
|
-
/**
|
|
364
|
-
* 弹幕类型
|
|
365
|
-
*/
|
|
366
|
-
@IsEnum(Modes)
|
|
367
|
-
@IsNotEmpty()
|
|
368
|
-
@Expose()
|
|
369
|
-
public mode: Modes = Modes.Normal
|
|
370
|
-
/**
|
|
371
|
-
* 字号
|
|
372
|
-
* @default 25
|
|
373
|
-
* - 12
|
|
374
|
-
* - 16
|
|
375
|
-
* - 18:小
|
|
376
|
-
* - 25:标准
|
|
377
|
-
* - 36:大
|
|
378
|
-
* - 45
|
|
379
|
-
* - 64
|
|
380
|
-
*/
|
|
381
|
-
@Max(64)
|
|
382
|
-
@Min(12)
|
|
383
|
-
@IsNumber()
|
|
384
|
-
@IsNotEmpty()
|
|
385
|
-
@Expose()
|
|
386
|
-
public fontsize: number = 25
|
|
387
|
-
/**
|
|
388
|
-
* 颜色
|
|
389
|
-
* @description 为DEC值(十进制RGB888值),默认白色
|
|
390
|
-
* @default 16777215
|
|
391
|
-
*/
|
|
392
|
-
@IsNumber()
|
|
393
|
-
@IsNotEmpty()
|
|
394
|
-
@Expose()
|
|
395
|
-
public color: number = 16777215
|
|
396
|
-
/**
|
|
397
|
-
* 发送者 senderID
|
|
398
|
-
*/
|
|
399
|
-
@IsEmail({ require_tld: false })
|
|
400
|
-
@IsString()
|
|
401
|
-
@IsNotEmpty()
|
|
402
|
-
@Expose()
|
|
403
|
-
public senderID: string = ID.fromNull().toString()
|
|
404
|
-
/**
|
|
405
|
-
* 正文
|
|
406
|
-
*/
|
|
407
|
-
@IsString()
|
|
408
|
-
@IsNotEmpty()
|
|
409
|
-
@Expose()
|
|
410
|
-
public content: string = ''
|
|
411
|
-
/**
|
|
412
|
-
* 发送时间
|
|
413
|
-
*/
|
|
414
|
-
@IsDate()
|
|
415
|
-
@IsNotEmpty()
|
|
416
|
-
@Expose()
|
|
417
|
-
public ctime: Date = new Date()
|
|
418
|
-
/**
|
|
419
|
-
* 权重 用于屏蔽等级 区间:[0,11]
|
|
420
|
-
* @description 参考B站,源弹幕有该参数则直接利用,
|
|
421
|
-
* 本实现默认取5,再经过ruleset匹配加减分数
|
|
422
|
-
* @description 为0时表示暂时未计算权重
|
|
423
|
-
*/
|
|
424
|
-
@Max(11)
|
|
425
|
-
@Min(0)
|
|
426
|
-
@IsInt()
|
|
427
|
-
@IsNotEmpty()
|
|
428
|
-
@Expose()
|
|
429
|
-
public weight: number = 0
|
|
430
|
-
/**
|
|
431
|
-
* 弹幕池 0:普通池 1:字幕池 2:特殊池(代码/BAS弹幕) 3:互动池(互动弹幕中选择投票快速发送的弹幕)
|
|
432
|
-
*/
|
|
433
|
-
@IsEnum(Pools)
|
|
434
|
-
@IsNotEmpty()
|
|
435
|
-
@Expose()
|
|
436
|
-
public pool: Pools = Pools.Def
|
|
437
|
-
/**
|
|
438
|
-
* 弹幕属性位(bin求AND)
|
|
439
|
-
* bit0:保护 bit1:直播 bit2:高赞
|
|
440
|
-
*/
|
|
441
|
-
@IsEnum(DMAttr, { each: true })
|
|
442
|
-
@IsNotEmpty()
|
|
443
|
-
@Expose()
|
|
444
|
-
public attr: DMAttr[] = []
|
|
445
|
-
/**
|
|
446
|
-
* 初始来源平台
|
|
447
|
-
* `danuni`与任意空值(可隐式转换为false的值)等价
|
|
448
|
-
*/
|
|
449
|
-
@IsString()
|
|
450
|
-
@IsOptional()
|
|
451
|
-
@Expose()
|
|
452
|
-
public platform?: PlatformDanmakuSource | string
|
|
453
|
-
/**
|
|
454
|
-
* 弹幕原始数据(不推荐使用)
|
|
455
|
-
* @description 适用于无法解析的B站代码弹幕、Artplayer弹幕样式等
|
|
456
|
-
* @description 初步约定:
|
|
457
|
-
* - Artplayer: style不为空时,将其JSON.stringify()存入
|
|
458
|
-
*/
|
|
459
|
-
@IsString()
|
|
460
|
-
@IsOptional()
|
|
461
|
-
@Expose()
|
|
462
|
-
public extraStr?: string
|
|
463
|
-
@IsString()
|
|
464
|
-
@IsOptional()
|
|
465
|
-
@Expose()
|
|
466
|
-
public DMID?: string
|
|
467
|
-
private options: Options = { dmid: createDMID }
|
|
468
|
-
@Expose()
|
|
469
|
-
init(options?: Options) {
|
|
470
|
-
this.options = options || this.options
|
|
471
|
-
const def = new UniDM()
|
|
472
|
-
|
|
473
|
-
if (this.options.dmid === undefined || this.options.dmid === true)
|
|
474
|
-
this.options.dmid = createDMID
|
|
475
|
-
|
|
476
|
-
this.content = String(this.content)
|
|
477
|
-
this.ctime = UniDM.transCtime(this.ctime)
|
|
478
|
-
|
|
479
|
-
if (!this.SOID) this.SOID = def.SOID
|
|
480
|
-
if (!this.progress) this.progress = def.progress
|
|
481
|
-
if (!this.mode) this.mode = def.mode
|
|
482
|
-
if (!this.fontsize) this.fontsize = def.fontsize
|
|
483
|
-
if (!this.color) this.color = def.color
|
|
484
|
-
if (!this.senderID) this.senderID = def.senderID
|
|
485
|
-
if (!this.content) this.content = def.content
|
|
486
|
-
if (!this.ctime) this.ctime = def.ctime
|
|
487
|
-
if (!this.weight) this.weight = def.weight
|
|
488
|
-
if (!this.pool) this.pool = def.pool
|
|
489
|
-
if (!this.attr) this.attr = def.attr
|
|
490
|
-
|
|
491
|
-
if (!this.DMID && this.options.dmid !== false) this.DMID = this.toDMID()
|
|
492
|
-
this.progress = Number.parseFloat(this.progress.toFixed(3))
|
|
493
|
-
if (this.extraStr)
|
|
494
|
-
this.extraStr = JSON.stringify(
|
|
495
|
-
cleanEmptyObjects(JSON.parse(this.extraStr)),
|
|
496
|
-
)
|
|
497
|
-
if (this.extraStr === '{}') this.extraStr = undefined
|
|
498
|
-
else if (this.mode !== Modes.Ext) {
|
|
499
|
-
const checkExtraBili = (obj?: ExtraBili) =>
|
|
500
|
-
obj
|
|
501
|
-
? (['adv', 'bas', 'code', 'command'] as (keyof ExtraBili)[]).some(
|
|
502
|
-
(k) => obj[k],
|
|
503
|
-
)
|
|
504
|
-
: false
|
|
505
|
-
if (
|
|
506
|
-
this.extra.artplayer ||
|
|
507
|
-
this.extra.danuni?.chapter ||
|
|
508
|
-
checkExtraBili(this.extra.bili)
|
|
509
|
-
)
|
|
510
|
-
this.mode = Modes.Ext
|
|
511
|
-
}
|
|
512
|
-
return this
|
|
513
|
-
}
|
|
514
|
-
@Expose()
|
|
515
|
-
async validate() {
|
|
516
|
-
return validateOrReject(this)
|
|
517
|
-
}
|
|
518
|
-
static create(pjson?: Partial<UniDMObj>, options?: Options) {
|
|
519
|
-
return pjson
|
|
520
|
-
? plainToInstance(
|
|
521
|
-
UniDM,
|
|
522
|
-
pjson.extra
|
|
523
|
-
? {
|
|
524
|
-
...pjson,
|
|
525
|
-
extraStr: pjson.extra
|
|
526
|
-
? JSON.stringify(pjson.extra)
|
|
527
|
-
: pjson.extraStr,
|
|
528
|
-
}
|
|
529
|
-
: pjson,
|
|
530
|
-
{ excludeExtraneousValues: true },
|
|
531
|
-
).init(options)
|
|
532
|
-
: new UniDM()
|
|
533
|
-
}
|
|
534
|
-
@Expose()
|
|
535
|
-
get extra(): Extra {
|
|
536
|
-
const extra = JSON.parse(this.extraStr || '{}')
|
|
537
|
-
// this.extraStr = JSON.stringify(cleanEmptyObjects(extra))
|
|
538
|
-
return extra
|
|
539
|
-
// return cleanEmptyObjects(extra) as Extra
|
|
540
|
-
}
|
|
541
|
-
@Expose()
|
|
542
|
-
get isFrom3rdPlatform() {
|
|
543
|
-
if (
|
|
544
|
-
this.platform &&
|
|
545
|
-
PlatformDanmakuSources.includes(this.platform as PlatformDanmakuSource)
|
|
546
|
-
)
|
|
547
|
-
return true
|
|
548
|
-
else return false
|
|
549
|
-
}
|
|
550
|
-
/**
|
|
551
|
-
* 弹幕id
|
|
552
|
-
* @description sha3-256(content+senderID+ctime)截取前8位
|
|
553
|
-
* @description 同一SOID下唯一
|
|
554
|
-
*/
|
|
555
|
-
@Expose()
|
|
556
|
-
toDMID() {
|
|
557
|
-
if (this.options.dmid === false) return
|
|
558
|
-
else if (this.options.dmid === true) return createDMID(this)
|
|
559
|
-
else if (typeof this.options.dmid === 'number')
|
|
560
|
-
return createDMID(this, this.options.dmid)
|
|
561
|
-
return this.options.dmid!(this)
|
|
562
|
-
}
|
|
563
|
-
@Expose()
|
|
564
|
-
isSameAs(dan: UniDM, options?: { skipDanuniMerge?: boolean }): boolean {
|
|
565
|
-
// 引用相同直接返回
|
|
566
|
-
if (this === dan) return true
|
|
567
|
-
// 不支持比较高级弹幕
|
|
568
|
-
if (this.mode === Modes.Ext || dan.mode === Modes.Ext) return false
|
|
569
|
-
// 合并过视为不同,防止存在合并完成弹幕后再次合并造成计数错误
|
|
570
|
-
if (
|
|
571
|
-
!options?.skipDanuniMerge &&
|
|
572
|
-
(this.extra.danuni?.merge || dan.extra.danuni?.merge)
|
|
573
|
-
)
|
|
574
|
-
return false
|
|
575
|
-
// 如果是bili弹幕,则以dmid判断是否相同
|
|
576
|
-
if (this.extra.bili?.dmid && dan.extra.bili?.dmid) {
|
|
577
|
-
// 当来源不同(标准源/创作中心源)时,视为不同弹幕
|
|
578
|
-
if (
|
|
579
|
-
(this.extra.bili.dmid && !dan.extra.bili.dmid) ||
|
|
580
|
-
(!this.extra.bili.dmid && dan.extra.bili.dmid)
|
|
581
|
-
)
|
|
582
|
-
return false
|
|
583
|
-
if (this.extra.bili.dmid === dan.extra.bili.dmid) return true
|
|
584
|
-
else return false
|
|
585
|
-
}
|
|
586
|
-
// 如果是artplayer弹幕,需额外比较extra项目
|
|
587
|
-
if (
|
|
588
|
-
(this.extra.artplayer && !dan.extra.artplayer) ||
|
|
589
|
-
(!this.extra.artplayer && dan.extra.artplayer)
|
|
590
|
-
)
|
|
591
|
-
return false
|
|
592
|
-
else if (
|
|
593
|
-
this.extra.artplayer &&
|
|
594
|
-
dan.extra.artplayer &&
|
|
595
|
-
(this.extra.artplayer.border !== dan.extra.artplayer.border ||
|
|
596
|
-
JSON.stringify(this.extra.artplayer.style) !==
|
|
597
|
-
JSON.stringify(dan.extra.artplayer.style))
|
|
598
|
-
)
|
|
599
|
-
return false
|
|
600
|
-
const isSame = (k: keyof UniDMObj) => this[k] === dan[k]
|
|
601
|
-
const checks = (
|
|
602
|
-
[
|
|
603
|
-
'SOID',
|
|
604
|
-
'content',
|
|
605
|
-
'mode',
|
|
606
|
-
'pool',
|
|
607
|
-
'platform',
|
|
608
|
-
] satisfies (keyof UniDMObj)[]
|
|
609
|
-
).every((k) => isSame(k))
|
|
610
|
-
// 忽略使用了extra字段却不在mode里标记的弹幕
|
|
611
|
-
return checks
|
|
612
|
-
}
|
|
613
|
-
@Expose()
|
|
614
|
-
minify() {
|
|
615
|
-
type UObj = Partial<UniDMObj> & Pick<UniDMObj, 'SOID'>
|
|
616
|
-
const def = new UniDM()
|
|
617
|
-
const result: UObj = { SOID: this.SOID }
|
|
618
|
-
if (this.progress !== def.progress) result.progress = this.progress
|
|
619
|
-
if (this.mode !== def.mode) result.mode = this.mode
|
|
620
|
-
if (this.fontsize !== def.fontsize) result.fontsize = this.fontsize
|
|
621
|
-
if (this.color !== def.color) result.color = this.color
|
|
622
|
-
if (this.senderID !== def.senderID) result.senderID = this.senderID
|
|
623
|
-
if (this.content !== def.content) result.content = this.content
|
|
624
|
-
if (this.weight !== def.weight) result.weight = this.weight
|
|
625
|
-
if (this.pool !== def.pool) result.pool = this.pool
|
|
626
|
-
if (this.attr.length > 0) result.attr = this.attr
|
|
627
|
-
if (this.platform !== undefined) result.platform = this.platform
|
|
628
|
-
if (this.extraStr && this.extraStr !== '{}') result.extraStr = this.extraStr
|
|
629
|
-
if (this.DMID !== undefined && this.options.dmid) result.DMID = this.DMID
|
|
630
|
-
return result
|
|
631
|
-
}
|
|
632
|
-
@Expose()
|
|
633
|
-
downgradeAdvcancedDan({
|
|
634
|
-
include,
|
|
635
|
-
exclude,
|
|
636
|
-
cleanExtra = false,
|
|
637
|
-
}: {
|
|
638
|
-
include?: (keyof Extra)[]
|
|
639
|
-
exclude?: (keyof Extra)[]
|
|
640
|
-
cleanExtra?: boolean
|
|
641
|
-
} = {}) {
|
|
642
|
-
if (this.extra) {
|
|
643
|
-
if (!include) include = []
|
|
644
|
-
if (!exclude) exclude = []
|
|
645
|
-
const check = (k: keyof Extra) =>
|
|
646
|
-
include?.includes(k) || !exclude?.includes(k)
|
|
647
|
-
// TODO 分别对 mode7/8/9 command artplayer等正常播放器无法绘制的弹幕做降级处理
|
|
648
|
-
const clone = UniDM.create(this)
|
|
649
|
-
clone.mode = Modes.Top
|
|
650
|
-
if (check('danuni') && clone.extra.danuni) {
|
|
651
|
-
const danuni = clone.extra.danuni
|
|
652
|
-
if (danuni.merge) {
|
|
653
|
-
const merge = danuni.merge
|
|
654
|
-
clone.content = `${this.content} x${merge.count}`
|
|
655
|
-
} else if (danuni.chapter) {
|
|
656
|
-
const chapter = danuni.chapter
|
|
657
|
-
if (chapter.type === ExtraDanUniChapterType.Cut)
|
|
658
|
-
clone.content = `[提示]${clone.platform}源${ExtraDanUniChapterTypeDict.chs[chapter.type]}了${chapter.duration}秒`
|
|
659
|
-
else if (chapter.type === ExtraDanUniChapterType.Duplicate)
|
|
660
|
-
clone.content = `[提示(${ExtraDanUniChapterTypeDict.chs[chapter.type]})]${clone.platform}源-${chapter.duration}秒`
|
|
661
|
-
else
|
|
662
|
-
clone.content = `[空降(${ExtraDanUniChapterTypeDict.chs[chapter.type]})]${TimeFormat.fromS(clone.progress + chapter.duration)}`
|
|
663
|
-
}
|
|
664
|
-
} else if (check('bili') && clone.extra.bili) {
|
|
665
|
-
const bili = clone.extra.bili
|
|
666
|
-
if (bili.mode === 7 && bili.adv) {
|
|
667
|
-
clone.content = `[B站高级弹幕]${JSON.parse(bili.adv)[4] || ''}`
|
|
668
|
-
} else if (bili.command) {
|
|
669
|
-
const command = bili.command
|
|
670
|
-
clone.content = `[B站指令弹幕]${command.content}`
|
|
671
|
-
clone.fontsize = 36
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
clone.senderID = 'compat[bot]@dan-any'
|
|
675
|
-
clone.attr.push(DMAttr.Compatible)
|
|
676
|
-
if (cleanExtra) clone.extraStr = undefined
|
|
677
|
-
return clone
|
|
678
|
-
} else return this
|
|
679
|
-
}
|
|
680
|
-
/**
|
|
681
|
-
* 将各种类型的时间进行格式化
|
|
682
|
-
* @param oriCtime
|
|
683
|
-
* @param tsUnit 当`oriCtime`为数字类型表时间戳时的单位;
|
|
684
|
-
* 为 毫秒(ms)/秒(s)
|
|
685
|
-
* @returns {Date} Date格式时间
|
|
686
|
-
*/
|
|
687
|
-
static transCtime(oriCtime: ctime, tsUnit?: 'ms' | 's'): Date {
|
|
688
|
-
function isMsTs(ts: number | bigint) {
|
|
689
|
-
if (tsUnit === 'ms') return true
|
|
690
|
-
else if (tsUnit === 's') return false
|
|
691
|
-
else return ts < 100000000
|
|
692
|
-
}
|
|
693
|
-
if (typeof oriCtime === 'number' || typeof oriCtime === 'bigint')
|
|
694
|
-
if (isMsTs(oriCtime)) return new Date(Number(oriCtime))
|
|
695
|
-
else return new Date(Number(oriCtime) * 1000)
|
|
696
|
-
else if (typeof oriCtime === 'string') {
|
|
697
|
-
if (/^\d+n$/.test(oriCtime))
|
|
698
|
-
return new Date(Number(oriCtime.slice(0, -1)))
|
|
699
|
-
// else return Date.parse(oriCtime)
|
|
700
|
-
else return new Date(oriCtime)
|
|
701
|
-
}
|
|
702
|
-
// } else if (typeof oriCtime === 'object') return BigInt(oriCtime.getTime())
|
|
703
|
-
else return oriCtime // BigInt(Date.now())
|
|
704
|
-
}
|
|
705
|
-
// static reviveCtime(ctime: bigint, fmt: ctimeFmt = ctimeFmt.bigintStr) {
|
|
706
|
-
// if (fmt === ctimeFmt.dateObj || fmt === ctimeFmt.dateStr) {
|
|
707
|
-
// const date = new Date(Number(ctime))
|
|
708
|
-
// if (fmt === ctimeFmt.dateStr) return date.toString()
|
|
709
|
-
// else return date
|
|
710
|
-
// } else return ctime.toString() + 'n'
|
|
711
|
-
// }
|
|
712
|
-
static transMode(
|
|
713
|
-
oriMode: number,
|
|
714
|
-
fmt: 'bili' | 'dplayer' | 'artplayer' | 'ddplay',
|
|
715
|
-
): Modes {
|
|
716
|
-
let mode = Modes.Normal
|
|
717
|
-
switch (fmt) {
|
|
718
|
-
case 'bili':
|
|
719
|
-
// 类型 1 2 3:普通弹幕 4:底部弹幕 5:顶部弹幕 6:逆向弹幕 7:高级弹幕 8:代码弹幕 9:BAS弹幕(pool必须为2)
|
|
720
|
-
switch (oriMode) {
|
|
721
|
-
case 4:
|
|
722
|
-
mode = Modes.Bottom
|
|
723
|
-
break
|
|
724
|
-
case 5:
|
|
725
|
-
mode = Modes.Top
|
|
726
|
-
break
|
|
727
|
-
case 6:
|
|
728
|
-
mode = Modes.Reverse
|
|
729
|
-
break
|
|
730
|
-
case 7:
|
|
731
|
-
mode = Modes.Ext
|
|
732
|
-
break
|
|
733
|
-
case 8:
|
|
734
|
-
mode = Modes.Ext
|
|
735
|
-
break
|
|
736
|
-
case 9:
|
|
737
|
-
mode = Modes.Ext
|
|
738
|
-
break
|
|
739
|
-
}
|
|
740
|
-
break
|
|
741
|
-
|
|
742
|
-
case 'dplayer':
|
|
743
|
-
if (oriMode === 1) mode = Modes.Top
|
|
744
|
-
else if (oriMode === 2) mode = Modes.Bottom
|
|
745
|
-
break
|
|
746
|
-
|
|
747
|
-
case 'artplayer':
|
|
748
|
-
if (oriMode === 1) mode = Modes.Top
|
|
749
|
-
else if (oriMode === 2) mode = Modes.Bottom
|
|
750
|
-
break
|
|
751
|
-
|
|
752
|
-
case 'ddplay':
|
|
753
|
-
// 弹幕模式:1-普通弹幕,4-底部弹幕,5-顶部弹幕
|
|
754
|
-
// 其适配为bili格式子集
|
|
755
|
-
mode = this.transMode(oriMode, 'bili')
|
|
756
|
-
break
|
|
757
|
-
|
|
758
|
-
default:
|
|
759
|
-
mode = Modes.Normal
|
|
760
|
-
break
|
|
761
|
-
}
|
|
762
|
-
return mode
|
|
763
|
-
}
|
|
764
|
-
static parseBiliSingle(p: string, c: string) {
|
|
765
|
-
const p_arr = p.split(',')
|
|
766
|
-
return {
|
|
767
|
-
content: c,
|
|
768
|
-
progress: Number.parseFloat(p_arr[0]),
|
|
769
|
-
mode: Number.parseInt(p_arr[1]),
|
|
770
|
-
fontsize: Number.parseInt(p_arr[2]),
|
|
771
|
-
color: Number.parseInt(p_arr[3]),
|
|
772
|
-
ctime: BigInt(p_arr[4]),
|
|
773
|
-
pool: Number.parseInt(p_arr[5]),
|
|
774
|
-
midHash: p_arr[6],
|
|
775
|
-
id: BigInt(p_arr[7]),
|
|
776
|
-
weight: Number.parseInt(p_arr[8]),
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
static fromBili(
|
|
780
|
-
args: DMBili,
|
|
781
|
-
cid?: bigint,
|
|
782
|
-
options?: Options,
|
|
783
|
-
recSOID?: string,
|
|
784
|
-
) {
|
|
785
|
-
interface TExtra extends Extra {
|
|
786
|
-
bili: ExtraBili
|
|
787
|
-
}
|
|
788
|
-
if (args.oid && !cid) cid = args.oid
|
|
789
|
-
const SOID =
|
|
790
|
-
recSOID || `def_${PlatformVideoSource.Bilibili}+${ID.fromBili({ cid })}`
|
|
791
|
-
const senderID = isEmail(args.midHash, { require_tld: false })
|
|
792
|
-
? args.midHash
|
|
793
|
-
: ID.fromBili({ midHash: args.midHash })
|
|
794
|
-
let mode: Modes
|
|
795
|
-
const pool = args.pool //暂时不做处理,兼容bili的pool格式
|
|
796
|
-
const extra: TExtra = {
|
|
797
|
-
bili: {
|
|
798
|
-
mode: args.mode,
|
|
799
|
-
pool: args.pool,
|
|
800
|
-
dmid: args.id,
|
|
801
|
-
attr: args.attr,
|
|
802
|
-
mid: args.mid,
|
|
803
|
-
},
|
|
804
|
-
}
|
|
805
|
-
//重复 transMode ,但此处有关于extra的额外处理
|
|
806
|
-
switch (args.mode) {
|
|
807
|
-
case 4:
|
|
808
|
-
mode = Modes.Bottom
|
|
809
|
-
break
|
|
810
|
-
case 5:
|
|
811
|
-
mode = Modes.Top
|
|
812
|
-
break
|
|
813
|
-
case 6:
|
|
814
|
-
mode = Modes.Reverse
|
|
815
|
-
break
|
|
816
|
-
case 7:
|
|
817
|
-
mode = Modes.Ext
|
|
818
|
-
extra.bili.adv = args.content
|
|
819
|
-
break
|
|
820
|
-
case 8:
|
|
821
|
-
mode = Modes.Ext
|
|
822
|
-
extra.bili.code = args.content
|
|
823
|
-
break
|
|
824
|
-
case 9:
|
|
825
|
-
mode = Modes.Ext
|
|
826
|
-
extra.bili.bas = args.content
|
|
827
|
-
break
|
|
828
|
-
|
|
829
|
-
default:
|
|
830
|
-
mode = Modes.Normal
|
|
831
|
-
break
|
|
832
|
-
}
|
|
833
|
-
return this.create(
|
|
834
|
-
{
|
|
835
|
-
...args,
|
|
836
|
-
SOID,
|
|
837
|
-
// progress: args.progress,
|
|
838
|
-
mode,
|
|
839
|
-
// fontsize: args.fontsize,
|
|
840
|
-
// color: args.color,
|
|
841
|
-
senderID: senderID.toString(),
|
|
842
|
-
// content: args.content,
|
|
843
|
-
ctime: this.transCtime(args.ctime, 's'),
|
|
844
|
-
weight: args.weight || (pool === Pools.Ix ? 1 : 0),
|
|
845
|
-
pool,
|
|
846
|
-
attr: DMAttrUtils.fromBin(args.attr, PlatformVideoSource.Bilibili),
|
|
847
|
-
platform: PlatformVideoSource.Bilibili,
|
|
848
|
-
// 需改进,7=>advanced 8=>code 9=>bas 互动=>command
|
|
849
|
-
// 同时塞进无法/无需直接解析的数据
|
|
850
|
-
// 另开一个解析器,为大部分播放器(无法解析该类dm)做文本类型降级处理
|
|
851
|
-
extra,
|
|
852
|
-
},
|
|
853
|
-
options,
|
|
854
|
-
)
|
|
855
|
-
}
|
|
856
|
-
@Expose()
|
|
857
|
-
toBiliXML(options?: {
|
|
858
|
-
skipBiliCommand?: boolean
|
|
859
|
-
/**
|
|
860
|
-
* 见 ../index.ts UniPool.toBiliXML() 的 options,该option不宜手动调用,判断逻辑未封装
|
|
861
|
-
*/
|
|
862
|
-
avoidSenderIDWithAt?: boolean
|
|
863
|
-
}) {
|
|
864
|
-
if (options?.skipBiliCommand && this.extra.bili?.command) {
|
|
865
|
-
return null
|
|
866
|
-
}
|
|
867
|
-
const recMode = (mode: Modes, extra?: ExtraBili) => {
|
|
868
|
-
switch (mode) {
|
|
869
|
-
case Modes.Normal:
|
|
870
|
-
return 1
|
|
871
|
-
case Modes.Bottom:
|
|
872
|
-
return 4
|
|
873
|
-
case Modes.Top:
|
|
874
|
-
return 5
|
|
875
|
-
case Modes.Reverse:
|
|
876
|
-
return 6
|
|
877
|
-
case Modes.Ext:
|
|
878
|
-
if (!extra) return 1
|
|
879
|
-
else if (extra.adv) return 7
|
|
880
|
-
else if (extra.code) return 8
|
|
881
|
-
else if (extra.bas) return 9
|
|
882
|
-
else return 1
|
|
883
|
-
default:
|
|
884
|
-
return 1
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
const rMode = this.extra.bili?.mode || recMode(this.mode, this.extra?.bili)
|
|
888
|
-
let content
|
|
889
|
-
switch (rMode) {
|
|
890
|
-
case 7:
|
|
891
|
-
content = this.extra?.bili?.adv
|
|
892
|
-
break
|
|
893
|
-
case 8:
|
|
894
|
-
content = this.extra?.bili?.code
|
|
895
|
-
break
|
|
896
|
-
case 9:
|
|
897
|
-
content = this.extra?.bili?.bas
|
|
898
|
-
break
|
|
899
|
-
default:
|
|
900
|
-
content = this.content
|
|
901
|
-
break
|
|
902
|
-
}
|
|
903
|
-
return {
|
|
904
|
-
'#text': content ?? this.content,
|
|
905
|
-
'@_p': [
|
|
906
|
-
this.progress,
|
|
907
|
-
rMode,
|
|
908
|
-
this.fontsize,
|
|
909
|
-
this.color,
|
|
910
|
-
this.ctime.getTime() / 1000,
|
|
911
|
-
this.extra.bili?.pool || this.pool, // 目前pool与bili兼容
|
|
912
|
-
options?.avoidSenderIDWithAt
|
|
913
|
-
? this.senderID.replaceAll(`@${PlatformVideoSource.Bilibili}`, '')
|
|
914
|
-
: this.senderID,
|
|
915
|
-
this.extra.bili?.dmid || this.DMID || this.toDMID(),
|
|
916
|
-
this.weight,
|
|
917
|
-
].join(','),
|
|
918
|
-
}
|
|
919
|
-
}
|
|
920
|
-
static fromBiliCommand(args: DMBiliCommand, cid?: bigint, options?: Options) {
|
|
921
|
-
if (args.oid && !cid) cid = args.oid
|
|
922
|
-
const SOID = `def_${PlatformVideoSource.Bilibili}+${ID.fromBili({ cid })}`
|
|
923
|
-
const senderID = ID.fromBili({ mid: args.mid })
|
|
924
|
-
return this.create(
|
|
925
|
-
{
|
|
926
|
-
...args,
|
|
927
|
-
SOID,
|
|
928
|
-
// progress: args.progress,
|
|
929
|
-
mode: Modes.Ext,
|
|
930
|
-
// fontsize: args.fontsize,
|
|
931
|
-
// color: args.color,
|
|
932
|
-
senderID: senderID.toString(),
|
|
933
|
-
// content: args.content,
|
|
934
|
-
ctime: new Date(`${args.ctime} GMT+0800`), // 无视本地时区,按照B站的东8区计算时间
|
|
935
|
-
weight: 11,
|
|
936
|
-
pool: Pools.Adv,
|
|
937
|
-
attr: [DMAttr.Protect],
|
|
938
|
-
platform: PlatformVideoSource.Bilibili,
|
|
939
|
-
extra: {
|
|
940
|
-
bili: {
|
|
941
|
-
dmid: args.id,
|
|
942
|
-
attr: args.attr,
|
|
943
|
-
mid: args.mid,
|
|
944
|
-
command: args,
|
|
945
|
-
},
|
|
946
|
-
},
|
|
947
|
-
},
|
|
948
|
-
options,
|
|
949
|
-
)
|
|
950
|
-
}
|
|
951
|
-
static fromDplayer(
|
|
952
|
-
args: DMDplayer,
|
|
953
|
-
playerID: string,
|
|
954
|
-
domain: string,
|
|
955
|
-
options?: Options,
|
|
956
|
-
) {
|
|
957
|
-
const SOID = ID.fromUnknown(playerID, domain)
|
|
958
|
-
const senderID = ID.fromUnknown(args.midHash, domain)
|
|
959
|
-
return this.create(
|
|
960
|
-
{
|
|
961
|
-
...args,
|
|
962
|
-
SOID: SOID.toString(),
|
|
963
|
-
// progress: args.progress,
|
|
964
|
-
mode: this.transMode(args.mode, 'dplayer'),
|
|
965
|
-
// fontsize: 25,
|
|
966
|
-
// color: args.color,
|
|
967
|
-
senderID: senderID.toString(),
|
|
968
|
-
// content: args.content,
|
|
969
|
-
platform: domain,
|
|
970
|
-
},
|
|
971
|
-
options,
|
|
972
|
-
)
|
|
973
|
-
}
|
|
974
|
-
@Expose()
|
|
975
|
-
toDplayer(): DMDplayer {
|
|
976
|
-
let mode = 0
|
|
977
|
-
if (this.mode === Modes.Top) mode = 1
|
|
978
|
-
else if (this.mode === Modes.Bottom) mode = 2
|
|
979
|
-
return {
|
|
980
|
-
mode,
|
|
981
|
-
progress: this.progress,
|
|
982
|
-
color: this.color,
|
|
983
|
-
midHash: this.senderID,
|
|
984
|
-
content: this.content,
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
static fromArtplayer(
|
|
988
|
-
args: DMArtplayer,
|
|
989
|
-
playerID: string,
|
|
990
|
-
domain: string,
|
|
991
|
-
options?: Options,
|
|
992
|
-
) {
|
|
993
|
-
const SOID = ID.fromUnknown(playerID, domain)
|
|
994
|
-
const senderID = ID.fromUnknown('', domain)
|
|
995
|
-
let extra = args.border
|
|
996
|
-
? ({ artplayer: { border: args.border, style: {} } } as Extra)
|
|
997
|
-
: undefined
|
|
998
|
-
if (args.style) {
|
|
999
|
-
if (extra)
|
|
1000
|
-
extra = {
|
|
1001
|
-
...extra,
|
|
1002
|
-
artplayer: {
|
|
1003
|
-
...extra.artplayer,
|
|
1004
|
-
border: args.border,
|
|
1005
|
-
style: args.style,
|
|
1006
|
-
},
|
|
1007
|
-
}
|
|
1008
|
-
else extra = { artplayer: { border: args.border, style: args.style } }
|
|
1009
|
-
}
|
|
1010
|
-
return this.create(
|
|
1011
|
-
{
|
|
1012
|
-
...args,
|
|
1013
|
-
SOID: SOID.toString(),
|
|
1014
|
-
// progress: args.progress,
|
|
1015
|
-
mode: this.transMode(args.mode, 'artplayer'),
|
|
1016
|
-
// fontsize: 25,
|
|
1017
|
-
// color: args.color,
|
|
1018
|
-
senderID: senderID.toString(),
|
|
1019
|
-
// content: args.content,
|
|
1020
|
-
platform: domain,
|
|
1021
|
-
extra, //optional BigINt parser
|
|
1022
|
-
},
|
|
1023
|
-
options,
|
|
1024
|
-
)
|
|
1025
|
-
}
|
|
1026
|
-
@Expose()
|
|
1027
|
-
toArtplayer(): DMArtplayer {
|
|
1028
|
-
let mode = 0
|
|
1029
|
-
if (this.mode === Modes.Top) mode = 1
|
|
1030
|
-
else if (this.mode === Modes.Bottom) mode = 2
|
|
1031
|
-
return {
|
|
1032
|
-
progress: this.progress,
|
|
1033
|
-
mode,
|
|
1034
|
-
color: this.color,
|
|
1035
|
-
content: this.content,
|
|
1036
|
-
border: this.extra.artplayer?.border,
|
|
1037
|
-
style: this.extra.artplayer?.style,
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
static fromDDPlay(
|
|
1041
|
-
args: DMDDPlay,
|
|
1042
|
-
episodeId: string,
|
|
1043
|
-
domain = PlatformDanmakuOnlySource.DanDanPlay,
|
|
1044
|
-
options?: Options,
|
|
1045
|
-
) {
|
|
1046
|
-
const SOID = ID.fromUnknown(
|
|
1047
|
-
`def_${PlatformDanmakuOnlySource.DanDanPlay}+${episodeId}`,
|
|
1048
|
-
domain,
|
|
1049
|
-
)
|
|
1050
|
-
return this.create(
|
|
1051
|
-
{
|
|
1052
|
-
...args,
|
|
1053
|
-
SOID: SOID.toString(),
|
|
1054
|
-
// progress: args.progress,
|
|
1055
|
-
mode: this.transMode(args.mode, 'ddplay'),
|
|
1056
|
-
// fontsize: 25,
|
|
1057
|
-
// color: args.color,
|
|
1058
|
-
senderID: args.uid,
|
|
1059
|
-
content: args.m,
|
|
1060
|
-
platform: domain,
|
|
1061
|
-
DMID: args.cid.toString(), //无需 new ID() 获取带suffix的ID
|
|
1062
|
-
},
|
|
1063
|
-
options,
|
|
1064
|
-
)
|
|
1065
|
-
}
|
|
1066
|
-
@Expose()
|
|
1067
|
-
toDDPlay(): DMDDPlay {
|
|
1068
|
-
let mode = 1
|
|
1069
|
-
if (this.mode === Modes.Top) mode = 5
|
|
1070
|
-
else if (this.mode === Modes.Bottom) mode = 4
|
|
1071
|
-
return {
|
|
1072
|
-
progress: this.progress,
|
|
1073
|
-
mode,
|
|
1074
|
-
color: this.color,
|
|
1075
|
-
uid: this.senderID,
|
|
1076
|
-
m: this.content,
|
|
1077
|
-
cid: this.DMID
|
|
1078
|
-
? BigInt(`0x${Buffer.from(this.DMID).toString('hex')}`)
|
|
1079
|
-
: 0n,
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
}
|