@songmu/mdhq 0.0.3 → 0.0.5
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 +10 -5
- package/dist/cli.js +17 -8
- package/docs/configuration.md +5 -4
- package/docs/specification.md +23 -24
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -21,6 +21,7 @@ mdhq get https://example.com/article
|
|
|
21
21
|
mdhq get https://example.com/article https://example.com/another-article
|
|
22
22
|
cat urls.txt | mdhq get
|
|
23
23
|
mdhq get --update https://example.com/article
|
|
24
|
+
mdhq get --assets https://example.com/article
|
|
24
25
|
mdhq get --no-assets https://example.com/article
|
|
25
26
|
mdhq get --json --header 'Cookie: session=value' https://example.com/article
|
|
26
27
|
mdhq list
|
|
@@ -30,10 +31,13 @@ mdhq root
|
|
|
30
31
|
|
|
31
32
|
`mdhq get` accepts multiple URLs as arguments or one URL per line on standard
|
|
32
33
|
input; both sources are merged. It prints one absolute Markdown path per URL
|
|
33
|
-
to stdout by default. Warnings are written to stderr. `--json`
|
|
34
|
-
result object
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
to stdout by default. Warnings are written to stderr. `--json` writes one
|
|
35
|
+
compact JSON result object per URL as JSON Lines. Results are written as soon
|
|
36
|
+
as each URL finishes, so parallel requests can produce output in completion
|
|
37
|
+
order rather than input order. If a later request fails, results already
|
|
38
|
+
written to stdout remain available.
|
|
39
|
+
Requests are limited to eight in parallel, with requests to the same host
|
|
40
|
+
serialized and spaced one second apart; image downloads use the same limits.
|
|
37
41
|
|
|
38
42
|
`mdhq list` recursively lists `.md` files below the storage root, one per
|
|
39
43
|
line, in sorted root-relative form. Use `-p` or `--full-path` to print absolute
|
|
@@ -99,7 +103,8 @@ const saved = await getPage({
|
|
|
99
103
|
|
|
100
104
|
`convertHtml` performs extraction without fetching or writing files.
|
|
101
105
|
`getPage` fetches, converts, optionally localizes images, adds frontmatter,
|
|
102
|
-
and saves the document.
|
|
106
|
+
and saves the document. Use `--assets` or `--no-assets` to override the
|
|
107
|
+
configured asset behavior. Set `assets: false` or use `--no-assets` to keep
|
|
103
108
|
absolute image URLs without creating `_assets`.
|
|
104
109
|
|
|
105
110
|
Saved frontmatter uses Obsidian Web Clipper-compatible names such as `title`,
|
package/dist/cli.js
CHANGED
|
@@ -65,11 +65,12 @@ export function createProgram(io = process) {
|
|
|
65
65
|
.description("Fetch and save web pages.")
|
|
66
66
|
.argument("[urls...]")
|
|
67
67
|
.option("--root <path>", "storage root")
|
|
68
|
+
.option("--assets", "download images")
|
|
68
69
|
.option("--no-assets", "do not download images")
|
|
69
70
|
.option("--update", "update an existing page")
|
|
70
71
|
.option("--user-agent <value>", "HTTP User-Agent")
|
|
71
72
|
.option("--header <header>", "additional HTTP header", collect, [])
|
|
72
|
-
.addOption(new Option("--json", "print
|
|
73
|
+
.addOption(new Option("--json", "print results as JSON Lines"))
|
|
73
74
|
.action(async (urls, options) => {
|
|
74
75
|
const inputUrls = await readStdinUrls(io.stdin);
|
|
75
76
|
const requestedUrls = [...(urls ?? []), ...inputUrls]
|
|
@@ -79,7 +80,6 @@ export function createProgram(io = process) {
|
|
|
79
80
|
throw new MdhqError("INVALID_URL", "At least one URL is required");
|
|
80
81
|
}
|
|
81
82
|
const scheduler = new RequestScheduler();
|
|
82
|
-
const results = [];
|
|
83
83
|
let nextIndex = 0;
|
|
84
84
|
const worker = async () => {
|
|
85
85
|
while (nextIndex < requestedUrls.length) {
|
|
@@ -89,22 +89,31 @@ export function createProgram(io = process) {
|
|
|
89
89
|
if (url === undefined) {
|
|
90
90
|
continue;
|
|
91
91
|
}
|
|
92
|
-
|
|
92
|
+
const result = await getPage({
|
|
93
93
|
url,
|
|
94
94
|
...(options.root ? { root: options.root } : {}),
|
|
95
|
-
...(options.assets
|
|
95
|
+
...(options.assets !== undefined ? { assets: options.assets } : {}),
|
|
96
96
|
update: options.update ?? false,
|
|
97
97
|
...(options.userAgent ? { userAgent: options.userAgent } : {}),
|
|
98
98
|
headers: parseHeaders(options.header),
|
|
99
99
|
scheduler,
|
|
100
100
|
onWarning: (warning) => io.stderr.write(`warning: ${warning.message}\n`)
|
|
101
101
|
});
|
|
102
|
+
io.stdout.write(`${options.json ? JSON.stringify(result) : result.path}\n`);
|
|
102
103
|
}
|
|
103
104
|
};
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
const failures = [];
|
|
106
|
+
await Promise.all(Array.from({ length: Math.min(8, requestedUrls.length) }, async () => {
|
|
107
|
+
try {
|
|
108
|
+
await worker();
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
failures.push(error);
|
|
112
|
+
}
|
|
113
|
+
}));
|
|
114
|
+
if (failures.length > 0) {
|
|
115
|
+
throw failures[0];
|
|
116
|
+
}
|
|
108
117
|
});
|
|
109
118
|
program
|
|
110
119
|
.command("list")
|
package/docs/configuration.md
CHANGED
|
@@ -106,10 +106,11 @@ Otherwise configuration overrides the built-in default.
|
|
|
106
106
|
The CLI `--user-agent` option is passed as `GetPageOptions.userAgent` and
|
|
107
107
|
therefore overrides configuration `userAgent`.
|
|
108
108
|
|
|
109
|
-
The CLI `--
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
109
|
+
The CLI `--assets` and `--no-assets` options pass
|
|
110
|
+
`GetPageOptions.assets: true` and `GetPageOptions.assets: false`,
|
|
111
|
+
respectively, and therefore override configuration `assets`. When asset
|
|
112
|
+
localization is disabled, image destinations remain absolute URLs, the result
|
|
113
|
+
contains no asset entries, and mdhq does not create `_assets`.
|
|
113
114
|
|
|
114
115
|
Generic CLI `--header` values and library `headers` values are appended after
|
|
115
116
|
mdhq creates its `Accept` and User-Agent headers. A generic `User-Agent` or
|
package/docs/specification.md
CHANGED
|
@@ -21,13 +21,13 @@ Runtime requirements:
|
|
|
21
21
|
The executable provides three subcommands:
|
|
22
22
|
|
|
23
23
|
```text
|
|
24
|
-
mdhq get [options]
|
|
24
|
+
mdhq get [options] [urls...]
|
|
25
25
|
mdhq list [options]
|
|
26
26
|
mdhq root [options]
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
`mdhq get` accepts
|
|
30
|
-
|
|
29
|
+
`mdhq get` accepts multiple URL arguments and one URL per line from standard
|
|
30
|
+
input. Both sources are merged, and up to eight URLs are processed in parallel.
|
|
31
31
|
|
|
32
32
|
### `get` options
|
|
33
33
|
|
|
@@ -37,22 +37,19 @@ processing is delegated to external tools such as `xargs`.
|
|
|
37
37
|
| `--update` | Fetch and replace an existing document with the same URL identity. |
|
|
38
38
|
| `--user-agent <value>` | Override the default HTTP User-Agent. |
|
|
39
39
|
| `--header <header>` | Add an HTTP header. The option is repeatable and uses `Name: value` syntax. |
|
|
40
|
-
| `--json` | Write
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
path followed by a newline.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"assets": [],
|
|
54
|
-
"warnings": []
|
|
55
|
-
}
|
|
40
|
+
| `--json` | Write one result per line as JSON Lines instead of only the Markdown path. |
|
|
41
|
+
|
|
42
|
+
Without `--json`, stdout receives one absolute Markdown path per requested URL,
|
|
43
|
+
with each path followed by a newline. Each result is written as soon as that
|
|
44
|
+
URL finishes, so parallel requests can produce output in completion order
|
|
45
|
+
rather than input order.
|
|
46
|
+
Warnings are written to stderr.
|
|
47
|
+
|
|
48
|
+
With `--json`, stdout contains one compact JSON object per requested URL,
|
|
49
|
+
also written as soon as the URL finishes. Each line has this shape:
|
|
50
|
+
|
|
51
|
+
```jsonl
|
|
52
|
+
{"requestedUrl":"https://example.com/start","sourceUrl":"https://example.com/article","path":"/data/mdhq/example.com/article.md","status":"saved","assets":[],"warnings":[]}
|
|
56
53
|
```
|
|
57
54
|
|
|
58
55
|
`status` is one of:
|
|
@@ -63,7 +60,8 @@ With `--json`, stdout contains an object with this shape:
|
|
|
63
60
|
body, including an HTTP 304 response.
|
|
64
61
|
- `skipped`: an existing same-identity file was kept.
|
|
65
62
|
|
|
66
|
-
An error is written to stderr and causes exit status `1`.
|
|
63
|
+
An error is written to stderr and causes exit status `1`. Results written to
|
|
64
|
+
stdout before the error remain available to downstream consumers.
|
|
67
65
|
|
|
68
66
|
### `list`
|
|
69
67
|
|
|
@@ -508,10 +506,11 @@ For images:
|
|
|
508
506
|
|
|
509
507
|
Asset localization is enabled by default. It can be disabled with the
|
|
510
508
|
top-level configuration field `assets: false`, library option
|
|
511
|
-
`GetPageOptions.assets: false`, or CLI option `--no-assets`. The
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
509
|
+
`GetPageOptions.assets: false`, or CLI option `--no-assets`. The CLI options
|
|
510
|
+
`--assets` and `--no-assets` explicitly enable or disable localization and
|
|
511
|
+
take precedence over configuration, as does the library option. When
|
|
512
|
+
disabled, HTTP(S) image destinations are kept as absolute URLs, the result
|
|
513
|
+
`assets` array is empty, and `_assets` is not created.
|
|
515
514
|
|
|
516
515
|
mdhq does not rewrite ordinary links to other locally stored Markdown
|
|
517
516
|
files.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@songmu/mdhq",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Save web pages as Markdown in a ghq-inspired filesystem layout.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -69,6 +69,6 @@
|
|
|
69
69
|
"@types/node": "^26.4.0",
|
|
70
70
|
"@types/proper-lockfile": "4.1.4",
|
|
71
71
|
"typescript": "^7.0.2",
|
|
72
|
-
"vitest": "^
|
|
72
|
+
"vitest": "^5.0.0"
|
|
73
73
|
}
|
|
74
74
|
}
|