@huiqinghuang/videocut-cli 1.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 (53) hide show
  1. package/bin/videocut.js +2 -0
  2. package/dist/commands/apply-edits.d.ts +4 -0
  3. package/dist/commands/apply-edits.d.ts.map +1 -0
  4. package/dist/commands/apply-edits.js +27 -0
  5. package/dist/commands/apply-edits.js.map +1 -0
  6. package/dist/commands/cut-video.d.ts +5 -0
  7. package/dist/commands/cut-video.d.ts.map +1 -0
  8. package/dist/commands/cut-video.js +33 -0
  9. package/dist/commands/cut-video.js.map +1 -0
  10. package/dist/commands/generate-readable.d.ts +4 -0
  11. package/dist/commands/generate-readable.d.ts.map +1 -0
  12. package/dist/commands/generate-readable.js +33 -0
  13. package/dist/commands/generate-readable.js.map +1 -0
  14. package/dist/commands/generate-review.d.ts +4 -0
  15. package/dist/commands/generate-review.d.ts.map +1 -0
  16. package/dist/commands/generate-review.js +33 -0
  17. package/dist/commands/generate-review.js.map +1 -0
  18. package/dist/commands/generate-subtitles.d.ts +4 -0
  19. package/dist/commands/generate-subtitles.d.ts.map +1 -0
  20. package/dist/commands/generate-subtitles.js +68 -0
  21. package/dist/commands/generate-subtitles.js.map +1 -0
  22. package/dist/commands/review-server.d.ts +4 -0
  23. package/dist/commands/review-server.d.ts.map +1 -0
  24. package/dist/commands/review-server.js +344 -0
  25. package/dist/commands/review-server.js.map +1 -0
  26. package/dist/commands/transcribe.d.ts +4 -0
  27. package/dist/commands/transcribe.d.ts.map +1 -0
  28. package/dist/commands/transcribe.js +114 -0
  29. package/dist/commands/transcribe.js.map +1 -0
  30. package/dist/core/edits.d.ts +10 -0
  31. package/dist/core/edits.d.ts.map +1 -0
  32. package/dist/core/edits.js +110 -0
  33. package/dist/core/edits.js.map +1 -0
  34. package/dist/core/subtitle.d.ts +6 -0
  35. package/dist/core/subtitle.d.ts.map +1 -0
  36. package/dist/core/subtitle.js +87 -0
  37. package/dist/core/subtitle.js.map +1 -0
  38. package/dist/core/types.d.ts +68 -0
  39. package/dist/core/types.d.ts.map +1 -0
  40. package/dist/core/types.js +2 -0
  41. package/dist/core/types.js.map +1 -0
  42. package/dist/core/video.d.ts +13 -0
  43. package/dist/core/video.d.ts.map +1 -0
  44. package/dist/core/video.js +188 -0
  45. package/dist/core/video.js.map +1 -0
  46. package/dist/index.d.ts +3 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +46 -0
  49. package/dist/index.js.map +1 -0
  50. package/package.json +45 -0
  51. package/static/assets/index-BeR4WwzJ.js +54 -0
  52. package/static/assets/index-CsW22Sz0.css +1 -0
  53. package/static/index.html +13 -0
@@ -0,0 +1,188 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { execSync } from 'child_process';
4
+ const BUFFER_MS = 50;
5
+ const CROSSFADE_MS = 30;
6
+ function detectEncoder() {
7
+ const platform = process.platform;
8
+ const encoders = [];
9
+ if (platform === 'darwin') {
10
+ encoders.push({ name: 'h264_videotoolbox', args: '-q:v 60', label: 'VideoToolbox (macOS)' });
11
+ }
12
+ else if (platform === 'win32') {
13
+ encoders.push({ name: 'h264_nvenc', args: '-preset p4 -cq 20', label: 'NVENC (NVIDIA)' });
14
+ encoders.push({ name: 'h264_qsv', args: '-global_quality 20', label: 'QSV (Intel)' });
15
+ encoders.push({ name: 'h264_amf', args: '-quality balanced', label: 'AMF (AMD)' });
16
+ }
17
+ else {
18
+ encoders.push({ name: 'h264_nvenc', args: '-preset p4 -cq 20', label: 'NVENC (NVIDIA)' });
19
+ encoders.push({ name: 'h264_vaapi', args: '-qp 20', label: 'VAAPI (Linux)' });
20
+ }
21
+ encoders.push({ name: 'libx264', args: '-preset fast -crf 18', label: 'x264 (软件)' });
22
+ for (const enc of encoders) {
23
+ try {
24
+ execSync(`ffmpeg -hide_banner -encoders 2>/dev/null | grep ${enc.name}`, { stdio: 'pipe' });
25
+ console.log(`🎯 检测到编码器: ${enc.label}`);
26
+ return enc;
27
+ }
28
+ catch {
29
+ // continue
30
+ }
31
+ }
32
+ return { name: 'libx264', args: '-preset fast -crf 18', label: 'x264 (软件)' };
33
+ }
34
+ let cachedEncoder = null;
35
+ function getEncoder() {
36
+ if (!cachedEncoder)
37
+ cachedEncoder = detectEncoder();
38
+ return cachedEncoder;
39
+ }
40
+ function getAudioOffset(projectPath) {
41
+ if (!projectPath)
42
+ return 0;
43
+ const audioPath = path.join(projectPath, '1_transcribe', 'audio.mp3');
44
+ if (!fs.existsSync(audioPath))
45
+ return 0;
46
+ try {
47
+ const offsetCmd = `ffprobe -v error -show_entries format=start_time -of csv=p=0 "${audioPath}"`;
48
+ const audioOffset = parseFloat(execSync(offsetCmd).toString().trim()) || 0;
49
+ if (audioOffset > 0) {
50
+ console.log(`🔧 检测到音频偏移: ${audioOffset.toFixed(3)}s,自动补偿`);
51
+ }
52
+ return audioOffset;
53
+ }
54
+ catch {
55
+ return 0;
56
+ }
57
+ }
58
+ function getVideoDuration(inputPath) {
59
+ const probeCmd = `ffprobe -v error -show_entries format=duration -of csv=p=0 "file:${inputPath}"`;
60
+ return parseFloat(execSync(probeCmd).toString().trim());
61
+ }
62
+ function mergeDeleteSegments(segments) {
63
+ const merged = [];
64
+ for (const seg of segments) {
65
+ if (!Number.isFinite(seg.start) || !Number.isFinite(seg.end) || seg.end <= seg.start)
66
+ continue;
67
+ if (merged.length === 0 || seg.start > merged[merged.length - 1].end) {
68
+ merged.push({ ...seg });
69
+ }
70
+ else {
71
+ merged[merged.length - 1].end = Math.max(merged[merged.length - 1].end, seg.end);
72
+ }
73
+ }
74
+ return merged;
75
+ }
76
+ export function computeCutPlan(inputPath, deleteList, projectPath) {
77
+ const duration = getVideoDuration(inputPath);
78
+ const audioOffset = getAudioOffset(projectPath);
79
+ const bufferSec = BUFFER_MS / 1000;
80
+ const expandedDelete = (Array.isArray(deleteList) ? deleteList : [])
81
+ .map((seg) => ({
82
+ start: Math.max(0, Number(seg.start || 0) - audioOffset - bufferSec),
83
+ end: Math.min(duration, Number(seg.end || 0) - audioOffset + bufferSec),
84
+ }))
85
+ .sort((a, b) => a.start - b.start);
86
+ const mergedDelete = mergeDeleteSegments(expandedDelete);
87
+ const keepSegments = [];
88
+ let cursor = 0;
89
+ for (const del of mergedDelete) {
90
+ if (del.start > cursor)
91
+ keepSegments.push({ start: cursor, end: del.start });
92
+ cursor = del.end;
93
+ }
94
+ if (cursor < duration)
95
+ keepSegments.push({ start: cursor, end: duration });
96
+ return {
97
+ duration,
98
+ audioOffset,
99
+ bufferSec,
100
+ crossfadeSec: CROSSFADE_MS / 1000,
101
+ mergedDelete,
102
+ keepSegments,
103
+ };
104
+ }
105
+ function buildFilterComplex(keepSegments, crossfadeSec) {
106
+ const filters = [];
107
+ let vconcat = '';
108
+ for (let i = 0; i < keepSegments.length; i += 1) {
109
+ const seg = keepSegments[i];
110
+ filters.push(`[0:v]trim=start=${seg.start.toFixed(3)}:end=${seg.end.toFixed(3)},setpts=PTS-STARTPTS[v${i}]`);
111
+ filters.push(`[0:a]atrim=start=${seg.start.toFixed(3)}:end=${seg.end.toFixed(3)},asetpts=PTS-STARTPTS[a${i}]`);
112
+ vconcat += `[v${i}]`;
113
+ }
114
+ filters.push(`${vconcat}concat=n=${keepSegments.length}:v=1:a=0[outv]`);
115
+ if (keepSegments.length === 1) {
116
+ filters.push('[a0]anull[outa]');
117
+ }
118
+ else {
119
+ let currentLabel = 'a0';
120
+ for (let i = 1; i < keepSegments.length; i += 1) {
121
+ const nextLabel = `a${i}`;
122
+ const outLabel = i === keepSegments.length - 1 ? 'outa' : `amid${i}`;
123
+ filters.push(`[${currentLabel}][${nextLabel}]acrossfade=d=${crossfadeSec.toFixed(3)}:c1=tri:c2=tri[${outLabel}]`);
124
+ currentLabel = outLabel;
125
+ }
126
+ }
127
+ return filters.join(';');
128
+ }
129
+ function executeFFmpegCutFallback(inputPath, keepSegments, outputPath) {
130
+ const tmpDir = `tmp_cut_${Date.now()}`;
131
+ fs.mkdirSync(tmpDir, { recursive: true });
132
+ try {
133
+ const partFiles = [];
134
+ keepSegments.forEach((seg, i) => {
135
+ const partFile = path.join(tmpDir, `part${i.toString().padStart(4, '0')}.mp4`);
136
+ const segDuration = seg.end - seg.start;
137
+ const encoder = getEncoder();
138
+ const cmd = `ffmpeg -y -ss ${seg.start.toFixed(3)} -i "file:${inputPath}" -t ${segDuration.toFixed(3)} -c:v ${encoder.name} ${encoder.args} -c:a aac -b:a 128k -avoid_negative_ts make_zero "${partFile}"`;
139
+ console.log(`切割片段 ${i + 1}/${keepSegments.length}: ${seg.start.toFixed(2)}s - ${seg.end.toFixed(2)}s`);
140
+ execSync(cmd, { stdio: 'pipe' });
141
+ partFiles.push(partFile);
142
+ });
143
+ const listFile = path.join(tmpDir, 'list.txt');
144
+ const listContent = partFiles.map((f) => `file '${path.resolve(f)}'`).join('\n');
145
+ fs.writeFileSync(listFile, listContent);
146
+ const concatCmd = `ffmpeg -y -f concat -safe 0 -i "${listFile}" -c copy "${outputPath}"`;
147
+ console.log('合并片段...');
148
+ execSync(concatCmd, { stdio: 'pipe' });
149
+ console.log(`✅ 输出: ${outputPath}`);
150
+ }
151
+ finally {
152
+ fs.rmSync(tmpDir, { recursive: true, force: true });
153
+ }
154
+ }
155
+ export function cutVideo(inputPath, deleteList, outputPath, projectPath) {
156
+ if (!Array.isArray(deleteList) || deleteList.length === 0) {
157
+ throw new Error('deleteList 不能为空');
158
+ }
159
+ const plan = computeCutPlan(inputPath, deleteList, projectPath);
160
+ if (plan.keepSegments.length === 0) {
161
+ throw new Error('删除范围覆盖整个视频,无法输出空视频');
162
+ }
163
+ console.log(`⚙️ 优化参数: 扩展范围=${BUFFER_MS}ms, 音频crossfade=${CROSSFADE_MS}ms`);
164
+ console.log(`保留 ${plan.keepSegments.length} 个片段,删除 ${plan.mergedDelete.length} 个片段`);
165
+ const filterComplex = buildFilterComplex(plan.keepSegments, plan.crossfadeSec);
166
+ const encoder = getEncoder();
167
+ console.log(`✂️ 执行 FFmpeg 精确剪辑(${encoder.label})...`);
168
+ const cmd = `ffmpeg -y -i "file:${inputPath}" -filter_complex "${filterComplex}" -map "[outv]" -map "[outa]" -c:v ${encoder.name} ${encoder.args} -c:a aac -b:a 192k "file:${outputPath}"`;
169
+ try {
170
+ execSync(cmd, { stdio: 'pipe' });
171
+ console.log(`✅ 输出: ${outputPath}`);
172
+ }
173
+ catch {
174
+ console.error('FFmpeg 执行失败,尝试分段方案...');
175
+ executeFFmpegCutFallback(inputPath, plan.keepSegments, outputPath);
176
+ }
177
+ const newDuration = getVideoDuration(outputPath);
178
+ console.log(`📹 新时长: ${newDuration.toFixed(2)}s`);
179
+ return {
180
+ outputPath,
181
+ keepSegments: plan.keepSegments,
182
+ mergedDelete: plan.mergedDelete,
183
+ audioOffset: plan.audioOffset,
184
+ originalDuration: plan.duration,
185
+ newDuration,
186
+ };
187
+ }
188
+ //# sourceMappingURL=video.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video.js","sourceRoot":"","sources":["../../src/core/video.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { transcribe } from './commands/transcribe.js';
4
+ import { generateSubtitles } from './commands/generate-subtitles.js';
5
+ import { generateReview } from './commands/generate-readable.js';
6
+ import { applyEdits } from './commands/apply-edits.js';
7
+ import { reviewServer } from './commands/review-server.js';
8
+ import { cutVideo } from './commands/cut-video.js';
9
+ const program = new Command();
10
+ program
11
+ .name('videocut')
12
+ .description('Video clipping CLI tool for podcast videos')
13
+ .version('1.0.0');
14
+ program
15
+ .command('transcribe <video>')
16
+ .description('Transcribe video using Volcengine API')
17
+ .option('-o, --output <dir>', 'Output directory')
18
+ .action(transcribe);
19
+ program
20
+ .command('generate-subtitles <json>')
21
+ .description('Generate subtitles structure from transcription')
22
+ .option('-o, --output <file>', 'Output file path')
23
+ .action(generateSubtitles);
24
+ program
25
+ .command('generate-readable <subtitles>')
26
+ .description('Generate readable review format from subtitles')
27
+ .option('-o, --output <file>', 'Output file path')
28
+ .action(generateReview);
29
+ program
30
+ .command('apply-edits <subtitles> <edits>')
31
+ .description('Apply edits to subtitles')
32
+ .option('-o, --output <file>', 'Output file path')
33
+ .action(applyEdits);
34
+ program
35
+ .command('review-server [port]')
36
+ .description('Start review server')
37
+ .option('-p, --path <path>', 'Root path for projects')
38
+ .action(reviewServer);
39
+ program
40
+ .command('cut <video> <segments>')
41
+ .description('Cut video based on delete segments')
42
+ .option('-o, --output <file>', 'Output video path')
43
+ .option('--project <path>', 'Project path for audio offset')
44
+ .action(cutVideo);
45
+ program.parse();
46
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEnD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CAAC,4CAA4C,CAAC;KACzD,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,oBAAoB,CAAC;KAC7B,WAAW,CAAC,uCAAuC,CAAC;KACpD,MAAM,CAAC,oBAAoB,EAAE,kBAAkB,CAAC;KAChD,MAAM,CAAC,UAAU,CAAC,CAAC;AAEtB,OAAO;KACJ,OAAO,CAAC,2BAA2B,CAAC;KACpC,WAAW,CAAC,iDAAiD,CAAC;KAC9D,MAAM,CAAC,qBAAqB,EAAE,kBAAkB,CAAC;KACjD,MAAM,CAAC,iBAAiB,CAAC,CAAC;AAE7B,OAAO;KACJ,OAAO,CAAC,+BAA+B,CAAC;KACxC,WAAW,CAAC,gDAAgD,CAAC;KAC7D,MAAM,CAAC,qBAAqB,EAAE,kBAAkB,CAAC;KACjD,MAAM,CAAC,cAAc,CAAC,CAAC;AAE1B,OAAO;KACJ,OAAO,CAAC,iCAAiC,CAAC;KAC1C,WAAW,CAAC,0BAA0B,CAAC;KACvC,MAAM,CAAC,qBAAqB,EAAE,kBAAkB,CAAC;KACjD,MAAM,CAAC,UAAU,CAAC,CAAC;AAEtB,OAAO;KACJ,OAAO,CAAC,sBAAsB,CAAC;KAC/B,WAAW,CAAC,qBAAqB,CAAC;KAClC,MAAM,CAAC,mBAAmB,EAAE,wBAAwB,CAAC;KACrD,MAAM,CAAC,YAAY,CAAC,CAAC;AAExB,OAAO;KACJ,OAAO,CAAC,wBAAwB,CAAC;KACjC,WAAW,CAAC,oCAAoC,CAAC;KACjD,MAAM,CAAC,qBAAqB,EAAE,mBAAmB,CAAC;KAClD,MAAM,CAAC,kBAAkB,EAAE,+BAA+B,CAAC;KAC3D,MAAM,CAAC,QAAQ,CAAC,CAAC;AAEpB,OAAO,CAAC,KAAK,EAAE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@huiqinghuang/videocut-cli",
3
+ "version": "1.0.0",
4
+ "description": "Video clipping CLI tool for podcast videos",
5
+ "type": "module",
6
+ "bin": {
7
+ "videocut": "./bin/videocut.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "bin",
12
+ "static"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "dev": "tsc --watch",
17
+ "prepublishOnly": "npm run build"
18
+ },
19
+ "keywords": [
20
+ "video",
21
+ "clipping",
22
+ "subtitle",
23
+ "ffmpeg"
24
+ ],
25
+ "author": "sunnyswag",
26
+ "license": "MIT",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git+https://github.com/sunnyswag/videocut.git"
30
+ },
31
+ "bugs": {
32
+ "url": "https://github.com/sunnyswag/videocut/issues"
33
+ },
34
+ "homepage": "https://github.com/sunnyswag/videocut#readme",
35
+ "dependencies": {
36
+ "commander": "^12.0.0"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "^20.10.0",
40
+ "typescript": "^5.3.0"
41
+ },
42
+ "engines": {
43
+ "node": ">=18.0.0"
44
+ }
45
+ }