const fs = require('fs'); const path = require('path'); const axios = require('axios'); const https = require('https'); const FormData = require('form-data'); const UPLOAD_URL = 'https://api.unblurimage.ai/api/common/upload/upload-image'; const CREATE_JOB_URL = 'https://api.unblurimage.ai/api/imgupscaler/v1/ai-image-upscaler-v2/create-job'; const PRODUCT_SERIAL = '79661c82d918475e7458944c2f66857e'; const TMP_DIR = '/tmp/upscaler'; const axiosInstance = axios.create({ timeout: 60000, httpsAgent: new https.Agent({ rejectUnauthorized: false, }), }); function ensureTmpDir() { if (!fs.existsSync(TMP_DIR)) { fs.mkdirSync(TMP_DIR, { recursive: true }); } } async function downloadImage(imageUrl) { const response = await axiosInstance.get(imageUrl, { responseType: 'arraybuffer', }); return Buffer.from(response.data); } function saveImageToTmp(imageBuffer) { ensureTmpDir(); const fileName = `image_${Date.now()}_${Math.random().toString(36).substr(2, 9)}.jpg`; const filePath = path.join(TMP_DIR, fileName); fs.writeFileSync(filePath, imageBuffer); return filePath; } function deleteFileAfterDelay(filePath, delayMs = 10000) { setTimeout(() => { try { if (fs.existsSync(filePath)) { fs.unlinkSync(filePath); } } catch (error) { console.error(`Failed to delete file ${filePath}:`, error.message); } }, delayMs); } async function uploadImage(filePath) { const imageBuffer = fs.readFileSync(filePath); const fileName = path.basename(filePath); const contentType = 'image/jpeg'; const form = new FormData(); form.append('file_name', fileName); form.append('file', imageBuffer, fileName); const uploadResponse = await axiosInstance.post(UPLOAD_URL, form, { headers: { ...form.getHeaders(), 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Mobile Safari/537.36', }, }); if (uploadResponse.data.code !== 100000) { throw new Error(`Upload failed: ${uploadResponse.data.message.en}`); } const uploadUrl = uploadResponse.data.result.url; await axiosInstance.put(uploadUrl, imageBuffer, { headers: { 'Content-Type': contentType, 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Mobile Safari/537.36', }, }); return { url: uploadUrl.split('?')[0], }; } async function createJob(imageUrl, upscaleLevel) { const form = new FormData(); form.append('original_image_url', imageUrl); form.append('upscale_type', upscaleLevel.toString()); const response = await axiosInstance.post(CREATE_JOB_URL, form, { headers: { ...form.getHeaders(), 'Product-Serial': PRODUCT_SERIAL, 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Mobile Safari/537.36', }, }); if (response.data.code !== 100000) { throw new Error(`Job creation failed: ${response.data.message.en}`); } return response.data.result; } async function upscaleImage(imageUrl, scaleNumber) { let tmpFilePath = null; try { if (!imageUrl) { throw new Error('Image URL is required'); } if (![2, 4, 8, 16].includes(scaleNumber)) { throw new Error('Scale number must be 2, 4, 8, or 16'); } const imageBuffer = await downloadImage(imageUrl); tmpFilePath = saveImageToTmp(imageBuffer); const uploadResult = await uploadImage(tmpFilePath); const result = await createJob(uploadResult.url, scaleNumber); deleteFileAfterDelay(tmpFilePath, 10000); return result; } catch (error) { if (tmpFilePath && fs.existsSync(tmpFilePath)) { fs.unlinkSync(tmpFilePath); } throw error; } } const handler = async (req, res) => { try { const { image_url, scale, key } = req.query; if (!image_url) { return res.status(400).json({ success: false, error: 'Missing required parameter: image_url' }); } if (!scale) { return res.status(400).json({ success: false, error: 'Missing required parameter: scale' }); } const scaleNum = parseInt(scale); if (![2, 4, 8, 16].includes(scaleNum)) { return res.status(400).json({ success: false, error: 'Scale must be 2, 4, 8, or 16' }); } const result = await upscaleImage(image_url, scaleNum); return res.json({ author: "Herza", success: true, data: result }); } catch (error) { res.status(500).json({ success: false, error: error.message, timestamp: new Date().toISOString() }); } }; module.exports = { name: 'Image Upscaler', description: 'Upscale images to 2x, 4x, 8x, or 16x resolution', type: 'GET', routes: ['api/tools/upscale'], tags: ['image', 'upscale', 'enhancement'], parameters: ['image_url', 'scale', 'key'], limit: 5, enabled: true, main: ['tools'], handler };