118 lines
2.9 KiB
TypeScript
118 lines
2.9 KiB
TypeScript
import * as fs from "fs";
|
|
import * as path from "path";
|
|
import * as https from "https";
|
|
import "dotenv/config";
|
|
import FormData from "form-data";
|
|
|
|
const API_URL = "https://api.banatie.app/api/v1/images/upload";
|
|
|
|
interface UploadResponse {
|
|
success: boolean;
|
|
data: {
|
|
id: string;
|
|
storageUrl: string;
|
|
alias?: string;
|
|
source: string;
|
|
width: number | null;
|
|
height: number | null;
|
|
mimeType: string;
|
|
fileSize: number;
|
|
};
|
|
}
|
|
|
|
function getMimeType(filePath: string): string {
|
|
const ext = path.extname(filePath).toLowerCase();
|
|
const mimeTypes: Record<string, string> = {
|
|
".jpg": "image/jpeg",
|
|
".jpeg": "image/jpeg",
|
|
".png": "image/png",
|
|
".webp": "image/webp",
|
|
};
|
|
return mimeTypes[ext] || "application/octet-stream";
|
|
}
|
|
|
|
async function uploadImage(filePath: string): Promise<UploadResponse> {
|
|
const apiKey = process.env.BANATIE_API_KEY;
|
|
if (!apiKey) {
|
|
throw new Error("BANATIE_API_KEY not found in environment");
|
|
}
|
|
|
|
const absolutePath = path.resolve(filePath);
|
|
if (!fs.existsSync(absolutePath)) {
|
|
throw new Error(`File not found: ${absolutePath}`);
|
|
}
|
|
|
|
const fileName = path.basename(absolutePath);
|
|
const mimeType = getMimeType(absolutePath);
|
|
|
|
const form = new FormData();
|
|
form.append("file", fs.createReadStream(absolutePath), {
|
|
filename: fileName,
|
|
contentType: mimeType,
|
|
});
|
|
|
|
return new Promise((resolve, reject) => {
|
|
const url = new URL(API_URL);
|
|
|
|
const req = https.request(
|
|
{
|
|
hostname: url.hostname,
|
|
port: 443,
|
|
path: url.pathname,
|
|
method: "POST",
|
|
headers: {
|
|
"X-API-Key": apiKey,
|
|
...form.getHeaders(),
|
|
},
|
|
},
|
|
(res) => {
|
|
let data = "";
|
|
res.on("data", (chunk) => (data += chunk));
|
|
res.on("end", () => {
|
|
try {
|
|
const json = JSON.parse(data);
|
|
if (res.statusCode === 200 || res.statusCode === 201) {
|
|
resolve(json);
|
|
} else {
|
|
reject(
|
|
new Error(`Upload failed (${res.statusCode}): ${data}`)
|
|
);
|
|
}
|
|
} catch {
|
|
reject(new Error(`Invalid response: ${data}`));
|
|
}
|
|
});
|
|
}
|
|
);
|
|
|
|
req.on("error", reject);
|
|
form.pipe(req);
|
|
});
|
|
}
|
|
|
|
async function main() {
|
|
const filePath = process.argv[2];
|
|
|
|
if (!filePath) {
|
|
console.error("Usage: pnpm upload:image <path-to-image>");
|
|
process.exit(1);
|
|
}
|
|
|
|
try {
|
|
console.log(`Uploading: ${filePath}`);
|
|
const result = await uploadImage(filePath);
|
|
|
|
console.log(`\nSuccess!`);
|
|
console.log(`ID: ${result.data.id}`);
|
|
console.log(`URL: ${result.data.storageUrl}`);
|
|
if (result.data.width && result.data.height) {
|
|
console.log(`Size: ${result.data.width}x${result.data.height}`);
|
|
}
|
|
} catch (error) {
|
|
console.error("Error:", error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
main();
|