Skip to content

Commit 2a60f2c

Browse files
committed
imgdl now returns nothing (void)
1 parent ba8067f commit 2a60f2c

File tree

3 files changed

+139
-143
lines changed

3 files changed

+139
-143
lines changed

README.md

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,12 @@ imgdl https://example.com/image-{i}.jpg --increment --start=1 --end=10
124124
```js
125125
import imgdl from 'img-dl';
126126

127-
const image = await imgdl('https://example.com/image.jpg');
127+
const image = await new Promise((resolve, reject) => {
128+
imgdl('https://example.com/image.jpg', {
129+
onSuccess: resolve,
130+
onError: reject,
131+
});
132+
});
128133
console.log(image);
129134
/*
130135
{
@@ -144,16 +149,31 @@ console.log(image);
144149
```js
145150
import imgdl from 'img-dl';
146151

147-
const images = await imgdl([
152+
const urls = [
148153
'https://example.com/image.jpg',
149154
'https://example.com/image2.jpg',
150-
]);
155+
];
156+
157+
await imgdl(urls, {
158+
onSuccess: (image) => {
159+
// Do something with the downloaded image
160+
console.log(image);
161+
},
162+
onError: (error, url) => {
163+
// Do something when the image fails to download
164+
console.error(`Failed to download ${url}: ${error.message}`);
165+
},
166+
});
167+
168+
console.log('Download completed');
151169
```
152170

153171
## API
154172

155173
### imgdl(url, ?options)
156174

175+
Returns: `Promise<void>`
176+
157177
Download image(s) from the given URL(s).
158178

159179
#### `url`
@@ -215,14 +235,14 @@ Set the maximum number of times to retry the request if it fails.
215235
Type: `(image: Image) => void`<br>
216236
Default: `undefined`
217237

218-
The callback function to be called when the image is successfully downloaded. Only available when downloading multiple images.
238+
The callback function to be called when the image is successfully downloaded.
219239

220240
##### `onError`
221241

222242
Type: `(error: Error, url: string) => void`<br>
223243
Default: `undefined`
224244

225-
The callback function to be called when the image fails to download. Only available when downloading multiple images.
245+
The callback function to be called when the image fails to download.
226246

227247
##### `signal`
228248

src/index.ts

Lines changed: 53 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import PQueue from 'p-queue';
22
import { setMaxListeners } from 'node:events';
3-
import { CancelError } from 'got';
43
import { DEFAULT_INTERVAL, DEFAULT_STEP } from './constanta.js';
54
import {
65
DownloadOptions,
@@ -43,19 +42,13 @@ export type Image = {
4342

4443
export type Options = (ImageOptions & DownloadOptions) & {
4544
/**
46-
* Do something when the image is successfully downloaded.
47-
* For example, counting the number of successful downloads.
48-
*
49-
* Only called when downloading multiple images.
45+
* Do something when an image is successfully downloaded.
5046
*
5147
* @param image The downloaded image.
5248
*/
5349
onSuccess?: (image: Image) => void;
5450
/**
55-
* Do something when the image download failed.
56-
* For example, counting the number of failed downloads.
57-
*
58-
* Only called when downloading multiple images.
51+
* Do something when an image fails to download.
5952
*
6053
* @param error The error that caused the download to fail.
6154
* @param url The URL of the image that failed to download.
@@ -79,98 +72,65 @@ export type Options = (ImageOptions & DownloadOptions) & {
7972
signal?: AbortSignal;
8073
};
8174

82-
async function imgdl(url: string, options?: Options): Promise<Image>;
83-
async function imgdl(url: string[], options?: Options): Promise<Image[]>;
84-
async function imgdl(
85-
url: string | string[],
86-
options?: Options,
87-
): Promise<Image | Image[]>;
88-
async function imgdl(
89-
url: string | string[],
90-
options?: Options,
91-
): Promise<Image | Image[]> {
92-
if (Array.isArray(url)) {
93-
const queue = new PQueue({
94-
concurrency: options?.step ?? DEFAULT_STEP,
95-
interval: options?.interval ?? DEFAULT_INTERVAL,
96-
intervalCap: options?.step ?? DEFAULT_STEP,
97-
});
75+
async function imgdl(url: string | string[], options?: Options): Promise<void> {
76+
const {
77+
directory,
78+
name,
79+
extension,
80+
onSuccess,
81+
onError,
82+
step,
83+
interval,
84+
...downloadOptions
85+
} = options ?? {};
9886

99-
// Set max listeners to infinity to prevent memory leak warning
100-
if (options?.signal) {
101-
setMaxListeners(Infinity, options.signal);
102-
}
87+
const urls = Array.isArray(url) ? url : [url];
88+
const queue = new PQueue({
89+
concurrency: step ?? DEFAULT_STEP,
90+
interval: interval ?? DEFAULT_INTERVAL,
91+
intervalCap: step ?? DEFAULT_STEP,
92+
});
10393

104-
return new Promise<Image[]>((resolve, reject) => {
105-
const images: Image[] = [];
106-
const countNames = new Map<string, number>();
94+
// Set max listeners to infinity to prevent memory leak warning
95+
if (downloadOptions?.signal) {
96+
setMaxListeners(Infinity, downloadOptions.signal);
97+
}
10798

108-
url.forEach((_url) => {
109-
const img = parseImageParams(_url, options);
99+
const countNames = new Map<string, number>();
110100

111-
// Make sure the name is unique
112-
const nameKey = `${img.name}.${img.extension}`;
113-
const count = countNames.get(nameKey);
114-
if (count) {
115-
img.name = `${img.name} (${count})`;
116-
img.path = path.resolve(
117-
img.directory,
118-
`${img.name}.${img.extension}`,
119-
);
120-
}
121-
countNames.set(nameKey, (count || 0) + 1);
101+
for (const _url of urls) {
102+
const img = parseImageParams(_url, { directory, name, extension });
122103

123-
// Add the download task to queue
124-
queue
125-
.add(
126-
async ({ signal }) => {
127-
try {
128-
return await download(img, {
129-
...options,
130-
signal,
131-
});
132-
} catch (error) {
133-
options?.onError?.(
134-
error instanceof Error
135-
? error
136-
: new Error('Unknown error', { cause: error }),
137-
_url,
138-
);
139-
return undefined;
140-
}
141-
},
142-
{ signal: options?.signal },
143-
)
144-
.then((image) => {
145-
if (image) {
146-
options?.onSuccess?.(image);
147-
images.push(image);
148-
}
149-
})
150-
.catch((error) => {
151-
if (!(error instanceof CancelError)) {
152-
reject(error);
153-
}
154-
});
155-
});
104+
// Make sure the name is unique
105+
const nameKey = `${img.name}.${img.extension}`;
106+
const count = countNames.get(nameKey);
107+
if (count) {
108+
img.name = `${img.name} (${count})`;
109+
img.path = path.resolve(img.directory, `${img.name}.${img.extension}`);
110+
}
111+
countNames.set(nameKey, (count || 0) + 1);
112+
113+
// Add the download task to queue
114+
try {
115+
const image = await queue.add(
116+
({ signal }) => download(img, { ...downloadOptions, signal }),
117+
{ signal: downloadOptions?.signal },
118+
);
156119

157-
// Resolve/reject when all task is finished
158-
queue
159-
.onIdle()
160-
.then(() => {
161-
resolve(images);
162-
})
163-
.catch((error) => {
164-
reject(error);
165-
});
166-
});
120+
if (image) {
121+
onSuccess?.(image);
122+
}
123+
} catch (error) {
124+
onError?.(
125+
error instanceof Error
126+
? error
127+
: new Error('Unknown error', { cause: error }),
128+
_url,
129+
);
130+
}
167131
}
168132

169-
// TODO: implement `onSuccess` and `onError` for single download
170-
return download(parseImageParams(url, options), {
171-
...options,
172-
signal: options?.signal,
173-
});
133+
await queue.onIdle();
174134
}
175135

176136
export default imgdl;

0 commit comments

Comments
 (0)