@dan-uni/dan-any 1.4.7 → 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.
Files changed (200) hide show
  1. package/README.md +87 -43
  2. package/dist/adapters.d.mts +2 -0
  3. package/dist/adapters.mjs +1 -0
  4. package/dist/chunk-0Lt9GpW0.mjs +1 -0
  5. package/dist/core/db/schema.d.mts +2 -0
  6. package/dist/core/db/schema.mjs +2 -0
  7. package/dist/core/db/schema.mjs.map +1 -0
  8. package/dist/core/db/utils.d.mts +1707 -0
  9. package/dist/core/db/utils.d.mts.map +1 -0
  10. package/dist/core/db/utils.mjs +1 -0
  11. package/dist/core-D7LMAB5h.mjs +2 -0
  12. package/dist/core-D7LMAB5h.mjs.map +1 -0
  13. package/dist/core.d.mts +2 -0
  14. package/dist/core.mjs +1 -0
  15. package/dist/db-DWWzkRBb.mjs +41 -0
  16. package/dist/db-DWWzkRBb.mjs.map +1 -0
  17. package/dist/dm-extra-DrAQCrFv.d.mts +135 -0
  18. package/dist/dm-extra-DrAQCrFv.d.mts.map +1 -0
  19. package/dist/dm-tkTdR_W6.mjs +2 -0
  20. package/dist/dm-tkTdR_W6.mjs.map +1 -0
  21. package/dist/index-vAs4qV9A.d.mts +6195 -0
  22. package/dist/index-vAs4qV9A.d.mts.map +1 -0
  23. package/dist/index.d.mts +4 -0
  24. package/dist/index.mjs +1 -0
  25. package/dist/isSame-D4G9eoE4.mjs +2 -0
  26. package/dist/isSame-D4G9eoE4.mjs.map +1 -0
  27. package/dist/plugins.d.mts +105 -0
  28. package/dist/plugins.d.mts.map +1 -0
  29. package/dist/plugins.mjs +2 -0
  30. package/dist/plugins.mjs.map +1 -0
  31. package/dist/schema-BuenbDx9.d.mts +1619 -0
  32. package/dist/schema-BuenbDx9.d.mts.map +1 -0
  33. package/dist/utils.d.mts +25 -0
  34. package/dist/utils.d.mts.map +1 -0
  35. package/dist/utils.mjs +2 -0
  36. package/dist/utils.mjs.map +1 -0
  37. package/package.json +65 -37
  38. package/.babelrc.json +0 -12
  39. package/buf.gen.yaml +0 -10
  40. package/buf.yaml +0 -12
  41. package/dist/browser/1~rslib-runtime.min.js +0 -49
  42. package/dist/browser/index.min.js +0 -13521
  43. package/dist/browser/index.min.js.LICENSE.txt +0 -17
  44. package/dist/browser/plugins/bili.min.js +0 -1
  45. package/dist/browser/plugins/index.min.js +0 -2
  46. package/dist/browser/plugins/stats.min.js +0 -10
  47. package/dist/browser/src/ass-gen/__tests__/canvas.test.d.ts +0 -1
  48. package/dist/browser/src/ass-gen/__tests__/generate.test.d.ts +0 -1
  49. package/dist/browser/src/ass-gen/ass/create.d.ts +0 -4
  50. package/dist/browser/src/ass-gen/ass/dialogue.d.ts +0 -16
  51. package/dist/browser/src/ass-gen/ass/event.d.ts +0 -2
  52. package/dist/browser/src/ass-gen/ass/info.d.ts +0 -8
  53. package/dist/browser/src/ass-gen/ass/raw.d.ts +0 -14
  54. package/dist/browser/src/ass-gen/ass/style.d.ts +0 -2
  55. package/dist/browser/src/ass-gen/config.d.ts +0 -2
  56. package/dist/browser/src/ass-gen/index.d.ts +0 -30
  57. package/dist/browser/src/ass-gen/types.d.ts +0 -71
  58. package/dist/browser/src/ass-gen/util/color.d.ts +0 -18
  59. package/dist/browser/src/ass-gen/util/danconvert.d.ts +0 -5
  60. package/dist/browser/src/ass-gen/util/index.d.ts +0 -4
  61. package/dist/browser/src/ass-gen/util/lang.d.ts +0 -3
  62. package/dist/browser/src/ass-gen/util/layout.d.ts +0 -4
  63. package/dist/browser/src/index.d.ts +0 -283
  64. package/dist/browser/src/index.test.d.ts +0 -1
  65. package/dist/browser/src/plugins/bili/dedupe.d.ts +0 -3
  66. package/dist/browser/src/plugins/bili/history-danmaku-fast-forward.d.ts +0 -18
  67. package/dist/browser/src/plugins/bili/index.d.ts +0 -2
  68. package/dist/browser/src/plugins/bili/index.test.d.ts +0 -1
  69. package/dist/browser/src/plugins/index.d.ts +0 -2
  70. package/dist/browser/src/plugins/stats/getLatestDan.d.ts +0 -6
  71. package/dist/browser/src/plugins/stats/index.d.ts +0 -1
  72. package/dist/browser/src/plugins/stats/index.test.d.ts +0 -1
  73. package/dist/browser/src/proto/gen/bilibili/community/service/dm/v1/dm_pb.d.ts +0 -3426
  74. package/dist/browser/src/proto/gen/danuni/danmaku/v1/danmaku_pb.d.ts +0 -176
  75. package/dist/browser/src/utils/dm-gen.d.ts +0 -309
  76. package/dist/browser/src/utils/dm-gen.test.d.ts +0 -1
  77. package/dist/browser/src/utils/fileParser.d.ts +0 -3
  78. package/dist/browser/src/utils/id-gen.d.ts +0 -50
  79. package/dist/browser/src/utils/platform.d.ts +0 -24
  80. package/dist/node/0~rslib-runtime.js +0 -23
  81. package/dist/node/index.js +0 -2097
  82. package/dist/node/plugins/bili.js +0 -1
  83. package/dist/node/plugins/index.js +0 -2
  84. package/dist/node/plugins/stats.js +0 -10
  85. package/dist/node/src/ass-gen/__tests__/canvas.test.d.ts +0 -1
  86. package/dist/node/src/ass-gen/__tests__/generate.test.d.ts +0 -1
  87. package/dist/node/src/ass-gen/ass/create.d.ts +0 -4
  88. package/dist/node/src/ass-gen/ass/dialogue.d.ts +0 -16
  89. package/dist/node/src/ass-gen/ass/event.d.ts +0 -2
  90. package/dist/node/src/ass-gen/ass/info.d.ts +0 -8
  91. package/dist/node/src/ass-gen/ass/raw.d.ts +0 -14
  92. package/dist/node/src/ass-gen/ass/style.d.ts +0 -2
  93. package/dist/node/src/ass-gen/config.d.ts +0 -2
  94. package/dist/node/src/ass-gen/index.d.ts +0 -30
  95. package/dist/node/src/ass-gen/types.d.ts +0 -71
  96. package/dist/node/src/ass-gen/util/color.d.ts +0 -18
  97. package/dist/node/src/ass-gen/util/danconvert.d.ts +0 -5
  98. package/dist/node/src/ass-gen/util/index.d.ts +0 -4
  99. package/dist/node/src/ass-gen/util/lang.d.ts +0 -3
  100. package/dist/node/src/ass-gen/util/layout.d.ts +0 -4
  101. package/dist/node/src/index.d.ts +0 -283
  102. package/dist/node/src/index.test.d.ts +0 -1
  103. package/dist/node/src/plugins/bili/dedupe.d.ts +0 -3
  104. package/dist/node/src/plugins/bili/history-danmaku-fast-forward.d.ts +0 -18
  105. package/dist/node/src/plugins/bili/index.d.ts +0 -2
  106. package/dist/node/src/plugins/bili/index.test.d.ts +0 -1
  107. package/dist/node/src/plugins/index.d.ts +0 -2
  108. package/dist/node/src/plugins/stats/getLatestDan.d.ts +0 -6
  109. package/dist/node/src/plugins/stats/index.d.ts +0 -1
  110. package/dist/node/src/plugins/stats/index.test.d.ts +0 -1
  111. package/dist/node/src/proto/gen/bilibili/community/service/dm/v1/dm_pb.d.ts +0 -3426
  112. package/dist/node/src/proto/gen/danuni/danmaku/v1/danmaku_pb.d.ts +0 -176
  113. package/dist/node/src/utils/dm-gen.d.ts +0 -309
  114. package/dist/node/src/utils/dm-gen.test.d.ts +0 -1
  115. package/dist/node/src/utils/fileParser.d.ts +0 -3
  116. package/dist/node/src/utils/id-gen.d.ts +0 -50
  117. package/dist/node/src/utils/platform.d.ts +0 -24
  118. package/dist/umd/index.umd.min.js +0 -32091
  119. package/dist/umd/index.umd.min.js.LICENSE.txt +0 -34
  120. package/dist/umd/plugins/bili.umd.min.js +0 -32002
  121. package/dist/umd/plugins/bili.umd.min.js.LICENSE.txt +0 -34
  122. package/dist/umd/plugins/index.umd.min.js +0 -32018
  123. package/dist/umd/plugins/index.umd.min.js.LICENSE.txt +0 -34
  124. package/dist/umd/plugins/stats.umd.min.js +0 -39
  125. package/dist/umd/src/ass-gen/__tests__/canvas.test.d.ts +0 -1
  126. package/dist/umd/src/ass-gen/__tests__/generate.test.d.ts +0 -1
  127. package/dist/umd/src/ass-gen/ass/create.d.ts +0 -4
  128. package/dist/umd/src/ass-gen/ass/dialogue.d.ts +0 -16
  129. package/dist/umd/src/ass-gen/ass/event.d.ts +0 -2
  130. package/dist/umd/src/ass-gen/ass/info.d.ts +0 -8
  131. package/dist/umd/src/ass-gen/ass/raw.d.ts +0 -14
  132. package/dist/umd/src/ass-gen/ass/style.d.ts +0 -2
  133. package/dist/umd/src/ass-gen/config.d.ts +0 -2
  134. package/dist/umd/src/ass-gen/index.d.ts +0 -30
  135. package/dist/umd/src/ass-gen/types.d.ts +0 -71
  136. package/dist/umd/src/ass-gen/util/color.d.ts +0 -18
  137. package/dist/umd/src/ass-gen/util/danconvert.d.ts +0 -5
  138. package/dist/umd/src/ass-gen/util/index.d.ts +0 -4
  139. package/dist/umd/src/ass-gen/util/lang.d.ts +0 -3
  140. package/dist/umd/src/ass-gen/util/layout.d.ts +0 -4
  141. package/dist/umd/src/index.d.ts +0 -283
  142. package/dist/umd/src/index.test.d.ts +0 -1
  143. package/dist/umd/src/plugins/bili/dedupe.d.ts +0 -3
  144. package/dist/umd/src/plugins/bili/history-danmaku-fast-forward.d.ts +0 -18
  145. package/dist/umd/src/plugins/bili/index.d.ts +0 -2
  146. package/dist/umd/src/plugins/bili/index.test.d.ts +0 -1
  147. package/dist/umd/src/plugins/index.d.ts +0 -2
  148. package/dist/umd/src/plugins/stats/getLatestDan.d.ts +0 -6
  149. package/dist/umd/src/plugins/stats/index.d.ts +0 -1
  150. package/dist/umd/src/plugins/stats/index.test.d.ts +0 -1
  151. package/dist/umd/src/proto/gen/bilibili/community/service/dm/v1/dm_pb.d.ts +0 -3426
  152. package/dist/umd/src/proto/gen/danuni/danmaku/v1/danmaku_pb.d.ts +0 -176
  153. package/dist/umd/src/utils/dm-gen.d.ts +0 -309
  154. package/dist/umd/src/utils/dm-gen.test.d.ts +0 -1
  155. package/dist/umd/src/utils/fileParser.d.ts +0 -3
  156. package/dist/umd/src/utils/id-gen.d.ts +0 -50
  157. package/dist/umd/src/utils/platform.d.ts +0 -24
  158. package/plugins/package.json +0 -6
  159. package/rslib.config.ts +0 -101
  160. package/src/ass-gen/__tests__/898651903.xml +0 -1619
  161. package/src/ass-gen/__tests__/898651903.xml.ass +0 -1516
  162. package/src/ass-gen/__tests__/canvas.test.ts +0 -15
  163. package/src/ass-gen/__tests__/generate.test.ts +0 -26
  164. package/src/ass-gen/ass/create.ts +0 -37
  165. package/src/ass-gen/ass/dialogue.ts +0 -90
  166. package/src/ass-gen/ass/event.ts +0 -57
  167. package/src/ass-gen/ass/info.ts +0 -27
  168. package/src/ass-gen/ass/raw.ts +0 -78
  169. package/src/ass-gen/ass/style.ts +0 -66
  170. package/src/ass-gen/config.ts +0 -45
  171. package/src/ass-gen/index.ts +0 -73
  172. package/src/ass-gen/types.ts +0 -76
  173. package/src/ass-gen/util/color.ts +0 -55
  174. package/src/ass-gen/util/danconvert.ts +0 -43
  175. package/src/ass-gen/util/index.ts +0 -10
  176. package/src/ass-gen/util/lang.ts +0 -35
  177. package/src/ass-gen/util/layout.ts +0 -242
  178. package/src/index.test.ts +0 -157
  179. package/src/index.ts +0 -1144
  180. package/src/plugins/bili/README.md +0 -87
  181. package/src/plugins/bili/dedupe.ts +0 -29
  182. package/src/plugins/bili/history-danmaku-fast-forward.ts +0 -86
  183. package/src/plugins/bili/index.test.ts +0 -129
  184. package/src/plugins/bili/index.ts +0 -2
  185. package/src/plugins/index.ts +0 -2
  186. package/src/plugins/stats/README.md +0 -44
  187. package/src/plugins/stats/getLatestDan.ts +0 -13
  188. package/src/plugins/stats/index.test.ts +0 -39
  189. package/src/plugins/stats/index.ts +0 -1
  190. package/src/proto/gen/bilibili/community/service/dm/v1/dm_pb.ts +0 -4072
  191. package/src/proto/gen/danuni/danmaku/v1/danmaku_pb.ts +0 -223
  192. package/src/proto/src/bilibili/community/service/dm/v1/dm.proto +0 -1095
  193. package/src/proto/src/danuni/danmaku/v1/danmaku.proto +0 -52
  194. package/src/utils/dm-gen.test.ts +0 -129
  195. package/src/utils/dm-gen.ts +0 -1078
  196. package/src/utils/fileParser.ts +0 -37
  197. package/src/utils/id-gen.ts +0 -73
  198. package/src/utils/platform.ts +0 -38
  199. package/tsconfig.json +0 -108
  200. package/types/tsconfig.tsbuildinfo +0 -1
@@ -1,15 +0,0 @@
1
- import { createCanvas } from 'canvas'
2
- import { assertType, it } from 'vitest'
3
-
4
- import { measureTextWidthConstructor } from '../util/layout'
5
-
6
- it('canvas measureTextWidth', () => {
7
- const text = '一段测试文字'
8
- const canvas = createCanvas(50, 50)
9
- const width = measureTextWidthConstructor(
10
- canvas.getContext('2d') as unknown as CanvasRenderingContext2D,
11
- )('SimHei', 25, false, text)
12
- assertType<number>(width)
13
- console.info(width, text.length)
14
- // assert(width >= 25 * text.length)
15
- })
@@ -1,26 +0,0 @@
1
- import fs from 'node:fs'
2
- import path, { dirname } from 'node:path'
3
- import { fileURLToPath } from 'node:url'
4
- import { createCanvas } from 'canvas'
5
- import { it } from 'vitest'
6
-
7
- import { generateASS } from '../'
8
- import { UniPool } from '../..'
9
-
10
- const __dirname = dirname(fileURLToPath(import.meta.url))
11
-
12
- it('generate ass from xml', () => {
13
- const filename = '898651903.xml'
14
- const xmlPath = path.join(__dirname, filename)
15
- const xmlText = fs.readFileSync(xmlPath, 'utf8')
16
- const canvas = createCanvas(50, 50)
17
- const assText = generateASS(
18
- UniPool.fromBiliXML(xmlText),
19
- {
20
- // filename,
21
- // title: '我的忏悔',
22
- },
23
- canvas.getContext('2d') as unknown as CanvasRenderingContext2D,
24
- )
25
- fs.writeFileSync(path.join(__dirname, `${filename}.ass`), assText, 'utf8')
26
- })
@@ -1,37 +0,0 @@
1
- import type { UniPool } from '../..'
2
- import type { Context, SubtitleStyle } from '../types'
3
- import type { RawConfig } from './raw'
4
-
5
- import { UniPool2DanmakuLists } from '../util'
6
- import { event } from './event'
7
- import { info } from './info'
8
- import { raw } from './raw'
9
- import { style } from './style'
10
-
11
- const default_context = { filename: 'unknown', title: 'unknown' }
12
-
13
- export const ass = (
14
- list: UniPool,
15
- rawList: UniPool,
16
- config: SubtitleStyle,
17
- context: Context = default_context,
18
- rawConfig?: RawConfig,
19
- ) => {
20
- const Elist = UniPool2DanmakuLists(list)
21
- const ErawList = UniPool2DanmakuLists(rawList)
22
- const content = [info(config, context), style(config), event(Elist, config)]
23
-
24
- if (config.includeRaw) {
25
- content.push(
26
- raw(
27
- ErawList,
28
- config,
29
- context,
30
- rawConfig?.compressType,
31
- rawConfig?.baseType,
32
- ),
33
- )
34
- }
35
-
36
- return `${content.join('\n\n')}\n`
37
- }
@@ -1,90 +0,0 @@
1
- import type { RGB } from '../types'
2
-
3
- import { DanmakuType } from '../types'
4
- import { formatColor, getDecoratingColor, isWhite } from '../util'
5
-
6
- // Dialogue: 0,0:00:00.00,0:00:08.00,R2L,,20,20,2,,{\move(622.5,25,-62.5,25)}标准小裤裤
7
- // Dialogue: 0,0:00:08.35,0:00:12.35,Fix,,20,20,2,,{\pos(280,50)\c&HEAA000}没男主吗
8
-
9
- const formatTime = (seconds: number) => {
10
- const div = (i: number, j: number) => Math.floor(i / j)
11
- const pad = (n: number) => (n < 10 ? `0${n}` : String(n))
12
-
13
- const integer = Math.floor(seconds)
14
- const hour = div(integer, 60 * 60)
15
- const minute = div(integer, 60) % 60
16
- const second = integer % 60
17
- const minorSecond = Math.floor((seconds - integer) * 100) // 取小数部分2位
18
-
19
- return `${hour}:${pad(minute)}:${pad(second)}.${minorSecond}`
20
- }
21
-
22
- const encode = (text: string) =>
23
- text
24
- .toString()
25
- .replaceAll('{', '{')
26
- .replaceAll('}', '}')
27
- .replaceAll(/\r|\n/g, '')
28
-
29
- const scrollCommand = ({
30
- start,
31
- end,
32
- top,
33
- }: {
34
- start: number
35
- end: number
36
- top: number
37
- }) => String.raw`\move(${start},${top},${end},${top})`
38
- const fixCommand = ({ top, left }: { top: number; left: number }) =>
39
- String.raw`\an8\pos(${left},${top})`
40
- const colorCommand = (color: RGB) => String.raw`\c${formatColor(color)}`
41
- const borderColorCommand = (color: RGB) => String.raw`\3c${formatColor(color)}`
42
-
43
- export const dialogue = (
44
- danmaku: {
45
- type: (typeof DanmakuType)[keyof typeof DanmakuType]
46
- color: RGB
47
- fontSizeType: number
48
- content: string
49
- time: number
50
- start: number
51
- end: number
52
- top: number
53
- left: number
54
- },
55
- config: { scrollTime: number; fixTime: number },
56
- ) => {
57
- const { fontSizeType, content, time } = danmaku
58
- const { scrollTime, fixTime } = config
59
-
60
- const commands = [
61
- danmaku.type === DanmakuType.SCROLL
62
- ? scrollCommand({
63
- start: danmaku.start,
64
- end: danmaku.end,
65
- top: danmaku.top,
66
- })
67
- : fixCommand({ top: danmaku.top, left: danmaku.left }),
68
- // 所有网站的原始默认色是白色,所以白色的时候不用额外加和颜色相关的指令
69
- isWhite(danmaku.color) ? '' : colorCommand(danmaku.color),
70
- isWhite(danmaku.color)
71
- ? ''
72
- : borderColorCommand(getDecoratingColor(danmaku.color)),
73
- ]
74
- const fields = [
75
- 0, // Layer,
76
- formatTime(time), // Start
77
- formatTime(
78
- time + (danmaku.type === DanmakuType.SCROLL ? scrollTime : fixTime),
79
- ), // End
80
- `F${fontSizeType}`, // Style
81
- '', // Name
82
- '0000', // MarginL
83
- '0000', // MarginR
84
- '0000', // MarginV
85
- '', // Effect
86
- `{${commands.join('')}}${encode(content)}`, // Text
87
- ]
88
-
89
- return `Dialogue: ${fields.join(',')}`
90
- }
@@ -1,57 +0,0 @@
1
- import type { Danmaku, SubtitleStyle } from '../types'
2
-
3
- import { DanmakuType } from '../types'
4
- import { dialogue } from './dialogue'
5
-
6
- const calculateDanmakuPosition = (danmaku: Danmaku, config: SubtitleStyle) => {
7
- const { playResX, playResY, scrollTime, fixTime } = config
8
-
9
- switch (danmaku.type) {
10
- case DanmakuType.SCROLL: {
11
- const start = playResX
12
- const end = -playResX / 10 // Some extra space for complete exit
13
- const top = (danmaku.fontSizeType * playResY) / 20
14
- return {
15
- ...danmaku,
16
- start,
17
- end,
18
- top,
19
- left: 0,
20
- duration: scrollTime,
21
- }
22
- }
23
- case DanmakuType.TOP:
24
- case DanmakuType.BOTTOM: {
25
- const left = playResX / 2
26
- const top =
27
- danmaku.type === DanmakuType.TOP
28
- ? (danmaku.fontSizeType * playResY) / 20
29
- : playResY -
30
- config.bottomSpace -
31
- (danmaku.fontSizeType * playResY) / 20
32
- return {
33
- ...danmaku,
34
- start: 0,
35
- end: 0,
36
- top,
37
- left,
38
- duration: fixTime,
39
- }
40
- }
41
- default:
42
- throw new Error(`Unknown danmaku type: ${danmaku.type}`)
43
- }
44
- }
45
-
46
- export const event = (list: Danmaku[], config: SubtitleStyle) => {
47
- const content = [
48
- '[Events]',
49
- 'Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text',
50
- ...list.map((danmaku) => {
51
- const positionedDanmaku = calculateDanmakuPosition(danmaku, config)
52
- return dialogue(positionedDanmaku, config)
53
- }),
54
- ]
55
-
56
- return content.join('\n')
57
- }
@@ -1,27 +0,0 @@
1
- import type { Context } from '../types'
2
-
3
- import pkg from '../../../package.json' with { type: 'json' }
4
-
5
- type ExtraInfo = Context
6
-
7
- type Resolution = {
8
- playResX: number
9
- playResY: number
10
- }
11
-
12
- export const info = (
13
- { playResX, playResY }: Resolution,
14
- { filename, title }: ExtraInfo,
15
- ) => {
16
- const content = [
17
- '[Script Info]',
18
- `Title: ${title}`,
19
- `Original Script: 根据 ${filename} 的弹幕信息,由 ${pkg.homepage} 生成`,
20
- 'ScriptType: v4.00+',
21
- 'Collisions: Reverse',
22
- `PlayResX: ${playResX}`,
23
- `PlayResY: ${playResY}`,
24
- 'Timer: 100.0000',
25
- ]
26
- return content.join('\n')
27
- }
@@ -1,78 +0,0 @@
1
- import {
2
- brotliCompressSync,
3
- brotliDecompressSync,
4
- gunzipSync,
5
- gzipSync,
6
- } from 'node:zlib'
7
- import * as base16384 from 'base16384'
8
- import type { Context, Danmaku, SubtitleStyle } from '../types'
9
-
10
- type compressType = 'brotli' | 'gzip'
11
- type baseType = 'base64' | 'base18384'
12
- const compressTypes = new Set(['brotli', 'gzip'])
13
- const baseTypes = new Set(['base64', 'base18384'])
14
-
15
- export interface RawConfig {
16
- compressType: compressType
17
- baseType: baseType
18
- }
19
-
20
- function fromUint16Array(array: Uint16Array): string {
21
- let result = ''
22
- for (const element of array) {
23
- result += String.fromCodePoint(element)
24
- }
25
- return result
26
- }
27
-
28
- export function raw(
29
- list: Danmaku[],
30
- config: SubtitleStyle,
31
- context: Context,
32
- compressType: compressType = 'brotli',
33
- baseType: baseType = 'base18384',
34
- ) {
35
- const raw = { list, config, context }
36
- const rawText = JSON.stringify(raw)
37
- let compress: Buffer
38
- if (compressType === 'brotli') compress = brotliCompressSync(rawText)
39
- else compress = gzipSync(rawText)
40
- return `;RawCompressType: ${compressType}\n;RawBaseType: ${baseType}\n;Raw: ${baseType === 'base64' ? compress.toString('base64') : fromUint16Array(base16384.encode(compress))}`
41
- }
42
-
43
- export function deRaw(ass: string):
44
- | {
45
- list: Danmaku[]
46
- config: SubtitleStyle
47
- context: Context
48
- }
49
- | undefined {
50
- const arr = ass.split('\n')
51
- const lineCompressType = arr.find((line) =>
52
- line.startsWith(';RawCompressType:'),
53
- )
54
- const lineBaseType = arr.find((line) => line.startsWith(';RawBaseType:'))
55
- const lineRaw = arr.find((line) => line.startsWith(';Raw:'))
56
- if (!lineCompressType || !lineBaseType || !lineRaw) return undefined
57
- else {
58
- let compressType = lineCompressType.replace(';RawCompressType: ', '').trim()
59
- let baseType = lineBaseType.replace(';RawBaseType: ', '').trim()
60
- if (!compressTypes.has(compressType)) compressType = 'gzip'
61
- if (!baseTypes.has(baseType)) baseType = 'base64'
62
- const text = lineRaw.replace(';Raw: ', '').trim()
63
- const buffer =
64
- baseType === 'base64'
65
- ? Buffer.from(text, 'base64')
66
- : Buffer.from(
67
- base16384.decode(Buffer.from(text, 'utf8').toString('utf8')),
68
- )
69
- let decompress: Buffer
70
- if (compressType === 'brotli') decompress = brotliDecompressSync(buffer)
71
- else decompress = gunzipSync(buffer)
72
- try {
73
- return JSON.parse(decompress.toString('utf8'))
74
- } catch {
75
- return undefined
76
- }
77
- }
78
- }
@@ -1,66 +0,0 @@
1
- import type { SubtitleStyle } from '../types'
2
-
3
- import { formatColor, getDecoratingColor, hexColorToRGB } from '../util'
4
-
5
- export const style = ({
6
- fontName,
7
- fontSize,
8
- color: configColor,
9
- outlineColor,
10
- backColor,
11
- bold,
12
- outline,
13
- shadow,
14
- opacity,
15
- }: SubtitleStyle) => {
16
- const fields = [
17
- 'Name',
18
- 'Fontname',
19
- 'Fontsize',
20
- 'PrimaryColour',
21
- 'SecondaryColour',
22
- 'OutlineColour',
23
- 'BackColour',
24
- 'Bold',
25
- 'Italic',
26
- 'Underline',
27
- 'StrikeOut',
28
- 'ScaleX',
29
- 'ScaleY',
30
- 'Spacing',
31
- 'Angle',
32
- 'BorderStyle',
33
- 'Outline',
34
- 'Shadow',
35
- 'Alignment',
36
- 'MarginL',
37
- 'MarginR',
38
- 'MarginV',
39
- 'Encoding',
40
- ]
41
- // 默认白底黑框
42
- const primaryColorValue = formatColor(hexColorToRGB(configColor), opacity)
43
- // 边框和阴影颜色没给的话算一个出来,不是黑就是白
44
- const secondaryColor = getDecoratingColor(hexColorToRGB(configColor))
45
- const outlineColorValue = formatColor(
46
- outlineColor ? hexColorToRGB(outlineColor) : secondaryColor,
47
- opacity,
48
- )
49
- const backColorValue = formatColor(
50
- backColor ? hexColorToRGB(backColor) : secondaryColor,
51
- opacity,
52
- )
53
- const colorStyle = `${primaryColorValue},${primaryColorValue},${outlineColorValue},${backColorValue}`
54
-
55
- const boldValue = bold ? '1' : '0'
56
- const fontStyle = `${boldValue},0,0,0,100,100,0,0,1,${outline},${shadow},7,0,0,0,0`
57
-
58
- const fontDeclaration = (size: number, i: number) =>
59
- `Style: F${i},${fontName},${size},${colorStyle},${fontStyle}`
60
- const content = [
61
- '[V4+ Styles]',
62
- `Format: ${fields.join(',')}`,
63
- ...fontSize.map(fontDeclaration),
64
- ]
65
- return content.join('\n')
66
- }
@@ -1,45 +0,0 @@
1
- import type { SubtitleStyle } from './types'
2
-
3
- import { assign, formatColor, hexColorToRGB } from './util'
4
-
5
- // const builtinRules = {
6
- // COLOR: true,
7
- // TOP: true,
8
- // BOTTOM: true
9
- // }
10
-
11
- // const convertBlockRule = (rule: string) =>
12
- // builtinRules[rule] ? rule : new RegExp(rule)
13
-
14
- export const getConfig = (overrides = {}): SubtitleStyle => {
15
- const defaults = {
16
- fontSize: [25, 25, 36],
17
- fontName: 'SimHei',
18
- color: '#ffffff',
19
- outlineColor: undefined,
20
- backColor: undefined,
21
- outline: 2,
22
- shadow: 0,
23
- bold: false,
24
- padding: [2, 2, 2, 2],
25
- playResX: 1920,
26
- playResY: 1080,
27
- scrollTime: 8,
28
- fixTime: 4,
29
- opacity: 0.6,
30
- bottomSpace: 60,
31
- includeRaw: true,
32
- mergeIn: -1,
33
- // block: [],
34
- }
35
-
36
- const config = assign(defaults, overrides)
37
- config.color = formatColor(hexColorToRGB(config.color))
38
- config.outlineColor =
39
- config.outlineColor && formatColor(hexColorToRGB(config.outlineColor))
40
- config.backColor =
41
- config.backColor && formatColor(hexColorToRGB(config.backColor))
42
- // config.block = uniqueArray(config.block).map(convertBlockRule)
43
-
44
- return config
45
- }
@@ -1,73 +0,0 @@
1
- // import parse from './parse/bilibili'
2
- import type { Options as UniPoolOptions } from '..'
3
- import type { RawConfig } from './ass/raw'
4
- import type { CanvasCtx, SubtitleStyle } from './types'
5
-
6
- import { UniPool } from '..'
7
- import { ass } from './ass/create'
8
- import { deRaw } from './ass/raw'
9
- import { getConfig } from './config'
10
- import { DanmakuList2UniPool, layoutDanmaku } from './util'
11
-
12
- export { CanvasCtx }
13
-
14
- export type Options = {
15
- filename?: string
16
- title?: string
17
- substyle?: Partial<SubtitleStyle>
18
- raw?: RawConfig
19
- }
20
-
21
- /**
22
- * 使用bilibili弹幕(XMl)生成ASS字幕文件
23
- * @param {string} danmaku XML弹幕文件内容
24
- * @param {Options} options 杂项
25
- * @returns {string} 返回ASS字幕文件内容
26
- * @description 杂项相关
27
- `filename`: 还原文件为XML时使用的默认文件名
28
- `title`: ASS [Script Info] Title 项的值,显示于播放器字幕选择
29
- `substyle`: ASS字幕样式
30
- * @example ```ts
31
- import fs from 'fs'
32
- const filename = 'example.xml'
33
- const xmlText = fs.readFileSync(filename, 'utf-8')
34
- const assText = generateASS(xmlText, { filename, title: 'Quick Example' })
35
- fs.writeFileSync(`${filename}.ass`, assText, 'utf-8')
36
- ```
37
- */
38
- export function generateASS(
39
- danmaku: UniPool,
40
- options: Options,
41
- canvasCtx: CanvasCtx,
42
- ): string {
43
- // const result = parse(text)
44
- const config = getConfig(options.substyle)
45
- // const filteredList = filterDanmaku(result.list, config.block)
46
- // const mergedList = mergeDanmaku(result.list, config.mergeIn)
47
- const mergedList = danmaku.merge(config.mergeIn)
48
- const layoutList = layoutDanmaku(mergedList, config, canvasCtx)
49
- const content = ass(
50
- layoutList,
51
- danmaku,
52
- config,
53
- {
54
- filename: options?.filename || 'unknown',
55
- title: options?.title || 'unknown',
56
- },
57
- options.raw,
58
- )
59
-
60
- return content
61
- }
62
-
63
- export function parseAssRawField(
64
- ass: string,
65
- options?: UniPoolOptions,
66
- ): UniPool {
67
- const raw = deRaw(ass)
68
- if (raw) {
69
- return DanmakuList2UniPool(raw.list, options)
70
- } else {
71
- return UniPool.create()
72
- }
73
- }
@@ -1,76 +0,0 @@
1
- // export type BlockRule = string | RegExp
2
- import type { CanvasRenderingContext2D as NodeCRCtx2D } from 'canvas'
3
- import type { UniDM } from '../utils/dm-gen'
4
-
5
- /**
6
- * 请根据您的使用环境提供一个 50x50 的 2D Canvas 上下文
7
- * @example
8
- * // Node.js + canvas
9
- * import { createCanvas } from 'canvas'
10
- * const canvas = createCanvas(50, 50)
11
- * const ctx = canvas.getContext('2d')
12
- * @example
13
- * // Node.js + Fabric.js
14
- * import { StaticCanvas } from 'fabric/node'
15
- * const ctx = new StaticCanvas(null, { width: 50, height: 50 }).getContext()
16
- * @example
17
- * // Browser + Native Canvas
18
- * const canvas = document.createElement('canvas')
19
- * canvas.width = 50
20
- * canvas.height = 50
21
- * const ctx = canvas.getContext('2d')
22
- * @example
23
- * // Browser + Fabric.js
24
- * import { Canvas } from 'fabric'
25
- * const ctx = new Canvas('canvas', { width: 50, height: 50 }).getContext()
26
- */
27
- export type CanvasCtx = NodeCRCtx2D | CanvasRenderingContext2D
28
-
29
- export interface Context {
30
- filename: string
31
- title: string
32
- }
33
-
34
- export interface SubtitleStyle {
35
- fontSize: number[]
36
- fontName: string
37
- color: string
38
- outlineColor?: string
39
- backColor?: string
40
- outline: number
41
- shadow: number
42
- bold: boolean
43
- padding: number[]
44
- playResX: number
45
- playResY: number
46
- scrollTime: number
47
- fixTime: number
48
- opacity: number
49
- bottomSpace: number
50
- // block: BlockRule[]
51
- includeRaw: boolean
52
- mergeIn: number
53
- }
54
-
55
- export type RGB = { r: number; g: number; b: number }
56
-
57
- export const DanmakuType = {
58
- SCROLL: 1,
59
- BOTTOM: 2,
60
- TOP: 3,
61
- }
62
-
63
- export const FontSize = {
64
- SMALL: 0,
65
- NORMAL: 1,
66
- LARGE: 2,
67
- }
68
-
69
- export type Danmaku = {
70
- time: number
71
- type: number
72
- fontSizeType: number
73
- color: RGB
74
- content: string
75
- extra: UniDM
76
- }
@@ -1,55 +0,0 @@
1
- import type { RGB } from '../types'
2
-
3
- const pad = (s: string) => (s.length < 2 ? `0${s}` : s)
4
- const decimalToHex = (n: number) => pad(n.toString(16))
5
-
6
- /**
7
- * 本函数实现复制自 [us-danmaku](https://github.com/tiansh/us-danmaku) 项目
8
- */
9
- const isDarkColor = ({ r, g, b }: RGB) =>
10
- r * 0.299 + g * 0.587 + b * 0.114 < 0x30
11
-
12
- const WHITE = { r: 255, g: 255, b: 255 }
13
- const BLACK = { r: 0, g: 0, b: 0 }
14
-
15
- export const hexColorToRGB = (hex: string) => {
16
- if (hex.indexOf('#') === 0) {
17
- hex = hex.slice(1)
18
- }
19
-
20
- const [r, g, b] =
21
- hex.length === 3 ? hex.split('').map((c) => c + c) : hex.match(/../g) || []
22
-
23
- return {
24
- r: Number.parseInt(r, 16),
25
- g: Number.parseInt(g, 16),
26
- b: Number.parseInt(b, 16),
27
- }
28
- }
29
-
30
- export const decimalColorToRGB = (decimal: number) => {
31
- const div = (i: number, j: number) => Math.floor(i / j)
32
-
33
- return {
34
- r: div(decimal, 256 * 256),
35
- g: div(decimal, 256) % 256,
36
- b: decimal % 256,
37
- }
38
- }
39
-
40
- export const formatColor = ({ r, g, b }: RGB, opacity?: number) => {
41
- const color = [b, g, r]
42
-
43
- if (opacity !== undefined) {
44
- const alpha = Math.round((1 - opacity) * 255)
45
- color.unshift(alpha)
46
- }
47
-
48
- return `&H${color.map(decimalToHex).join('').toUpperCase()}`
49
- }
50
-
51
- export const getDecoratingColor = (color: RGB) =>
52
- isDarkColor(color) ? WHITE : BLACK
53
-
54
- export const isWhite = (color: RGB) =>
55
- color.r === 255 && color.g === 255 && color.b === 255
@@ -1,43 +0,0 @@
1
- import type { Options as UniPoolOptions } from '../..'
2
- import type { Danmaku, RGB } from '../types'
3
-
4
- import { UniPool } from '../..'
5
- import { Modes, UniDM } from '../../utils/dm-gen'
6
- import { DanmakuType } from '../types'
7
-
8
- function decimalToRGB888(decimal: number): RGB {
9
- const r = (decimal >> 16) & 0xff
10
- const g = (decimal >> 8) & 0xff
11
- const b = decimal & 0xff
12
- return {
13
- r,
14
- g,
15
- b,
16
- } satisfies RGB
17
- }
18
-
19
- export function UniPool2DanmakuLists(UP: UniPool): Danmaku[] {
20
- const dans = UP.dans
21
- let type = DanmakuType.SCROLL
22
- return dans.map((d) => {
23
- if (d.mode === Modes.Bottom) type = DanmakuType.BOTTOM
24
- else if (d.mode === Modes.Top) type = DanmakuType.TOP
25
- return {
26
- time: d.progress,
27
- type,
28
- fontSizeType: d.fontsize,
29
- content: d.content,
30
- color: decimalToRGB888(d.color),
31
- extra: d,
32
- } satisfies Danmaku
33
- })
34
- }
35
- export function DanmakuList2UniPool(
36
- d: Danmaku[],
37
- options?: UniPoolOptions,
38
- ): UniPool {
39
- return new UniPool(
40
- d.map((d) => UniDM.create(d.extra)),
41
- options,
42
- )
43
- }