transcribly 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.
package/dist/index.js ADDED
@@ -0,0 +1,288 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ var __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const commander_1 = require("commander");
43
+ const chalk_1 = __importDefault(require("chalk"));
44
+ const dotenv_1 = require("dotenv");
45
+ const transcriber_1 = require("./transcriber");
46
+ const youtube_1 = require("./youtube");
47
+ const utils_1 = require("./utils");
48
+ const dependencies_1 = require("./dependencies");
49
+ const config_1 = require("./config");
50
+ const readline = __importStar(require("readline"));
51
+ const openai_1 = __importDefault(require("openai"));
52
+ const program = new commander_1.Command();
53
+ program
54
+ .name("transcribly")
55
+ .description("Transcribe YouTube videos and local audio/video files using OpenAI Whisper API")
56
+ .version("1.0.0");
57
+ program
58
+ .command("url <youtube-url>")
59
+ .description("Transcribe a YouTube video")
60
+ .option("-o, --output <dir>", "Output directory", "./text")
61
+ .option("-f, --format <format>", "Output format (txt or json)", "txt")
62
+ .option("-k, --api-key <key>", "OpenAI API key")
63
+ .action(async (url, options) => {
64
+ await handleTranscribeUrl(url, options);
65
+ });
66
+ program
67
+ .command("file <path>")
68
+ .description("Transcribe a local audio/video file")
69
+ .option("-o, --output <dir>", "Output directory", "./text")
70
+ .option("-f, --format <format>", "Output format (txt or json)", "txt")
71
+ .option("-k, --api-key <key>", "OpenAI API key")
72
+ .action(async (filePath, options) => {
73
+ await handleTranscribeFile(filePath, options);
74
+ });
75
+ // Default command: auto-detect URL vs file path
76
+ program
77
+ .argument("[input]", "YouTube URL or local file path")
78
+ .option("-o, --output <dir>", "Output directory", "./text")
79
+ .option("-f, --format <format>", "Output format (txt or json)", "txt")
80
+ .option("-k, --api-key <key>", "OpenAI API key")
81
+ .option("--setup", "Set up OpenAI API key interactively")
82
+ .option("--doctor", "Check all system dependencies and report status")
83
+ .action(async (input, options) => {
84
+ if (options.doctor) {
85
+ await (0, dependencies_1.runDoctor)();
86
+ return;
87
+ }
88
+ if (options.setup) {
89
+ await runSetup();
90
+ return;
91
+ }
92
+ if (!input) {
93
+ program.help();
94
+ return;
95
+ }
96
+ if ((0, youtube_1.isYouTubeUrl)(input)) {
97
+ await handleTranscribeUrl(input, options);
98
+ }
99
+ else {
100
+ await handleTranscribeFile(input, options);
101
+ }
102
+ });
103
+ function getApiKey(options) {
104
+ // 1. --api-key flag
105
+ if (options.apiKey)
106
+ return options.apiKey;
107
+ // 2. Real OPENAI_API_KEY env var (before loading .env)
108
+ const envKey = process.env.OPENAI_API_KEY;
109
+ if (envKey)
110
+ return envKey;
111
+ // 3. ~/.transcribly/config.json
112
+ const configKey = (0, config_1.readConfig)().apiKey;
113
+ if (configKey)
114
+ return configKey;
115
+ // 4. .env file in current working directory
116
+ (0, dotenv_1.config)({ path: path.resolve(process.cwd(), ".env"), override: false });
117
+ if (process.env.OPENAI_API_KEY)
118
+ return process.env.OPENAI_API_KEY;
119
+ // 5. .env in CLI directory
120
+ (0, dotenv_1.config)({ path: path.resolve(__dirname, "..", ".env"), override: false });
121
+ if (process.env.OPENAI_API_KEY)
122
+ return process.env.OPENAI_API_KEY;
123
+ // No key found — show helpful error
124
+ console.error(chalk_1.default.red("Error: OpenAI API key required for transcription.\n"));
125
+ console.error("Set it up in one of these ways:");
126
+ console.error(" 1. Run: transcribly --setup");
127
+ console.error(' 2. Set env var: export OPENAI_API_KEY="sk-..."');
128
+ console.error(" 3. Add to .env file: OPENAI_API_KEY=sk-...");
129
+ console.error("\nGet your API key at: https://platform.openai.com/api-keys");
130
+ process.exit(1);
131
+ }
132
+ async function promptApiKey() {
133
+ return new Promise((resolve) => {
134
+ process.stdout.write("Enter your OpenAI API key: ");
135
+ if (process.stdin.isTTY) {
136
+ // Mask input in interactive terminals
137
+ const stdin = process.stdin;
138
+ stdin.setRawMode(true);
139
+ stdin.resume();
140
+ stdin.setEncoding("utf8");
141
+ let input = "";
142
+ const onData = (char) => {
143
+ const code = char.charCodeAt(0);
144
+ if (char === "\r" || char === "\n") {
145
+ stdin.setRawMode(false);
146
+ stdin.pause();
147
+ stdin.removeListener("data", onData);
148
+ process.stdout.write("\n");
149
+ resolve(input.trim());
150
+ }
151
+ else if (code === 3) {
152
+ // Ctrl+C
153
+ stdin.setRawMode(false);
154
+ process.stdout.write("\n");
155
+ process.exit(1);
156
+ }
157
+ else if (code === 127 || code === 8) {
158
+ // Backspace
159
+ if (input.length > 0) {
160
+ input = input.slice(0, -1);
161
+ process.stdout.write("\b \b");
162
+ }
163
+ }
164
+ else {
165
+ input += char;
166
+ process.stdout.write("*");
167
+ }
168
+ };
169
+ stdin.on("data", onData);
170
+ }
171
+ else {
172
+ // Non-TTY fallback (piped input)
173
+ const rl = readline.createInterface({
174
+ input: process.stdin,
175
+ output: process.stdout,
176
+ });
177
+ rl.question("", (answer) => {
178
+ rl.close();
179
+ resolve(answer.trim());
180
+ });
181
+ }
182
+ });
183
+ }
184
+ async function validateApiKey(apiKey) {
185
+ try {
186
+ const client = new openai_1.default({ apiKey });
187
+ await client.models.list();
188
+ return true;
189
+ }
190
+ catch {
191
+ return false;
192
+ }
193
+ }
194
+ async function runSetup() {
195
+ console.log(chalk_1.default.bold("\nTranscribly — API Key Setup\n"));
196
+ const apiKey = await promptApiKey();
197
+ if (!apiKey) {
198
+ console.error(chalk_1.default.red("No API key entered. Setup cancelled."));
199
+ process.exit(1);
200
+ }
201
+ const spinner = (0, utils_1.createSpinner)("Validating API key...");
202
+ spinner.start();
203
+ const valid = await validateApiKey(apiKey);
204
+ if (!valid) {
205
+ spinner.fail("API key validation failed. Please check the key and try again.");
206
+ process.exit(1);
207
+ }
208
+ spinner.succeed("API key validated.");
209
+ (0, config_1.writeConfig)({ apiKey });
210
+ console.log(chalk_1.default.green("\nAPI key saved to ~/.transcribly/config.json\n" +
211
+ "You can now run transcribly without setting OPENAI_API_KEY manually."));
212
+ }
213
+ async function handleTranscribeUrl(url, options) {
214
+ const apiKey = getApiKey(options);
215
+ if (!(0, youtube_1.isYouTubeUrl)(url)) {
216
+ console.error(chalk_1.default.red("Error: Invalid YouTube URL."));
217
+ process.exit(1);
218
+ }
219
+ const hasFfmpeg = await (0, dependencies_1.checkFfmpeg)();
220
+ if (!hasFfmpeg) {
221
+ console.error(chalk_1.default.red("Error: FFmpeg is required but not found."));
222
+ console.error(chalk_1.default.yellow((0, dependencies_1.getFfmpegInstallMessage)()));
223
+ console.error(chalk_1.default.gray("\nRun 'transcribly --doctor' to check all dependencies."));
224
+ process.exit(1);
225
+ }
226
+ const pythonResult = await (0, dependencies_1.checkPython)();
227
+ if (!pythonResult.ok) {
228
+ if (pythonResult.version) {
229
+ console.error(chalk_1.default.red(`Error: Python ${pythonResult.version} found, but 3.8+ is required.`));
230
+ }
231
+ else {
232
+ console.error(chalk_1.default.red("Error: Python 3.8+ is required but not found."));
233
+ }
234
+ console.error(chalk_1.default.yellow((0, dependencies_1.getPythonInstallMessage)()));
235
+ console.error(chalk_1.default.gray("\nRun 'transcribly --doctor' to check all dependencies."));
236
+ process.exit(1);
237
+ }
238
+ const tempDir = (0, utils_1.createTempDir)();
239
+ try {
240
+ const downloadResult = await (0, youtube_1.downloadYouTubeAudio)(url, tempDir);
241
+ const result = await (0, transcriber_1.transcribe)(downloadResult.filePath, apiKey);
242
+ console.log("\n" + chalk_1.default.green("--- Transcript ---"));
243
+ console.log(result.transcript);
244
+ console.log(chalk_1.default.green("--- End ---\n"));
245
+ saveOutput(result, downloadResult.videoId, options);
246
+ }
247
+ finally {
248
+ (0, utils_1.cleanupTempDir)(tempDir);
249
+ }
250
+ }
251
+ async function handleTranscribeFile(filePath, options) {
252
+ const apiKey = getApiKey(options);
253
+ const resolvedPath = (0, utils_1.validateFilePath)(filePath);
254
+ const hasFfmpeg = await (0, dependencies_1.checkFfmpeg)();
255
+ if (!hasFfmpeg) {
256
+ console.error(chalk_1.default.red("Error: FFmpeg is required but not found."));
257
+ console.error(chalk_1.default.yellow((0, dependencies_1.getFfmpegInstallMessage)()));
258
+ console.error(chalk_1.default.gray("\nRun 'transcribly --doctor' to check all dependencies."));
259
+ process.exit(1);
260
+ }
261
+ const result = await (0, transcriber_1.transcribe)(resolvedPath, apiKey);
262
+ const baseName = path.basename(resolvedPath, path.extname(resolvedPath));
263
+ console.log("\n" + chalk_1.default.green("--- Transcript ---"));
264
+ console.log(result.transcript);
265
+ console.log(chalk_1.default.green("--- End ---\n"));
266
+ saveOutput(result, baseName, options);
267
+ }
268
+ function saveOutput(result, baseName, options) {
269
+ const format = options.format;
270
+ (0, utils_1.ensureOutputDir)(options.output);
271
+ const outputPath = (0, utils_1.getOutputFilePath)(options.output, baseName, format);
272
+ if (format === "json") {
273
+ const jsonOutput = {
274
+ audioFile: result.audioFile,
275
+ transcript: result.transcript,
276
+ };
277
+ fs.writeFileSync(outputPath, JSON.stringify(jsonOutput, null, 2));
278
+ }
279
+ else {
280
+ fs.writeFileSync(outputPath, result.transcript);
281
+ }
282
+ console.log(chalk_1.default.blue(`Transcript saved to: ${outputPath}`));
283
+ }
284
+ program.parseAsync(process.argv).catch((error) => {
285
+ console.error(chalk_1.default.red(`Error: ${error.message}`));
286
+ process.exit(1);
287
+ });
288
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export interface TranscriptionResult {
2
+ transcript: string;
3
+ audioFile: string;
4
+ }
5
+ export declare function transcribe(filePath: string, apiKey: string): Promise<TranscriptionResult>;
6
+ //# sourceMappingURL=transcriber.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcriber.d.ts","sourceRoot":"","sources":["../src/transcriber.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AA8FD,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,mBAAmB,CAAC,CAoC9B"}
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.transcribe = transcribe;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const openai_1 = __importDefault(require("openai"));
43
+ const fluent_ffmpeg_1 = __importDefault(require("fluent-ffmpeg"));
44
+ const utils_1 = require("./utils");
45
+ // Whisper API has a 25MB file size limit
46
+ const MAX_CHUNK_SIZE_MB = 24;
47
+ const CHUNK_DURATION_SECONDS = 180; // 3 minutes per chunk
48
+ function getOpenAIClient(apiKey) {
49
+ return new openai_1.default({ apiKey });
50
+ }
51
+ function getFileSizeMB(filePath) {
52
+ const stats = fs.statSync(filePath);
53
+ return stats.size / (1024 * 1024);
54
+ }
55
+ function getAudioDuration(filePath) {
56
+ return new Promise((resolve, reject) => {
57
+ fluent_ffmpeg_1.default.ffprobe(filePath, (err, metadata) => {
58
+ if (err) {
59
+ reject(new Error(`Failed to probe audio file: ${err.message}`));
60
+ return;
61
+ }
62
+ resolve(metadata.format.duration || 0);
63
+ });
64
+ });
65
+ }
66
+ function splitAudioChunk(inputPath, outputPath, startSeconds, durationSeconds) {
67
+ return new Promise((resolve, reject) => {
68
+ (0, fluent_ffmpeg_1.default)(inputPath)
69
+ .setStartTime(startSeconds)
70
+ .setDuration(durationSeconds)
71
+ .output(outputPath)
72
+ .audioCodec("libmp3lame")
73
+ .on("end", () => resolve())
74
+ .on("error", (err) => reject(new Error(`Failed to split audio: ${err.message}`)))
75
+ .run();
76
+ });
77
+ }
78
+ async function splitAudio(filePath) {
79
+ const sizeMB = getFileSizeMB(filePath);
80
+ // If file is small enough, no splitting needed
81
+ if (sizeMB <= MAX_CHUNK_SIZE_MB) {
82
+ return [filePath];
83
+ }
84
+ const spinner = (0, utils_1.createSpinner)("Splitting audio into chunks...");
85
+ spinner.start();
86
+ try {
87
+ const duration = await getAudioDuration(filePath);
88
+ const chunkDir = (0, utils_1.createTempDir)();
89
+ const chunks = [];
90
+ let start = 0;
91
+ let index = 0;
92
+ while (start < duration) {
93
+ const chunkDuration = Math.min(CHUNK_DURATION_SECONDS, duration - start);
94
+ const chunkPath = path.join(chunkDir, `chunk_${index}.mp3`);
95
+ await splitAudioChunk(filePath, chunkPath, start, chunkDuration);
96
+ chunks.push(chunkPath);
97
+ start += chunkDuration;
98
+ index++;
99
+ }
100
+ spinner.succeed(`Split into ${chunks.length} chunks`);
101
+ return chunks;
102
+ }
103
+ catch (error) {
104
+ spinner.fail("Failed to split audio");
105
+ throw error;
106
+ }
107
+ }
108
+ async function transcribeFile(client, filePath) {
109
+ const fileStream = fs.createReadStream(filePath);
110
+ const response = await client.audio.transcriptions.create({
111
+ model: "whisper-1",
112
+ file: fileStream,
113
+ response_format: "text",
114
+ });
115
+ return response;
116
+ }
117
+ async function transcribe(filePath, apiKey) {
118
+ const client = getOpenAIClient(apiKey);
119
+ const chunks = await splitAudio(filePath);
120
+ const spinner = (0, utils_1.createSpinner)(`Transcribing${chunks.length > 1 ? ` ${chunks.length} chunks` : ""}...`);
121
+ spinner.start();
122
+ try {
123
+ const transcripts = [];
124
+ for (let i = 0; i < chunks.length; i++) {
125
+ if (chunks.length > 1) {
126
+ spinner.text = `Transcribing chunk ${i + 1}/${chunks.length}...`;
127
+ }
128
+ const text = await transcribeFile(client, chunks[i]);
129
+ transcripts.push(text.trim());
130
+ }
131
+ spinner.succeed("Transcription complete");
132
+ // Clean up chunk temp directory if we created chunks
133
+ if (chunks.length > 1 && chunks[0] !== filePath) {
134
+ const chunkDir = path.dirname(chunks[0]);
135
+ fs.rmSync(chunkDir, { recursive: true, force: true });
136
+ }
137
+ return {
138
+ transcript: transcripts.join(" "),
139
+ audioFile: filePath,
140
+ };
141
+ }
142
+ catch (error) {
143
+ spinner.fail("Transcription failed");
144
+ throw error;
145
+ }
146
+ }
147
+ //# sourceMappingURL=transcriber.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcriber.js","sourceRoot":"","sources":["../src/transcriber.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { Ora } from "ora";
2
+ export declare function createTempDir(): string;
3
+ export declare function cleanupTempDir(tempDir: string): void;
4
+ export declare function isSupportedAudioFile(filePath: string): boolean;
5
+ export declare function validateFilePath(filePath: string): string;
6
+ export declare function createSpinner(text: string): Ora;
7
+ export declare function ensureOutputDir(outputDir: string): void;
8
+ export declare function getOutputFilePath(outputDir: string, baseName: string, format: "txt" | "json"): string;
9
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAGA,OAAY,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAc/B,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAEpD;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAG9D;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAYzD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAE/C;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAIvD;AAED,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,KAAK,GAAG,MAAM,GACrB,MAAM,CAER"}
package/dist/utils.js ADDED
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.createTempDir = createTempDir;
40
+ exports.cleanupTempDir = cleanupTempDir;
41
+ exports.isSupportedAudioFile = isSupportedAudioFile;
42
+ exports.validateFilePath = validateFilePath;
43
+ exports.createSpinner = createSpinner;
44
+ exports.ensureOutputDir = ensureOutputDir;
45
+ exports.getOutputFilePath = getOutputFilePath;
46
+ const fs = __importStar(require("fs"));
47
+ const path = __importStar(require("path"));
48
+ const os = __importStar(require("os"));
49
+ const ora_1 = __importDefault(require("ora"));
50
+ const SUPPORTED_EXTENSIONS = new Set([
51
+ ".mp3",
52
+ ".mp4",
53
+ ".wav",
54
+ ".webm",
55
+ ".m4a",
56
+ ".ogg",
57
+ ".flac",
58
+ ".mpeg",
59
+ ".mpga",
60
+ ]);
61
+ function createTempDir() {
62
+ return fs.mkdtempSync(path.join(os.tmpdir(), "transcribly-"));
63
+ }
64
+ function cleanupTempDir(tempDir) {
65
+ fs.rmSync(tempDir, { recursive: true, force: true });
66
+ }
67
+ function isSupportedAudioFile(filePath) {
68
+ const ext = path.extname(filePath).toLowerCase();
69
+ return SUPPORTED_EXTENSIONS.has(ext);
70
+ }
71
+ function validateFilePath(filePath) {
72
+ const resolved = path.resolve(filePath);
73
+ if (!fs.existsSync(resolved)) {
74
+ throw new Error(`File not found: ${resolved}`);
75
+ }
76
+ if (!isSupportedAudioFile(resolved)) {
77
+ const ext = path.extname(resolved);
78
+ throw new Error(`Unsupported file type "${ext}". Supported: ${[...SUPPORTED_EXTENSIONS].join(", ")}`);
79
+ }
80
+ return resolved;
81
+ }
82
+ function createSpinner(text) {
83
+ return (0, ora_1.default)({ text, spinner: "dots" });
84
+ }
85
+ function ensureOutputDir(outputDir) {
86
+ if (!fs.existsSync(outputDir)) {
87
+ fs.mkdirSync(outputDir, { recursive: true });
88
+ }
89
+ }
90
+ function getOutputFilePath(outputDir, baseName, format) {
91
+ return path.join(outputDir, `${baseName}.${format}`);
92
+ }
93
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiBA,sCAEC;AAED,wCAEC;AAED,oDAGC;AAED,4CAYC;AAED,sCAEC;AAED,0CAIC;AAED,8CAMC;AA5DD,uCAAyB;AACzB,2CAA6B;AAC7B,uCAAyB;AACzB,8CAA+B;AAE/B,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,MAAM;IACN,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,OAAO;CACR,CAAC,CAAC;AAEH,SAAgB,aAAa;IAC3B,OAAO,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;AAChE,CAAC;AAED,SAAgB,cAAc,CAAC,OAAe;IAC5C,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AACvD,CAAC;AAED,SAAgB,oBAAoB,CAAC,QAAgB;IACnD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IACjD,OAAO,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACvC,CAAC;AAED,SAAgB,gBAAgB,CAAC,QAAgB;IAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,mBAAmB,QAAQ,EAAE,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,IAAI,KAAK,CACb,0BAA0B,GAAG,iBAAiB,CAAC,GAAG,oBAAoB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACrF,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAgB,aAAa,CAAC,IAAY;IACxC,OAAO,IAAA,aAAG,EAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;AACxC,CAAC;AAED,SAAgB,eAAe,CAAC,SAAiB;IAC/C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9B,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC;AAED,SAAgB,iBAAiB,CAC/B,SAAiB,EACjB,QAAgB,EAChB,MAAsB;IAEtB,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,QAAQ,IAAI,MAAM,EAAE,CAAC,CAAC;AACvD,CAAC"}
@@ -0,0 +1,8 @@
1
+ export interface YouTubeDownloadResult {
2
+ filePath: string;
3
+ videoId: string;
4
+ title: string;
5
+ }
6
+ export declare function downloadYouTubeAudio(url: string, outputDir: string): Promise<YouTubeDownloadResult>;
7
+ export declare function isYouTubeUrl(url: string): boolean;
8
+ //# sourceMappingURL=youtube.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"youtube.d.ts","sourceRoot":"","sources":["../src/youtube.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,qBAAqB,CAAC,CAqChC;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEjD"}