@nghiavuive/random-image 1.0.2 → 1.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/README.md CHANGED
@@ -1,11 +1,11 @@
1
1
  # random-image
2
2
 
3
- A generic utility library to fetch random images from various providers like Unsplash and Pexels.
3
+ A generic utility library to fetch random images from various providers like Unsplash and Pexels, with built-in download capabilities.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
- npm install random-image
8
+ npm install @nghiavuive/random-image
9
9
  ```
10
10
 
11
11
  ## Usage
@@ -14,33 +14,91 @@ You need to obtain API keys from the respective providers:
14
14
  - [Unsplash Developers](https://unsplash.com/developers)
15
15
  - [Pexels API](https://www.pexels.com/api/)
16
16
 
17
+ ### Basic Usage - Fetching Random Images
18
+
17
19
  ```typescript
18
- import { RandomImage, UnsplashProvider, PexelsProvider } from 'random-image';
20
+ import { RandomImage, UnsplashProvider, PexelsProvider } from '@nghiavuive/random-image';
19
21
 
20
22
  // Using Unsplash
21
23
  const unsplash = new UnsplashProvider('YOUR_UNSPLASH_ACCESS_KEY');
22
24
  const fetcher = new RandomImage(unsplash);
23
25
 
24
- fetcher.getRandom({
26
+ const image = await fetcher.getRandom({
25
27
  width: 1920,
26
28
  height: 1080,
27
29
  query: 'nature'
28
- }).then(image => {
29
- console.log(image.url); // URL to the image
30
- console.log(image.author); // Photographer's name
31
30
  });
32
31
 
32
+ console.log(image.url); // URL to the image
33
+ console.log(image.author); // Photographer's name
34
+
33
35
  // Using Pexels
34
36
  const pexels = new PexelsProvider('YOUR_PEXELS_API_KEY');
35
37
  const pexelsFetcher = new RandomImage(pexels);
36
38
 
37
- pexelsFetcher.getRandom({
39
+ const pexelsImage = await pexelsFetcher.getRandom({
38
40
  width: 800,
39
41
  height: 600,
40
42
  query: 'cats'
41
- }).then(image => {
42
- console.log(image.url);
43
43
  });
44
+
45
+ console.log(pexelsImage.url);
46
+ ```
47
+
48
+ ### Downloading Images
49
+
50
+ The library now supports downloading images directly to your local filesystem:
51
+
52
+ ```typescript
53
+ import { RandomImage, UnsplashProvider } from '@nghiavuive/random-image';
54
+
55
+ const provider = new UnsplashProvider('YOUR_API_KEY');
56
+ const fetcher = new RandomImage(provider);
57
+
58
+ // Fetch and download a random image
59
+ const image = await fetcher.getRandom({ query: 'mountains' });
60
+
61
+ // Download with auto-generated filename
62
+ const filePath = await fetcher.download(image, './downloads');
63
+ console.log(`Image saved to: ${filePath}`);
64
+
65
+ // Download with custom filename
66
+ const customPath = await fetcher.download(
67
+ image,
68
+ './downloads',
69
+ { filename: 'my-mountain.jpg' }
70
+ );
71
+
72
+ // Download with overwrite option
73
+ const overwritePath = await fetcher.download(
74
+ image,
75
+ './downloads',
76
+ {
77
+ filename: 'mountain.jpg',
78
+ overwrite: true // Will replace existing file
79
+ }
80
+ );
81
+
82
+ // Download directly from URL
83
+ await fetcher.download(
84
+ 'https://example.com/image.jpg',
85
+ './downloads',
86
+ { filename: 'direct-download.jpg' }
87
+ );
88
+
89
+ // Download with UUID-based random filename
90
+ await fetcher.download(
91
+ image,
92
+ './downloads',
93
+ { keepOriginalName: false }
94
+ );
95
+
96
+ // Download keeping original filename (default behavior)
97
+ await fetcher.download(
98
+ image,
99
+ './downloads',
100
+ { keepOriginalName: true }
101
+ );
44
102
  ```
45
103
 
46
104
  ## API
@@ -51,24 +109,66 @@ The main class to interact with.
51
109
  ```typescript
52
110
  class RandomImage {
53
111
  constructor(provider: ImageProvider);
112
+
113
+ // Fetch a random image
54
114
  getRandom(options: ImageOptions): Promise<ImageResult>;
115
+
116
+ // Download an image to local filesystem
117
+ download(
118
+ imageUrl: string | ImageResult,
119
+ destinationPath: string,
120
+ options?: DownloadOptions
121
+ ): Promise<string>;
55
122
  }
56
123
  ```
57
124
 
58
125
  ### `ImageOptions`
59
- - `width` (number): Desired width of the image.
60
- - `height` (number): Desired height of the image.
61
- - `quality` (number): Quality (0-100) if supported.
62
- - `query` (string): Search query (e.g. "nature", "city").
126
+ Configuration for fetching random images:
127
+ - `width` (number, optional): Desired width of the image.
128
+ - `height` (number, optional): Desired height of the image.
129
+ - `quality` (number, optional): Quality (0-100) if supported by provider.
130
+ - `query` (string, optional): Search query (e.g. "nature", "city").
131
+ - `orientation` ("landscape" | "portrait", optional): Image orientation.
132
+
133
+ ### `DownloadOptions`
134
+ Configuration for downloading images:
135
+ - `filename` (string, optional): Custom filename for the downloaded image. If provided, this takes precedence over `keepOriginalName`.
136
+ - `overwrite` (boolean, optional): Whether to overwrite existing files. Default is `false`. If `false` and file exists, an error will be thrown.
137
+ - `keepOriginalName` (boolean, optional): Controls filename generation when `filename` is not provided:
138
+ - `true` or `undefined` (default): Extract and use the original filename from the URL
139
+ - `false`: Generate a random UUID-based filename
63
140
 
64
141
  ### `ImageResult`
142
+ Result object containing image information:
65
143
  - `url` (string): Direct URL to the image.
66
144
  - `width` (number): Width of the image.
67
145
  - `height` (number): Height of the image.
68
146
  - `author` (string): Name of the photographer.
69
- - `authorUrl` (string): URL to photographer's profile.
147
+ - `authorUrl` (string, optional): URL to photographer's profile.
70
148
  - `originalUrl` (string): URL to the original photo page.
71
149
 
150
+ ## Features
151
+
152
+ ### Download Functionality
153
+ - ✅ Automatic directory creation
154
+ - ✅ Flexible filename options:
155
+ - Custom filename
156
+ - Keep original filename from URL (default)
157
+ - Generate random UUID-based filename
158
+ - ✅ Overwrite protection
159
+ - ✅ Automatic file extension detection
160
+ - ✅ Support for both HTTP and HTTPS
161
+ - ✅ Automatic redirect handling (up to 5 redirects)
162
+ - ✅ Stream-based downloading for memory efficiency
163
+ - ✅ Error handling with cleanup of partial downloads
164
+
165
+ ## Supported Providers
166
+
167
+ - **Unsplash**: High-quality photos with attribution
168
+ - **Pexels**: Free stock photos and videos
169
+ - **Pixabay**: Free images and videos
170
+
72
171
  ## License
73
172
 
74
173
  ISC
174
+
package/dist/index.d.mts CHANGED
@@ -16,6 +16,11 @@ interface ImageResult {
16
16
  interface ImageProvider {
17
17
  fetchRandomImage(options: ImageOptions): Promise<ImageResult>;
18
18
  }
19
+ interface DownloadOptions {
20
+ filename?: string;
21
+ overwrite?: boolean;
22
+ keepOriginalName?: boolean;
23
+ }
19
24
 
20
25
  declare class UnsplashProvider implements ImageProvider {
21
26
  private accessKey;
@@ -44,6 +49,20 @@ declare class RandomImage {
44
49
  * @returns A promise that resolves to an ImageResult object.
45
50
  */
46
51
  getRandom(options?: ImageOptions): Promise<ImageResult>;
52
+ /**
53
+ * Downloads an image to a specified directory.
54
+ * @param imageUrl - The URL of the image to download (can be a string or ImageResult object)
55
+ * @param destinationPath - The directory path where the image will be saved
56
+ * @param options - Download options (filename, overwrite, etc.)
57
+ * @returns A promise that resolves to the full path of the downloaded file
58
+ */
59
+ download(imageUrl: string | ImageResult, destinationPath: string, options?: DownloadOptions): Promise<string>;
60
+ /**
61
+ * Helper method to extract file extension from URL
62
+ * @param url - The URL to extract extension from
63
+ * @returns The file extension (e.g., '.jpg', '.png') or null
64
+ */
65
+ private getExtensionFromUrl;
47
66
  }
48
67
 
49
- export { type ImageOptions, type ImageProvider, type ImageResult, PexelsProvider, PixabayProvider, RandomImage, UnsplashProvider };
68
+ export { type DownloadOptions, type ImageOptions, type ImageProvider, type ImageResult, PexelsProvider, PixabayProvider, RandomImage, UnsplashProvider };
package/dist/index.d.ts CHANGED
@@ -16,6 +16,11 @@ interface ImageResult {
16
16
  interface ImageProvider {
17
17
  fetchRandomImage(options: ImageOptions): Promise<ImageResult>;
18
18
  }
19
+ interface DownloadOptions {
20
+ filename?: string;
21
+ overwrite?: boolean;
22
+ keepOriginalName?: boolean;
23
+ }
19
24
 
20
25
  declare class UnsplashProvider implements ImageProvider {
21
26
  private accessKey;
@@ -44,6 +49,20 @@ declare class RandomImage {
44
49
  * @returns A promise that resolves to an ImageResult object.
45
50
  */
46
51
  getRandom(options?: ImageOptions): Promise<ImageResult>;
52
+ /**
53
+ * Downloads an image to a specified directory.
54
+ * @param imageUrl - The URL of the image to download (can be a string or ImageResult object)
55
+ * @param destinationPath - The directory path where the image will be saved
56
+ * @param options - Download options (filename, overwrite, etc.)
57
+ * @returns A promise that resolves to the full path of the downloaded file
58
+ */
59
+ download(imageUrl: string | ImageResult, destinationPath: string, options?: DownloadOptions): Promise<string>;
60
+ /**
61
+ * Helper method to extract file extension from URL
62
+ * @param url - The URL to extract extension from
63
+ * @returns The file extension (e.g., '.jpg', '.png') or null
64
+ */
65
+ private getExtensionFromUrl;
47
66
  }
48
67
 
49
- export { type ImageOptions, type ImageProvider, type ImageResult, PexelsProvider, PixabayProvider, RandomImage, UnsplashProvider };
68
+ export { type DownloadOptions, type ImageOptions, type ImageProvider, type ImageResult, PexelsProvider, PixabayProvider, RandomImage, UnsplashProvider };
package/dist/index.js CHANGED
@@ -156,6 +156,10 @@ var PixabayProvider = class {
156
156
  };
157
157
 
158
158
  // src/image-fetcher.ts
159
+ var fs = __toESM(require("fs"));
160
+ var path = __toESM(require("path"));
161
+ var import_axios4 = __toESM(require("axios"));
162
+ var import_uuid = require("uuid");
159
163
  var RandomImage = class {
160
164
  constructor(provider) {
161
165
  this.provider = provider;
@@ -168,6 +172,86 @@ var RandomImage = class {
168
172
  async getRandom(options = {}) {
169
173
  return this.provider.fetchRandomImage(options);
170
174
  }
175
+ /**
176
+ * Downloads an image to a specified directory.
177
+ * @param imageUrl - The URL of the image to download (can be a string or ImageResult object)
178
+ * @param destinationPath - The directory path where the image will be saved
179
+ * @param options - Download options (filename, overwrite, etc.)
180
+ * @returns A promise that resolves to the full path of the downloaded file
181
+ */
182
+ async download(imageUrl, destinationPath, options = {}) {
183
+ const url = typeof imageUrl === "string" ? imageUrl : imageUrl.url;
184
+ if (!fs.existsSync(destinationPath)) {
185
+ fs.mkdirSync(destinationPath, { recursive: true });
186
+ }
187
+ let finalFilename;
188
+ if (options.filename) {
189
+ finalFilename = options.filename;
190
+ } else if (options.keepOriginalName) {
191
+ const urlPath = new URL(url).pathname;
192
+ const urlFilename = path.basename(urlPath);
193
+ if (urlFilename && urlFilename.length > 0 && urlFilename !== "/") {
194
+ finalFilename = urlFilename;
195
+ } else {
196
+ const ext = this.getExtensionFromUrl(url) || ".jpg";
197
+ finalFilename = `${(0, import_uuid.v7)()}${ext}`;
198
+ }
199
+ } else {
200
+ const ext = this.getExtensionFromUrl(url) || ".jpg";
201
+ finalFilename = `${(0, import_uuid.v7)()}${ext}`;
202
+ }
203
+ if (!path.extname(finalFilename)) {
204
+ finalFilename += ".jpg";
205
+ }
206
+ const fullPath = path.join(destinationPath, finalFilename);
207
+ if (fs.existsSync(fullPath) && !options.overwrite) {
208
+ throw new Error(`File already exists: ${fullPath}. Set overwrite: true to replace it.`);
209
+ }
210
+ try {
211
+ const response = await import_axios4.default.get(url, {
212
+ responseType: "stream",
213
+ maxRedirects: 5
214
+ // Automatically handle redirects
215
+ });
216
+ const writer = fs.createWriteStream(fullPath);
217
+ response.data.pipe(writer);
218
+ return new Promise((resolve, reject) => {
219
+ writer.on("finish", () => {
220
+ resolve(fullPath);
221
+ });
222
+ writer.on("error", (err) => {
223
+ fs.unlink(fullPath, () => {
224
+ });
225
+ reject(err);
226
+ });
227
+ response.data.on("error", (err) => {
228
+ writer.close();
229
+ fs.unlink(fullPath, () => {
230
+ });
231
+ reject(err);
232
+ });
233
+ });
234
+ } catch (error) {
235
+ if (import_axios4.default.isAxiosError(error)) {
236
+ throw new Error(`Failed to download image: ${error.message}`);
237
+ }
238
+ throw error;
239
+ }
240
+ }
241
+ /**
242
+ * Helper method to extract file extension from URL
243
+ * @param url - The URL to extract extension from
244
+ * @returns The file extension (e.g., '.jpg', '.png') or null
245
+ */
246
+ getExtensionFromUrl(url) {
247
+ try {
248
+ const urlPath = new URL(url).pathname;
249
+ const ext = path.extname(urlPath);
250
+ return ext || null;
251
+ } catch {
252
+ return null;
253
+ }
254
+ }
171
255
  };
172
256
  // Annotate the CommonJS export names for ESM import in node:
173
257
  0 && (module.exports = {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/providers/unsplash.ts","../src/providers/pexels.ts","../src/providers/pixabay.ts","../src/image-fetcher.ts"],"sourcesContent":["export * from \"./types\";\nexport * from \"./providers/unsplash\";\nexport * from \"./providers/pexels\";\nexport * from \"./providers/pixabay\";\nexport * from \"./image-fetcher\";\n","import axios from \"axios\";\nimport { ImageProvider, ImageOptions, ImageResult } from \"../types\";\n\nexport class UnsplashProvider implements ImageProvider {\n private accessKey: string;\n\n constructor(accessKey: string) {\n this.accessKey = accessKey;\n }\n\n async fetchRandomImage(options: ImageOptions): Promise<ImageResult> {\n const response = await axios.get(\"https://api.unsplash.com/photos/random\", {\n headers: {\n Authorization: `Client-ID ${this.accessKey}`,\n },\n params: {\n query: options.query,\n orientation: options.orientation,\n },\n });\n\n const data = response.data;\n\n // Handle single random photo (array if count param used, but here generic assumes one)\n const photo = Array.isArray(data) ? data[0] : data;\n\n // Construct resized URL\n // Unsplash uses Imgix. We can append parameters.\n const baseUrl = photo.urls.raw;\n const sizeParams = new URLSearchParams();\n if (options.height || options.width) {\n sizeParams.append(\"fit\", \"crop\");\n sizeParams.append(\"crop\", \"entropy\");\n }\n if (options.width) sizeParams.append(\"w\", options.width.toString());\n if (options.height) sizeParams.append(\"h\", options.height.toString());\n if (options.quality) sizeParams.append(\"q\", options.quality.toString());\n\n const finalUrl = `${baseUrl}&${sizeParams.toString()}`;\n\n return {\n url: finalUrl,\n width: options.width || photo.width,\n height: options.height || photo.height,\n author: photo.user.name,\n authorUrl: photo.user.links.html,\n originalUrl: photo.links.html, // Link to photo page\n };\n }\n}\n","import axios from \"axios\";\nimport { ImageProvider, ImageOptions, ImageResult } from \"../types\";\n\nexport class PexelsProvider implements ImageProvider {\n private apiKey: string;\n\n constructor(apiKey: string) {\n this.apiKey = apiKey;\n }\n\n async fetchRandomImage(options: ImageOptions): Promise<ImageResult> {\n const endpoint = options.query\n ? \"https://api.pexels.com/v1/search\"\n : \"https://api.pexels.com/v1/curated\";\n\n // Randomizing page number (1-100) to get a \"random\" image\n const randomPage = Math.floor(Math.random() * 100) + 1;\n\n const params: any = {\n per_page: 1,\n page: randomPage,\n };\n if (options.query) params.query = options.query;\n\n const response = await axios.get(endpoint, {\n headers: {\n Authorization: this.apiKey,\n },\n params: params,\n });\n\n const data = response.data;\n\n if (!data.photos || data.photos.length === 0) {\n throw new Error(\"No images found on Pexels\");\n }\n\n const photo = data.photos[0];\n\n const baseUrl = photo.src.original;\n const sizeParams = new URLSearchParams();\n sizeParams.append(\"auto\", \"compress\");\n sizeParams.append(\"cs\", \"tinysrgb\"); // Default pexels param\n if (options.width) sizeParams.append(\"w\", options.width.toString());\n if (options.height) sizeParams.append(\"h\", options.height.toString());\n\n const finalUrl = `${baseUrl}?${sizeParams.toString()}`;\n\n return {\n url: finalUrl,\n width: options.width || photo.width,\n height: options.height || photo.height,\n author: photo.photographer,\n authorUrl: photo.photographer_url,\n originalUrl: photo.url,\n };\n }\n}\n","import axios from \"axios\";\nimport { ImageProvider, ImageOptions, ImageResult } from \"../types\";\n\nexport class PixabayProvider implements ImageProvider {\n private apiKey: string;\n\n constructor(apiKey: string) {\n this.apiKey = apiKey;\n }\n\n async fetchRandomImage(options: ImageOptions): Promise<ImageResult> {\n const params: any = {\n key: this.apiKey,\n q: options.query || \"\",\n per_page: 20, // Fetch a few to pick randomly\n };\n\n if (options.orientation) {\n params.orientation =\n options.orientation === \"portrait\" ? \"vertical\" : \"horizontal\";\n }\n\n const response = await axios.get(\"https://pixabay.com/api/\", {\n params,\n });\n\n const hits = response.data.hits;\n\n if (!hits || hits.length === 0) {\n throw new Error(\"No images found\");\n }\n\n // Pick a random hit\n const randomHit = hits[Math.floor(Math.random() * hits.length)];\n\n return {\n url: randomHit.largeImageURL || randomHit.webformatURL,\n width: randomHit.imageWidth || randomHit.webformatWidth,\n height: randomHit.imageHeight || randomHit.webformatHeight,\n author: randomHit.user,\n authorUrl: `https://pixabay.com/users/${randomHit.user}-${randomHit.user_id}/`,\n originalUrl: randomHit.pageURL,\n };\n }\n}\n","import { ImageProvider, ImageOptions, ImageResult } from './types';\n\nexport class RandomImage {\n private provider: ImageProvider;\n\n constructor(provider: ImageProvider) {\n this.provider = provider;\n }\n\n /**\n * Fetches a random image based on the provided options.\n * @param options - Configuration options for the image (width, height, query, etc.)\n * @returns A promise that resolves to an ImageResult object.\n */\n async getRandom(options: ImageOptions = {}): Promise<ImageResult> {\n return this.provider.fetchRandomImage(options);\n }\n}\n"],"mappings":"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","names":["axios","import_axios","axios","import_axios","axios"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/providers/unsplash.ts","../src/providers/pexels.ts","../src/providers/pixabay.ts","../src/image-fetcher.ts"],"sourcesContent":["export * from \"./types\";\nexport * from \"./providers/unsplash\";\nexport * from \"./providers/pexels\";\nexport * from \"./providers/pixabay\";\nexport * from \"./image-fetcher\";\n","import axios from \"axios\";\nimport { ImageProvider, ImageOptions, ImageResult } from \"../types\";\n\nexport class UnsplashProvider implements ImageProvider {\n private accessKey: string;\n\n constructor(accessKey: string) {\n this.accessKey = accessKey;\n }\n\n async fetchRandomImage(options: ImageOptions): Promise<ImageResult> {\n const response = await axios.get(\"https://api.unsplash.com/photos/random\", {\n headers: {\n Authorization: `Client-ID ${this.accessKey}`,\n },\n params: {\n query: options.query,\n orientation: options.orientation,\n },\n });\n\n const data = response.data;\n\n // Handle single random photo (array if count param used, but here generic assumes one)\n const photo = Array.isArray(data) ? data[0] : data;\n\n // Construct resized URL\n // Unsplash uses Imgix. We can append parameters.\n const baseUrl = photo.urls.raw;\n const sizeParams = new URLSearchParams();\n if (options.height || options.width) {\n sizeParams.append(\"fit\", \"crop\");\n sizeParams.append(\"crop\", \"entropy\");\n }\n if (options.width) sizeParams.append(\"w\", options.width.toString());\n if (options.height) sizeParams.append(\"h\", options.height.toString());\n if (options.quality) sizeParams.append(\"q\", options.quality.toString());\n\n const finalUrl = `${baseUrl}&${sizeParams.toString()}`;\n\n return {\n url: finalUrl,\n width: options.width || photo.width,\n height: options.height || photo.height,\n author: photo.user.name,\n authorUrl: photo.user.links.html,\n originalUrl: photo.links.html, // Link to photo page\n };\n }\n}\n","import axios from \"axios\";\nimport { ImageProvider, ImageOptions, ImageResult } from \"../types\";\n\nexport class PexelsProvider implements ImageProvider {\n private apiKey: string;\n\n constructor(apiKey: string) {\n this.apiKey = apiKey;\n }\n\n async fetchRandomImage(options: ImageOptions): Promise<ImageResult> {\n const endpoint = options.query\n ? \"https://api.pexels.com/v1/search\"\n : \"https://api.pexels.com/v1/curated\";\n\n // Randomizing page number (1-100) to get a \"random\" image\n const randomPage = Math.floor(Math.random() * 100) + 1;\n\n const params: any = {\n per_page: 1,\n page: randomPage,\n };\n if (options.query) params.query = options.query;\n\n const response = await axios.get(endpoint, {\n headers: {\n Authorization: this.apiKey,\n },\n params: params,\n });\n\n const data = response.data;\n\n if (!data.photos || data.photos.length === 0) {\n throw new Error(\"No images found on Pexels\");\n }\n\n const photo = data.photos[0];\n\n const baseUrl = photo.src.original;\n const sizeParams = new URLSearchParams();\n sizeParams.append(\"auto\", \"compress\");\n sizeParams.append(\"cs\", \"tinysrgb\"); // Default pexels param\n if (options.width) sizeParams.append(\"w\", options.width.toString());\n if (options.height) sizeParams.append(\"h\", options.height.toString());\n\n const finalUrl = `${baseUrl}?${sizeParams.toString()}`;\n\n return {\n url: finalUrl,\n width: options.width || photo.width,\n height: options.height || photo.height,\n author: photo.photographer,\n authorUrl: photo.photographer_url,\n originalUrl: photo.url,\n };\n }\n}\n","import axios from \"axios\";\nimport { ImageProvider, ImageOptions, ImageResult } from \"../types\";\n\nexport class PixabayProvider implements ImageProvider {\n private apiKey: string;\n\n constructor(apiKey: string) {\n this.apiKey = apiKey;\n }\n\n async fetchRandomImage(options: ImageOptions): Promise<ImageResult> {\n const params: any = {\n key: this.apiKey,\n q: options.query || \"\",\n per_page: 20, // Fetch a few to pick randomly\n };\n\n if (options.orientation) {\n params.orientation =\n options.orientation === \"portrait\" ? \"vertical\" : \"horizontal\";\n }\n\n const response = await axios.get(\"https://pixabay.com/api/\", {\n params,\n });\n\n const hits = response.data.hits;\n\n if (!hits || hits.length === 0) {\n throw new Error(\"No images found\");\n }\n\n // Pick a random hit\n const randomHit = hits[Math.floor(Math.random() * hits.length)];\n\n return {\n url: randomHit.largeImageURL || randomHit.webformatURL,\n width: randomHit.imageWidth || randomHit.webformatWidth,\n height: randomHit.imageHeight || randomHit.webformatHeight,\n author: randomHit.user,\n authorUrl: `https://pixabay.com/users/${randomHit.user}-${randomHit.user_id}/`,\n originalUrl: randomHit.pageURL,\n };\n }\n}\n","import { ImageProvider, ImageOptions, ImageResult, DownloadOptions } from './types';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport axios from 'axios';\nimport { v7 as uuidv4 } from 'uuid';\n\nexport class RandomImage {\n private provider: ImageProvider;\n\n constructor(provider: ImageProvider) {\n this.provider = provider;\n }\n\n /**\n * Fetches a random image based on the provided options.\n * @param options - Configuration options for the image (width, height, query, etc.)\n * @returns A promise that resolves to an ImageResult object.\n */\n async getRandom(options: ImageOptions = {}): Promise<ImageResult> {\n return this.provider.fetchRandomImage(options);\n }\n\n /**\n * Downloads an image to a specified directory.\n * @param imageUrl - The URL of the image to download (can be a string or ImageResult object)\n * @param destinationPath - The directory path where the image will be saved\n * @param options - Download options (filename, overwrite, etc.)\n * @returns A promise that resolves to the full path of the downloaded file\n */\n async download(\n imageUrl: string | ImageResult,\n destinationPath: string,\n options: DownloadOptions = {}\n ): Promise<string> {\n const url = typeof imageUrl === 'string' ? imageUrl : imageUrl.url;\n\n // Create directory if it doesn't exist\n if (!fs.existsSync(destinationPath)) {\n fs.mkdirSync(destinationPath, { recursive: true });\n }\n\n // Determine filename\n let finalFilename: string;\n if (options.filename) {\n finalFilename = options.filename;\n } else if (options.keepOriginalName) {\n // keepOriginalName === true or undefined (default behavior: try to keep original)\n const urlPath = new URL(url).pathname;\n const urlFilename = path.basename(urlPath);\n if (urlFilename && urlFilename.length > 0 && urlFilename !== '/') {\n finalFilename = urlFilename;\n } else {\n // Fallback if no filename in URL\n const ext = this.getExtensionFromUrl(url) || '.jpg';\n finalFilename = `${uuidv4()}${ext}`;\n }\n } else {\n // Generate UUID v4 filename\n const ext = this.getExtensionFromUrl(url) || '.jpg';\n finalFilename = `${uuidv4()}${ext}`;\n }\n\n // Ensure filename has an extension\n if (!path.extname(finalFilename)) {\n finalFilename += '.jpg';\n }\n\n const fullPath = path.join(destinationPath, finalFilename);\n\n // Check if file exists and overwrite option\n if (fs.existsSync(fullPath) && !options.overwrite) {\n throw new Error(`File already exists: ${fullPath}. Set overwrite: true to replace it.`);\n }\n\n try {\n const response = await axios.get(url, {\n responseType: 'stream',\n maxRedirects: 5, // Automatically handle redirects\n });\n\n const writer = fs.createWriteStream(fullPath);\n\n response.data.pipe(writer);\n\n return new Promise((resolve, reject) => {\n writer.on('finish', () => {\n resolve(fullPath);\n });\n\n writer.on('error', (err) => {\n fs.unlink(fullPath, () => { }); // Delete partial file\n reject(err);\n });\n\n response.data.on('error', (err: Error) => {\n writer.close();\n fs.unlink(fullPath, () => { }); // Delete partial file\n reject(err);\n });\n });\n } catch (error) {\n if (axios.isAxiosError(error)) {\n throw new Error(`Failed to download image: ${error.message}`);\n }\n throw error;\n }\n }\n\n /**\n * Helper method to extract file extension from URL\n * @param url - The URL to extract extension from\n * @returns The file extension (e.g., '.jpg', '.png') or null\n */\n private getExtensionFromUrl(url: string): string | null {\n try {\n const urlPath = new URL(url).pathname;\n const ext = path.extname(urlPath);\n return ext || null;\n } catch {\n return null;\n }\n }\n}\n"],"mappings":"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","names":["axios","import_axios","axios","import_axios","axios","import_axios","uuidv4","axios"]}
package/dist/index.mjs CHANGED
@@ -117,6 +117,10 @@ var PixabayProvider = class {
117
117
  };
118
118
 
119
119
  // src/image-fetcher.ts
120
+ import * as fs from "fs";
121
+ import * as path from "path";
122
+ import axios4 from "axios";
123
+ import { v7 as uuidv4 } from "uuid";
120
124
  var RandomImage = class {
121
125
  constructor(provider) {
122
126
  this.provider = provider;
@@ -129,6 +133,86 @@ var RandomImage = class {
129
133
  async getRandom(options = {}) {
130
134
  return this.provider.fetchRandomImage(options);
131
135
  }
136
+ /**
137
+ * Downloads an image to a specified directory.
138
+ * @param imageUrl - The URL of the image to download (can be a string or ImageResult object)
139
+ * @param destinationPath - The directory path where the image will be saved
140
+ * @param options - Download options (filename, overwrite, etc.)
141
+ * @returns A promise that resolves to the full path of the downloaded file
142
+ */
143
+ async download(imageUrl, destinationPath, options = {}) {
144
+ const url = typeof imageUrl === "string" ? imageUrl : imageUrl.url;
145
+ if (!fs.existsSync(destinationPath)) {
146
+ fs.mkdirSync(destinationPath, { recursive: true });
147
+ }
148
+ let finalFilename;
149
+ if (options.filename) {
150
+ finalFilename = options.filename;
151
+ } else if (options.keepOriginalName) {
152
+ const urlPath = new URL(url).pathname;
153
+ const urlFilename = path.basename(urlPath);
154
+ if (urlFilename && urlFilename.length > 0 && urlFilename !== "/") {
155
+ finalFilename = urlFilename;
156
+ } else {
157
+ const ext = this.getExtensionFromUrl(url) || ".jpg";
158
+ finalFilename = `${uuidv4()}${ext}`;
159
+ }
160
+ } else {
161
+ const ext = this.getExtensionFromUrl(url) || ".jpg";
162
+ finalFilename = `${uuidv4()}${ext}`;
163
+ }
164
+ if (!path.extname(finalFilename)) {
165
+ finalFilename += ".jpg";
166
+ }
167
+ const fullPath = path.join(destinationPath, finalFilename);
168
+ if (fs.existsSync(fullPath) && !options.overwrite) {
169
+ throw new Error(`File already exists: ${fullPath}. Set overwrite: true to replace it.`);
170
+ }
171
+ try {
172
+ const response = await axios4.get(url, {
173
+ responseType: "stream",
174
+ maxRedirects: 5
175
+ // Automatically handle redirects
176
+ });
177
+ const writer = fs.createWriteStream(fullPath);
178
+ response.data.pipe(writer);
179
+ return new Promise((resolve, reject) => {
180
+ writer.on("finish", () => {
181
+ resolve(fullPath);
182
+ });
183
+ writer.on("error", (err) => {
184
+ fs.unlink(fullPath, () => {
185
+ });
186
+ reject(err);
187
+ });
188
+ response.data.on("error", (err) => {
189
+ writer.close();
190
+ fs.unlink(fullPath, () => {
191
+ });
192
+ reject(err);
193
+ });
194
+ });
195
+ } catch (error) {
196
+ if (axios4.isAxiosError(error)) {
197
+ throw new Error(`Failed to download image: ${error.message}`);
198
+ }
199
+ throw error;
200
+ }
201
+ }
202
+ /**
203
+ * Helper method to extract file extension from URL
204
+ * @param url - The URL to extract extension from
205
+ * @returns The file extension (e.g., '.jpg', '.png') or null
206
+ */
207
+ getExtensionFromUrl(url) {
208
+ try {
209
+ const urlPath = new URL(url).pathname;
210
+ const ext = path.extname(urlPath);
211
+ return ext || null;
212
+ } catch {
213
+ return null;
214
+ }
215
+ }
132
216
  };
133
217
  export {
134
218
  PexelsProvider,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/providers/unsplash.ts","../src/providers/pexels.ts","../src/providers/pixabay.ts","../src/image-fetcher.ts"],"sourcesContent":["import axios from \"axios\";\nimport { ImageProvider, ImageOptions, ImageResult } from \"../types\";\n\nexport class UnsplashProvider implements ImageProvider {\n private accessKey: string;\n\n constructor(accessKey: string) {\n this.accessKey = accessKey;\n }\n\n async fetchRandomImage(options: ImageOptions): Promise<ImageResult> {\n const response = await axios.get(\"https://api.unsplash.com/photos/random\", {\n headers: {\n Authorization: `Client-ID ${this.accessKey}`,\n },\n params: {\n query: options.query,\n orientation: options.orientation,\n },\n });\n\n const data = response.data;\n\n // Handle single random photo (array if count param used, but here generic assumes one)\n const photo = Array.isArray(data) ? data[0] : data;\n\n // Construct resized URL\n // Unsplash uses Imgix. We can append parameters.\n const baseUrl = photo.urls.raw;\n const sizeParams = new URLSearchParams();\n if (options.height || options.width) {\n sizeParams.append(\"fit\", \"crop\");\n sizeParams.append(\"crop\", \"entropy\");\n }\n if (options.width) sizeParams.append(\"w\", options.width.toString());\n if (options.height) sizeParams.append(\"h\", options.height.toString());\n if (options.quality) sizeParams.append(\"q\", options.quality.toString());\n\n const finalUrl = `${baseUrl}&${sizeParams.toString()}`;\n\n return {\n url: finalUrl,\n width: options.width || photo.width,\n height: options.height || photo.height,\n author: photo.user.name,\n authorUrl: photo.user.links.html,\n originalUrl: photo.links.html, // Link to photo page\n };\n }\n}\n","import axios from \"axios\";\nimport { ImageProvider, ImageOptions, ImageResult } from \"../types\";\n\nexport class PexelsProvider implements ImageProvider {\n private apiKey: string;\n\n constructor(apiKey: string) {\n this.apiKey = apiKey;\n }\n\n async fetchRandomImage(options: ImageOptions): Promise<ImageResult> {\n const endpoint = options.query\n ? \"https://api.pexels.com/v1/search\"\n : \"https://api.pexels.com/v1/curated\";\n\n // Randomizing page number (1-100) to get a \"random\" image\n const randomPage = Math.floor(Math.random() * 100) + 1;\n\n const params: any = {\n per_page: 1,\n page: randomPage,\n };\n if (options.query) params.query = options.query;\n\n const response = await axios.get(endpoint, {\n headers: {\n Authorization: this.apiKey,\n },\n params: params,\n });\n\n const data = response.data;\n\n if (!data.photos || data.photos.length === 0) {\n throw new Error(\"No images found on Pexels\");\n }\n\n const photo = data.photos[0];\n\n const baseUrl = photo.src.original;\n const sizeParams = new URLSearchParams();\n sizeParams.append(\"auto\", \"compress\");\n sizeParams.append(\"cs\", \"tinysrgb\"); // Default pexels param\n if (options.width) sizeParams.append(\"w\", options.width.toString());\n if (options.height) sizeParams.append(\"h\", options.height.toString());\n\n const finalUrl = `${baseUrl}?${sizeParams.toString()}`;\n\n return {\n url: finalUrl,\n width: options.width || photo.width,\n height: options.height || photo.height,\n author: photo.photographer,\n authorUrl: photo.photographer_url,\n originalUrl: photo.url,\n };\n }\n}\n","import axios from \"axios\";\nimport { ImageProvider, ImageOptions, ImageResult } from \"../types\";\n\nexport class PixabayProvider implements ImageProvider {\n private apiKey: string;\n\n constructor(apiKey: string) {\n this.apiKey = apiKey;\n }\n\n async fetchRandomImage(options: ImageOptions): Promise<ImageResult> {\n const params: any = {\n key: this.apiKey,\n q: options.query || \"\",\n per_page: 20, // Fetch a few to pick randomly\n };\n\n if (options.orientation) {\n params.orientation =\n options.orientation === \"portrait\" ? \"vertical\" : \"horizontal\";\n }\n\n const response = await axios.get(\"https://pixabay.com/api/\", {\n params,\n });\n\n const hits = response.data.hits;\n\n if (!hits || hits.length === 0) {\n throw new Error(\"No images found\");\n }\n\n // Pick a random hit\n const randomHit = hits[Math.floor(Math.random() * hits.length)];\n\n return {\n url: randomHit.largeImageURL || randomHit.webformatURL,\n width: randomHit.imageWidth || randomHit.webformatWidth,\n height: randomHit.imageHeight || randomHit.webformatHeight,\n author: randomHit.user,\n authorUrl: `https://pixabay.com/users/${randomHit.user}-${randomHit.user_id}/`,\n originalUrl: randomHit.pageURL,\n };\n }\n}\n","import { ImageProvider, ImageOptions, ImageResult } from './types';\n\nexport class RandomImage {\n private provider: ImageProvider;\n\n constructor(provider: ImageProvider) {\n this.provider = provider;\n }\n\n /**\n * Fetches a random image based on the provided options.\n * @param options - Configuration options for the image (width, height, query, etc.)\n * @returns A promise that resolves to an ImageResult object.\n */\n async getRandom(options: ImageOptions = {}): Promise<ImageResult> {\n return this.provider.fetchRandomImage(options);\n }\n}\n"],"mappings":"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","names":["axios","axios"]}
1
+ {"version":3,"sources":["../src/providers/unsplash.ts","../src/providers/pexels.ts","../src/providers/pixabay.ts","../src/image-fetcher.ts"],"sourcesContent":["import axios from \"axios\";\nimport { ImageProvider, ImageOptions, ImageResult } from \"../types\";\n\nexport class UnsplashProvider implements ImageProvider {\n private accessKey: string;\n\n constructor(accessKey: string) {\n this.accessKey = accessKey;\n }\n\n async fetchRandomImage(options: ImageOptions): Promise<ImageResult> {\n const response = await axios.get(\"https://api.unsplash.com/photos/random\", {\n headers: {\n Authorization: `Client-ID ${this.accessKey}`,\n },\n params: {\n query: options.query,\n orientation: options.orientation,\n },\n });\n\n const data = response.data;\n\n // Handle single random photo (array if count param used, but here generic assumes one)\n const photo = Array.isArray(data) ? data[0] : data;\n\n // Construct resized URL\n // Unsplash uses Imgix. We can append parameters.\n const baseUrl = photo.urls.raw;\n const sizeParams = new URLSearchParams();\n if (options.height || options.width) {\n sizeParams.append(\"fit\", \"crop\");\n sizeParams.append(\"crop\", \"entropy\");\n }\n if (options.width) sizeParams.append(\"w\", options.width.toString());\n if (options.height) sizeParams.append(\"h\", options.height.toString());\n if (options.quality) sizeParams.append(\"q\", options.quality.toString());\n\n const finalUrl = `${baseUrl}&${sizeParams.toString()}`;\n\n return {\n url: finalUrl,\n width: options.width || photo.width,\n height: options.height || photo.height,\n author: photo.user.name,\n authorUrl: photo.user.links.html,\n originalUrl: photo.links.html, // Link to photo page\n };\n }\n}\n","import axios from \"axios\";\nimport { ImageProvider, ImageOptions, ImageResult } from \"../types\";\n\nexport class PexelsProvider implements ImageProvider {\n private apiKey: string;\n\n constructor(apiKey: string) {\n this.apiKey = apiKey;\n }\n\n async fetchRandomImage(options: ImageOptions): Promise<ImageResult> {\n const endpoint = options.query\n ? \"https://api.pexels.com/v1/search\"\n : \"https://api.pexels.com/v1/curated\";\n\n // Randomizing page number (1-100) to get a \"random\" image\n const randomPage = Math.floor(Math.random() * 100) + 1;\n\n const params: any = {\n per_page: 1,\n page: randomPage,\n };\n if (options.query) params.query = options.query;\n\n const response = await axios.get(endpoint, {\n headers: {\n Authorization: this.apiKey,\n },\n params: params,\n });\n\n const data = response.data;\n\n if (!data.photos || data.photos.length === 0) {\n throw new Error(\"No images found on Pexels\");\n }\n\n const photo = data.photos[0];\n\n const baseUrl = photo.src.original;\n const sizeParams = new URLSearchParams();\n sizeParams.append(\"auto\", \"compress\");\n sizeParams.append(\"cs\", \"tinysrgb\"); // Default pexels param\n if (options.width) sizeParams.append(\"w\", options.width.toString());\n if (options.height) sizeParams.append(\"h\", options.height.toString());\n\n const finalUrl = `${baseUrl}?${sizeParams.toString()}`;\n\n return {\n url: finalUrl,\n width: options.width || photo.width,\n height: options.height || photo.height,\n author: photo.photographer,\n authorUrl: photo.photographer_url,\n originalUrl: photo.url,\n };\n }\n}\n","import axios from \"axios\";\nimport { ImageProvider, ImageOptions, ImageResult } from \"../types\";\n\nexport class PixabayProvider implements ImageProvider {\n private apiKey: string;\n\n constructor(apiKey: string) {\n this.apiKey = apiKey;\n }\n\n async fetchRandomImage(options: ImageOptions): Promise<ImageResult> {\n const params: any = {\n key: this.apiKey,\n q: options.query || \"\",\n per_page: 20, // Fetch a few to pick randomly\n };\n\n if (options.orientation) {\n params.orientation =\n options.orientation === \"portrait\" ? \"vertical\" : \"horizontal\";\n }\n\n const response = await axios.get(\"https://pixabay.com/api/\", {\n params,\n });\n\n const hits = response.data.hits;\n\n if (!hits || hits.length === 0) {\n throw new Error(\"No images found\");\n }\n\n // Pick a random hit\n const randomHit = hits[Math.floor(Math.random() * hits.length)];\n\n return {\n url: randomHit.largeImageURL || randomHit.webformatURL,\n width: randomHit.imageWidth || randomHit.webformatWidth,\n height: randomHit.imageHeight || randomHit.webformatHeight,\n author: randomHit.user,\n authorUrl: `https://pixabay.com/users/${randomHit.user}-${randomHit.user_id}/`,\n originalUrl: randomHit.pageURL,\n };\n }\n}\n","import { ImageProvider, ImageOptions, ImageResult, DownloadOptions } from './types';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport axios from 'axios';\nimport { v7 as uuidv4 } from 'uuid';\n\nexport class RandomImage {\n private provider: ImageProvider;\n\n constructor(provider: ImageProvider) {\n this.provider = provider;\n }\n\n /**\n * Fetches a random image based on the provided options.\n * @param options - Configuration options for the image (width, height, query, etc.)\n * @returns A promise that resolves to an ImageResult object.\n */\n async getRandom(options: ImageOptions = {}): Promise<ImageResult> {\n return this.provider.fetchRandomImage(options);\n }\n\n /**\n * Downloads an image to a specified directory.\n * @param imageUrl - The URL of the image to download (can be a string or ImageResult object)\n * @param destinationPath - The directory path where the image will be saved\n * @param options - Download options (filename, overwrite, etc.)\n * @returns A promise that resolves to the full path of the downloaded file\n */\n async download(\n imageUrl: string | ImageResult,\n destinationPath: string,\n options: DownloadOptions = {}\n ): Promise<string> {\n const url = typeof imageUrl === 'string' ? imageUrl : imageUrl.url;\n\n // Create directory if it doesn't exist\n if (!fs.existsSync(destinationPath)) {\n fs.mkdirSync(destinationPath, { recursive: true });\n }\n\n // Determine filename\n let finalFilename: string;\n if (options.filename) {\n finalFilename = options.filename;\n } else if (options.keepOriginalName) {\n // keepOriginalName === true or undefined (default behavior: try to keep original)\n const urlPath = new URL(url).pathname;\n const urlFilename = path.basename(urlPath);\n if (urlFilename && urlFilename.length > 0 && urlFilename !== '/') {\n finalFilename = urlFilename;\n } else {\n // Fallback if no filename in URL\n const ext = this.getExtensionFromUrl(url) || '.jpg';\n finalFilename = `${uuidv4()}${ext}`;\n }\n } else {\n // Generate UUID v4 filename\n const ext = this.getExtensionFromUrl(url) || '.jpg';\n finalFilename = `${uuidv4()}${ext}`;\n }\n\n // Ensure filename has an extension\n if (!path.extname(finalFilename)) {\n finalFilename += '.jpg';\n }\n\n const fullPath = path.join(destinationPath, finalFilename);\n\n // Check if file exists and overwrite option\n if (fs.existsSync(fullPath) && !options.overwrite) {\n throw new Error(`File already exists: ${fullPath}. Set overwrite: true to replace it.`);\n }\n\n try {\n const response = await axios.get(url, {\n responseType: 'stream',\n maxRedirects: 5, // Automatically handle redirects\n });\n\n const writer = fs.createWriteStream(fullPath);\n\n response.data.pipe(writer);\n\n return new Promise((resolve, reject) => {\n writer.on('finish', () => {\n resolve(fullPath);\n });\n\n writer.on('error', (err) => {\n fs.unlink(fullPath, () => { }); // Delete partial file\n reject(err);\n });\n\n response.data.on('error', (err: Error) => {\n writer.close();\n fs.unlink(fullPath, () => { }); // Delete partial file\n reject(err);\n });\n });\n } catch (error) {\n if (axios.isAxiosError(error)) {\n throw new Error(`Failed to download image: ${error.message}`);\n }\n throw error;\n }\n }\n\n /**\n * Helper method to extract file extension from URL\n * @param url - The URL to extract extension from\n * @returns The file extension (e.g., '.jpg', '.png') or null\n */\n private getExtensionFromUrl(url: string): string | null {\n try {\n const urlPath = new URL(url).pathname;\n const ext = path.extname(urlPath);\n return ext || null;\n } catch {\n return null;\n }\n }\n}\n"],"mappings":"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","names":["axios","axios","axios"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nghiavuive/random-image",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -31,12 +31,14 @@
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/node": "^25.2.0",
34
+ "@types/uuid": "^10.0.0",
34
35
  "dotenv": "^17.2.3",
35
36
  "tsup": "^8.5.1",
36
37
  "typescript": "^5.9.3",
37
38
  "vitest": "^4.0.18"
38
39
  },
39
40
  "dependencies": {
40
- "axios": "^1.13.4"
41
+ "axios": "^1.13.4",
42
+ "uuid": "^13.0.0"
41
43
  }
42
44
  }