@xiping/node-utils 1.0.53 → 1.0.61
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/lib/src/ffmpeg/README.md +371 -0
- package/lib/src/ffmpeg/README_cutVideo.md +220 -0
- package/lib/src/ffmpeg/extractAudio.d.ts +36 -0
- package/lib/src/ffmpeg/extractAudio.js +186 -0
- package/lib/src/ffmpeg/getThumbnail.d.ts +15 -0
- package/lib/src/ffmpeg/getThumbnail.js +64 -10
- package/lib/src/ffmpeg/getVideoInfo.d.ts +47 -0
- package/lib/src/ffmpeg/getVideoInfo.js +109 -0
- package/lib/src/ffmpeg/index.d.ts +2 -47
- package/lib/src/ffmpeg/index.js +2 -109
- package/lib/src/image/README.md +230 -0
- package/lib/src/srt-to-vtt/README.md +189 -0
- package/package.json +3 -3
package/lib/src/ffmpeg/index.js
CHANGED
|
@@ -1,112 +1,5 @@
|
|
|
1
|
-
import shell from "shelljs";
|
|
2
1
|
export * from "./getThumbnail.js";
|
|
3
2
|
export * from "./check.js";
|
|
4
3
|
export * from "./cutVideo.js";
|
|
5
|
-
|
|
6
|
-
*
|
|
7
|
-
* @param videoPath 视频文件路径
|
|
8
|
-
* @returns 视频信息对象
|
|
9
|
-
*/
|
|
10
|
-
export function getVideoInfo(videoPath) {
|
|
11
|
-
// 检查文件是否存在
|
|
12
|
-
if (!shell.test("-f", videoPath)) {
|
|
13
|
-
throw new Error(`视频文件不存在: ${videoPath}`);
|
|
14
|
-
}
|
|
15
|
-
// 使用 ffprobe 获取 JSON 格式的视频信息
|
|
16
|
-
const result = shell.exec(`ffprobe -v quiet -print_format json -show_format -show_streams "${videoPath}"`, { silent: true });
|
|
17
|
-
if (result.code !== 0) {
|
|
18
|
-
throw new Error(`获取视频信息失败: ${result.stderr}`);
|
|
19
|
-
}
|
|
20
|
-
let probeData;
|
|
21
|
-
try {
|
|
22
|
-
probeData = JSON.parse(result.stdout);
|
|
23
|
-
}
|
|
24
|
-
catch (error) {
|
|
25
|
-
throw new Error(`解析 ffprobe 输出失败: ${error}`);
|
|
26
|
-
}
|
|
27
|
-
const info = {
|
|
28
|
-
path: videoPath,
|
|
29
|
-
rawInfo: JSON.stringify(probeData, null, 2),
|
|
30
|
-
};
|
|
31
|
-
// 从 format 信息中获取时长和文件大小
|
|
32
|
-
if (probeData.format) {
|
|
33
|
-
if (probeData.format.duration) {
|
|
34
|
-
info.duration = parseFloat(probeData.format.duration);
|
|
35
|
-
info.durationFormatted = formatDuration(info.duration);
|
|
36
|
-
}
|
|
37
|
-
if (probeData.format.size) {
|
|
38
|
-
info.fileSize = parseInt(probeData.format.size);
|
|
39
|
-
info.fileSizeFormatted = formatFileSize(info.fileSize);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
// 从视频流中获取信息
|
|
43
|
-
const videoStream = probeData.streams?.find((stream) => stream.codec_type === "video");
|
|
44
|
-
if (videoStream) {
|
|
45
|
-
info.videoCodec = videoStream.codec_name || "unknown";
|
|
46
|
-
info.width = videoStream.width || 0;
|
|
47
|
-
info.height = videoStream.height || 0;
|
|
48
|
-
if (videoStream.r_frame_rate) {
|
|
49
|
-
const [num, den] = videoStream.r_frame_rate.split("/");
|
|
50
|
-
info.fps = parseInt(num) / parseInt(den);
|
|
51
|
-
}
|
|
52
|
-
if (videoStream.bit_rate) {
|
|
53
|
-
info.bitrate = parseInt(videoStream.bit_rate);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
// 从音频流中获取信息
|
|
57
|
-
const audioStream = probeData.streams?.find((stream) => stream.codec_type === "audio");
|
|
58
|
-
if (audioStream) {
|
|
59
|
-
info.audioCodec = audioStream.codec_name || "unknown";
|
|
60
|
-
}
|
|
61
|
-
return info;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* 格式化文件大小
|
|
65
|
-
* @param bytes 字节数
|
|
66
|
-
* @returns 格式化后的文件大小字符串
|
|
67
|
-
*/
|
|
68
|
-
function formatFileSize(bytes) {
|
|
69
|
-
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
70
|
-
let size = bytes;
|
|
71
|
-
let unitIndex = 0;
|
|
72
|
-
while (size >= 1024 && unitIndex < units.length - 1) {
|
|
73
|
-
size /= 1024;
|
|
74
|
-
unitIndex++;
|
|
75
|
-
}
|
|
76
|
-
return `${size.toFixed(2)} ${units[unitIndex]}`;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* 格式化时长
|
|
80
|
-
* @param seconds 秒数
|
|
81
|
-
* @returns 格式化后的时长字符串
|
|
82
|
-
*/
|
|
83
|
-
function formatDuration(seconds) {
|
|
84
|
-
const hours = Math.floor(seconds / 3600);
|
|
85
|
-
const minutes = Math.floor((seconds % 3600) / 60);
|
|
86
|
-
const secs = Math.floor(seconds % 60);
|
|
87
|
-
const ms = Math.floor((seconds % 1) * 100);
|
|
88
|
-
return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}.${ms.toString().padStart(2, "0")}`;
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* 批量获取视频信息
|
|
92
|
-
* @param videoPaths 视频文件路径数组
|
|
93
|
-
* @returns 视频信息对象数组
|
|
94
|
-
*/
|
|
95
|
-
export function getMultipleVideoInfo(videoPaths) {
|
|
96
|
-
return videoPaths.map((path) => getVideoInfo(path));
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* 获取详细的视频信息(包含更多元数据)
|
|
100
|
-
* @param videoPath 视频文件路径
|
|
101
|
-
* @returns 详细的视频信息
|
|
102
|
-
*/
|
|
103
|
-
export function getDetailedVideoInfo(videoPath) {
|
|
104
|
-
if (!shell.test("-f", videoPath)) {
|
|
105
|
-
throw new Error(`视频文件不存在: ${videoPath}`);
|
|
106
|
-
}
|
|
107
|
-
const result = shell.exec(`ffprobe -v quiet -print_format json -show_format -show_streams -show_chapters -show_private_data "${videoPath}"`, { silent: true });
|
|
108
|
-
if (result.code !== 0) {
|
|
109
|
-
throw new Error(`获取详细视频信息失败: ${result.stderr}`);
|
|
110
|
-
}
|
|
111
|
-
return JSON.parse(result.stdout);
|
|
112
|
-
}
|
|
4
|
+
export * from "./getVideoInfo.js";
|
|
5
|
+
export * from "./extractAudio.js";
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# 图片格式转换工具
|
|
2
|
+
|
|
3
|
+
基于 Sharp 的高性能图片格式转换工具,支持多种图片格式之间的转换,包括 JPG、PNG、WebP、AVIF 等。
|
|
4
|
+
|
|
5
|
+
## 功能特性
|
|
6
|
+
|
|
7
|
+
- 🚀 高性能图片格式转换
|
|
8
|
+
- 📐 支持尺寸调整和缩放
|
|
9
|
+
- 🎨 支持质量控制和压缩选项
|
|
10
|
+
- 📦 批量转换支持
|
|
11
|
+
- 🖼️ 缩略图生成
|
|
12
|
+
- 📊 详细的转换统计信息
|
|
13
|
+
- 🔍 图片信息获取
|
|
14
|
+
|
|
15
|
+
## 支持的格式
|
|
16
|
+
|
|
17
|
+
### 输入格式
|
|
18
|
+
- JPEG/JPG
|
|
19
|
+
- PNG
|
|
20
|
+
- WebP
|
|
21
|
+
- AVIF
|
|
22
|
+
- TIFF
|
|
23
|
+
- GIF
|
|
24
|
+
|
|
25
|
+
### 输出格式
|
|
26
|
+
- JPEG/JPG
|
|
27
|
+
- PNG
|
|
28
|
+
- WebP
|
|
29
|
+
- AVIF
|
|
30
|
+
- TIFF
|
|
31
|
+
|
|
32
|
+
## 安装依赖
|
|
33
|
+
|
|
34
|
+
确保项目中已安装 Sharp:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install sharp
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 基本用法
|
|
41
|
+
|
|
42
|
+
### 1. 单张图片转换
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import { convertImage } from '@xiping/node-utils';
|
|
46
|
+
|
|
47
|
+
// 将 JPG 转换为 WebP
|
|
48
|
+
const result = await convertImage(
|
|
49
|
+
'./input/sample.jpg',
|
|
50
|
+
'./output/sample.webp',
|
|
51
|
+
'webp',
|
|
52
|
+
{
|
|
53
|
+
quality: 85,
|
|
54
|
+
width: 800,
|
|
55
|
+
height: 600
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
console.log('转换结果:', result);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 2. 批量转换
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { batchConvert } from '@xiping/node-utils';
|
|
66
|
+
|
|
67
|
+
const files = [
|
|
68
|
+
{
|
|
69
|
+
inputPath: './input/image1.jpg',
|
|
70
|
+
outputPath: './output/image1.webp',
|
|
71
|
+
format: 'webp'
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
inputPath: './input/image2.png',
|
|
75
|
+
outputPath: './output/image2.avif',
|
|
76
|
+
format: 'avif'
|
|
77
|
+
}
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
const results = await batchConvert(files, {
|
|
81
|
+
quality: 80,
|
|
82
|
+
width: 1200
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 3. 创建缩略图
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { createThumbnail } from '@xiping/node-utils';
|
|
90
|
+
|
|
91
|
+
const result = await createThumbnail(
|
|
92
|
+
'./input/large-image.jpg',
|
|
93
|
+
'./output/thumbnail.jpg',
|
|
94
|
+
200,
|
|
95
|
+
200,
|
|
96
|
+
'jpeg',
|
|
97
|
+
{ quality: 90 }
|
|
98
|
+
);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 4. 获取图片信息
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
import { getImageInfo } from '@xiping/node-utils';
|
|
105
|
+
|
|
106
|
+
const info = await getImageInfo('./input/sample.jpg');
|
|
107
|
+
console.log('图片信息:', info);
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## 高级用法
|
|
111
|
+
|
|
112
|
+
### 使用 ImageConverter 类
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
import { ImageConverter } from '@xiping/node-utils';
|
|
116
|
+
|
|
117
|
+
// 转换为 WebP(推荐用于 Web)
|
|
118
|
+
await ImageConverter.toWebP('./input.jpg', './output.webp', 85);
|
|
119
|
+
|
|
120
|
+
// 转换为 AVIF(最新格式,压缩率更高)
|
|
121
|
+
await ImageConverter.toAVIF('./input.jpg', './output.avif', 80);
|
|
122
|
+
|
|
123
|
+
// 转换为 PNG(保持透明度)
|
|
124
|
+
await ImageConverter.toPNG('./input.jpg', './output.png', true);
|
|
125
|
+
|
|
126
|
+
// 转换为 JPEG(通用格式)
|
|
127
|
+
await ImageConverter.toJPEG('./input.png', './output.jpg', 90);
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 创建响应式图片
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import { ImageConverter } from '@xiping/node-utils';
|
|
134
|
+
|
|
135
|
+
const sizes = [
|
|
136
|
+
{ width: 320, height: 240, suffix: 'small' },
|
|
137
|
+
{ width: 640, height: 480, suffix: 'medium' },
|
|
138
|
+
{ width: 1280, height: 960, suffix: 'large' }
|
|
139
|
+
];
|
|
140
|
+
|
|
141
|
+
const results = await ImageConverter.createResponsiveImages(
|
|
142
|
+
'./input/hero-image.jpg',
|
|
143
|
+
'./output/',
|
|
144
|
+
'hero',
|
|
145
|
+
sizes
|
|
146
|
+
);
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## 转换选项
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
interface ConvertOptions {
|
|
153
|
+
/** 输出质量 (1-100),仅对 JPEG、WebP、AVIF 有效 */
|
|
154
|
+
quality?: number;
|
|
155
|
+
/** 是否保持透明度,仅对 PNG、WebP 有效 */
|
|
156
|
+
keepTransparency?: boolean;
|
|
157
|
+
/** 输出宽度,保持宽高比 */
|
|
158
|
+
width?: number;
|
|
159
|
+
/** 输出高度,保持宽高比 */
|
|
160
|
+
height?: number;
|
|
161
|
+
/** 是否强制调整尺寸(不保持宽高比) */
|
|
162
|
+
forceResize?: boolean;
|
|
163
|
+
/** 压缩级别 (0-9),仅对 PNG 有效 */
|
|
164
|
+
compressionLevel?: number;
|
|
165
|
+
/** 是否渐进式编码,仅对 JPEG 有效 */
|
|
166
|
+
progressive?: boolean;
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## 转换结果
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
interface ConvertResult {
|
|
174
|
+
/** 输入文件路径 */
|
|
175
|
+
inputPath: string;
|
|
176
|
+
/** 输出文件路径 */
|
|
177
|
+
outputPath: string;
|
|
178
|
+
/** 原始文件大小(字节) */
|
|
179
|
+
originalSize: number;
|
|
180
|
+
/** 转换后文件大小(字节) */
|
|
181
|
+
convertedSize: number;
|
|
182
|
+
/** 压缩率 */
|
|
183
|
+
compressionRatio: number;
|
|
184
|
+
/** 转换耗时(毫秒) */
|
|
185
|
+
processingTime: number;
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## 格式推荐
|
|
190
|
+
|
|
191
|
+
### Web 应用
|
|
192
|
+
- **WebP**: 现代浏览器支持,压缩率高,推荐用于 Web
|
|
193
|
+
- **AVIF**: 最新格式,压缩率最高,但浏览器支持有限
|
|
194
|
+
- **JPEG**: 通用格式,兼容性最好
|
|
195
|
+
|
|
196
|
+
### 移动应用
|
|
197
|
+
- **WebP**: Android 原生支持,iOS 14+ 支持
|
|
198
|
+
- **JPEG**: 通用兼容性
|
|
199
|
+
|
|
200
|
+
### 打印/专业用途
|
|
201
|
+
- **PNG**: 无损压缩,支持透明度
|
|
202
|
+
- **TIFF**: 专业格式,支持多种压缩算法
|
|
203
|
+
|
|
204
|
+
## 性能优化建议
|
|
205
|
+
|
|
206
|
+
1. **批量处理**: 使用 `batchConvert` 进行批量转换
|
|
207
|
+
2. **质量设置**: 根据用途调整质量参数(Web 用 80-85,打印用 90-95)
|
|
208
|
+
3. **尺寸优化**: 根据显示需求设置合适的输出尺寸
|
|
209
|
+
4. **格式选择**: 优先使用 WebP 或 AVIF 以获得更好的压缩率
|
|
210
|
+
|
|
211
|
+
## 错误处理
|
|
212
|
+
|
|
213
|
+
所有函数都会抛出详细的错误信息,建议使用 try-catch 进行错误处理:
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
try {
|
|
217
|
+
const result = await convertImage(inputPath, outputPath, 'webp');
|
|
218
|
+
console.log('转换成功:', result);
|
|
219
|
+
} catch (error) {
|
|
220
|
+
console.error('转换失败:', error.message);
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## 注意事项
|
|
225
|
+
|
|
226
|
+
1. 确保输入文件存在且可读
|
|
227
|
+
2. 输出目录会自动创建
|
|
228
|
+
3. GIF 格式暂不支持输出
|
|
229
|
+
4. 大文件转换可能需要较长时间,建议在后台处理
|
|
230
|
+
5. 某些格式转换可能不支持所有选项(如透明度)
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# SRT到VTT转换器
|
|
2
|
+
|
|
3
|
+
这个模块提供了在Node.js环境中将SRT字幕文件转换为WebVTT格式的功能。
|
|
4
|
+
|
|
5
|
+
## 功能特性
|
|
6
|
+
|
|
7
|
+
- ✅ 从文件读取SRT并转换为VTT
|
|
8
|
+
- ✅ 支持批量转换多个SRT文件
|
|
9
|
+
- ✅ 支持字符串内容直接转换
|
|
10
|
+
- ✅ 自动验证SRT格式
|
|
11
|
+
- ✅ 完整的错误处理
|
|
12
|
+
- ✅ TypeScript支持
|
|
13
|
+
|
|
14
|
+
## 安装
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @xiping/node-utils
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 使用方法
|
|
21
|
+
|
|
22
|
+
### 1. 从文件读取SRT并转换为VTT字符串
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { convertSrtFileToVtt } from '@xiping/node-utils/src/srt-to-vtt';
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const vttContent = convertSrtFileToVtt('./subtitles.srt');
|
|
29
|
+
console.log('转换后的VTT内容:', vttContent);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.error('转换失败:', error);
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 2. 从文件读取SRT并保存为VTT文件
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import { convertSrtFileToVttFile } from '@xiping/node-utils/src/srt-to-vtt';
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
// 指定输出路径
|
|
42
|
+
const outputPath = convertSrtFileToVttFile('./subtitles.srt', './output/subtitles.vtt');
|
|
43
|
+
console.log('VTT文件已保存到:', outputPath);
|
|
44
|
+
|
|
45
|
+
// 或者使用默认输出路径(同目录,扩展名改为.vtt)
|
|
46
|
+
const defaultOutputPath = convertSrtFileToVttFile('./subtitles.srt');
|
|
47
|
+
console.log('默认输出路径:', defaultOutputPath);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error('文件转换失败:', error);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 3. 批量转换多个SRT文件
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { batchConvertSrtToVtt } from '@xiping/node-utils/src/srt-to-vtt';
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const srtFiles = [
|
|
60
|
+
'./subtitles1.srt',
|
|
61
|
+
'./subtitles2.srt',
|
|
62
|
+
'./subtitles3.srt'
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
const results = batchConvertSrtToVtt(srtFiles, './output');
|
|
66
|
+
|
|
67
|
+
results.forEach(result => {
|
|
68
|
+
if (result.success) {
|
|
69
|
+
console.log(`✅ ${result.input} -> ${result.output}`);
|
|
70
|
+
} else {
|
|
71
|
+
console.error(`❌ ${result.input}: ${result.error}`);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.error('批量转换失败:', error);
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 4. 从字符串内容直接转换
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import { convertSrtStringToVtt } from '@xiping/node-utils/src/srt-to-vtt';
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
const srtContent = `1
|
|
86
|
+
00:00:00,000 --> 00:00:04,000
|
|
87
|
+
这是第一行字幕
|
|
88
|
+
|
|
89
|
+
2
|
|
90
|
+
00:00:04,000 --> 00:00:08,000
|
|
91
|
+
这是第二行字幕`;
|
|
92
|
+
|
|
93
|
+
const vttContent = convertSrtStringToVtt(srtContent);
|
|
94
|
+
console.log('转换后的VTT内容:', vttContent);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error('字符串转换失败:', error);
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## API参考
|
|
101
|
+
|
|
102
|
+
### convertSrtFileToVtt(srtFilePath: string): string
|
|
103
|
+
|
|
104
|
+
从文件读取SRT内容并转换为VTT格式字符串。
|
|
105
|
+
|
|
106
|
+
**参数:**
|
|
107
|
+
- `srtFilePath`: SRT文件路径
|
|
108
|
+
|
|
109
|
+
**返回值:**
|
|
110
|
+
- 转换后的VTT内容字符串
|
|
111
|
+
|
|
112
|
+
**异常:**
|
|
113
|
+
- 文件不存在时抛出错误
|
|
114
|
+
- 文件格式无效时抛出错误
|
|
115
|
+
|
|
116
|
+
### convertSrtFileToVttFile(srtFilePath: string, outputPath?: string): string
|
|
117
|
+
|
|
118
|
+
从文件读取SRT内容并转换为VTT格式,同时保存到文件。
|
|
119
|
+
|
|
120
|
+
**参数:**
|
|
121
|
+
- `srtFilePath`: SRT文件路径
|
|
122
|
+
- `outputPath`: 输出VTT文件路径(可选)
|
|
123
|
+
|
|
124
|
+
**返回值:**
|
|
125
|
+
- 输出文件路径
|
|
126
|
+
|
|
127
|
+
### batchConvertSrtToVtt(srtFilePaths: string[], outputDir?: string): Array<{ input: string; output: string; success: boolean; error?: string }>
|
|
128
|
+
|
|
129
|
+
批量转换多个SRT文件到VTT格式。
|
|
130
|
+
|
|
131
|
+
**参数:**
|
|
132
|
+
- `srtFilePaths`: SRT文件路径数组
|
|
133
|
+
- `outputDir`: 输出目录(可选)
|
|
134
|
+
|
|
135
|
+
**返回值:**
|
|
136
|
+
- 转换结果数组,包含每个文件的转换状态
|
|
137
|
+
|
|
138
|
+
### convertSrtStringToVtt(srtContent: string): string
|
|
139
|
+
|
|
140
|
+
从字符串内容直接转换为VTT格式。
|
|
141
|
+
|
|
142
|
+
**参数:**
|
|
143
|
+
- `srtContent`: SRT内容字符串
|
|
144
|
+
|
|
145
|
+
**返回值:**
|
|
146
|
+
- VTT格式字符串
|
|
147
|
+
|
|
148
|
+
## 格式说明
|
|
149
|
+
|
|
150
|
+
### SRT格式
|
|
151
|
+
```
|
|
152
|
+
1
|
|
153
|
+
00:00:00,000 --> 00:00:04,000
|
|
154
|
+
字幕内容
|
|
155
|
+
|
|
156
|
+
2
|
|
157
|
+
00:00:04,000 --> 00:00:08,000
|
|
158
|
+
字幕内容
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### WebVTT格式
|
|
162
|
+
```
|
|
163
|
+
WEBVTT
|
|
164
|
+
|
|
165
|
+
00:00:00.000 --> 00:00:04.000
|
|
166
|
+
字幕内容
|
|
167
|
+
|
|
168
|
+
00:00:04.000 --> 00:00:08.000
|
|
169
|
+
字幕内容
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## 主要差异
|
|
173
|
+
|
|
174
|
+
1. **时间格式**: SRT使用逗号分隔毫秒,VTT使用点分隔
|
|
175
|
+
2. **头部**: VTT需要`WEBVTT`头部
|
|
176
|
+
3. **索引**: SRT包含序号,VTT不包含
|
|
177
|
+
|
|
178
|
+
## 错误处理
|
|
179
|
+
|
|
180
|
+
所有函数都包含完整的错误处理:
|
|
181
|
+
|
|
182
|
+
- 文件不存在
|
|
183
|
+
- 文件格式错误
|
|
184
|
+
- 权限问题
|
|
185
|
+
- 编码问题
|
|
186
|
+
|
|
187
|
+
## 示例
|
|
188
|
+
|
|
189
|
+
查看 `example.ts` 文件获取完整的使用示例。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xiping/node-utils",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.61",
|
|
4
4
|
"description": "node-utils",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "The-End-Hero <527409987@qq.com>",
|
|
@@ -20,12 +20,12 @@
|
|
|
20
20
|
},
|
|
21
21
|
"scripts": {
|
|
22
22
|
"test": "echo \"Error: run tests from root\" && exit 1",
|
|
23
|
-
"build": "tsc"
|
|
23
|
+
"build": "tsc && node scripts/copy-readmes.js"
|
|
24
24
|
},
|
|
25
25
|
"bugs": {
|
|
26
26
|
"url": "https://github.com/The-End-Hero/wang-ping/issues"
|
|
27
27
|
},
|
|
28
|
-
"gitHead": "
|
|
28
|
+
"gitHead": "6cb2ac8c64a780abb18ec793978d3adfff71fba7",
|
|
29
29
|
"publishConfig": {
|
|
30
30
|
"access": "public",
|
|
31
31
|
"registry": "https://registry.npmjs.org/"
|