feat(baoyu-url-to-markdown): add --output-dir option for custom output directory

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jim Liu 宝玉 2026-03-05 14:34:07 -06:00
parent 9437581c48
commit fff1a54b6b
2 changed files with 28 additions and 8 deletions

View File

@ -82,8 +82,14 @@ Full reference: [references/config/first-time-setup.md](references/config/first-
| `download_media` | `ask` | `ask` / `1` / `0` | `ask` = prompt each time, `1` = always download, `0` = never |
| `default_output_dir` | empty | path or empty | Default output directory (empty = `./url-to-markdown/`) |
**EXTEND.md → CLI mapping**:
| EXTEND.md key | CLI argument | Notes |
|---------------|-------------|-------|
| `download_media: 1` | `--download-media` | |
| `default_output_dir: ./posts/` | `--output-dir ./posts/` | Directory path. Do NOT pass to `-o` (which expects a file path) |
**Value priority**:
1. CLI arguments (`--download-media`, `-o`)
1. CLI arguments (`--download-media`, `-o`, `--output-dir`)
2. EXTEND.md
3. Skill defaults
@ -107,6 +113,9 @@ ${BUN_X} ${SKILL_DIR}/scripts/main.ts <url> --wait
# Save to specific file
${BUN_X} ${SKILL_DIR}/scripts/main.ts <url> -o output.md
# Save to a custom output directory (auto-generates filename)
${BUN_X} ${SKILL_DIR}/scripts/main.ts <url> --output-dir ./posts/
# Download images and videos to local directories
${BUN_X} ${SKILL_DIR}/scripts/main.ts <url> --download-media
```
@ -116,7 +125,8 @@ ${BUN_X} ${SKILL_DIR}/scripts/main.ts <url> --download-media
| Option | Description |
|--------|-------------|
| `<url>` | URL to fetch |
| `-o <path>` | Output file path (default: auto-generated) |
| `-o <path>` | Output file path — must be a **file** path, not directory (default: auto-generated) |
| `--output-dir <dir>` | Base output directory — auto-generates `{dir}/{domain}/{slug}.md` (default: `./url-to-markdown/`) |
| `--wait` | Wait for user signal before capturing |
| `--timeout <ms>` | Page load timeout (default: 30000) |
| `--download-media` | Download image/video assets to local `imgs/` and `videos/`, and rewrite markdown links to local relative paths |
@ -139,9 +149,8 @@ YAML front matter with `url`, `title`, `description`, `author`, `published`, `ca
## Output Directory
```
url-to-markdown/<domain>/<slug>.md
```
Default: `url-to-markdown/<domain>/<slug>.md`
With `--output-dir ./posts/`: `./posts/<domain>/<slug>.md`
- `<slug>`: From page title or URL path (kebab-case, 2-6 words)
- Conflict resolution: Append timestamp `<slug>-YYYYMMDD-HHMMSS.md`

View File

@ -25,6 +25,7 @@ async function fileExists(filePath: string): Promise<boolean> {
interface Args {
url: string;
output?: string;
outputDir?: string;
wait: boolean;
timeout: number;
downloadMedia: boolean;
@ -40,6 +41,8 @@ function parseArgs(argv: string[]): Args {
args.output = argv[++i];
} else if (arg === "--timeout" || arg === "-t") {
args.timeout = parseInt(argv[++i], 10) || DEFAULT_TIMEOUT_MS;
} else if (arg === "--output-dir") {
args.outputDir = argv[++i];
} else if (arg === "--download-media") {
args.downloadMedia = true;
} else if (!arg.startsWith("-") && !args.url) {
@ -66,10 +69,10 @@ function formatTimestamp(): string {
return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
}
async function generateOutputPath(url: string, title: string): Promise<string> {
async function generateOutputPath(url: string, title: string, outputDir?: string): Promise<string> {
const domain = new URL(url).hostname.replace(/^www\./, "");
const slug = generateSlug(title, url);
const dataDir = resolveUrlToMarkdownDataDir();
const dataDir = outputDir ? path.resolve(outputDir) : resolveUrlToMarkdownDataDir();
const basePath = path.join(dataDir, domain, `${slug}.md`);
if (!(await fileExists(basePath))) {
@ -149,11 +152,19 @@ async function main(): Promise<void> {
process.exit(1);
}
if (args.output) {
const stat = await import("node:fs").then(fs => fs.statSync(args.output!, { throwIfNoEntry: false }));
if (stat?.isDirectory()) {
console.error(`Error: -o path is a directory, not a file: ${args.output}`);
process.exit(1);
}
}
console.log(`Fetching: ${args.url}`);
console.log(`Mode: ${args.wait ? "wait" : "auto"}`);
const result = await captureUrl(args);
const outputPath = args.output || await generateOutputPath(args.url, result.metadata.title);
const outputPath = args.output || await generateOutputPath(args.url, result.metadata.title, args.outputDir);
const outputDir = path.dirname(outputPath);
await mkdir(outputDir, { recursive: true });