yt-dlp-bridge 0.1.6 → 0.2.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/README.md +207 -87
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +33 -14
- package/dist/config.js.map +1 -1
- package/dist/environment.d.ts +2 -2
- package/dist/environment.d.ts.map +1 -1
- package/dist/environment.js +26 -52
- package/dist/environment.js.map +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +25 -43
- package/dist/errors.js.map +1 -1
- package/dist/filesystem.d.ts +7 -3
- package/dist/filesystem.d.ts.map +1 -1
- package/dist/filesystem.js +18 -19
- package/dist/filesystem.js.map +1 -1
- package/dist/generated/ytdlp-options.json +2087 -5511
- package/dist/index.d.ts +3 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -12
- package/dist/index.js.map +1 -1
- package/dist/option-catalog.d.ts +4 -3
- package/dist/option-catalog.d.ts.map +1 -1
- package/dist/option-catalog.js +65 -69
- package/dist/option-catalog.js.map +1 -1
- package/dist/output-events.d.ts +34 -0
- package/dist/output-events.d.ts.map +1 -0
- package/dist/output-events.js +51 -0
- package/dist/output-events.js.map +1 -0
- package/dist/parsers.d.ts +2 -1
- package/dist/parsers.d.ts.map +1 -1
- package/dist/parsers.js +90 -98
- package/dist/parsers.js.map +1 -1
- package/dist/redaction.d.ts.map +1 -1
- package/dist/redaction.js +32 -18
- package/dist/redaction.js.map +1 -1
- package/dist/runner.d.ts +1 -1
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +27 -31
- package/dist/runner.js.map +1 -1
- package/dist/schemas.d.ts +480 -40
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +47 -42
- package/dist/schemas.js.map +1 -1
- package/dist/types.d.ts +5 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/workflow.d.ts +165 -0
- package/dist/workflow.d.ts.map +1 -0
- package/dist/workflow.js +807 -0
- package/dist/workflow.js.map +1 -0
- package/package.json +88 -72
- package/dist/argv.d.ts +0 -18
- package/dist/argv.d.ts.map +0 -1
- package/dist/argv.js +0 -276
- package/dist/argv.js.map +0 -1
- package/dist/planner.d.ts +0 -10
- package/dist/planner.d.ts.map +0 -1
- package/dist/planner.js +0 -233
- package/dist/planner.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
# yt-dlp-bridge
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/yt-dlp-bridge)
|
|
4
|
+
[](https://www.npmjs.com/package/yt-dlp-bridge)
|
|
5
|
+
[](https://github.com/antonio-orionus/Arroxy/actions/workflows/ci.yml)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
|
-
TypeScript library for safe, no-shell `yt-dlp` integration in Node.js services:
|
|
8
|
+
TypeScript library for safe, no-shell `yt-dlp` integration in Node.js services: workflow planning, argv generation, command facts, environment checks, process execution, output parsing, secret redaction, filesystem policy, and structured errors.
|
|
9
9
|
|
|
10
|
-
`yt-dlp-bridge` is intentionally
|
|
10
|
+
`yt-dlp-bridge` is intentionally app-agnostic. It is used by Arroxy and `yt-dlp-mcp-server`, but it does not own Electron token minting, binary resolution, retries, queue lifecycle, settings stores, plugin installation, or UI progress policy.
|
|
11
|
+
|
|
12
|
+
Source and contributions live in the Arroxy monorepo at [`packages/yt-dlp-bridge`](https://github.com/antonio-orionus/Arroxy/tree/main/packages/yt-dlp-bridge).
|
|
11
13
|
|
|
12
14
|
- [Install](#install)
|
|
13
15
|
- [Features](#features)
|
|
16
|
+
- [What changed in 0.2.0](#what-changed-in-020)
|
|
14
17
|
- [Usage](#usage)
|
|
15
18
|
- [API](#api)
|
|
16
19
|
- [Configuration](#configuration)
|
|
@@ -22,100 +25,205 @@ TypeScript library for safe, no-shell `yt-dlp` integration in Node.js services:
|
|
|
22
25
|
## Install
|
|
23
26
|
|
|
24
27
|
```bash
|
|
25
|
-
|
|
28
|
+
bun add yt-dlp-bridge
|
|
26
29
|
# pnpm add yt-dlp-bridge
|
|
27
30
|
# yarn add yt-dlp-bridge
|
|
28
|
-
# bun add yt-dlp-bridge
|
|
29
31
|
```
|
|
30
32
|
|
|
31
33
|
Requires Node.js >= 22.13 and ESM.
|
|
32
34
|
|
|
33
|
-
```ts
|
|
34
|
-
import { PlanDownloadInputSchema, loadConfig, planDownload } from "yt-dlp-bridge";
|
|
35
|
-
|
|
36
|
-
const config = loadConfig();
|
|
37
|
-
const input = PlanDownloadInputSchema.parse({
|
|
38
|
-
url: "https://www.youtube.com/watch?v=BaW_jenozKc",
|
|
39
|
-
kind: "audio",
|
|
40
|
-
postprocess: { audioFormat: "mp3" },
|
|
41
|
-
output: { outputRoot: "audio" }
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
const plan = await planDownload(input, config);
|
|
45
|
-
console.log(plan.commandPreview.redactedArgs);
|
|
46
|
-
console.log(plan.requiredDependencies);
|
|
47
|
-
```
|
|
48
|
-
|
|
49
35
|
## Features
|
|
50
36
|
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
37
|
+
- One canonical `planWorkflow(input, options?)` planner with caller-owned app inputs and managed/server schema inputs.
|
|
38
|
+
- Caller-owned probe/media/subtitle inputs for apps that already resolved output directories, format selection, subtitles, embeds, resume info JSON, and audio conversion policy.
|
|
39
|
+
- Managed schema inputs for inspect, media, audio, subtitles, thumbnail, playlist, postprocess, and expert/raw workflows that need bridge-owned normalization.
|
|
40
|
+
- Workflow facts for media-vs-sidecar behavior, output roots/templates, playlist sentinel scope, subtitle format, dependencies, risks, and side effects.
|
|
41
|
+
- Safe argv arrays instead of shell command strings.
|
|
54
42
|
- Managed output policy for output roots, temp roots, archive files, overwrite behavior, and parent-directory traversal checks.
|
|
55
|
-
- Secret redaction for auth flags, cookies, signed URLs, and command previews.
|
|
56
|
-
- Parsers for JSON lines, format lists, subtitle lists, thumbnail lists, progress output, and
|
|
57
|
-
-
|
|
43
|
+
- Secret redaction for auth flags, cookies, PO tokens, visitor data, proxies, signed URLs, and command previews.
|
|
44
|
+
- Parsers for JSON lines, format lists, subtitle lists, thumbnail lists, progress output, final output paths, and live yt-dlp output events.
|
|
45
|
+
- Low-level process runner using `spawn` with `shell: false`, bounded output capture, timeouts, and structured failures.
|
|
46
|
+
- Source-derived option catalog generated from `yt_dlp.options.create_parser`.
|
|
58
47
|
- ESM and TypeScript declarations.
|
|
59
48
|
|
|
49
|
+
## What changed in 0.2.0
|
|
50
|
+
|
|
51
|
+
`0.2.0` keeps `planWorkflow` as the single planner, but separates the public input surface into two paths:
|
|
52
|
+
|
|
53
|
+
- Use caller-owned inputs (`ProbeWorkflowInput`, `CallerMediaWorkflowInput`, `CallerSubtitlesWorkflowInput`) when your app owns job state, output folders, format selectors, subtitle mode, resume metadata, and user-facing workflow policy.
|
|
54
|
+
- Use managed Zod schemas (`WorkflowDownloadInputSchema`, `WorkflowInspectInputSchema`, `WorkflowPostprocessInputSchema`, `WorkflowExpertInputSchema`) when a server integration wants the bridge to normalize config, auth, network, output roots, and yt-dlp workflow options from request-like input.
|
|
55
|
+
|
|
56
|
+
Migration notes for `0.1.x` consumers:
|
|
57
|
+
|
|
58
|
+
- If you used managed download schemas only to plan app-owned downloads, map your app job to `CallerMediaWorkflowInput` or `CallerSubtitlesWorkflowInput` instead.
|
|
59
|
+
- `WorkflowInputSchema` validates the managed/server schema family. Caller-owned app inputs are TypeScript interfaces, so validate local job state before mapping it into the bridge.
|
|
60
|
+
- Media planning now includes app-oriented resume hardening, including `--continue`, chunk sizing, temp info JSON output, and `resume.loadInfoJsonPath` planning that omits the original URL.
|
|
61
|
+
- Embedded subtitle planning forces the safe MKV merge container and suppresses thumbnail embedding when needed for subtitle muxing.
|
|
62
|
+
- App runtime decisions still stay outside the package: binary selection, token minting, retries, queue lifecycle, cancellation UI, progress display, and settings persistence remain caller-owned.
|
|
63
|
+
|
|
60
64
|
## Usage
|
|
61
65
|
|
|
62
|
-
|
|
66
|
+
Choose the input style based on ownership. App integrations should usually start with caller-owned inputs. MCP/server-style integrations should usually start with managed schemas.
|
|
63
67
|
|
|
64
|
-
|
|
68
|
+
### Plan from a caller-owned app adapter
|
|
69
|
+
|
|
70
|
+
App adapters should map local state into `WorkflowInput`, then keep app-owned orchestration outside the bridge.
|
|
65
71
|
|
|
66
72
|
```ts
|
|
67
|
-
import {
|
|
73
|
+
import { planWorkflow, type CallerMediaWorkflowInput } from "yt-dlp-bridge";
|
|
74
|
+
|
|
75
|
+
function toWorkflowInput(job: PreparedJob): CallerMediaWorkflowInput {
|
|
76
|
+
return {
|
|
77
|
+
kind: "media",
|
|
78
|
+
url: job.url,
|
|
79
|
+
output: { directory: job.outputDir, tempDirectory: job.tempDir },
|
|
80
|
+
selection: {
|
|
81
|
+
formatSelector: job.formatSelector,
|
|
82
|
+
mergeOutputFormat: job.mergeOutputFormat
|
|
83
|
+
},
|
|
84
|
+
subtitles: job.embedSubtitles
|
|
85
|
+
? { embed: true, languages: job.subtitleLanguages, writeAuto: job.writeAutoSubtitles }
|
|
86
|
+
: undefined,
|
|
87
|
+
embed: {
|
|
88
|
+
metadata: job.embedMetadata,
|
|
89
|
+
thumbnail: job.embedThumbnail,
|
|
90
|
+
chapters: job.embedChapters
|
|
91
|
+
},
|
|
92
|
+
resume: job.infoJsonPath ? { loadInfoJsonPath: job.infoJsonPath } : undefined
|
|
93
|
+
};
|
|
94
|
+
}
|
|
68
95
|
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// ["--ignore-config", "--no-warnings", "--dump-json", "https://www.youtube.com/watch?v=BaW_jenozKc"]
|
|
96
|
+
const plan = planWorkflow(toWorkflowInput(job));
|
|
97
|
+
|
|
98
|
+
console.log(plan.args);
|
|
99
|
+
console.log(plan.facts.sideEffects);
|
|
74
100
|
```
|
|
75
101
|
|
|
76
|
-
|
|
102
|
+
The bridge owns yt-dlp semantics such as audio conversion arguments, subtitle/embed container rules, playlist sentinel logic, dependency reasons, risk/side-effect facts, output path facts, resume argv, and redaction. The adapter owns local job models, runtime selection, retries, token minting, cancellation, progress policy, and user-facing status.
|
|
103
|
+
|
|
104
|
+
### Plan a managed workflow
|
|
77
105
|
|
|
78
|
-
|
|
106
|
+
Use managed schemas when a consumer accepts request-like input and wants the bridge to normalize defaults before planning a stable `yt-dlp` argv plus facts.
|
|
79
107
|
|
|
80
108
|
```ts
|
|
81
|
-
import {
|
|
109
|
+
import { WorkflowDownloadInputSchema, planWorkflow } from "yt-dlp-bridge";
|
|
110
|
+
import { loadConfig } from "yt-dlp-bridge/config";
|
|
82
111
|
|
|
83
112
|
const config = loadConfig({
|
|
84
113
|
YTDLP_MCP_OUTPUT_ROOT: "/srv/downloads",
|
|
85
114
|
YTDLP_MCP_TEMP_ROOT: "/srv/downloads/.tmp"
|
|
86
115
|
});
|
|
87
|
-
|
|
116
|
+
|
|
117
|
+
const input = WorkflowDownloadInputSchema.parse({
|
|
118
|
+
kind: "audio",
|
|
88
119
|
url: "https://www.youtube.com/watch?v=BaW_jenozKc",
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
format: { format: "bv*+ba/b" },
|
|
92
|
-
output: { outputTemplate: "%(playlist_index)s-%(title).180B [%(id)s].%(ext)s" }
|
|
120
|
+
postprocess: { audioFormat: "mp3" },
|
|
121
|
+
output: { outputTemplate: "%(title).180B [%(id)s].%(ext)s" }
|
|
93
122
|
});
|
|
94
123
|
|
|
95
|
-
const plan =
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
124
|
+
const plan = planWorkflow(input, {
|
|
125
|
+
config,
|
|
126
|
+
configFiles: { mode: "disabled" },
|
|
127
|
+
plugins: { mode: "native" }
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
console.log(plan.args);
|
|
131
|
+
console.log(plan.redactedArgs);
|
|
132
|
+
console.log(plan.facts.dependencies.required);
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Managed schemas are the runtime-validation layer for this path:
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
import { WorkflowInputSchema } from "yt-dlp-bridge";
|
|
139
|
+
|
|
140
|
+
const input = WorkflowInputSchema.parse(request.body);
|
|
141
|
+
const plan = planWorkflow(input, { config });
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
`WorkflowPlan` has this shape:
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
{
|
|
148
|
+
kind: "probe" | "inspect" | "media" | "audio" | "subtitles" | "thumbnail" | "playlist" | "postprocess" | "expert",
|
|
149
|
+
args: string[],
|
|
150
|
+
redactedArgs: string[],
|
|
151
|
+
facts: {
|
|
152
|
+
isMediaDownload: boolean,
|
|
153
|
+
output?: {
|
|
154
|
+
directory?: string,
|
|
155
|
+
tempDirectory?: string,
|
|
156
|
+
outputRoot?: string,
|
|
157
|
+
tempRoot?: string,
|
|
158
|
+
template?: string,
|
|
159
|
+
allowOverwrite?: boolean
|
|
160
|
+
},
|
|
161
|
+
playlistScope?: {
|
|
162
|
+
requestedCount: number,
|
|
163
|
+
sentinel: boolean,
|
|
164
|
+
ytDlpFlag: "--playlist-end" | "--playlist-items",
|
|
165
|
+
ytDlpValue: string
|
|
166
|
+
},
|
|
167
|
+
effectiveSubtitleFormat?: "srt" | "vtt" | "ass",
|
|
168
|
+
dependencies: { required: unknown[], optional: unknown[] },
|
|
169
|
+
risks: string[],
|
|
170
|
+
sideEffects: string[]
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Probe playlists
|
|
176
|
+
|
|
177
|
+
Probe planning owns playlist mode and sentinel range behavior.
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
import { planWorkflow } from "yt-dlp-bridge";
|
|
181
|
+
|
|
182
|
+
const probe = planWorkflow({
|
|
183
|
+
kind: "probe",
|
|
184
|
+
url: "https://www.youtube.com/playlist?list=...",
|
|
185
|
+
selection: {
|
|
186
|
+
playlistMode: "playlist",
|
|
187
|
+
playlistScope: { items: { kind: "first", count: 50 } }
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
console.log(probe.args);
|
|
192
|
+
console.log(probe.facts.playlistScope);
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Parse live yt-dlp output
|
|
196
|
+
|
|
197
|
+
Use `parseYtDlpOutputLine` to turn noisy output into stable events. App-specific adapters can map these events to progress bars, queue resume evidence, logs, or MCP notifications.
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
import { parseYtDlpOutputLine } from "yt-dlp-bridge/parsers";
|
|
201
|
+
|
|
202
|
+
const event = parseYtDlpOutputLine('[Merger] Merging formats into "/tmp/video.mp4"');
|
|
203
|
+
|
|
204
|
+
if (event?.kind === "merge") {
|
|
205
|
+
console.log(event.path);
|
|
206
|
+
}
|
|
99
207
|
```
|
|
100
208
|
|
|
101
209
|
### Run a planned command
|
|
102
210
|
|
|
103
|
-
The runner
|
|
211
|
+
The bridge runner is low-level. It executes a command path plus argv; it does not resolve binaries or decide retries.
|
|
104
212
|
|
|
105
213
|
```ts
|
|
106
|
-
import {
|
|
214
|
+
import { planWorkflow } from "yt-dlp-bridge";
|
|
215
|
+
import { runCommand } from "yt-dlp-bridge/runner";
|
|
216
|
+
import { toStructuredError } from "yt-dlp-bridge/errors";
|
|
107
217
|
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
url: "https://www.youtube.com/watch?v=BaW_jenozKc"
|
|
111
|
-
kind: "video"
|
|
218
|
+
const plan = planWorkflow({
|
|
219
|
+
kind: "media",
|
|
220
|
+
url: "https://www.youtube.com/watch?v=BaW_jenozKc"
|
|
112
221
|
});
|
|
113
|
-
const plan = await planDownload(input, config);
|
|
114
222
|
|
|
115
223
|
try {
|
|
116
|
-
const result = await runCommand(
|
|
117
|
-
timeoutMs:
|
|
118
|
-
maxOutputBytes:
|
|
224
|
+
const result = await runCommand("yt-dlp", plan.args, {
|
|
225
|
+
timeoutMs: 900_000,
|
|
226
|
+
maxOutputBytes: 4 * 1024 * 1024
|
|
119
227
|
});
|
|
120
228
|
console.log(result.stdout);
|
|
121
229
|
} catch (error) {
|
|
@@ -128,27 +236,39 @@ try {
|
|
|
128
236
|
The bundled catalog is generated from `yt_dlp.options.create_parser` for yt-dlp `2026.03.17` and contains 323 upstream options.
|
|
129
237
|
|
|
130
238
|
```ts
|
|
131
|
-
import { UPSTREAM_OPTION_CATALOG, findOptionByFlag, listLongFlags, optionMetadata } from "yt-dlp-bridge";
|
|
239
|
+
import { UPSTREAM_OPTION_CATALOG, findOptionByFlag, listLongFlags, optionMetadata } from "yt-dlp-bridge/option-catalog";
|
|
132
240
|
|
|
133
241
|
const format = findOptionByFlag("--format");
|
|
134
|
-
console.log(UPSTREAM_OPTION_CATALOG.optionCount);
|
|
135
|
-
console.log(listLongFlags().includes("--dump-json"));
|
|
242
|
+
console.log(UPSTREAM_OPTION_CATALOG.optionCount);
|
|
243
|
+
console.log(listLongFlags().includes("--dump-json"));
|
|
136
244
|
console.log(format ? optionMetadata(format) : undefined);
|
|
137
245
|
```
|
|
138
246
|
|
|
139
247
|
## API
|
|
140
248
|
|
|
249
|
+
Prefer the root export for workflow planning and subpaths for lower-level utilities.
|
|
250
|
+
|
|
141
251
|
| Area | Exports |
|
|
142
252
|
| --- | --- |
|
|
143
|
-
|
|
|
144
|
-
|
|
|
145
|
-
| Config
|
|
146
|
-
|
|
|
147
|
-
|
|
|
148
|
-
|
|
|
149
|
-
|
|
|
150
|
-
|
|
|
151
|
-
|
|
|
253
|
+
| Workflow planning | `planWorkflow`, workflow input/plan/fact types |
|
|
254
|
+
| Schemas | `WorkflowInspectInputSchema`, `WorkflowDownloadInputSchema`, `WorkflowExecutionInputSchema`, `WorkflowPostprocessInputSchema`, `WorkflowExpertInputSchema`, `WorkflowInputSchema`, `ValidateWorkflowInputSchema` |
|
|
255
|
+
| Config | `loadConfig`, `CONFIG` from `yt-dlp-bridge/config` |
|
|
256
|
+
| Environment | `checkEnvironment` from `yt-dlp-bridge/environment` |
|
|
257
|
+
| Filesystem policy | `resolveOutputPolicy`, `resolveManagedPath`, `ensureWithinRoot`, `isPathInside`, `isPathInsideWith`, `hasParentTraversal`, `ensureDirectory`, `readArchive` from `yt-dlp-bridge/filesystem` |
|
|
258
|
+
| Option catalog | `UPSTREAM_OPTION_CATALOG`, `listLongFlags`, `findOptionByFlag`, `optionMetadata` from `yt-dlp-bridge/option-catalog` |
|
|
259
|
+
| Parsers | `parseYtDlpOutputLine`, `parseJsonLines`, `sanitizeMetadataItem`, `sanitizeMetadataItems`, `paginate`, `parseFormats`, `parseSubtitles`, `parseThumbnails`, `parseProgress`, `parseFinalPaths` from `yt-dlp-bridge/parsers` |
|
|
260
|
+
| Runner | `runCommand`, `CommandExecutionError` from `yt-dlp-bridge/runner` |
|
|
261
|
+
| Redaction | `redactArgs`, `redactText`, `excerpt` from `yt-dlp-bridge/redaction` |
|
|
262
|
+
| Structured errors | `toStructuredError` from `yt-dlp-bridge/errors` |
|
|
263
|
+
|
|
264
|
+
Example imports:
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
import { planWorkflow } from "yt-dlp-bridge";
|
|
268
|
+
import { parseYtDlpOutputLine } from "yt-dlp-bridge/parsers";
|
|
269
|
+
import { runCommand } from "yt-dlp-bridge/runner";
|
|
270
|
+
import { redactArgs } from "yt-dlp-bridge/redaction";
|
|
271
|
+
```
|
|
152
272
|
|
|
153
273
|
## Configuration
|
|
154
274
|
|
|
@@ -174,38 +294,38 @@ console.log(format ? optionMetadata(format) : undefined);
|
|
|
174
294
|
## Requirements
|
|
175
295
|
|
|
176
296
|
- Node.js >= 22.13, ESM.
|
|
177
|
-
- `yt-dlp` installed when
|
|
297
|
+
- `yt-dlp` installed when running yt-dlp workflows.
|
|
178
298
|
- `ffmpeg` and `ffprobe` for audio extraction, merge, remux, recode, segment editing, subtitle/thumbnail conversion, and embedding workflows.
|
|
179
|
-
- Python `yt_dlp` package
|
|
299
|
+
- Python `yt_dlp` package, or `PYTHONPATH` pointing at a yt-dlp checkout, when regenerating or verifying the option catalog.
|
|
180
300
|
|
|
181
301
|
## Development
|
|
182
302
|
|
|
183
303
|
```bash
|
|
184
|
-
git clone https://github.com/antonio-orionus/
|
|
185
|
-
cd
|
|
186
|
-
|
|
304
|
+
git clone https://github.com/antonio-orionus/Arroxy.git
|
|
305
|
+
cd Arroxy
|
|
306
|
+
bun install
|
|
187
307
|
```
|
|
188
308
|
|
|
189
309
|
| Command | Description |
|
|
190
310
|
| --- | --- |
|
|
191
|
-
| `
|
|
192
|
-
| `
|
|
193
|
-
| `
|
|
194
|
-
| `
|
|
195
|
-
| `
|
|
196
|
-
| `
|
|
311
|
+
| `bun run --filter yt-dlp-bridge build` | Compile TypeScript and copy generated assets into `dist`. |
|
|
312
|
+
| `bun run --filter yt-dlp-bridge test` | Run Vitest tests. |
|
|
313
|
+
| `bun run --filter yt-dlp-bridge typecheck` | TypeScript check without emitting. |
|
|
314
|
+
| `bun run --filter yt-dlp-bridge generate:options` | Regenerate the option catalog from Python `yt_dlp`. |
|
|
315
|
+
| `bun run --filter yt-dlp-bridge verify:options` | Verify the catalog matches Python `yt_dlp`. |
|
|
316
|
+
| `bun run bridge:check` | Run the package gate used by Arroxy CI and registry publishing. |
|
|
197
317
|
|
|
198
318
|
## Troubleshooting
|
|
199
319
|
|
|
200
|
-
**`yt-dlp` is missing**
|
|
320
|
+
**`yt-dlp` is missing** - Install `yt-dlp` or set `YTDLP_MCP_YTDLP_PATH`. `checkEnvironment()` reports detected command, status, version, and notes.
|
|
201
321
|
|
|
202
|
-
**`ffmpeg`/`ffprobe` missing**
|
|
322
|
+
**`ffmpeg`/`ffprobe` missing** - Install the binary or set `YTDLP_MCP_FFMPEG_PATH` / `YTDLP_MCP_FFPROBE_PATH`. Planning still returns dependency info so callers can surface which workflow requires the missing tool.
|
|
203
323
|
|
|
204
|
-
**`auth.cookiesFile requires YTDLP_MCP_ALLOW_CONFIG_FILES=true`**
|
|
324
|
+
**`auth.cookiesFile requires YTDLP_MCP_ALLOW_CONFIG_FILES=true`** - User-provided config-file paths are blocked by default. Prefer server-level `YTDLP_MCP_COOKIES_FILE` or enable `YTDLP_MCP_ALLOW_CONFIG_FILES=true` only after reviewing the trust boundary.
|
|
205
325
|
|
|
206
|
-
**`outputTemplate must not contain parent-directory traversal`**
|
|
326
|
+
**`outputTemplate must not contain parent-directory traversal`** - Relative templates cannot contain `..` segments unless `YTDLP_MCP_ALLOW_ARBITRARY_OUTPUT_PATHS=true`.
|
|
207
327
|
|
|
208
|
-
Bugs and feature requests: [GitHub Issues](https://github.com/antonio-orionus/
|
|
328
|
+
Bugs and feature requests: [GitHub Issues](https://github.com/antonio-orionus/Arroxy/issues).
|
|
209
329
|
|
|
210
330
|
## License
|
|
211
331
|
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC5B,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC/B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,yBAAyB,EAAE,OAAO,CAAA;IAClC,gBAAgB,EAAE,OAAO,CAAA;IACzB,eAAe,EAAE,OAAO,CAAA;IACxB,gBAAgB,EAAE,OAAO,CAAA;IACzB,gBAAgB,EAAE,MAAM,CAAA;IACxB,cAAc,EAAE,MAAM,CAAA;IACtB,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC,kBAAkB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,UAAU,EAAE,MAAM,EAAE,CAAA;CACpB;AA2BD,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIhD;AAED,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,YAAY,CAoB7E;AAED,eAAO,MAAM,MAAM,cAAe,CAAA"}
|
package/dist/config.js
CHANGED
|
@@ -1,35 +1,54 @@
|
|
|
1
|
-
import os from
|
|
2
|
-
import path from
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
3
|
function bool(value) {
|
|
4
|
-
|
|
4
|
+
const normalized = blankToUndefined(value);
|
|
5
|
+
return normalized ? ['1', 'true', 'yes', 'on'].includes(normalized.toLowerCase()) : false;
|
|
5
6
|
}
|
|
6
7
|
function int(value, fallback) {
|
|
7
|
-
const
|
|
8
|
+
const normalized = blankToUndefined(value);
|
|
9
|
+
const parsed = normalized ? Number.parseInt(normalized, 10) : Number.NaN;
|
|
8
10
|
return Number.isFinite(parsed) ? parsed : fallback;
|
|
9
11
|
}
|
|
12
|
+
function blankToUndefined(value) {
|
|
13
|
+
const normalized = value?.trim();
|
|
14
|
+
if (!normalized)
|
|
15
|
+
return undefined;
|
|
16
|
+
return normalized;
|
|
17
|
+
}
|
|
18
|
+
function firstNonBlank(...values) {
|
|
19
|
+
for (const value of values) {
|
|
20
|
+
const normalized = blankToUndefined(value);
|
|
21
|
+
if (normalized !== undefined)
|
|
22
|
+
return normalized;
|
|
23
|
+
}
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
10
26
|
export function expandHome(input) {
|
|
11
|
-
if (input ===
|
|
27
|
+
if (input === '~')
|
|
12
28
|
return os.homedir();
|
|
13
|
-
if (input.startsWith(
|
|
29
|
+
if (input.startsWith('~/') || input.startsWith('~\\'))
|
|
14
30
|
return path.join(os.homedir(), input.slice(2));
|
|
15
31
|
return input;
|
|
16
32
|
}
|
|
17
33
|
export function loadConfig(env = process.env) {
|
|
18
34
|
return {
|
|
19
|
-
ytdlpPath: env.YTDLP_MCP_YTDLP_PATH
|
|
20
|
-
ffmpegPath: env.YTDLP_MCP_FFMPEG_PATH
|
|
21
|
-
ffprobePath: env.YTDLP_MCP_FFPROBE_PATH
|
|
22
|
-
outputRoot: path.resolve(expandHome(env.YTDLP_MCP_OUTPUT_ROOT ?? path.join(os.homedir(),
|
|
23
|
-
tempRoot: path.resolve(expandHome(env.YTDLP_MCP_TEMP_ROOT ?? path.join(os.tmpdir(),
|
|
35
|
+
ytdlpPath: firstNonBlank(env.YTDLP_MCP_YTDLP_PATH, env.YTDLP_PATH) ?? 'yt-dlp',
|
|
36
|
+
ffmpegPath: firstNonBlank(env.YTDLP_MCP_FFMPEG_PATH, env.FFMPEG_PATH),
|
|
37
|
+
ffprobePath: firstNonBlank(env.YTDLP_MCP_FFPROBE_PATH, env.FFPROBE_PATH),
|
|
38
|
+
outputRoot: path.resolve(expandHome(firstNonBlank(env.YTDLP_MCP_OUTPUT_ROOT) ?? path.join(os.homedir(), 'Downloads', 'yt-dlp-mcp'))),
|
|
39
|
+
tempRoot: path.resolve(expandHome(firstNonBlank(env.YTDLP_MCP_TEMP_ROOT) ?? path.join(os.tmpdir(), 'yt-dlp-mcp'))),
|
|
24
40
|
allowArbitraryOutputPaths: bool(env.YTDLP_MCP_ALLOW_ARBITRARY_OUTPUT_PATHS),
|
|
25
41
|
allowConfigFiles: bool(env.YTDLP_MCP_ALLOW_CONFIG_FILES),
|
|
26
42
|
allowPluginDirs: bool(env.YTDLP_MCP_ALLOW_PLUGIN_DIRS),
|
|
27
43
|
enableExpertMode: bool(env.YTDLP_MCP_ENABLE_EXPERT),
|
|
28
44
|
defaultTimeoutMs: int(env.YTDLP_MCP_TIMEOUT_MS, 15 * 60 * 1000),
|
|
29
45
|
maxOutputBytes: int(env.YTDLP_MCP_MAX_OUTPUT_BYTES, 4 * 1024 * 1024),
|
|
30
|
-
cookiesFile: env.YTDLP_MCP_COOKIES_FILE,
|
|
31
|
-
cookiesFromBrowser: env.YTDLP_MCP_COOKIES_FROM_BROWSER,
|
|
32
|
-
jsRuntimes: (env.YTDLP_MCP_JS_RUNTIMES ??
|
|
46
|
+
cookiesFile: firstNonBlank(env.YTDLP_MCP_COOKIES_FILE),
|
|
47
|
+
cookiesFromBrowser: firstNonBlank(env.YTDLP_MCP_COOKIES_FROM_BROWSER),
|
|
48
|
+
jsRuntimes: (firstNonBlank(env.YTDLP_MCP_JS_RUNTIMES) ?? 'deno,node,bun,quickjs')
|
|
49
|
+
.split(',')
|
|
50
|
+
.map(v => v.trim())
|
|
51
|
+
.filter(Boolean)
|
|
33
52
|
};
|
|
34
53
|
}
|
|
35
54
|
export const CONFIG = loadConfig();
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/environment.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type ServerConfig } from
|
|
2
|
-
import type { DetectedDependency } from
|
|
1
|
+
import { type ServerConfig } from './config.js';
|
|
2
|
+
import type { DetectedDependency } from './types.js';
|
|
3
3
|
export interface EnvironmentReport {
|
|
4
4
|
platform: NodeJS.Platform;
|
|
5
5
|
arch: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../src/environment.ts"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../src/environment.ts"],"names":[],"mappings":"AAEA,OAAO,EAAS,KAAK,YAAY,EAAC,MAAM,aAAa,CAAA;AAErD,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,YAAY,CAAA;AAElD,MAAM,WAAW,iBAAiB;IACjC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAA;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC,CAAA;IACzC,YAAY,EAAE,kBAAkB,EAAE,CAAA;IAClC,OAAO,EAAE;QAAC,cAAc,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAC;QAAC,iBAAiB,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAC,CAAA;IACtG,MAAM,EAAE;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,yBAAyB,EAAE,OAAO,CAAC;QAAC,gBAAgB,EAAE,OAAO,CAAC;QAAC,eAAe,EAAE,OAAO,CAAC;QAAC,gBAAgB,EAAE,OAAO,CAAA;KAAC,CAAA;CAClK;AAED,wBAAsB,gBAAgB,CAAC,MAAM,GAAE,YAAqB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAuBhG"}
|
package/dist/environment.js
CHANGED
|
@@ -1,80 +1,54 @@
|
|
|
1
|
-
import fs from
|
|
2
|
-
import os from
|
|
3
|
-
import { CONFIG } from
|
|
4
|
-
import { runCommand } from
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import { CONFIG } from './config.js';
|
|
4
|
+
import { runCommand } from './runner.js';
|
|
5
5
|
export async function checkEnvironment(config = CONFIG) {
|
|
6
6
|
const dependencies = await Promise.all([
|
|
7
|
-
detectBinary(
|
|
8
|
-
detectBinary(
|
|
9
|
-
detectBinary(
|
|
10
|
-
detectBinary(
|
|
11
|
-
detectBinary(
|
|
12
|
-
detectBinary(
|
|
13
|
-
detectBinary(
|
|
14
|
-
detectBinary(
|
|
15
|
-
detectBinary(
|
|
16
|
-
detectBinary(
|
|
17
|
-
detectBinary(
|
|
7
|
+
detectBinary('yt-dlp', config.ytdlpPath, ['--version'], ['all yt-dlp operations'], true, config),
|
|
8
|
+
detectBinary('ffmpeg', config.ffmpegPath ?? 'ffmpeg', ['-version'], ['merge', 'remux', 'recode', 'extract audio', 'embed assets'], false, config),
|
|
9
|
+
detectBinary('ffprobe', config.ffprobePath ?? 'ffprobe', ['-version'], ['audio extraction', 'media probing'], false, config),
|
|
10
|
+
detectBinary('deno', 'deno', ['--version'], ['yt-dlp JavaScript challenges'], false, config),
|
|
11
|
+
detectBinary('node', 'node', ['--version'], ['yt-dlp JavaScript challenges'], false, config),
|
|
12
|
+
detectBinary('bun', 'bun', ['--version'], ['yt-dlp JavaScript challenges'], false, config),
|
|
13
|
+
detectBinary('qjs', 'qjs', ['--version'], ['yt-dlp JavaScript challenges'], false, config),
|
|
14
|
+
detectBinary('AtomicParsley', 'AtomicParsley', ['--version'], ['legacy thumbnail embedding'], false, config),
|
|
15
|
+
detectBinary('aria2c', 'aria2c', ['--version'], ['external downloader'], false, config),
|
|
16
|
+
detectBinary('curl', 'curl', ['--version'], ['external downloader'], false, config),
|
|
17
|
+
detectBinary('wget', 'wget', ['--version'], ['external downloader'], false, config)
|
|
18
18
|
]);
|
|
19
19
|
return {
|
|
20
20
|
platform: process.platform,
|
|
21
21
|
arch: os.arch(),
|
|
22
|
-
node: {
|
|
23
|
-
version: process.version,
|
|
24
|
-
execPath: process.execPath
|
|
25
|
-
},
|
|
22
|
+
node: { version: process.version, execPath: process.execPath },
|
|
26
23
|
dependencies,
|
|
27
24
|
cookies: cookieStatus(config),
|
|
28
|
-
policy: {
|
|
29
|
-
outputRoot: config.outputRoot,
|
|
30
|
-
tempRoot: config.tempRoot,
|
|
31
|
-
allowArbitraryOutputPaths: config.allowArbitraryOutputPaths,
|
|
32
|
-
allowConfigFiles: config.allowConfigFiles,
|
|
33
|
-
allowPluginDirs: config.allowPluginDirs,
|
|
34
|
-
enableExpertMode: config.enableExpertMode
|
|
35
|
-
}
|
|
25
|
+
policy: { outputRoot: config.outputRoot, tempRoot: config.tempRoot, allowArbitraryOutputPaths: config.allowArbitraryOutputPaths, allowConfigFiles: config.allowConfigFiles, allowPluginDirs: config.allowPluginDirs, enableExpertMode: config.enableExpertMode }
|
|
36
26
|
};
|
|
37
27
|
}
|
|
38
28
|
async function detectBinary(name, command, args, requiredFor, required, config) {
|
|
39
29
|
try {
|
|
40
|
-
const result = await runCommand(command, args, {
|
|
41
|
-
|
|
42
|
-
maxOutputBytes: 64 * 1024
|
|
43
|
-
});
|
|
44
|
-
return {
|
|
45
|
-
name,
|
|
46
|
-
status: "available",
|
|
47
|
-
command,
|
|
48
|
-
version: firstLine(result.stdout || result.stderr),
|
|
49
|
-
requiredFor,
|
|
50
|
-
notes: required ? [] : ["Optional dependency; required only for matching workflows."]
|
|
51
|
-
};
|
|
30
|
+
const result = await runCommand(command, args, { timeoutMs: Math.min(config.defaultTimeoutMs, 10_000), maxOutputBytes: 64 * 1024 });
|
|
31
|
+
return { name, status: 'available', command, version: firstLine(result.stdout || result.stderr), requiredFor, notes: required ? [] : ['Optional dependency; required only for matching workflows.'] };
|
|
52
32
|
}
|
|
53
33
|
catch (error) {
|
|
54
|
-
return {
|
|
55
|
-
name,
|
|
56
|
-
status: "missing",
|
|
57
|
-
command,
|
|
58
|
-
requiredFor,
|
|
59
|
-
notes: [required ? "Required dependency is not available." : "Optional dependency is not available.", error instanceof Error ? error.message : String(error)]
|
|
60
|
-
};
|
|
34
|
+
return { name, status: 'missing', command, requiredFor, notes: [required ? 'Required dependency is not available.' : 'Optional dependency is not available.', error instanceof Error ? error.message : String(error)] };
|
|
61
35
|
}
|
|
62
36
|
}
|
|
63
37
|
function cookieStatus(config) {
|
|
64
|
-
const status = {
|
|
65
|
-
fileConfigured: Boolean(config.cookiesFile),
|
|
66
|
-
browserConfigured: Boolean(config.cookiesFromBrowser)
|
|
67
|
-
};
|
|
38
|
+
const status = { fileConfigured: Boolean(config.cookiesFile), browserConfigured: Boolean(config.cookiesFromBrowser) };
|
|
68
39
|
if (config.cookiesFile)
|
|
69
40
|
status.fileExists = fs.existsSync(config.cookiesFile);
|
|
70
41
|
if (config.cookiesFromBrowser) {
|
|
71
|
-
const browser = config.cookiesFromBrowser.split(
|
|
42
|
+
const browser = config.cookiesFromBrowser.split(':')[0];
|
|
72
43
|
if (browser)
|
|
73
44
|
status.browser = browser;
|
|
74
45
|
}
|
|
75
46
|
return status;
|
|
76
47
|
}
|
|
77
48
|
function firstLine(value) {
|
|
78
|
-
return value
|
|
49
|
+
return (value
|
|
50
|
+
.split(/\r?\n/)
|
|
51
|
+
.map(line => line.trim())
|
|
52
|
+
.find(Boolean) ?? '');
|
|
79
53
|
}
|
|
80
54
|
//# sourceMappingURL=environment.js.map
|