duck-poacher 0.6.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 +15 -0
- package/README.md +101 -0
- package/dist/DuckDuckGo.cjs +11 -0
- package/dist/DuckDuckGo.d.cts +10 -0
- package/dist/DuckDuckGo.d.mts +10 -0
- package/dist/DuckDuckGo.mjs +11 -0
- package/dist/_virtual/_rolldown/runtime.cjs +23 -0
- package/dist/image/ImageSearchClient.cjs +70 -0
- package/dist/image/ImageSearchClient.d.cts +18 -0
- package/dist/image/ImageSearchClient.d.mts +18 -0
- package/dist/image/ImageSearchClient.mjs +69 -0
- package/dist/image/ImageSearchParser.cjs +12 -0
- package/dist/image/ImageSearchParser.mjs +12 -0
- package/dist/image/ImageSearchResult.cjs +11 -0
- package/dist/image/ImageSearchResult.d.cts +8 -0
- package/dist/image/ImageSearchResult.d.mts +8 -0
- package/dist/image/ImageSearchResult.mjs +11 -0
- package/dist/index.cjs +5 -0
- package/dist/index.d.cts +4 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.mjs +3 -0
- package/package.json +80 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lars Dreier
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# duck-poacher
|
|
2
|
+
|
|
3
|
+
A Node.js library for image search via DuckDuckGo. Returns image and thumbnail
|
|
4
|
+
URLs for a query, with optional filters for size, color, type, and more.
|
|
5
|
+
|
|
6
|
+
It calls DuckDuckGo's image-search endpoints, which are not a public, versioned
|
|
7
|
+
API. Response formats can change on DuckDuckGo's side and break the library.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install duck-poacher
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Requires Node.js 18 or newer. The package ships dual ESM/CJS and exposes both an
|
|
16
|
+
`import` and a `require` entry through its `exports` map.
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
`DuckDuckGo` is the client. Construct one and call `imageSearch` — it returns a
|
|
21
|
+
parsed `ImageSearchResult[]` (objects with `imageUrl` / `thumbnailUrl`, not a raw
|
|
22
|
+
string) and manages the per-session `vqd` token for you, so there is no token to
|
|
23
|
+
pass.
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { DuckDuckGo, type DdgSearchOptions, type ImageSearchResult } from 'duck-poacher';
|
|
27
|
+
|
|
28
|
+
const ddg = new DuckDuckGo();
|
|
29
|
+
|
|
30
|
+
const options: DdgSearchOptions = {
|
|
31
|
+
size: 'Large',
|
|
32
|
+
layout: 'Square',
|
|
33
|
+
safeSearch: true,
|
|
34
|
+
};
|
|
35
|
+
const results: ImageSearchResult[] = await ddg.imageSearch('mountain landscape', options);
|
|
36
|
+
|
|
37
|
+
for (const result of results) {
|
|
38
|
+
console.log(result.imageUrl, result.thumbnailUrl);
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Each call makes two live requests (mint the token, then search). There is no
|
|
43
|
+
built-in multi-query, dedupe, or cap.
|
|
44
|
+
|
|
45
|
+
## API
|
|
46
|
+
|
|
47
|
+
| Export | Kind | Purpose |
|
|
48
|
+
|--------|------|---------|
|
|
49
|
+
| `DuckDuckGo` | class | The client: `imageSearch(query, options?)`, token managed internally |
|
|
50
|
+
| `ImageSearchResult` | class | Immutable value object `{ thumbnailUrl, imageUrl }` |
|
|
51
|
+
| `DdgSearchOptions` | type | Filter options for `imageSearch` |
|
|
52
|
+
| `DdgTime` `DdgSize` `DdgColor` `DdgType` `DdgLayout` `DdgLicense` | type | String-union option values |
|
|
53
|
+
|
|
54
|
+
### `DuckDuckGo`
|
|
55
|
+
|
|
56
|
+
- **`imageSearch(query: string, options?: DdgSearchOptions): Promise<ImageSearchResult[]>`**
|
|
57
|
+
— generates a per-session `vqd` token, runs the image search, and returns the
|
|
58
|
+
parsed results. Throws `Error('Unable to read token from DuckDuckGo response.')`
|
|
59
|
+
if the token cannot be scraped; a malformed response body throws.
|
|
60
|
+
|
|
61
|
+
### `DdgSearchOptions`
|
|
62
|
+
|
|
63
|
+
All fields are optional. `safeSearch` is a boolean; the rest are string unions:
|
|
64
|
+
|
|
65
|
+
| Option | Type | Values |
|
|
66
|
+
|--------|------|--------|
|
|
67
|
+
| `time` | `DdgTime` | `Day` `Week` `Month` |
|
|
68
|
+
| `size` | `DdgSize` | `Small` `Medium` `Large` `Wallpaper` |
|
|
69
|
+
| `color` | `DdgColor` | `color` `Monochrome` |
|
|
70
|
+
| `type` | `DdgType` | `photo` `clipart` `gif` `transparent` `line` |
|
|
71
|
+
| `layout` | `DdgLayout` | `Square` `Tall` `Wide` |
|
|
72
|
+
| `license` | `DdgLicense` | `Any` `Public` |
|
|
73
|
+
| `safeSearch` | `boolean` | safe search on / off |
|
|
74
|
+
|
|
75
|
+
## Error handling
|
|
76
|
+
|
|
77
|
+
Errors are thrown rather than swallowed. `generateToken` throws if no token can
|
|
78
|
+
be read from the response. HTTP failures (status ≥ 400, network errors,
|
|
79
|
+
timeouts) reject from the underlying request and propagate to the caller.
|
|
80
|
+
|
|
81
|
+
## Development
|
|
82
|
+
|
|
83
|
+
| Command | Does |
|
|
84
|
+
|---------|------|
|
|
85
|
+
| `npm run build` | tsdown → dual ESM/CJS in `dist/` |
|
|
86
|
+
| `npm test` | run all `test/**/*.test.ts` (hits the live DuckDuckGo API) |
|
|
87
|
+
| `npm run typecheck` | `tsc --noEmit` over `src/` |
|
|
88
|
+
| `npm run lint` / `lint:fix` | ESLint |
|
|
89
|
+
| `npm run format` / `format:check` | dprint |
|
|
90
|
+
| `npm run check:exports` | `attw` validates the published export map |
|
|
91
|
+
|
|
92
|
+
The only runtime dependency is
|
|
93
|
+
[`node-http-toolkit`](https://www.npmjs.com/package/node-http-toolkit), which
|
|
94
|
+
provides the HTTP layer.
|
|
95
|
+
|
|
96
|
+
The tests run against the live DuckDuckGo endpoints, so they require network
|
|
97
|
+
access.
|
|
98
|
+
|
|
99
|
+
## License
|
|
100
|
+
|
|
101
|
+
ISC © Lars Dreier
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const require_ImageSearchClient = require("./image/ImageSearchClient.cjs");
|
|
2
|
+
//#region src/DuckDuckGo.ts
|
|
3
|
+
var DuckDuckGo = class {
|
|
4
|
+
_imageSearch = new require_ImageSearchClient.default();
|
|
5
|
+
async imageSearch(query, options) {
|
|
6
|
+
const token = await this._imageSearch.generateToken(query);
|
|
7
|
+
return this._imageSearch.imageSearch(query, token, options);
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
exports.default = DuckDuckGo;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ImageSearchResult } from "./image/ImageSearchResult.cjs";
|
|
2
|
+
import { DdgSearchOptions } from "./image/ImageSearchClient.cjs";
|
|
3
|
+
|
|
4
|
+
//#region src/DuckDuckGo.d.ts
|
|
5
|
+
declare class DuckDuckGo {
|
|
6
|
+
private readonly _imageSearch;
|
|
7
|
+
imageSearch(query: string, options?: DdgSearchOptions): Promise<ImageSearchResult[]>;
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
export { DuckDuckGo };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ImageSearchResult } from "./image/ImageSearchResult.mjs";
|
|
2
|
+
import { DdgSearchOptions } from "./image/ImageSearchClient.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/DuckDuckGo.d.ts
|
|
5
|
+
declare class DuckDuckGo {
|
|
6
|
+
private readonly _imageSearch;
|
|
7
|
+
imageSearch(query: string, options?: DdgSearchOptions): Promise<ImageSearchResult[]>;
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
export { DuckDuckGo };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import ImageSearchClient from "./image/ImageSearchClient.mjs";
|
|
2
|
+
//#region src/DuckDuckGo.ts
|
|
3
|
+
var DuckDuckGo = class {
|
|
4
|
+
_imageSearch = new ImageSearchClient();
|
|
5
|
+
async imageSearch(query, options) {
|
|
6
|
+
const token = await this._imageSearch.generateToken(query);
|
|
7
|
+
return this._imageSearch.imageSearch(query, token, options);
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
export { DuckDuckGo as default };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
22
|
+
//#endregion
|
|
23
|
+
exports.__toESM = __toESM;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
const require_ImageSearchParser = require("./ImageSearchParser.cjs");
|
|
3
|
+
let node_http_toolkit = require("node-http-toolkit");
|
|
4
|
+
//#region src/image/ImageSearchClient.ts
|
|
5
|
+
var ImageSearchClient = class {
|
|
6
|
+
OPTION_NAMES = [
|
|
7
|
+
"time",
|
|
8
|
+
"size",
|
|
9
|
+
"color",
|
|
10
|
+
"type",
|
|
11
|
+
"layout",
|
|
12
|
+
"license"
|
|
13
|
+
];
|
|
14
|
+
TOKEN_HEADERS = { dnt: "1" };
|
|
15
|
+
SEARCH_HEADERS = {
|
|
16
|
+
dnt: "1",
|
|
17
|
+
"accept-encoding": "gzip, deflate, sdch, br",
|
|
18
|
+
"x-requested-with": "XMLHttpRequest",
|
|
19
|
+
"accept-language": "en-GB,en-US;q=0.8,en;q=0.6,ms;q=0.4",
|
|
20
|
+
"user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
|
|
21
|
+
accept: "application/json, text/javascript, */*; q=0.01",
|
|
22
|
+
referer: "https://duckduckgo.com/",
|
|
23
|
+
authority: "duckduckgo.com"
|
|
24
|
+
};
|
|
25
|
+
TOKEN_REGEX = /vqd=(?<vqd>[\d-]+)/;
|
|
26
|
+
_parser = new require_ImageSearchParser.default();
|
|
27
|
+
async generateToken(query) {
|
|
28
|
+
const params = new URLSearchParams();
|
|
29
|
+
params.append("q", query);
|
|
30
|
+
params.append("atb", "v299-1");
|
|
31
|
+
params.append("iar", "images");
|
|
32
|
+
params.append("iax", "images");
|
|
33
|
+
params.append("ia", "images");
|
|
34
|
+
const url = `https://duckduckgo.com/?${params.toString()}`;
|
|
35
|
+
const vqd = (await this.get(url, this.TOKEN_HEADERS)).match(this.TOKEN_REGEX)?.groups?.["vqd"];
|
|
36
|
+
if (vqd == null) throw new Error("Unable to read token from DuckDuckGo response.");
|
|
37
|
+
return vqd;
|
|
38
|
+
}
|
|
39
|
+
async imageSearch(query, token, options) {
|
|
40
|
+
const searchOptions = options ?? {};
|
|
41
|
+
const url = this.createSearchUrl(query, token, searchOptions);
|
|
42
|
+
const responseText = await this.get(url, this.SEARCH_HEADERS);
|
|
43
|
+
return this._parser.parse(responseText);
|
|
44
|
+
}
|
|
45
|
+
async get(url, headers) {
|
|
46
|
+
const response = await new node_http_toolkit.AsyncResolvingHttpRequest(url, node_http_toolkit.HttpMethod.GET, headers).resolve();
|
|
47
|
+
return new node_http_toolkit.HttpResponseReader().readData(response);
|
|
48
|
+
}
|
|
49
|
+
createSearchUrl(query, token, options) {
|
|
50
|
+
const params = new URLSearchParams();
|
|
51
|
+
params.append("l", "de-de");
|
|
52
|
+
params.append("o", "json");
|
|
53
|
+
params.append("q", query);
|
|
54
|
+
params.append("vqd", token);
|
|
55
|
+
params.append("f", this.createImageSearchOptionsHeader(options));
|
|
56
|
+
params.append("p", options.safeSearch == true ? "1" : "-1");
|
|
57
|
+
return `https://duckduckgo.com/i.js?${params.toString()}`;
|
|
58
|
+
}
|
|
59
|
+
createImageSearchOptionsHeader(options) {
|
|
60
|
+
const optionValues = [];
|
|
61
|
+
for (const optionName of this.OPTION_NAMES) {
|
|
62
|
+
const optionValue = options[optionName]?.toString();
|
|
63
|
+
if (optionValue == null) optionValues.push("");
|
|
64
|
+
else optionValues.push(`${optionName}:${optionValue}`);
|
|
65
|
+
}
|
|
66
|
+
return optionValues.join(",");
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
//#endregion
|
|
70
|
+
exports.default = ImageSearchClient;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/image/ImageSearchClient.d.ts
|
|
2
|
+
type DdgTime = 'Day' | 'Week' | 'Month';
|
|
3
|
+
type DdgSize = 'Small' | 'Medium' | 'Large' | 'Wallpaper';
|
|
4
|
+
type DdgColor = 'color' | 'Monochrome';
|
|
5
|
+
type DdgType = 'photo' | 'clipart' | 'gif' | 'transparent' | 'line';
|
|
6
|
+
type DdgLayout = 'Square' | 'Tall' | 'Wide';
|
|
7
|
+
type DdgLicense = 'Any' | 'Public';
|
|
8
|
+
interface DdgSearchOptions {
|
|
9
|
+
time?: DdgTime;
|
|
10
|
+
size?: DdgSize;
|
|
11
|
+
color?: DdgColor;
|
|
12
|
+
type?: DdgType;
|
|
13
|
+
layout?: DdgLayout;
|
|
14
|
+
license?: DdgLicense;
|
|
15
|
+
safeSearch?: boolean;
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { DdgColor, DdgLayout, DdgLicense, DdgSearchOptions, DdgSize, DdgTime, DdgType };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/image/ImageSearchClient.d.ts
|
|
2
|
+
type DdgTime = 'Day' | 'Week' | 'Month';
|
|
3
|
+
type DdgSize = 'Small' | 'Medium' | 'Large' | 'Wallpaper';
|
|
4
|
+
type DdgColor = 'color' | 'Monochrome';
|
|
5
|
+
type DdgType = 'photo' | 'clipart' | 'gif' | 'transparent' | 'line';
|
|
6
|
+
type DdgLayout = 'Square' | 'Tall' | 'Wide';
|
|
7
|
+
type DdgLicense = 'Any' | 'Public';
|
|
8
|
+
interface DdgSearchOptions {
|
|
9
|
+
time?: DdgTime;
|
|
10
|
+
size?: DdgSize;
|
|
11
|
+
color?: DdgColor;
|
|
12
|
+
type?: DdgType;
|
|
13
|
+
layout?: DdgLayout;
|
|
14
|
+
license?: DdgLicense;
|
|
15
|
+
safeSearch?: boolean;
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { DdgColor, DdgLayout, DdgLicense, DdgSearchOptions, DdgSize, DdgTime, DdgType };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import ImageSearchParser from "./ImageSearchParser.mjs";
|
|
2
|
+
import { AsyncResolvingHttpRequest, HttpMethod, HttpResponseReader } from "node-http-toolkit";
|
|
3
|
+
//#region src/image/ImageSearchClient.ts
|
|
4
|
+
var ImageSearchClient = class {
|
|
5
|
+
OPTION_NAMES = [
|
|
6
|
+
"time",
|
|
7
|
+
"size",
|
|
8
|
+
"color",
|
|
9
|
+
"type",
|
|
10
|
+
"layout",
|
|
11
|
+
"license"
|
|
12
|
+
];
|
|
13
|
+
TOKEN_HEADERS = { dnt: "1" };
|
|
14
|
+
SEARCH_HEADERS = {
|
|
15
|
+
dnt: "1",
|
|
16
|
+
"accept-encoding": "gzip, deflate, sdch, br",
|
|
17
|
+
"x-requested-with": "XMLHttpRequest",
|
|
18
|
+
"accept-language": "en-GB,en-US;q=0.8,en;q=0.6,ms;q=0.4",
|
|
19
|
+
"user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
|
|
20
|
+
accept: "application/json, text/javascript, */*; q=0.01",
|
|
21
|
+
referer: "https://duckduckgo.com/",
|
|
22
|
+
authority: "duckduckgo.com"
|
|
23
|
+
};
|
|
24
|
+
TOKEN_REGEX = /vqd=(?<vqd>[\d-]+)/;
|
|
25
|
+
_parser = new ImageSearchParser();
|
|
26
|
+
async generateToken(query) {
|
|
27
|
+
const params = new URLSearchParams();
|
|
28
|
+
params.append("q", query);
|
|
29
|
+
params.append("atb", "v299-1");
|
|
30
|
+
params.append("iar", "images");
|
|
31
|
+
params.append("iax", "images");
|
|
32
|
+
params.append("ia", "images");
|
|
33
|
+
const url = `https://duckduckgo.com/?${params.toString()}`;
|
|
34
|
+
const vqd = (await this.get(url, this.TOKEN_HEADERS)).match(this.TOKEN_REGEX)?.groups?.["vqd"];
|
|
35
|
+
if (vqd == null) throw new Error("Unable to read token from DuckDuckGo response.");
|
|
36
|
+
return vqd;
|
|
37
|
+
}
|
|
38
|
+
async imageSearch(query, token, options) {
|
|
39
|
+
const searchOptions = options ?? {};
|
|
40
|
+
const url = this.createSearchUrl(query, token, searchOptions);
|
|
41
|
+
const responseText = await this.get(url, this.SEARCH_HEADERS);
|
|
42
|
+
return this._parser.parse(responseText);
|
|
43
|
+
}
|
|
44
|
+
async get(url, headers) {
|
|
45
|
+
const response = await new AsyncResolvingHttpRequest(url, HttpMethod.GET, headers).resolve();
|
|
46
|
+
return new HttpResponseReader().readData(response);
|
|
47
|
+
}
|
|
48
|
+
createSearchUrl(query, token, options) {
|
|
49
|
+
const params = new URLSearchParams();
|
|
50
|
+
params.append("l", "de-de");
|
|
51
|
+
params.append("o", "json");
|
|
52
|
+
params.append("q", query);
|
|
53
|
+
params.append("vqd", token);
|
|
54
|
+
params.append("f", this.createImageSearchOptionsHeader(options));
|
|
55
|
+
params.append("p", options.safeSearch == true ? "1" : "-1");
|
|
56
|
+
return `https://duckduckgo.com/i.js?${params.toString()}`;
|
|
57
|
+
}
|
|
58
|
+
createImageSearchOptionsHeader(options) {
|
|
59
|
+
const optionValues = [];
|
|
60
|
+
for (const optionName of this.OPTION_NAMES) {
|
|
61
|
+
const optionValue = options[optionName]?.toString();
|
|
62
|
+
if (optionValue == null) optionValues.push("");
|
|
63
|
+
else optionValues.push(`${optionName}:${optionValue}`);
|
|
64
|
+
}
|
|
65
|
+
return optionValues.join(",");
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
//#endregion
|
|
69
|
+
export { ImageSearchClient as default };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const require_ImageSearchResult = require("./ImageSearchResult.cjs");
|
|
2
|
+
//#region src/image/ImageSearchParser.ts
|
|
3
|
+
var ImageSearchParser = class {
|
|
4
|
+
parse(responseText) {
|
|
5
|
+
const parsedResults = JSON.parse(responseText).results;
|
|
6
|
+
const searchResults = [];
|
|
7
|
+
for (const result of parsedResults) searchResults.push(new require_ImageSearchResult.default(result.thumbnail, result.image));
|
|
8
|
+
return searchResults;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
//#endregion
|
|
12
|
+
exports.default = ImageSearchParser;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import ImageSearchResult from "./ImageSearchResult.mjs";
|
|
2
|
+
//#region src/image/ImageSearchParser.ts
|
|
3
|
+
var ImageSearchParser = class {
|
|
4
|
+
parse(responseText) {
|
|
5
|
+
const parsedResults = JSON.parse(responseText).results;
|
|
6
|
+
const searchResults = [];
|
|
7
|
+
for (const result of parsedResults) searchResults.push(new ImageSearchResult(result.thumbnail, result.image));
|
|
8
|
+
return searchResults;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
//#endregion
|
|
12
|
+
export { ImageSearchParser as default };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/image/ImageSearchResult.ts
|
|
2
|
+
var ImageSearchResult = class {
|
|
3
|
+
thumbnailUrl;
|
|
4
|
+
imageUrl;
|
|
5
|
+
constructor(thumbnailUrl, imageUrl) {
|
|
6
|
+
this.thumbnailUrl = thumbnailUrl;
|
|
7
|
+
this.imageUrl = imageUrl;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
exports.default = ImageSearchResult;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/image/ImageSearchResult.ts
|
|
2
|
+
var ImageSearchResult = class {
|
|
3
|
+
thumbnailUrl;
|
|
4
|
+
imageUrl;
|
|
5
|
+
constructor(thumbnailUrl, imageUrl) {
|
|
6
|
+
this.thumbnailUrl = thumbnailUrl;
|
|
7
|
+
this.imageUrl = imageUrl;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
export { ImageSearchResult as default };
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_ImageSearchResult = require("./image/ImageSearchResult.cjs");
|
|
3
|
+
const require_DuckDuckGo = require("./DuckDuckGo.cjs");
|
|
4
|
+
exports.DuckDuckGo = require_DuckDuckGo.default;
|
|
5
|
+
exports.ImageSearchResult = require_ImageSearchResult.default;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ImageSearchResult } from "./image/ImageSearchResult.cjs";
|
|
2
|
+
import { DdgColor, DdgLayout, DdgLicense, DdgSearchOptions, DdgSize, DdgTime, DdgType } from "./image/ImageSearchClient.cjs";
|
|
3
|
+
import { DuckDuckGo } from "./DuckDuckGo.cjs";
|
|
4
|
+
export { type DdgColor, type DdgLayout, type DdgLicense, type DdgSearchOptions, type DdgSize, type DdgTime, type DdgType, DuckDuckGo, ImageSearchResult };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ImageSearchResult } from "./image/ImageSearchResult.mjs";
|
|
2
|
+
import { DdgColor, DdgLayout, DdgLicense, DdgSearchOptions, DdgSize, DdgTime, DdgType } from "./image/ImageSearchClient.mjs";
|
|
3
|
+
import { DuckDuckGo } from "./DuckDuckGo.mjs";
|
|
4
|
+
export { type DdgColor, type DdgLayout, type DdgLicense, type DdgSearchOptions, type DdgSize, type DdgTime, type DdgType, DuckDuckGo, ImageSearchResult };
|
package/dist/index.mjs
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "duck-poacher",
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "DuckDuckGo image search scraper for Node.js.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"types": "./dist/index.d.mts",
|
|
7
|
+
"main": "./dist/index.cjs",
|
|
8
|
+
"module": "./dist/index.mjs",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.mts",
|
|
13
|
+
"default": "./dist/index.mjs"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"./package.json": "./package.json"
|
|
21
|
+
},
|
|
22
|
+
"sideEffects": false,
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsdown",
|
|
28
|
+
"typecheck": "tsc --noEmit",
|
|
29
|
+
"check:exports": "attw --pack .",
|
|
30
|
+
"prepublishOnly": "npm test && npm run typecheck && npm run build && npm run check:exports",
|
|
31
|
+
"dev": "tsdown --watch",
|
|
32
|
+
"test": "tsx --test \"test/**/*.test.ts\"",
|
|
33
|
+
"test:coverage": "tsx --test --experimental-test-coverage \"test/**/*.test.ts\"",
|
|
34
|
+
"test:watch": "tsx --test --watch \"test/**/*.test.ts\"",
|
|
35
|
+
"lint": "eslint .",
|
|
36
|
+
"lint:fix": "eslint . --fix",
|
|
37
|
+
"format": "dprint fmt",
|
|
38
|
+
"format:check": "dprint check"
|
|
39
|
+
},
|
|
40
|
+
"keywords": [
|
|
41
|
+
"duckduckgo",
|
|
42
|
+
"image-search",
|
|
43
|
+
"images",
|
|
44
|
+
"search",
|
|
45
|
+
"scraper",
|
|
46
|
+
"scraping"
|
|
47
|
+
],
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "git+https://github.com/lars-dreier/duck-poacher.git"
|
|
51
|
+
},
|
|
52
|
+
"bugs": {
|
|
53
|
+
"url": "https://github.com/lars-dreier/duck-poacher/issues"
|
|
54
|
+
},
|
|
55
|
+
"homepage": "https://github.com/lars-dreier/duck-poacher#readme",
|
|
56
|
+
"author": {
|
|
57
|
+
"name": "Lars Dreier",
|
|
58
|
+
"email": "ldreier@posteo.de"
|
|
59
|
+
},
|
|
60
|
+
"license": "ISC",
|
|
61
|
+
"engines": {
|
|
62
|
+
"node": ">=18"
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@arethetypeswrong/cli": "0.18.3",
|
|
66
|
+
"@eslint/js": "10.0.1",
|
|
67
|
+
"@types/node": "25.9.3",
|
|
68
|
+
"dprint": "0.54.0",
|
|
69
|
+
"eslint": "10.5.0",
|
|
70
|
+
"eslint-config-prettier": "10.1.8",
|
|
71
|
+
"globals": "17.6.0",
|
|
72
|
+
"tsdown": "0.22.2",
|
|
73
|
+
"tsx": "4.22.4",
|
|
74
|
+
"typescript": "6.0.3",
|
|
75
|
+
"typescript-eslint": "8.61.0"
|
|
76
|
+
},
|
|
77
|
+
"dependencies": {
|
|
78
|
+
"node-http-toolkit": "1.0.1"
|
|
79
|
+
}
|
|
80
|
+
}
|