yt2text 0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Lopleec
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 all
13
+ 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 THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,334 @@
1
+ # yt2text
2
+
3
+ Download audio from YouTube or another `yt-dlp` supported URL, transcribe it locally or through the platform speech interface, and save the result as `txt`, `json`, or `srt`.
4
+
5
+ Windows support is included but currently untested. macOS and Linux are the primary targets.
6
+
7
+ ## Features
8
+
9
+ - Downloads audio only through `yt-dlp`.
10
+ - Uses macOS Speech.framework by default on macOS.
11
+ - Uses local Whisper ASR by default on Linux.
12
+ - Includes a best-effort Windows SAPI helper, marked untested.
13
+ - Supports local multilingual ASR with `--multilingual` or `-l auto`.
14
+ - Optional anonymous speaker diarization with `--diarize`.
15
+ - Browser cookie auto-detection, manual cookies files, proxy, retries, timeouts, and fragment concurrency.
16
+ - Progress output for dependency downloads, media download, conversion, and transcription.
17
+ - JSON config file with CLI flags taking precedence.
18
+ - Output filename templates and optional audio retention.
19
+
20
+ ## Requirements
21
+
22
+ - Node.js 20 or newer.
23
+ - Network access on first use to download `yt-dlp` and, when local ASR is enabled, ASR models.
24
+ - macOS system ASR requires Speech Recognition permission and Xcode Command Line Tools for `swiftc`; yt2text automatically opens Apple's `xcode-select --install` installer when `swiftc` is missing.
25
+ - Linux local ASR requires the optional `sherpa-onnx-node` package to install correctly.
26
+ - `ffmpeg` is bundled through `@ffmpeg-installer/ffmpeg`; a system `ffmpeg` is used as fallback.
27
+
28
+ ## Install
29
+
30
+ Recommended:
31
+
32
+ ```bash
33
+ npm install -g yt2text
34
+ ```
35
+
36
+ From this repository:
37
+
38
+ ```bash
39
+ git clone https://github.com/lopleec/yt2text.git
40
+ cd yt2text
41
+ npm install
42
+ npm run build
43
+ npm link
44
+ ```
45
+
46
+ Run a local checkout without linking:
47
+
48
+ ```bash
49
+ npm run dev -- "https://www.youtube.com/watch?v=ROrOGwJDneo" -l en-US
50
+ ```
51
+
52
+ ## Quick Start
53
+
54
+ macOS default: browser cookies are auto-detected, the system Speech interface runs in offline/on-device mode, and the transcript is saved as `txt` in `~/Downloads`.
55
+
56
+ ```bash
57
+ yt2text "https://www.youtube.com/watch?v=ROrOGwJDneo" -l en-US
58
+ ```
59
+
60
+ Chinese video using the macOS default language:
61
+
62
+ ```bash
63
+ yt2text "https://www.youtube.com/watch?v=muAgkhaoLDA"
64
+ ```
65
+
66
+ Mixed-language or unknown-language video:
67
+
68
+ ```bash
69
+ yt2text "https://youtu.be/..." --multilingual
70
+ ```
71
+
72
+ Local file:
73
+
74
+ ```bash
75
+ yt2text file ./audio.wav -l en-US
76
+ ```
77
+
78
+ Interactive terminal mode:
79
+
80
+ ```bash
81
+ yt2text
82
+ ```
83
+
84
+ Check dependencies and effective configuration:
85
+
86
+ ```bash
87
+ yt2text doctor --fix --show-config
88
+ ```
89
+
90
+ `--fix` downloads missing small runtime tools such as `yt-dlp`. On macOS it also opens the Xcode Command Line Tools installer if `swiftc` is missing. That Apple installer still requires the user to finish the system dialog, then rerun yt2text.
91
+
92
+ ## Platform Defaults
93
+
94
+ | Platform | Default ASR | Notes |
95
+ | --- | --- | --- |
96
+ | macOS | `system` | Uses Speech.framework with `--system-mode offline`; browser cookies default to `auto`. |
97
+ | Linux | `local` | No single cross-distro system speech API is assumed; first local ASR run downloads models. |
98
+ | Windows | `system` | Uses a best-effort offline SAPI helper. This path is included but not tested. |
99
+
100
+ Use `--asr local` to force local ASR, or `--fallback local` to try local ASR if system ASR fails.
101
+
102
+ ## Common Commands
103
+
104
+ ```bash
105
+ yt2text "https://youtu.be/..." # direct run
106
+ yt2text "https://youtu.be/..." -l en-US # English locale
107
+ yt2text "https://youtu.be/..." --asr local # force local Whisper ASR
108
+ yt2text "https://youtu.be/..." --multilingual # local ASR with language auto-detect
109
+ yt2text "https://youtu.be/..." --diarize # anonymous speaker labels
110
+ yt2text "https://youtu.be/..." -f srt # subtitle output
111
+ yt2text "https://youtu.be/..." --audio-quality small # smaller download
112
+ yt2text "https://youtu.be/..." --parallel-downloads 8 # faster fragmented downloads
113
+ yt2text "https://youtu.be/..." --keep-original-audio --keep-audio
114
+ yt2text file ./meeting.m4a -l zh-CN
115
+ yt2text config
116
+ yt2text config --print
117
+ yt2text doctor
118
+ ```
119
+
120
+ ## Important Options
121
+
122
+ ASR:
123
+
124
+ - `--asr system|local`
125
+ - `--system-mode online|offline|auto`
126
+ - `--fallback local|fail`
127
+ - `-l, --language <locale>` such as `zh-CN`, `zh-TW`, `en-US`, `ja-JP`, or `auto`
128
+ - `--multilingual`
129
+ - `--model tiny|base|small|medium`
130
+ - `--diarize`
131
+ - `--chunk-seconds <seconds>`
132
+
133
+ Output:
134
+
135
+ - `-f, --format txt|json|srt`
136
+ - `-o, --output <dir>`
137
+ - `--filename-template <template>`
138
+ - `--keep-original-audio`
139
+ - `--keep-audio`
140
+ - `--log-file <file>`
141
+
142
+ Filename template tokens:
143
+
144
+ - `{title}`
145
+ - `{date}`
146
+ - `{datetime}`
147
+ - `{language}`
148
+ - `{engine}`
149
+ - `{source}`
150
+
151
+ Download and cookies:
152
+
153
+ - `--cookies <file>`
154
+ - `--cookies-from-browser auto|chrome|safari|firefox|edge|brave|chromium`
155
+ - `--no-browser-cookies`
156
+ - `--audio-quality best|balanced|small`
157
+ - `--parallel-downloads <n>`
158
+ - `--concurrent-fragments <n>`
159
+ - `--retries <n>`
160
+ - `--fragment-retries <n>`
161
+ - `--socket-timeout <seconds>`
162
+ - `--download-timeout <seconds>`
163
+ - `--proxy <url>`
164
+ - `--rate-limit <rate>`
165
+ - `--user-agent <ua>`
166
+ - `--update-ytdlp`
167
+
168
+ Runtime:
169
+
170
+ - `--config <file>`
171
+ - `--cache-dir <dir>`
172
+ - `--offline`
173
+ - `--convert-timeout <seconds>`
174
+ - `--asr-chunk-timeout <seconds>`
175
+ - `-v, --verbose`
176
+
177
+ ## Configuration
178
+
179
+ Create a config file:
180
+
181
+ ```bash
182
+ yt2text config
183
+ ```
184
+
185
+ Default paths:
186
+
187
+ - macOS/Linux: `~/.config/yt2text/config.json`
188
+ - Windows: `%APPDATA%\yt2text\config.json`
189
+
190
+ Print the platform-specific default config without writing:
191
+
192
+ ```bash
193
+ yt2text config --print
194
+ ```
195
+
196
+ Example:
197
+
198
+ ```json
199
+ {
200
+ "asr": "system",
201
+ "systemMode": "offline",
202
+ "fallback": "fail",
203
+ "language": "zh-CN",
204
+ "outputDir": "~/Downloads",
205
+ "format": "txt",
206
+ "cookiesFromBrowser": "auto",
207
+ "browserCookies": true,
208
+ "model": "small",
209
+ "offline": false,
210
+ "diarize": false,
211
+ "chunkSeconds": 55,
212
+ "filenameTemplate": "{date}-{title}",
213
+ "audioQuality": "balanced",
214
+ "keepAudio": false,
215
+ "keepOriginalAudio": false,
216
+ "parallelDownloads": 8,
217
+ "concurrentFragments": 8,
218
+ "retries": 20,
219
+ "fragmentRetries": 20,
220
+ "socketTimeout": 30,
221
+ "downloadTimeoutSeconds": 1800,
222
+ "convertTimeoutSeconds": 600,
223
+ "asrChunkTimeoutSeconds": 180,
224
+ "logFile": "~/Downloads/yt2text.log"
225
+ }
226
+ ```
227
+
228
+ CLI flags override config values. Environment variables:
229
+
230
+ - `YT2TEXT_CONFIG`
231
+ - `YT2TEXT_OUTPUT_DIR`
232
+ - `YT2TEXT_LANGUAGE`
233
+ - `YT2TEXT_CACHE_DIR`
234
+
235
+ ## Cookies
236
+
237
+ For many YouTube videos, cookies are not needed. When YouTube asks for sign-in or bot verification, use browser cookies:
238
+
239
+ ```bash
240
+ yt2text "https://youtu.be/..." --cookies-from-browser chrome
241
+ ```
242
+
243
+ macOS defaults to `--cookies-from-browser auto`. You can disable this:
244
+
245
+ ```bash
246
+ yt2text "https://youtu.be/..." --no-browser-cookies
247
+ ```
248
+
249
+ Manual Netscape cookies file:
250
+
251
+ ```bash
252
+ yt2text "https://youtu.be/..." --cookies ./cookies.txt
253
+ ```
254
+
255
+ ## Local ASR Models
256
+
257
+ Local ASR uses `sherpa-onnx-node` and Whisper-style models from the sherpa-onnx project. First use downloads model files into the cache directory. Larger models usually improve accuracy but cost more disk, memory, and CPU time.
258
+
259
+ ```bash
260
+ yt2text "https://youtu.be/..." --asr local --model tiny
261
+ yt2text "https://youtu.be/..." --asr local --model small
262
+ yt2text "https://youtu.be/..." --multilingual --model medium
263
+ ```
264
+
265
+ Use `--offline` only after dependencies and models are already cached.
266
+
267
+ ## Speaker Labels
268
+
269
+ `--diarize` adds anonymous labels such as `Speaker 1` and `Speaker 2`. It does not identify real people by name. Diarization downloads extra local models on first use.
270
+
271
+ ```bash
272
+ yt2text "https://youtu.be/..." --asr local --diarize
273
+ ```
274
+
275
+ ## Troubleshooting
276
+
277
+ Run:
278
+
279
+ ```bash
280
+ yt2text doctor --fix --show-config
281
+ ```
282
+
283
+ Common fixes:
284
+
285
+ - `npm` says `package.json` is missing: run commands from the project directory, or install/link the CLI globally first.
286
+ - YouTube requires sign-in: try `--cookies-from-browser chrome`, `safari`, or `firefox`.
287
+ - Browser cookie database is locked: fully quit the browser and retry.
288
+ - 403 or bot verification: use cookies, then try `--update-ytdlp`; if needed, configure `--proxy`.
289
+ - macOS Speech permission denied: allow Speech Recognition for the helper when macOS prompts.
290
+ - `swiftc` is missing: yt2text automatically opens the Xcode Command Line Tools installer on macOS. Finish the system installer and rerun the command; if it did not open, run `xcode-select --install`.
291
+ - Local ASR dependency missing: reinstall without `--no-optional`.
292
+ - Local model extraction fails: make sure `tar` with bzip2 support is available.
293
+ - Long files time out: increase `--download-timeout`, `--convert-timeout`, or `--asr-chunk-timeout`.
294
+
295
+ ## Development
296
+
297
+ ```bash
298
+ npm install
299
+ npm run check
300
+ npm run build
301
+ npm test
302
+ npm pack --dry-run
303
+ ```
304
+
305
+ Useful local commands:
306
+
307
+ ```bash
308
+ node dist/cli.js doctor --show-config
309
+ node dist/cli.js "https://www.youtube.com/watch?v=ROrOGwJDneo" -l en-US
310
+ node dist/cli.js file ./audio.wav -l en-US -o ./out
311
+ ```
312
+
313
+ ## Privacy
314
+
315
+ The CLI stores downloaded tools, ASR models, temporary audio, and optional logs on your machine. Temporary work files are removed after each run. If you pass browser cookies or a manual cookies file, `yt-dlp` reads them locally to access the requested media. Be careful when sharing logs, configs, transcripts, and retained audio files.
316
+
317
+ ## Acknowledgements
318
+
319
+ - [`yt-dlp`](https://github.com/yt-dlp/yt-dlp) for media extraction and download support.
320
+ - [`FFmpeg`](https://ffmpeg.org/) and `@ffmpeg-installer/ffmpeg` for audio conversion.
321
+ - [`sherpa-onnx`](https://github.com/k2-fsa/sherpa-onnx) and `sherpa-onnx-node` for local ASR and diarization runtime support.
322
+ - OpenAI Whisper model architecture and the broader open speech recognition ecosystem.
323
+ - Apple Speech.framework and Windows SAPI for platform speech interfaces.
324
+ - [`NotKiwy/trawl`](https://github.com/NotKiwy/trawl) for informing the initial downloader research direction. This project currently shells out to `yt-dlp` directly.
325
+
326
+ ## Disclaimer
327
+
328
+ This project is not affiliated with YouTube, Google, Apple, Microsoft, FFmpeg, yt-dlp, sherpa-onnx, OpenAI, or NotKiwy/trawl.
329
+
330
+ Use this tool only for media you are allowed to access, download, and transcribe. You are responsible for complying with copyright law, platform terms of service, privacy rules, consent requirements, and any laws that apply in your jurisdiction. The software is provided as-is under the MIT License, without warranty.
331
+
332
+ ## License
333
+
334
+ MIT.
package/dist/asr.js ADDED
@@ -0,0 +1,19 @@
1
+ import { transcribeWithLocal } from "./local-asr.js";
2
+ import { transcribeWithSystem } from "./system-asr.js";
3
+ import { asError } from "./errors.js";
4
+ export async function transcribe(wavPath, paths, options) {
5
+ const provider = options.asr;
6
+ if (provider === "local") {
7
+ return transcribeWithLocal(wavPath, paths, options);
8
+ }
9
+ try {
10
+ return await transcribeWithSystem(wavPath, paths, options);
11
+ }
12
+ catch (error) {
13
+ if (options.fallback !== "local")
14
+ throw error;
15
+ console.error(`System ASR unavailable: ${asError(error).message}`);
16
+ console.error("Falling back to local ASR.");
17
+ return transcribeWithLocal(wavPath, paths, options);
18
+ }
19
+ }
package/dist/cache.js ADDED
@@ -0,0 +1,28 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { mkdir } from "node:fs/promises";
3
+ import { homedir, tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ function defaultCacheDir() {
6
+ if (process.env.YT2TEXT_CACHE_DIR)
7
+ return process.env.YT2TEXT_CACHE_DIR;
8
+ if (process.platform === "darwin") {
9
+ return join(homedir(), "Library", "Caches", "yt2text");
10
+ }
11
+ if (process.platform === "win32") {
12
+ return join(process.env.LOCALAPPDATA ?? join(homedir(), "AppData", "Local"), "yt2text");
13
+ }
14
+ return join(process.env.XDG_CACHE_HOME ?? join(homedir(), ".cache"), "yt2text");
15
+ }
16
+ export async function createRuntimePaths(options) {
17
+ const cacheDir = options.cacheDir ?? defaultCacheDir();
18
+ const toolsDir = join(cacheDir, "tools");
19
+ const modelsDir = join(cacheDir, "models");
20
+ const workDir = join(tmpdir(), `yt2text-${randomUUID()}`);
21
+ await Promise.all([
22
+ mkdir(toolsDir, { recursive: true }),
23
+ mkdir(modelsDir, { recursive: true }),
24
+ mkdir(workDir, { recursive: true }),
25
+ mkdir(options.outputDir, { recursive: true }),
26
+ ]);
27
+ return { cacheDir, toolsDir, modelsDir, workDir };
28
+ }