anyfreebook-cli 0.0.0-stage → 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 +21 -0
- package/README.md +444 -2
- package/bin/anyfreebook.js +8 -0
- package/package.json +49 -4
- package/src/api.js +189 -0
- package/src/cli.js +241 -0
- package/src/commands/download.js +325 -0
- package/src/commands/health.js +24 -0
- package/src/commands/resolve.js +79 -0
- package/src/commands/search.js +128 -0
- package/src/config.js +113 -0
- package/src/errors.js +57 -0
- package/src/filename.js +75 -0
- package/src/format.js +167 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Michael Banigo
|
|
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
CHANGED
|
@@ -1,3 +1,445 @@
|
|
|
1
|
-
#
|
|
1
|
+
# anyfreebook-cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Search seven open-access book sources and download only what is verifiably public domain — from your terminal.**
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
anyfreebook download "pride and prejudice" --format epub
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Why this exists
|
|
12
|
+
|
|
13
|
+
Most "free book" APIs hand you a title and a link, and leave you to work out
|
|
14
|
+
whether the thing behind that link is actually free. Some are public domain.
|
|
15
|
+
Some are borrow-only loans you need an account for. Some are a catalogue
|
|
16
|
+
record for a book that is still under copyright.
|
|
17
|
+
|
|
18
|
+
This tool asks, per result, and tells you which one you have:
|
|
19
|
+
|
|
20
|
+
| tier | meaning | can you download it? |
|
|
21
|
+
| --- | --- | --- |
|
|
22
|
+
| `download` | A free, legally readable copy of this title. | **Yes**, when the API offers a file. A few sources are free to read but expose no file to fetch — the CLI says so instead of downloading nothing quietly. |
|
|
23
|
+
| `borrow` | A real copy, but borrow-only: a free Internet Archive account and a loan are required. | No. The CLI says so and points you at the loan page. |
|
|
24
|
+
| `unverified` | A catalogue record or a search page. No confirmed free copy of this exact title. | No. The CLI says so. |
|
|
25
|
+
|
|
26
|
+
The tier is never a guess. For the Internet Archive it comes from the item's
|
|
27
|
+
own metadata (`access-restricted-item` and `lending_identifier`); for Project
|
|
28
|
+
Gutenberg we only claim a download when the title and the author match a real
|
|
29
|
+
ebook and its id resolves to a real file.
|
|
30
|
+
|
|
31
|
+
The CLI will not download anything that is not `download`, and it never skips a
|
|
32
|
+
result silently — it tells you why.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
The package is not on npm yet. Run it from a clone:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
git clone https://github.com/michaelbanigo575-bot/anyfreebook-cli.git
|
|
42
|
+
cd anyfreebook-cli
|
|
43
|
+
npm install
|
|
44
|
+
npm link # puts `anyfreebook` on your PATH
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Or run it without installing:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
node bin/anyfreebook.js search "python"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Once it is published to npm this becomes:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm install -g anyfreebook-cli
|
|
57
|
+
npx anyfreebook-cli search "python"
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Requires Node 18 or newer. No runtime dependencies.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## What it looks like
|
|
65
|
+
|
|
66
|
+
```console
|
|
67
|
+
$ anyfreebook search "pride and prejudice" --source gutenberg --limit 5
|
|
68
|
+
|
|
69
|
+
Query pride and prejudice
|
|
70
|
+
Page 1 · limit 5 · 4 returned · 6 total matches
|
|
71
|
+
Sources Project Gutenberg 6
|
|
72
|
+
|
|
73
|
+
TITLE AUTHOR SOURCE TIER FORMATS
|
|
74
|
+
----------------------------------------------------------------------------------------------------
|
|
75
|
+
Pride and Prejudice Jane Austen Project Gutenberg download epub, txt, html
|
|
76
|
+
Pride and Prejudice Austen, Jane, 1775-1817 Project Gutenberg download epub, txt, html
|
|
77
|
+
Pride and Prejudice, a play founded Steele, Mrs. MacKaye, Jane A Project Gutenberg download epub, txt, html
|
|
78
|
+
on Jane Austen's novel
|
|
79
|
+
Pride and Prejudice Jane Austen, R. W. Chapman Project Gutenberg download epub, txt, html
|
|
80
|
+
|
|
81
|
+
More results available — use --page 2 for the next page.
|
|
82
|
+
|
|
83
|
+
download = verified public-domain full text · borrow = lending-restricted (needs a
|
|
84
|
+
free Internet Archive account + loan) · unverified = no confirmed free copy of this
|
|
85
|
+
exact title
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
And a download:
|
|
89
|
+
|
|
90
|
+
```console
|
|
91
|
+
$ anyfreebook download "pride and prejudice" --source gutenberg --format epub --limit 2
|
|
92
|
+
|
|
93
|
+
↓ pride-and-prejudice-pg-1342.epub 23.7 MB
|
|
94
|
+
✓ Pride and Prejudice — ./books/pride-and-prejudice-pg-1342.epub (23.7 MB)
|
|
95
|
+
|
|
96
|
+
Summary: downloaded 1 · skipped 0 · failed 0 · refused 0
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
When a source did not answer, the CLI says so rather than letting you think
|
|
100
|
+
you saw everything:
|
|
101
|
+
|
|
102
|
+
```console
|
|
103
|
+
$ anyfreebook search "python" --limit 5
|
|
104
|
+
|
|
105
|
+
! 1 source did not respond: Open Library. Results below are partial.
|
|
106
|
+
|
|
107
|
+
Query python
|
|
108
|
+
...
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Quick start
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# find books
|
|
117
|
+
anyfreebook search "python"
|
|
118
|
+
|
|
119
|
+
# only what is genuinely free to download
|
|
120
|
+
anyfreebook search "python" --free-only
|
|
121
|
+
|
|
122
|
+
# only one source
|
|
123
|
+
anyfreebook search "pride and prejudice" --source gutenberg
|
|
124
|
+
|
|
125
|
+
# only results that offer a specific format
|
|
126
|
+
anyfreebook search "python" --format epub
|
|
127
|
+
|
|
128
|
+
# download to disk (default folder: ./books)
|
|
129
|
+
anyfreebook download "pride and prejudice" --format epub --out ./books
|
|
130
|
+
|
|
131
|
+
# see what would happen, write nothing
|
|
132
|
+
anyfreebook download "pride and prejudice" --dry-run
|
|
133
|
+
|
|
134
|
+
# the careful answer for one title
|
|
135
|
+
anyfreebook resolve "Pride and Prejudice" --author "Jane Austen"
|
|
136
|
+
|
|
137
|
+
# machine-readable output
|
|
138
|
+
anyfreebook search "python" --json | jq '.results[] | select(.tier=="download") | .title'
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Commands
|
|
144
|
+
|
|
145
|
+
### `anyfreebook search <query>`
|
|
146
|
+
|
|
147
|
+
| Option | Default | Meaning |
|
|
148
|
+
| --- | --- | --- |
|
|
149
|
+
| `--limit <n>` | 10 | Results per page (max 50). |
|
|
150
|
+
| `--page <n>` | 1 | Page number. |
|
|
151
|
+
| `--source <name>` | `all` | `all`, `gutenberg`, `openlibrary`, `archive`, `googlebooks`, `pubmed`, `doaj`, `librivox`. |
|
|
152
|
+
| `--format <fmt>` | — | Keep only results offering `epub`, `pdf`, `txt` or `html`. |
|
|
153
|
+
| `--free-only` | off | Keep only `tier === "download"` results. |
|
|
154
|
+
| `--json` | off | Print the raw JSON response to stdout and nothing else. |
|
|
155
|
+
|
|
156
|
+
### `anyfreebook download <query>`
|
|
157
|
+
|
|
158
|
+
| Option | Default | Meaning |
|
|
159
|
+
| --- | --- | --- |
|
|
160
|
+
| `--limit <n>` | 5 | Results to consider. |
|
|
161
|
+
| `--source <name>` | `all` | Same values as `search`. |
|
|
162
|
+
| `--format <fmt>` | best available | `epub` > `pdf` > `txt` > `html`. |
|
|
163
|
+
| `--out <dir>` | `./books` | Destination folder. |
|
|
164
|
+
| `--force` | off | Overwrite a file that already exists. |
|
|
165
|
+
| `--dry-run` | off | Show what would be downloaded; write nothing. |
|
|
166
|
+
|
|
167
|
+
Downloads are **always** restricted to `tier === "download"`. A `borrow` or
|
|
168
|
+
`unverified` result is reported as refused, with the reason — it is never
|
|
169
|
+
skipped quietly.
|
|
170
|
+
|
|
171
|
+
File names are `<title-slug>-<source-id>.<ext>`, so two different books with
|
|
172
|
+
the same title do not overwrite each other.
|
|
173
|
+
|
|
174
|
+
### `anyfreebook resolve <title> [--author <name>]`
|
|
175
|
+
|
|
176
|
+
The authoritative answer for a single title. It checks the title and the author
|
|
177
|
+
against the real record, so a book by one Austen never resolves to a different
|
|
178
|
+
book that merely shares the surname — and a request for one title never comes
|
|
179
|
+
back with a different book attached.
|
|
180
|
+
|
|
181
|
+
```console
|
|
182
|
+
$ anyfreebook resolve "Pride and Prejudice" --author "Jane Austen"
|
|
183
|
+
|
|
184
|
+
Pride and Prejudice
|
|
185
|
+
Author Jane Austen
|
|
186
|
+
Tier download
|
|
187
|
+
Reason Verified public-domain full text on Project Gutenberg.
|
|
188
|
+
License Public domain
|
|
189
|
+
Source https://www.gutenberg.org/ebooks/1342 (gutenberg)
|
|
190
|
+
|
|
191
|
+
Files (3)
|
|
192
|
+
EPUB https://www.gutenberg.org/ebooks/1342.epub3.images
|
|
193
|
+
Plain text https://www.gutenberg.org/ebooks/1342.txt.utf-8
|
|
194
|
+
HTML https://www.gutenberg.org/ebooks/1342.html.images
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### `anyfreebook health`
|
|
198
|
+
|
|
199
|
+
```console
|
|
200
|
+
$ anyfreebook health
|
|
201
|
+
|
|
202
|
+
Status ok
|
|
203
|
+
API ver v1
|
|
204
|
+
Uptime 3h 12m
|
|
205
|
+
Base URL https://anyfreebook.com/api/v1
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Global options
|
|
209
|
+
|
|
210
|
+
| Option | Environment variable | Default |
|
|
211
|
+
| --- | --- | --- |
|
|
212
|
+
| `--api-base <url>` | `ANYFREEBOOK_API_BASE` | `https://anyfreebook.com/api/v1` |
|
|
213
|
+
| `--api-key <key>` | `ANYFREEBOOK_API_KEY` | none — the anonymous tier works without one |
|
|
214
|
+
| `--timeout <ms>` | — | 20000 |
|
|
215
|
+
| `--json` | — | off |
|
|
216
|
+
| `--no-color` | `NO_COLOR` is honoured too | off |
|
|
217
|
+
| `--help`, `--version` | — | |
|
|
218
|
+
|
|
219
|
+
### Exit codes
|
|
220
|
+
|
|
221
|
+
| Code | Meaning |
|
|
222
|
+
| --- | --- |
|
|
223
|
+
| `0` | Success. |
|
|
224
|
+
| `1` | Request or usage error. |
|
|
225
|
+
| `2` | Rate limited (HTTP 429). The message says how long to wait. |
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Python SDK
|
|
230
|
+
|
|
231
|
+
The same API from Python, with **no dependencies** — standard library only.
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
pip install anyfreebook-api
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
from anyfreebook_api import Client
|
|
239
|
+
|
|
240
|
+
client = Client() # base_url and api_key read from the environment
|
|
241
|
+
result = client.search("python", limit=5)
|
|
242
|
+
|
|
243
|
+
for book in result.results:
|
|
244
|
+
if book.tier == "download":
|
|
245
|
+
print(book.title, "->", book.files[0].url)
|
|
246
|
+
|
|
247
|
+
resolved = client.resolve("Pride and Prejudice", author="Jane Austen")
|
|
248
|
+
print(resolved.tier, resolved.tier_reason)
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
`Client(base_url=..., api_key=..., timeout=...)` — every argument is optional.
|
|
252
|
+
A `429` raises `RateLimitError` with `retry_after`; other failures raise
|
|
253
|
+
`ApiError`; a network failure raises `NetworkError`.
|
|
254
|
+
|
|
255
|
+
If `result.partial` is `True`, some sources did not answer — check
|
|
256
|
+
`result.failed_sources` before treating the list as complete.
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Use it in your app
|
|
261
|
+
|
|
262
|
+
```js
|
|
263
|
+
const res = await fetch('https://anyfreebook.com/api/v1/search?q=python&limit=5');
|
|
264
|
+
const data = await res.json();
|
|
265
|
+
|
|
266
|
+
for (const book of data.results) {
|
|
267
|
+
if (book.tier === 'download') {
|
|
268
|
+
console.log(book.title, book.files[0]?.url);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
```python
|
|
274
|
+
import json, urllib.request
|
|
275
|
+
|
|
276
|
+
url = "https://anyfreebook.com/api/v1/search?q=python&limit=5"
|
|
277
|
+
with urllib.request.urlopen(url) as r:
|
|
278
|
+
data = json.load(r)
|
|
279
|
+
|
|
280
|
+
for book in data["results"]:
|
|
281
|
+
if book["tier"] == "download":
|
|
282
|
+
print(book["title"], book["files"][0]["url"])
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## API reference
|
|
288
|
+
|
|
289
|
+
Base URL: `https://anyfreebook.com/api/v1`
|
|
290
|
+
|
|
291
|
+
### `GET /search`
|
|
292
|
+
|
|
293
|
+
| Parameter | Type | Default | Notes |
|
|
294
|
+
| --- | --- | --- | --- |
|
|
295
|
+
| `q` | string | — | **Required.** Max 200 characters. |
|
|
296
|
+
| `page` | integer | `1` | |
|
|
297
|
+
| `source` | string | `all` | `all`, `local`, `gutenberg`, `openlibrary`, `archive`, `googlebooks`, `pubmed`, `doaj`, `librivox`. |
|
|
298
|
+
| `limit` | integer | `20` | 1–50. |
|
|
299
|
+
|
|
300
|
+
```json
|
|
301
|
+
{
|
|
302
|
+
"query": "python",
|
|
303
|
+
"page": 1,
|
|
304
|
+
"limit": 20,
|
|
305
|
+
"total": 22537,
|
|
306
|
+
"count": 20,
|
|
307
|
+
"sources": { "Project Gutenberg": 120, "Open Library": 22417 },
|
|
308
|
+
"failedSources": [],
|
|
309
|
+
"partial": false,
|
|
310
|
+
"results": [
|
|
311
|
+
{
|
|
312
|
+
"id": "pg-39560",
|
|
313
|
+
"title": "Fairy Circles",
|
|
314
|
+
"author": "Villamaria",
|
|
315
|
+
"year": null,
|
|
316
|
+
"source": "Project Gutenberg",
|
|
317
|
+
"sourceType": "gutenberg",
|
|
318
|
+
"sourceUrl": "https://www.gutenberg.org/ebooks/39560",
|
|
319
|
+
"tier": "download",
|
|
320
|
+
"tierReason": "Verified public-domain full text on Project Gutenberg.",
|
|
321
|
+
"license": "Public domain (Project Gutenberg)",
|
|
322
|
+
"files": [
|
|
323
|
+
{ "format": "epub", "url": "https://www.gutenberg.org/ebooks/39560.epub3.images", "bytes": null, "label": "EPUB" }
|
|
324
|
+
],
|
|
325
|
+
"links": [
|
|
326
|
+
{ "label": "Read on Project Gutenberg", "url": "https://www.gutenberg.org/ebooks/39560", "source": "Project Gutenberg" }
|
|
327
|
+
],
|
|
328
|
+
"url": "https://anyfreebook.com/book/fairy-circles-pg-39560"
|
|
329
|
+
}
|
|
330
|
+
],
|
|
331
|
+
"meta": { "apiVersion": "v1", "generatedAt": "2026-10-23T23:30:00.000Z" }
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
`failedSources` lists the sources that did not answer, and `partial` is `true`
|
|
336
|
+
when it is non-empty. A partial result set is **not** an empty result set.
|
|
337
|
+
|
|
338
|
+
`files` holds direct file URLs, and only when the file genuinely exists.
|
|
339
|
+
Project Gutenberg always offers EPUB, plain text and HTML for a valid ebook
|
|
340
|
+
id; a PDF is listed only when the source reported one.
|
|
341
|
+
|
|
342
|
+
### `GET /resolve`
|
|
343
|
+
|
|
344
|
+
| Parameter | Type | Required | Notes |
|
|
345
|
+
| --- | --- | --- | --- |
|
|
346
|
+
| `title` | string | **yes** | Max 300 characters. |
|
|
347
|
+
| `author` | string | no | Used to confirm the match. |
|
|
348
|
+
|
|
349
|
+
```json
|
|
350
|
+
{
|
|
351
|
+
"title": "Pride and Prejudice",
|
|
352
|
+
"author": "Jane Austen",
|
|
353
|
+
"tier": "download",
|
|
354
|
+
"tierReason": "Verified public-domain full text on Project Gutenberg.",
|
|
355
|
+
"sourceType": "gutenberg",
|
|
356
|
+
"sourceUrl": "https://www.gutenberg.org/ebooks/1342",
|
|
357
|
+
"license": "Public domain",
|
|
358
|
+
"files": [
|
|
359
|
+
{ "format": "epub", "url": "https://www.gutenberg.org/ebooks/1342.epub3.images", "bytes": null, "label": "EPUB" }
|
|
360
|
+
],
|
|
361
|
+
"links": [
|
|
362
|
+
{ "label": "Read on Project Gutenberg", "url": "https://www.gutenberg.org/ebooks/1342", "source": "Project Gutenberg" }
|
|
363
|
+
],
|
|
364
|
+
"meta": { "apiVersion": "v1", "generatedAt": "2026-10-23T23:30:00.000Z" }
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### `GET /health`
|
|
369
|
+
|
|
370
|
+
```json
|
|
371
|
+
{ "status": "ok", "apiVersion": "v1", "uptimeSeconds": 1234 }
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### Authentication
|
|
375
|
+
|
|
376
|
+
Optional. The anonymous tier works with no setup — send a key only if you
|
|
377
|
+
need a bigger quota.
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
curl -H "Authorization: Bearer afb_..." "https://anyfreebook.com/api/v1/search?q=python"
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
| Tier | Requests / minute | Requests / day |
|
|
384
|
+
| --- | --- | --- |
|
|
385
|
+
| anonymous (no key) | 30 | 200 |
|
|
386
|
+
| `free` | 60 | 2,000 |
|
|
387
|
+
| `partner` | 300 | 50,000 |
|
|
388
|
+
|
|
389
|
+
A key that cannot be verified gets `401`. It is never silently downgraded to
|
|
390
|
+
the anonymous tier.
|
|
391
|
+
|
|
392
|
+
### Errors
|
|
393
|
+
|
|
394
|
+
| Status | Meaning |
|
|
395
|
+
| --- | --- |
|
|
396
|
+
| `400` | Missing or invalid parameter. |
|
|
397
|
+
| `401` | The presented API key could not be verified. |
|
|
398
|
+
| `429` | Rate limit exceeded. The `Retry-After` header says how long to wait. |
|
|
399
|
+
| `500` | Something broke on our side. |
|
|
400
|
+
|
|
401
|
+
### CORS
|
|
402
|
+
|
|
403
|
+
Closed by default. A command-line client or a server-side SDK does not need
|
|
404
|
+
CORS at all. Browser clients need their origin added to the server's
|
|
405
|
+
allowlist.
|
|
406
|
+
|
|
407
|
+
---
|
|
408
|
+
|
|
409
|
+
## Sources
|
|
410
|
+
|
|
411
|
+
Project Gutenberg · Open Library · Internet Archive · Google Books ·
|
|
412
|
+
PubMed Central · DOAJ · LibriVox
|
|
413
|
+
|
|
414
|
+
Google Books records are catalogue entries, not free copies, and are reported
|
|
415
|
+
as `unverified` for exactly that reason.
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
## Contributing
|
|
420
|
+
|
|
421
|
+
```bash
|
|
422
|
+
git clone https://github.com/michaelbanigo575-bot/anyfreebook-cli.git
|
|
423
|
+
cd anyfreebook-cli
|
|
424
|
+
npm install
|
|
425
|
+
npm test
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
The test suite runs entirely against a local mock server — no network access,
|
|
429
|
+
no API key needed. The Python SDK has its own suite:
|
|
430
|
+
|
|
431
|
+
```bash
|
|
432
|
+
cd python
|
|
433
|
+
python -m pytest tests/ -q
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
Issues and pull requests are welcome: <https://github.com/michaelbanigo575-bot/anyfreebook-cli/issues>
|
|
437
|
+
|
|
438
|
+
## License
|
|
439
|
+
|
|
440
|
+
MIT — see [LICENSE](./LICENSE).
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
The API behind this tool is free and needs no key to start:
|
|
445
|
+
<https://anyfreebook.com/developers>
|
package/package.json
CHANGED
|
@@ -1,6 +1,51 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "anyfreebook-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Search 7 open-access book sources and download only what is verifiably public domain.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"anyfreebook": "bin/anyfreebook.js"
|
|
8
|
+
},
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=18"
|
|
11
|
+
},
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/michaelbanigo575-bot/anyfreebook-cli.git"
|
|
16
|
+
},
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/michaelbanigo575-bot/anyfreebook-cli/issues"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://github.com/michaelbanigo575-bot/anyfreebook-cli#readme",
|
|
21
|
+
"keywords": [
|
|
22
|
+
"anyfreebook",
|
|
23
|
+
"books",
|
|
24
|
+
"ebook",
|
|
25
|
+
"open-access",
|
|
26
|
+
"public-domain",
|
|
27
|
+
"project-gutenberg",
|
|
28
|
+
"open-library",
|
|
29
|
+
"internet-archive",
|
|
30
|
+
"librivox",
|
|
31
|
+
"doaj",
|
|
32
|
+
"pubmed",
|
|
33
|
+
"cli",
|
|
34
|
+
"search",
|
|
35
|
+
"download",
|
|
36
|
+
"free"
|
|
37
|
+
],
|
|
38
|
+
"files": [
|
|
39
|
+
"bin",
|
|
40
|
+
"src",
|
|
41
|
+
"README.md",
|
|
42
|
+
"LICENSE"
|
|
43
|
+
],
|
|
44
|
+
"scripts": {
|
|
45
|
+
"test": "node --test \"test/*.test.js\"",
|
|
46
|
+
"help": "node bin/anyfreebook.js --help"
|
|
47
|
+
},
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public"
|
|
50
|
+
}
|
|
51
|
+
}
|