@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 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
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * 字幕条目接口
3
+ */
4
+ export interface SubtitleEntry {
5
+ index: number;
6
+ startTime: string;
7
+ endTime: string;
8
+ text: string;
9
+ }
@@ -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
+ }