ai-sub-translator 1.0.2 → 1.1.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.
- package/dist/ffmpeg.d.ts +13 -0
- package/dist/ffmpeg.d.ts.map +1 -0
- package/dist/ffmpeg.js +222 -0
- package/dist/ffmpeg.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/subtitle-extractor.d.ts +5 -0
- package/dist/subtitle-extractor.d.ts.map +1 -0
- package/dist/subtitle-extractor.js +83 -0
- package/dist/subtitle-extractor.js.map +1 -0
- package/dist/types.d.ts +60 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -2
package/dist/ffmpeg.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { FFmpegDownloadOptions, VideoInfo } from './types.js';
|
|
2
|
+
export declare const initializeFFmpeg: (options: FFmpegDownloadOptions) => Promise<string>;
|
|
3
|
+
export declare const getFfmpegExecPath: (outputDir: string) => string;
|
|
4
|
+
export declare function downloadFFmpeg(options: FFmpegDownloadOptions): Promise<string>;
|
|
5
|
+
/**
|
|
6
|
+
* Default ffmpeg directory in user's cache
|
|
7
|
+
*/
|
|
8
|
+
export declare const getUserDataDir: () => string;
|
|
9
|
+
/**
|
|
10
|
+
* Gets information about a video file, including available subtitle tracks
|
|
11
|
+
*/
|
|
12
|
+
export declare function getVideoInfo(videoPath: string): Promise<VideoInfo>;
|
|
13
|
+
//# sourceMappingURL=ffmpeg.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ffmpeg.d.ts","sourceRoot":"","sources":["../src/ffmpeg.ts"],"names":[],"mappings":"AASA,OAAO,EACH,qBAAqB,EACrB,SAAS,EACZ,MAAM,YAAY,CAAC;AAapB,eAAO,MAAM,gBAAgB,GAAU,SAAS,qBAAqB,KAAG,OAAO,CAAC,MAAM,CAYrF,CAAA;AAQD,eAAO,MAAM,iBAAiB,GAAI,WAAW,MAAM,WAElD,CAAA;AAyBD,wBAAsB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiJpF;AAsBD;;GAEG;AACH,eAAO,MAAM,cAAc,QAAO,MAGjC,CAAC;AAEF;;GAEG;AACH,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAIxE"}
|
package/dist/ffmpeg.js
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import unzipper from 'unzipper';
|
|
5
|
+
import { XzReadableStream } from 'xz-decompress';
|
|
6
|
+
import { extract as tarExtract } from 'tar';
|
|
7
|
+
import { detectSubtitles, } from './subtitle-extractor.js';
|
|
8
|
+
import { Readable } from 'stream';
|
|
9
|
+
import { promises as fsPromises } from 'fs';
|
|
10
|
+
const { rename: moveFile, rm: removeDir, chmod: chmodFile, unlink: removeFile, stat: statFile, mkdir: makeDir } = fsPromises;
|
|
11
|
+
const URL_MAC_X64 = 'https://evermeet.cx/pub/ffmpeg/ffmpeg-7.1.1.zip';
|
|
12
|
+
const URL_MAC_ARM64 = 'https://www.osxexperts.net/ffmpeg711arm.zip';
|
|
13
|
+
const URL_LINUX_X64 = 'https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz';
|
|
14
|
+
const URL_LINUX_ARM64 = 'https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-arm64-static.tar.xz';
|
|
15
|
+
const URL_WIN_X64 = 'https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip';
|
|
16
|
+
export const initializeFFmpeg = async (options) => {
|
|
17
|
+
const downloadPath = getUserDataDir();
|
|
18
|
+
const execPath = getFfmpegExecPath(downloadPath);
|
|
19
|
+
if (execPath && fs.existsSync(execPath)) {
|
|
20
|
+
console.log(`Using existing ffmpeg at ${execPath}`);
|
|
21
|
+
return execPath;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
options.outputDir = downloadPath;
|
|
25
|
+
}
|
|
26
|
+
return downloadFFmpeg(options);
|
|
27
|
+
};
|
|
28
|
+
const getExecName = () => {
|
|
29
|
+
const platform = os.platform();
|
|
30
|
+
const extension = platform === 'win32' ? '.exe' : '';
|
|
31
|
+
return `ffmpeg${extension}`;
|
|
32
|
+
};
|
|
33
|
+
export const getFfmpegExecPath = (outputDir) => {
|
|
34
|
+
return path.join(outputDir, getExecName());
|
|
35
|
+
};
|
|
36
|
+
const findExecutable = async (dir, execName) => {
|
|
37
|
+
const files = fs.readdirSync(dir);
|
|
38
|
+
for (const file of files) {
|
|
39
|
+
const filePath = path.join(dir, file);
|
|
40
|
+
let stat;
|
|
41
|
+
try {
|
|
42
|
+
stat = await statFile(filePath);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.error(`Error getting stats for file ${filePath}:`, error);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (stat.isFile() && execName === file) {
|
|
49
|
+
return filePath;
|
|
50
|
+
}
|
|
51
|
+
else if (stat.isDirectory()) {
|
|
52
|
+
const result = await findExecutable(filePath, execName);
|
|
53
|
+
if (result) {
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
};
|
|
60
|
+
export async function downloadFFmpeg(options) {
|
|
61
|
+
const platform = options.platform || os.platform();
|
|
62
|
+
const arch = os.arch();
|
|
63
|
+
const url = getFFmpegDownloadUrl(platform, arch);
|
|
64
|
+
let extension = url.split('.').pop();
|
|
65
|
+
if (extension === 'xz') {
|
|
66
|
+
extension = 'tar.xz';
|
|
67
|
+
}
|
|
68
|
+
// Create directory if it doesn't exist
|
|
69
|
+
if (!fs.existsSync(options.outputDir)) {
|
|
70
|
+
fs.mkdirSync(options.outputDir, { recursive: true });
|
|
71
|
+
}
|
|
72
|
+
const filename = `ffmpeg.${extension}`;
|
|
73
|
+
const outputPath = path.join(options.outputDir, filename);
|
|
74
|
+
try {
|
|
75
|
+
console.log(`Downloading ffmpeg from ${url}...`);
|
|
76
|
+
const response = await fetch(url);
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
throw new Error(`Failed to download ffmpeg: ${response.statusText}`);
|
|
79
|
+
}
|
|
80
|
+
const totalSize = parseInt(response.headers.get('content-length') || '0', 10);
|
|
81
|
+
const reader = response.body?.getReader();
|
|
82
|
+
if (!reader) {
|
|
83
|
+
throw new Error('Unable to read response body');
|
|
84
|
+
}
|
|
85
|
+
const writer = fs.createWriteStream(outputPath);
|
|
86
|
+
let receivedBytes = 0;
|
|
87
|
+
while (true) {
|
|
88
|
+
const { done, value } = await reader.read();
|
|
89
|
+
if (done)
|
|
90
|
+
break;
|
|
91
|
+
writer.write(Buffer.from(value));
|
|
92
|
+
receivedBytes += value.length;
|
|
93
|
+
if (options.onProgress && totalSize > 0) {
|
|
94
|
+
const progress = receivedBytes / totalSize;
|
|
95
|
+
options.onProgress(progress);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
writer.end();
|
|
99
|
+
console.log(`FFmpeg downloaded successfully to ${outputPath}`);
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
console.error('Error downloading ffmpeg:', error);
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
// Extract the file
|
|
106
|
+
const extractDir = path.join(options.outputDir, 'extracted');
|
|
107
|
+
if (extension === 'zip') {
|
|
108
|
+
const zip = fs.createReadStream(outputPath);
|
|
109
|
+
const extract = unzipper.Extract({ path: extractDir });
|
|
110
|
+
zip.pipe(extract);
|
|
111
|
+
try {
|
|
112
|
+
await new Promise((resolve, reject) => {
|
|
113
|
+
zip.on('end', () => resolve());
|
|
114
|
+
zip.on('error', reject);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
console.error('Error unzipping ffmpeg:', error);
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
else if (extension === 'tar.xz') {
|
|
123
|
+
try {
|
|
124
|
+
const decompressedFilePath = path.join(getUserDataDir(), 'ffmpeg.tar');
|
|
125
|
+
const decompressedFile = fs.createWriteStream(decompressedFilePath);
|
|
126
|
+
const compressedFile = fs.createReadStream(outputPath);
|
|
127
|
+
const webStream = Readable.toWeb(compressedFile);
|
|
128
|
+
const decompressor = new XzReadableStream(webStream);
|
|
129
|
+
const xzReader = decompressor.getReader();
|
|
130
|
+
while (true) {
|
|
131
|
+
const { done, value } = await xzReader.read();
|
|
132
|
+
if (done)
|
|
133
|
+
break;
|
|
134
|
+
decompressedFile.write(Buffer.from(value));
|
|
135
|
+
}
|
|
136
|
+
decompressedFile.end();
|
|
137
|
+
await new Promise((resolve, reject) => {
|
|
138
|
+
decompressedFile.on('finish', resolve);
|
|
139
|
+
decompressedFile.on('error', reject);
|
|
140
|
+
});
|
|
141
|
+
await makeDir(extractDir, { recursive: true });
|
|
142
|
+
await tarExtract({
|
|
143
|
+
file: decompressedFilePath,
|
|
144
|
+
cwd: extractDir,
|
|
145
|
+
});
|
|
146
|
+
await removeFile(decompressedFilePath);
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
console.error('Error decompressing ffmpeg:', error);
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
console.log(`Archive format not supported: ${extension}`);
|
|
155
|
+
}
|
|
156
|
+
const execName = getExecName();
|
|
157
|
+
const execOutputPath = getFfmpegExecPath(getUserDataDir());
|
|
158
|
+
const execExtractedOutputPath = await findExecutable(extractDir, execName);
|
|
159
|
+
try {
|
|
160
|
+
await moveFile(execExtractedOutputPath, execOutputPath);
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
console.error('Error moving ffmpeg:', error);
|
|
164
|
+
throw error;
|
|
165
|
+
}
|
|
166
|
+
try {
|
|
167
|
+
await removeDir(extractDir, { recursive: true });
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
console.error('Error removing extracted directory:', error);
|
|
171
|
+
}
|
|
172
|
+
try {
|
|
173
|
+
await removeFile(outputPath);
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
console.error('Error removing extracted file:', error);
|
|
177
|
+
}
|
|
178
|
+
if (platform !== 'win32') {
|
|
179
|
+
try {
|
|
180
|
+
await chmodFile(execOutputPath, 0o755);
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
console.error('Error chmodding ffmpeg:', error);
|
|
184
|
+
throw error;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return execOutputPath;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Gets the appropriate ffmpeg download URL based on the platform
|
|
191
|
+
*/
|
|
192
|
+
function getFFmpegDownloadUrl(platform, arch) {
|
|
193
|
+
switch (platform) {
|
|
194
|
+
case 'win32':
|
|
195
|
+
return URL_WIN_X64;
|
|
196
|
+
case 'darwin':
|
|
197
|
+
return arch === 'arm64'
|
|
198
|
+
? URL_MAC_ARM64
|
|
199
|
+
: URL_MAC_X64;
|
|
200
|
+
case 'linux':
|
|
201
|
+
return arch === 'arm64'
|
|
202
|
+
? URL_LINUX_ARM64
|
|
203
|
+
: URL_LINUX_X64;
|
|
204
|
+
default:
|
|
205
|
+
throw new Error(`Unsupported platform: ${platform}`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Default ffmpeg directory in user's cache
|
|
210
|
+
*/
|
|
211
|
+
export const getUserDataDir = () => {
|
|
212
|
+
const home = os.homedir();
|
|
213
|
+
return path.join(home, '.cache', 'ai-sub-translator');
|
|
214
|
+
};
|
|
215
|
+
/**
|
|
216
|
+
* Gets information about a video file, including available subtitle tracks
|
|
217
|
+
*/
|
|
218
|
+
export async function getVideoInfo(videoPath) {
|
|
219
|
+
const ffmpegPath = await initializeFFmpeg({});
|
|
220
|
+
return detectSubtitles(videoPath, ffmpegPath);
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=ffmpeg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ffmpeg.js","sourceRoot":"","sources":["../src/ffmpeg.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { translate } from './translator.js';
|
|
2
2
|
export { parseSrt, formatSrt } from './srt-parser.js';
|
|
3
|
-
export
|
|
3
|
+
export { initializeFFmpeg, getFfmpegExecPath, getVideoInfo, getUserDataDir } from './ffmpeg.js';
|
|
4
|
+
export { detectSubtitles, extractSubtitle, parseFfmpegSubtitleStreams } from './subtitle-extractor.js';
|
|
5
|
+
export type { TranslateOptions, TranslateResult, SrtEntry, FFmpegDownloadOptions, SubtitleTrack, VideoInfo, ExtractSubtitleOptions } from './types.js';
|
|
4
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACtD,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAChG,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AACvG,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,QAAQ,EAAE,qBAAqB,EAAE,aAAa,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { translate } from './translator.js';
|
|
2
2
|
export { parseSrt, formatSrt } from './srt-parser.js';
|
|
3
|
+
export { initializeFFmpeg, getFfmpegExecPath, getVideoInfo, getUserDataDir } from './ffmpeg.js';
|
|
4
|
+
export { detectSubtitles, extractSubtitle, parseFfmpegSubtitleStreams } from './subtitle-extractor.js';
|
|
3
5
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAChG,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { SubtitleTrack, VideoInfo } from './types.js';
|
|
2
|
+
export declare function parseFfmpegSubtitleStreams(output: string): SubtitleTrack[];
|
|
3
|
+
export declare function detectSubtitles(videoPath: string, ffmpegPath: string): Promise<VideoInfo>;
|
|
4
|
+
export declare function extractSubtitle(videoPath: string, subtitleIndex: number): Promise<string>;
|
|
5
|
+
//# sourceMappingURL=subtitle-extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subtitle-extractor.d.ts","sourceRoot":"","sources":["../src/subtitle-extractor.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAOtD,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,EAAE,CAgC1E;AAED,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAmB/F;AAED,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA+B/F"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as childProcess from 'child_process';
|
|
4
|
+
import { promisify } from 'util';
|
|
5
|
+
import { getFfmpegExecPath, getUserDataDir } from './ffmpeg.js';
|
|
6
|
+
import { promises as fsPromises } from 'fs';
|
|
7
|
+
const exec = promisify(childProcess.exec);
|
|
8
|
+
const { readFile, unlink: rmFile } = fsPromises;
|
|
9
|
+
export function parseFfmpegSubtitleStreams(output) {
|
|
10
|
+
const lines = output.split('\n');
|
|
11
|
+
const subtitles = [];
|
|
12
|
+
const streamRegex = /Stream #0:(\d+)(?:\((\w+)\))?: Subtitle: [^\s]+(?: \(([^\)]+)\))?(?: \(([^\)]+)\))?/i;
|
|
13
|
+
const titleRegex = /title\s+:\s+(.+)/i;
|
|
14
|
+
let currentStream = null;
|
|
15
|
+
for (const line of lines) {
|
|
16
|
+
const streamMatch = line.match(streamRegex);
|
|
17
|
+
if (streamMatch) {
|
|
18
|
+
const [, index, lang, flag1] = streamMatch;
|
|
19
|
+
currentStream = {
|
|
20
|
+
index: parseInt(index),
|
|
21
|
+
language: lang,
|
|
22
|
+
format: flag1,
|
|
23
|
+
};
|
|
24
|
+
subtitles.push(currentStream);
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (currentStream && line.includes('Metadata'))
|
|
28
|
+
continue;
|
|
29
|
+
const titleMatch = line.match(titleRegex);
|
|
30
|
+
if (titleMatch && currentStream) {
|
|
31
|
+
currentStream.title = titleMatch[1].trim();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return subtitles;
|
|
35
|
+
}
|
|
36
|
+
export async function detectSubtitles(videoPath, ffmpegPath) {
|
|
37
|
+
if (!fs.existsSync(videoPath)) {
|
|
38
|
+
throw new Error(`Video file does not exist: ${videoPath}`);
|
|
39
|
+
}
|
|
40
|
+
let commandOutput = '';
|
|
41
|
+
try {
|
|
42
|
+
await exec(`"${ffmpegPath}" -i "${videoPath}"`);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
commandOutput = error.message;
|
|
46
|
+
}
|
|
47
|
+
const subtitleTracks = parseFfmpegSubtitleStreams(commandOutput).filter((track) => track.format.includes('srt'));
|
|
48
|
+
return {
|
|
49
|
+
path: videoPath,
|
|
50
|
+
subtitleTracks
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export async function extractSubtitle(videoPath, subtitleIndex) {
|
|
54
|
+
const outputPath = path.join(getUserDataDir(), `subtitle-${Date.now()}.srt`);
|
|
55
|
+
const ffmpegPath = getFfmpegExecPath(getUserDataDir());
|
|
56
|
+
if (!fs.existsSync(videoPath)) {
|
|
57
|
+
throw new Error(`Video file does not exist: ${videoPath}`);
|
|
58
|
+
}
|
|
59
|
+
// Ensure cache directory exists
|
|
60
|
+
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
61
|
+
try {
|
|
62
|
+
await exec(`"${ffmpegPath}" -i "${videoPath}" -map 0:${subtitleIndex} -y "${outputPath}"`);
|
|
63
|
+
if (!fs.existsSync(outputPath)) {
|
|
64
|
+
throw new Error('Subtitle extraction failed: Output file not created');
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const text = await readFile(outputPath, 'utf8');
|
|
68
|
+
return text;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
console.error('Error reading subtitle file:', error);
|
|
72
|
+
throw new Error(`Failed to read subtitle file: ${error.message || error}`);
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
await rmFile(outputPath);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
console.error('Error extracting subtitle:', error);
|
|
80
|
+
throw new Error(`Failed to extract subtitle: ${error.message || error}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=subtitle-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subtitle-extractor.js","sourceRoot":"","sources":["../src/subtitle-extractor.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -18,4 +18,64 @@ export interface TranslateResult {
|
|
|
18
18
|
totalBatches: number;
|
|
19
19
|
completedBatches: number;
|
|
20
20
|
}
|
|
21
|
+
export interface FFmpegDownloadOptions {
|
|
22
|
+
/**
|
|
23
|
+
* Directory where the ffmpeg executable will be saved
|
|
24
|
+
*/
|
|
25
|
+
outputDir?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Platform to download ffmpeg for: 'darwin' (macOS), 'win32' (Windows), or 'linux'
|
|
28
|
+
*/
|
|
29
|
+
platform?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Progress callback function that receives download progress percentage
|
|
32
|
+
*/
|
|
33
|
+
onProgress?: (progress: number) => void;
|
|
34
|
+
}
|
|
35
|
+
export interface SubtitleTrack {
|
|
36
|
+
/**
|
|
37
|
+
* Subtitle track index in the video file
|
|
38
|
+
*/
|
|
39
|
+
index: number;
|
|
40
|
+
/**
|
|
41
|
+
* Language of the subtitle track (if available)
|
|
42
|
+
*/
|
|
43
|
+
language: string;
|
|
44
|
+
/**
|
|
45
|
+
* Title of the subtitle track (if available)
|
|
46
|
+
*/
|
|
47
|
+
title?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Format of the subtitle track (srt, ass, etc.)
|
|
50
|
+
*/
|
|
51
|
+
format: string;
|
|
52
|
+
}
|
|
53
|
+
export interface VideoInfo {
|
|
54
|
+
/**
|
|
55
|
+
* Full path to the video file
|
|
56
|
+
*/
|
|
57
|
+
path: string;
|
|
58
|
+
/**
|
|
59
|
+
* List of subtitle tracks found in the video
|
|
60
|
+
*/
|
|
61
|
+
subtitleTracks: SubtitleTrack[];
|
|
62
|
+
}
|
|
63
|
+
export interface ExtractSubtitleOptions {
|
|
64
|
+
/**
|
|
65
|
+
* Path to the video file
|
|
66
|
+
*/
|
|
67
|
+
videoPath: string;
|
|
68
|
+
/**
|
|
69
|
+
* Index of the subtitle track to extract
|
|
70
|
+
*/
|
|
71
|
+
subtitleIndex: number;
|
|
72
|
+
/**
|
|
73
|
+
* Output path where the subtitle file will be saved
|
|
74
|
+
*/
|
|
75
|
+
outputPath: string;
|
|
76
|
+
/**
|
|
77
|
+
* Path to the ffmpeg executable
|
|
78
|
+
*/
|
|
79
|
+
ffmpegPath: string;
|
|
80
|
+
}
|
|
21
81
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;CAC1B"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAED,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,SAAS;IACxB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,cAAc,EAAE,aAAa,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,aAAa,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;CACpB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-sub-translator",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "AI-powered subtitle translator using Google Gemini. Translates SRT subtitles to any language.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -34,9 +34,13 @@
|
|
|
34
34
|
},
|
|
35
35
|
"license": "MIT",
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@google/genai": "^0.8.0"
|
|
37
|
+
"@google/genai": "^0.8.0",
|
|
38
|
+
"tar": "^7.4.3",
|
|
39
|
+
"unzipper": "^0.12.3",
|
|
40
|
+
"xz-decompress": "^0.2.2"
|
|
38
41
|
},
|
|
39
42
|
"devDependencies": {
|
|
43
|
+
"@types/unzipper": "^0.10.11",
|
|
40
44
|
"typescript": "^5.7.2",
|
|
41
45
|
"vitest": "^2.1.8"
|
|
42
46
|
}
|