@xiping/subtitle 1.0.45
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/LICENSE +21 -0
- package/README.md +306 -0
- package/lib/index.d.ts +19 -0
- package/lib/index.js +22 -0
- package/lib/src/converter.d.ts +19 -0
- package/lib/src/converter.js +33 -0
- package/lib/src/json-converter.d.ts +12 -0
- package/lib/src/json-converter.js +19 -0
- package/lib/src/parser.d.ts +25 -0
- package/lib/src/parser.js +101 -0
- package/lib/src/types.d.ts +9 -0
- package/lib/src/types.js +1 -0
- package/package.json +32 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023-present, xiping.wang
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
# Subtitle
|
|
2
|
+
|
|
3
|
+
一个功能完整的字幕文件处理工具,支持SRT和WebVTT格式的解析、转换、验证和JSON导出。
|
|
4
|
+
|
|
5
|
+
## 功能特点
|
|
6
|
+
|
|
7
|
+
- 🚀 轻量级,零依赖
|
|
8
|
+
- 📝 完整的TypeScript类型支持
|
|
9
|
+
- 🔧 支持多行字幕文本
|
|
10
|
+
- ✅ 格式验证功能(SRT和WebVTT)
|
|
11
|
+
- 🎯 简单易用的API
|
|
12
|
+
- 🔄 支持SRT和WebVTT互相转换
|
|
13
|
+
- 📄 支持转换为JSON格式
|
|
14
|
+
|
|
15
|
+
## 安装
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @xiping/subtitle
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
或者使用pnpm:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pnpm add @xiping/subtitle
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## 使用方法
|
|
28
|
+
|
|
29
|
+
### 基本用法
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { srtToVtt } from '@xiping/subtitle';
|
|
33
|
+
|
|
34
|
+
const srtContent = `1
|
|
35
|
+
00:00:00,000 --> 00:00:04,000
|
|
36
|
+
你好,这是第一行字幕
|
|
37
|
+
|
|
38
|
+
2
|
|
39
|
+
00:00:05,000 --> 00:00:09,000
|
|
40
|
+
这是第二行字幕`;
|
|
41
|
+
|
|
42
|
+
const webvttContent = srtToVtt(srtContent);
|
|
43
|
+
console.log(webvttContent);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
输出结果:
|
|
47
|
+
```
|
|
48
|
+
WEBVTT
|
|
49
|
+
|
|
50
|
+
00:00:00.000 --> 00:00:04.000
|
|
51
|
+
你好,这是第一行字幕
|
|
52
|
+
|
|
53
|
+
00:00:05.000 --> 00:00:09.000
|
|
54
|
+
这是第二行字幕
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 高级用法
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import {
|
|
61
|
+
srtToVtt,
|
|
62
|
+
parseSRT,
|
|
63
|
+
parseVTT,
|
|
64
|
+
generateWebVTT,
|
|
65
|
+
validateSRT,
|
|
66
|
+
validateVTT,
|
|
67
|
+
SubtitleEntry
|
|
68
|
+
} from '@xiping/subtitle';
|
|
69
|
+
|
|
70
|
+
// 验证SRT格式
|
|
71
|
+
const isValid = validateSRT(srtContent);
|
|
72
|
+
if (!isValid) {
|
|
73
|
+
console.error('无效的SRT格式');
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// 解析SRT文件
|
|
78
|
+
const entries: SubtitleEntry[] = parseSRT(srtContent);
|
|
79
|
+
console.log('字幕条目数量:', entries.length);
|
|
80
|
+
|
|
81
|
+
// 手动生成WebVTT
|
|
82
|
+
const webvtt = generateWebVTT(entries);
|
|
83
|
+
|
|
84
|
+
// 解析WebVTT文件
|
|
85
|
+
const vttContent = `WEBVTT\n\n00:00:00.000 --> 00:00:04.000\n字幕内容`;
|
|
86
|
+
const vttEntries = parseVTT(vttContent);
|
|
87
|
+
|
|
88
|
+
// 验证WebVTT格式
|
|
89
|
+
const isVttValid = validateVTT(vttContent);
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### JSON转换
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { srtToJson, vttToJson } from '@xiping/subtitle';
|
|
96
|
+
|
|
97
|
+
// SRT转JSON
|
|
98
|
+
const srtContent = `1
|
|
99
|
+
00:00:00,000 --> 00:00:04,000
|
|
100
|
+
字幕内容`;
|
|
101
|
+
|
|
102
|
+
const jsonContent = srtToJson(srtContent);
|
|
103
|
+
console.log(jsonContent);
|
|
104
|
+
// 输出: [{"index":1,"startTime":"00:00:00,000","endTime":"00:00:04,000","text":"字幕内容"}]
|
|
105
|
+
|
|
106
|
+
// WebVTT转JSON
|
|
107
|
+
const vttContent = `WEBVTT
|
|
108
|
+
|
|
109
|
+
00:00:00.000 --> 00:00:04.000
|
|
110
|
+
字幕内容`;
|
|
111
|
+
|
|
112
|
+
const vttJson = vttToJson(vttContent);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 文件操作示例
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import fs from 'fs';
|
|
119
|
+
import { srtToVtt, srtToJson } from '@xiping/subtitle';
|
|
120
|
+
|
|
121
|
+
// 读取SRT文件
|
|
122
|
+
const srtContent = fs.readFileSync('subtitle.srt', 'utf-8');
|
|
123
|
+
|
|
124
|
+
// 转换为WebVTT
|
|
125
|
+
const webvttContent = srtToVtt(srtContent);
|
|
126
|
+
fs.writeFileSync('subtitle.vtt', webvttContent, 'utf-8');
|
|
127
|
+
|
|
128
|
+
// 转换为JSON
|
|
129
|
+
const jsonContent = srtToJson(srtContent);
|
|
130
|
+
fs.writeFileSync('subtitle.json', jsonContent, 'utf-8');
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## API 文档
|
|
134
|
+
|
|
135
|
+
### `srtToVtt(srtContent: string): string`
|
|
136
|
+
|
|
137
|
+
主转换函数,将SRT格式字幕转换为WebVTT格式。
|
|
138
|
+
|
|
139
|
+
**参数:**
|
|
140
|
+
- `srtContent` - SRT格式的字幕内容
|
|
141
|
+
|
|
142
|
+
**返回值:**
|
|
143
|
+
- WebVTT格式的字幕字符串
|
|
144
|
+
|
|
145
|
+
### `parseSRT(srtContent: string): SubtitleEntry[]`
|
|
146
|
+
|
|
147
|
+
解析SRT字幕文件内容。
|
|
148
|
+
|
|
149
|
+
**参数:**
|
|
150
|
+
- `srtContent` - SRT格式的字幕内容
|
|
151
|
+
|
|
152
|
+
**返回值:**
|
|
153
|
+
- 解析后的字幕条目数组
|
|
154
|
+
|
|
155
|
+
### `generateWebVTT(entries: SubtitleEntry[]): string`
|
|
156
|
+
|
|
157
|
+
将字幕条目数组转换为WebVTT格式字符串。
|
|
158
|
+
|
|
159
|
+
**参数:**
|
|
160
|
+
- `entries` - 字幕条目数组
|
|
161
|
+
|
|
162
|
+
**返回值:**
|
|
163
|
+
- WebVTT格式字符串
|
|
164
|
+
|
|
165
|
+
### `validateSRT(srtContent: string): boolean`
|
|
166
|
+
|
|
167
|
+
验证SRT文件格式是否正确。
|
|
168
|
+
|
|
169
|
+
**参数:**
|
|
170
|
+
- `srtContent` - SRT格式的字幕内容
|
|
171
|
+
|
|
172
|
+
**返回值:**
|
|
173
|
+
- 是否为有效的SRT格式
|
|
174
|
+
|
|
175
|
+
### `parseVTT(vttContent: string): SubtitleEntry[]`
|
|
176
|
+
|
|
177
|
+
解析WebVTT字幕文件内容。
|
|
178
|
+
|
|
179
|
+
**参数:**
|
|
180
|
+
- `vttContent` - WebVTT格式的字幕内容
|
|
181
|
+
|
|
182
|
+
**返回值:**
|
|
183
|
+
- 解析后的字幕条目数组
|
|
184
|
+
|
|
185
|
+
### `validateVTT(vttContent: string): boolean`
|
|
186
|
+
|
|
187
|
+
验证WebVTT文件格式是否正确。
|
|
188
|
+
|
|
189
|
+
**参数:**
|
|
190
|
+
- `vttContent` - WebVTT格式的字幕内容
|
|
191
|
+
|
|
192
|
+
**返回值:**
|
|
193
|
+
- 是否为有效的WebVTT格式
|
|
194
|
+
|
|
195
|
+
### `srtToJson(srtContent: string): string`
|
|
196
|
+
|
|
197
|
+
将SRT字幕转换为JSON格式字符串。
|
|
198
|
+
|
|
199
|
+
**参数:**
|
|
200
|
+
- `srtContent` - SRT格式的字幕内容
|
|
201
|
+
|
|
202
|
+
**返回值:**
|
|
203
|
+
- JSON格式字符串(格式化,缩进2空格)
|
|
204
|
+
|
|
205
|
+
### `vttToJson(vttContent: string): string`
|
|
206
|
+
|
|
207
|
+
将WebVTT字幕转换为JSON格式字符串。
|
|
208
|
+
|
|
209
|
+
**参数:**
|
|
210
|
+
- `vttContent` - WebVTT格式的字幕内容
|
|
211
|
+
|
|
212
|
+
**返回值:**
|
|
213
|
+
- JSON格式字符串(格式化,缩进2空格)
|
|
214
|
+
|
|
215
|
+
### `convertTimeFormat(srtTime: string): string`
|
|
216
|
+
|
|
217
|
+
将SRT时间格式转换为WebVTT时间格式。
|
|
218
|
+
|
|
219
|
+
**参数:**
|
|
220
|
+
- `srtTime` - SRT时间格式 (HH:MM:SS,mmm)
|
|
221
|
+
|
|
222
|
+
**返回值:**
|
|
223
|
+
- WebVTT时间格式 (HH:MM:SS.mmm)
|
|
224
|
+
|
|
225
|
+
## 类型定义
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
interface SubtitleEntry {
|
|
229
|
+
index: number; // 字幕序号
|
|
230
|
+
startTime: string; // 开始时间
|
|
231
|
+
endTime: string; // 结束时间
|
|
232
|
+
text: string; // 字幕文本
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## 格式说明
|
|
237
|
+
|
|
238
|
+
### SRT格式示例
|
|
239
|
+
```
|
|
240
|
+
1
|
|
241
|
+
00:00:00,000 --> 00:00:04,000
|
|
242
|
+
第一行字幕
|
|
243
|
+
|
|
244
|
+
2
|
|
245
|
+
00:00:05,000 --> 00:00:09,000
|
|
246
|
+
第二行字幕
|
|
247
|
+
可以是多行文本
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### WebVTT格式示例
|
|
251
|
+
```
|
|
252
|
+
WEBVTT
|
|
253
|
+
|
|
254
|
+
00:00:00.000 --> 00:00:04.000
|
|
255
|
+
第一行字幕
|
|
256
|
+
|
|
257
|
+
00:00:05.000 --> 00:00:09.000
|
|
258
|
+
第二行字幕
|
|
259
|
+
可以是多行文本
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### 主要差异
|
|
263
|
+
- **文件头**: WebVTT以`WEBVTT`开头
|
|
264
|
+
- **时间分隔符**: SRT使用逗号`,`,WebVTT使用点号`.`
|
|
265
|
+
- **序号**: SRT包含序号,WebVTT不需要
|
|
266
|
+
|
|
267
|
+
## 错误处理
|
|
268
|
+
|
|
269
|
+
库会自动处理常见的格式错误:
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
import { validateSRT, srtToVtt } from '@xiping/subtitle';
|
|
273
|
+
|
|
274
|
+
const srtContent = "invalid content";
|
|
275
|
+
|
|
276
|
+
if (!validateSRT(srtContent)) {
|
|
277
|
+
console.error('SRT格式无效');
|
|
278
|
+
} else {
|
|
279
|
+
const result = srtToVtt(srtContent);
|
|
280
|
+
console.log(result);
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## 浏览器支持
|
|
285
|
+
|
|
286
|
+
该库支持所有现代浏览器和Node.js环境。WebVTT格式被广泛支持:
|
|
287
|
+
|
|
288
|
+
- Chrome 23+
|
|
289
|
+
- Firefox 31+
|
|
290
|
+
- Safari 6+
|
|
291
|
+
- Edge 12+
|
|
292
|
+
- iOS Safari 7+
|
|
293
|
+
- Android Browser 4.4+
|
|
294
|
+
|
|
295
|
+
## 贡献
|
|
296
|
+
|
|
297
|
+
欢迎提交Issue和Pull Request!
|
|
298
|
+
|
|
299
|
+
## 许可证
|
|
300
|
+
|
|
301
|
+
MIT License
|
|
302
|
+
|
|
303
|
+
## 相关链接
|
|
304
|
+
|
|
305
|
+
- [WebVTT规范](https://www.w3.org/TR/webvtt1/)
|
|
306
|
+
- [SRT格式说明](https://en.wikipedia.org/wiki/SubRip)
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* subtitle
|
|
3
|
+
*
|
|
4
|
+
* SRT格式:
|
|
5
|
+
* 1
|
|
6
|
+
* 00:00:00,000 --> 00:00:04,000
|
|
7
|
+
* 字幕内容
|
|
8
|
+
*
|
|
9
|
+
* WebVTT格式:
|
|
10
|
+
* WEBVTT
|
|
11
|
+
*
|
|
12
|
+
* 00:00:00.000 --> 00:00:04.000
|
|
13
|
+
* 字幕内容
|
|
14
|
+
*/
|
|
15
|
+
export type { SubtitleEntry } from "./src/types.js";
|
|
16
|
+
export { parseSRT, parseVTT, validateSRT, validateVTT } from "./src/parser.js";
|
|
17
|
+
export { convertTimeFormat, generateWebVTT, srtToVtt, } from "./src/converter.js";
|
|
18
|
+
export { srtToJson, vttToJson } from "./src/json-converter.js";
|
|
19
|
+
export { srtToVtt as default } from "./src/converter.js";
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* subtitle
|
|
3
|
+
*
|
|
4
|
+
* SRT格式:
|
|
5
|
+
* 1
|
|
6
|
+
* 00:00:00,000 --> 00:00:04,000
|
|
7
|
+
* 字幕内容
|
|
8
|
+
*
|
|
9
|
+
* WebVTT格式:
|
|
10
|
+
* WEBVTT
|
|
11
|
+
*
|
|
12
|
+
* 00:00:00.000 --> 00:00:04.000
|
|
13
|
+
* 字幕内容
|
|
14
|
+
*/
|
|
15
|
+
// 解析功能
|
|
16
|
+
export { parseSRT, parseVTT, validateSRT, validateVTT } from "./src/parser.js";
|
|
17
|
+
// 转换功能
|
|
18
|
+
export { convertTimeFormat, generateWebVTT, srtToVtt, } from "./src/converter.js";
|
|
19
|
+
// JSON转换功能
|
|
20
|
+
export { srtToJson, vttToJson } from "./src/json-converter.js";
|
|
21
|
+
// 默认导出主函数
|
|
22
|
+
export { srtToVtt as default } from "./src/converter.js";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { SubtitleEntry } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* 将SRT时间格式转换为WebVTT时间格式
|
|
4
|
+
* @param srtTime SRT时间格式 (HH:MM:SS,mmm)
|
|
5
|
+
* @returns WebVTT时间格式 (HH:MM:SS.mmm)
|
|
6
|
+
*/
|
|
7
|
+
export declare function convertTimeFormat(srtTime: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* 将字幕条目数组转换为WebVTT格式
|
|
10
|
+
* @param entries 字幕条目数组
|
|
11
|
+
* @returns WebVTT格式字符串
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateWebVTT(entries: SubtitleEntry[]): string;
|
|
14
|
+
/**
|
|
15
|
+
* 将SRT字幕转换为WebVTT字幕
|
|
16
|
+
* @param srtContent SRT文件内容
|
|
17
|
+
* @returns WebVTT格式字符串
|
|
18
|
+
*/
|
|
19
|
+
export declare function srtToVtt(srtContent: string): string;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { parseSRT } from './parser.js';
|
|
2
|
+
/**
|
|
3
|
+
* 将SRT时间格式转换为WebVTT时间格式
|
|
4
|
+
* @param srtTime SRT时间格式 (HH:MM:SS,mmm)
|
|
5
|
+
* @returns WebVTT时间格式 (HH:MM:SS.mmm)
|
|
6
|
+
*/
|
|
7
|
+
export function convertTimeFormat(srtTime) {
|
|
8
|
+
return srtTime.replace(',', '.');
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 将字幕条目数组转换为WebVTT格式
|
|
12
|
+
* @param entries 字幕条目数组
|
|
13
|
+
* @returns WebVTT格式字符串
|
|
14
|
+
*/
|
|
15
|
+
export function generateWebVTT(entries) {
|
|
16
|
+
let webvtt = 'WEBVTT\n\n';
|
|
17
|
+
for (const entry of entries) {
|
|
18
|
+
const startTime = convertTimeFormat(entry.startTime);
|
|
19
|
+
const endTime = convertTimeFormat(entry.endTime);
|
|
20
|
+
webvtt += `${startTime} --> ${endTime}\n`;
|
|
21
|
+
webvtt += `${entry.text}\n\n`;
|
|
22
|
+
}
|
|
23
|
+
return webvtt.trim();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 将SRT字幕转换为WebVTT字幕
|
|
27
|
+
* @param srtContent SRT文件内容
|
|
28
|
+
* @returns WebVTT格式字符串
|
|
29
|
+
*/
|
|
30
|
+
export function srtToVtt(srtContent) {
|
|
31
|
+
const entries = parseSRT(srtContent);
|
|
32
|
+
return generateWebVTT(entries);
|
|
33
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 将SRT字幕转换为JSON格式
|
|
3
|
+
* @param srtContent SRT文件内容
|
|
4
|
+
* @returns JSON格式字符串
|
|
5
|
+
*/
|
|
6
|
+
export declare function srtToJson(srtContent: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* 将WebVTT字幕转换为JSON格式
|
|
9
|
+
* @param vttContent WebVTT文件内容
|
|
10
|
+
* @returns JSON格式字符串
|
|
11
|
+
*/
|
|
12
|
+
export declare function vttToJson(vttContent: string): string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { parseSRT, parseVTT } from './parser.js';
|
|
2
|
+
/**
|
|
3
|
+
* 将SRT字幕转换为JSON格式
|
|
4
|
+
* @param srtContent SRT文件内容
|
|
5
|
+
* @returns JSON格式字符串
|
|
6
|
+
*/
|
|
7
|
+
export function srtToJson(srtContent) {
|
|
8
|
+
const entries = parseSRT(srtContent);
|
|
9
|
+
return JSON.stringify(entries, null, 2);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 将WebVTT字幕转换为JSON格式
|
|
13
|
+
* @param vttContent WebVTT文件内容
|
|
14
|
+
* @returns JSON格式字符串
|
|
15
|
+
*/
|
|
16
|
+
export function vttToJson(vttContent) {
|
|
17
|
+
const entries = parseVTT(vttContent);
|
|
18
|
+
return JSON.stringify(entries, null, 2);
|
|
19
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { SubtitleEntry } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* 解析SRT字幕文件内容
|
|
4
|
+
* @param srtContent SRT文件内容
|
|
5
|
+
* @returns 解析后的字幕条目数组
|
|
6
|
+
*/
|
|
7
|
+
export declare function parseSRT(srtContent: string): SubtitleEntry[];
|
|
8
|
+
/**
|
|
9
|
+
* 解析WebVTT字幕文件内容
|
|
10
|
+
* @param vttContent WebVTT文件内容
|
|
11
|
+
* @returns 解析后的字幕条目数组
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseVTT(vttContent: string): SubtitleEntry[];
|
|
14
|
+
/**
|
|
15
|
+
* 验证SRT文件格式是否正确
|
|
16
|
+
* @param srtContent SRT文件内容
|
|
17
|
+
* @returns 是否为有效的SRT格式
|
|
18
|
+
*/
|
|
19
|
+
export declare function validateSRT(srtContent: string): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* 验证WebVTT文件格式是否正确
|
|
22
|
+
* @param vttContent WebVTT文件内容
|
|
23
|
+
* @returns 是否为有效的WebVTT格式
|
|
24
|
+
*/
|
|
25
|
+
export declare function validateVTT(vttContent: string): boolean;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 解析SRT字幕文件内容
|
|
3
|
+
* @param srtContent SRT文件内容
|
|
4
|
+
* @returns 解析后的字幕条目数组
|
|
5
|
+
*/
|
|
6
|
+
export function parseSRT(srtContent) {
|
|
7
|
+
const entries = [];
|
|
8
|
+
const blocks = srtContent.trim().split(/\n\s*\n/);
|
|
9
|
+
for (const block of blocks) {
|
|
10
|
+
const lines = block.trim().split('\n');
|
|
11
|
+
if (lines.length < 3)
|
|
12
|
+
continue;
|
|
13
|
+
const index = parseInt(lines[0], 10);
|
|
14
|
+
if (isNaN(index))
|
|
15
|
+
continue;
|
|
16
|
+
const timeMatch = lines[1].match(/(\d{2}:\d{2}:\d{2},\d{3})\s*-->\s*(\d{2}:\d{2}:\d{2},\d{3})/);
|
|
17
|
+
if (!timeMatch)
|
|
18
|
+
continue;
|
|
19
|
+
const startTime = timeMatch[1];
|
|
20
|
+
const endTime = timeMatch[2];
|
|
21
|
+
const text = lines.slice(2).join('\n');
|
|
22
|
+
entries.push({
|
|
23
|
+
index,
|
|
24
|
+
startTime,
|
|
25
|
+
endTime,
|
|
26
|
+
text
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return entries;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 解析WebVTT字幕文件内容
|
|
33
|
+
* @param vttContent WebVTT文件内容
|
|
34
|
+
* @returns 解析后的字幕条目数组
|
|
35
|
+
*/
|
|
36
|
+
export function parseVTT(vttContent) {
|
|
37
|
+
const entries = [];
|
|
38
|
+
// 移除WEBVTT头部(如果存在)
|
|
39
|
+
let content = vttContent.trim();
|
|
40
|
+
if (content.startsWith('WEBVTT')) {
|
|
41
|
+
content = content.replace(/^WEBVTT\s*\n*/, '');
|
|
42
|
+
}
|
|
43
|
+
const blocks = content.trim().split(/\n\s*\n/);
|
|
44
|
+
let index = 1;
|
|
45
|
+
for (const block of blocks) {
|
|
46
|
+
const lines = block.trim().split('\n');
|
|
47
|
+
if (lines.length < 2)
|
|
48
|
+
continue;
|
|
49
|
+
// VTT格式:第一行是时间,后面是文本
|
|
50
|
+
// 也可能有可选的序号(CUE标识符)
|
|
51
|
+
let timeLineIndex = 0;
|
|
52
|
+
// 如果第一行不是时间格式,可能是序号,跳过
|
|
53
|
+
if (!lines[0].includes('-->')) {
|
|
54
|
+
timeLineIndex = 1;
|
|
55
|
+
}
|
|
56
|
+
if (timeLineIndex >= lines.length)
|
|
57
|
+
continue;
|
|
58
|
+
const timeMatch = lines[timeLineIndex].match(/(\d{2}:\d{2}:\d{2}[.,]\d{3})\s*-->\s*(\d{2}:\d{2}:\d{2}[.,]\d{3})/);
|
|
59
|
+
if (!timeMatch)
|
|
60
|
+
continue;
|
|
61
|
+
// 统一转换为逗号格式(与SRT保持一致)
|
|
62
|
+
const startTime = timeMatch[1].replace('.', ',');
|
|
63
|
+
const endTime = timeMatch[2].replace('.', ',');
|
|
64
|
+
const text = lines.slice(timeLineIndex + 1).join('\n');
|
|
65
|
+
entries.push({
|
|
66
|
+
index: index++,
|
|
67
|
+
startTime,
|
|
68
|
+
endTime,
|
|
69
|
+
text
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return entries;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 验证SRT文件格式是否正确
|
|
76
|
+
* @param srtContent SRT文件内容
|
|
77
|
+
* @returns 是否为有效的SRT格式
|
|
78
|
+
*/
|
|
79
|
+
export function validateSRT(srtContent) {
|
|
80
|
+
try {
|
|
81
|
+
const entries = parseSRT(srtContent);
|
|
82
|
+
return entries.length > 0;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* 验证WebVTT文件格式是否正确
|
|
90
|
+
* @param vttContent WebVTT文件内容
|
|
91
|
+
* @returns 是否为有效的WebVTT格式
|
|
92
|
+
*/
|
|
93
|
+
export function validateVTT(vttContent) {
|
|
94
|
+
try {
|
|
95
|
+
const entries = parseVTT(vttContent);
|
|
96
|
+
return entries.length > 0;
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
}
|
package/lib/src/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xiping/subtitle",
|
|
3
|
+
"version": "1.0.45",
|
|
4
|
+
"description": "字幕文件处理工具,支持SRT和WebVTT格式的解析、转换和验证",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"author": "The-End-Hero <527409987@qq.com>",
|
|
7
|
+
"homepage": "https://github.com/The-End-Hero/xiping#readme",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"main": "lib/index.js",
|
|
10
|
+
"directories": {
|
|
11
|
+
"lib": "lib",
|
|
12
|
+
"test": "__tests__"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"lib"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
|
19
|
+
"build": "tsc"
|
|
20
|
+
},
|
|
21
|
+
"gitHead": "044508149840d2ba1b5f896ded9b3906f5866abb",
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public",
|
|
24
|
+
"registry": "https://registry.npmjs.org/"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/jest": "^30.0.0",
|
|
28
|
+
"jest": "^30.1.3",
|
|
29
|
+
"ts-jest": "^29.4.4",
|
|
30
|
+
"typescript": "^5.7.3"
|
|
31
|
+
}
|
|
32
|
+
}
|