60 lines
1.6 KiB
TypeScript
Executable File
60 lines
1.6 KiB
TypeScript
Executable File
import { existsSync, createWriteStream, mkdirSync } from "fs";
|
|
import { dirname } from "path";
|
|
import axios from "axios";
|
|
import { Logger } from "@nestjs/common";
|
|
|
|
export class ImageUtils {
|
|
private static readonly logger = new Logger("ImageUtils");
|
|
|
|
/**
|
|
* Downloads an image from a URL and saves it to a local path.
|
|
* Skips download if file already exists.
|
|
*/
|
|
static async downloadImage(url: string, localPath: string): Promise<boolean> {
|
|
try {
|
|
// Check if file exists
|
|
if (existsSync(localPath)) {
|
|
return true;
|
|
}
|
|
|
|
// Ensure directory exists
|
|
const dir = dirname(localPath);
|
|
if (!existsSync(dir)) {
|
|
mkdirSync(dir, { recursive: true });
|
|
}
|
|
|
|
// Download
|
|
const response = await axios({
|
|
url,
|
|
method: "GET",
|
|
responseType: "stream",
|
|
timeout: 5000,
|
|
validateStatus: (status) => status === 200, // Only save if 200 OK
|
|
});
|
|
|
|
const writer = createWriteStream(localPath);
|
|
|
|
response.data.pipe(writer);
|
|
|
|
return new Promise((resolve, reject) => {
|
|
writer.on("finish", () => resolve(true));
|
|
writer.on("error", (err) => {
|
|
this.logger.warn(
|
|
`Failed to write image to ${localPath}: ${err.message}`,
|
|
);
|
|
reject(new Error(`Failed to write image to ${localPath}`));
|
|
});
|
|
});
|
|
} catch (error: any) {
|
|
// Log warning but don't break the application
|
|
// 404s are common for missing logos
|
|
if (error.response?.status !== 404) {
|
|
this.logger.warn(
|
|
`Failed to download image from ${url}: ${error.message}`,
|
|
);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
}
|