HerzaJ commited on
Commit
520ddc6
·
verified ·
1 Parent(s): 0c256e0

Create upscale.js

Browse files
Files changed (1) hide show
  1. plugins/upscale.js +189 -0
plugins/upscale.js ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const axios = require('axios');
4
+ const https = require('https');
5
+ const FormData = require('form-data');
6
+
7
+ const UPLOAD_URL = 'https://api.unblurimage.ai/api/common/upload/upload-image';
8
+ const CREATE_JOB_URL = 'https://api.unblurimage.ai/api/imgupscaler/v1/ai-image-upscaler-v2/create-job';
9
+ const PRODUCT_SERIAL = '79661c82d918475e7458944c2f66857e';
10
+ const TMP_DIR = '/tmp/upscaler';
11
+
12
+ const axiosInstance = axios.create({
13
+ timeout: 60000,
14
+ httpsAgent: new https.Agent({
15
+ rejectUnauthorized: false,
16
+ }),
17
+ });
18
+
19
+ function ensureTmpDir() {
20
+ if (!fs.existsSync(TMP_DIR)) {
21
+ fs.mkdirSync(TMP_DIR, { recursive: true });
22
+ }
23
+ }
24
+
25
+ async function downloadImage(imageUrl) {
26
+ const response = await axiosInstance.get(imageUrl, {
27
+ responseType: 'arraybuffer',
28
+ });
29
+ return Buffer.from(response.data);
30
+ }
31
+
32
+ function saveImageToTmp(imageBuffer) {
33
+ ensureTmpDir();
34
+ const fileName = `image_${Date.now()}_${Math.random().toString(36).substr(2, 9)}.jpg`;
35
+ const filePath = path.join(TMP_DIR, fileName);
36
+ fs.writeFileSync(filePath, imageBuffer);
37
+ return filePath;
38
+ }
39
+
40
+ function deleteFileAfterDelay(filePath, delayMs = 10000) {
41
+ setTimeout(() => {
42
+ try {
43
+ if (fs.existsSync(filePath)) {
44
+ fs.unlinkSync(filePath);
45
+ }
46
+ } catch (error) {
47
+ console.error(`Failed to delete file ${filePath}:`, error.message);
48
+ }
49
+ }, delayMs);
50
+ }
51
+
52
+ async function uploadImage(filePath) {
53
+ const imageBuffer = fs.readFileSync(filePath);
54
+ const fileName = path.basename(filePath);
55
+ const contentType = 'image/jpeg';
56
+
57
+ const form = new FormData();
58
+ form.append('file_name', fileName);
59
+ form.append('file', imageBuffer, fileName);
60
+
61
+ const uploadResponse = await axiosInstance.post(UPLOAD_URL, form, {
62
+ headers: {
63
+ ...form.getHeaders(),
64
+ 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Mobile Safari/537.36',
65
+ },
66
+ });
67
+
68
+ if (uploadResponse.data.code !== 100000) {
69
+ throw new Error(`Upload failed: ${uploadResponse.data.message.en}`);
70
+ }
71
+
72
+ const uploadUrl = uploadResponse.data.result.url;
73
+
74
+ await axiosInstance.put(uploadUrl, imageBuffer, {
75
+ headers: {
76
+ 'Content-Type': contentType,
77
+ 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Mobile Safari/537.36',
78
+ },
79
+ });
80
+
81
+ return {
82
+ url: uploadUrl.split('?')[0],
83
+ };
84
+ }
85
+
86
+ async function createJob(imageUrl, upscaleLevel) {
87
+ const form = new FormData();
88
+ form.append('original_image_url', imageUrl);
89
+ form.append('upscale_type', upscaleLevel.toString());
90
+
91
+ const response = await axiosInstance.post(CREATE_JOB_URL, form, {
92
+ headers: {
93
+ ...form.getHeaders(),
94
+ 'Product-Serial': PRODUCT_SERIAL,
95
+ 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Mobile Safari/537.36',
96
+ },
97
+ });
98
+
99
+ if (response.data.code !== 100000) {
100
+ throw new Error(`Job creation failed: ${response.data.message.en}`);
101
+ }
102
+
103
+ return response.data.result;
104
+ }
105
+
106
+ async function upscaleImage(imageUrl, scaleNumber) {
107
+ let tmpFilePath = null;
108
+
109
+ try {
110
+ if (!imageUrl) {
111
+ throw new Error('Image URL is required');
112
+ }
113
+
114
+ if (![2, 4, 8, 16].includes(scaleNumber)) {
115
+ throw new Error('Scale number must be 2, 4, 8, or 16');
116
+ }
117
+
118
+ const imageBuffer = await downloadImage(imageUrl);
119
+ tmpFilePath = saveImageToTmp(imageBuffer);
120
+
121
+ const uploadResult = await uploadImage(tmpFilePath);
122
+ const result = await createJob(uploadResult.url, scaleNumber);
123
+
124
+ deleteFileAfterDelay(tmpFilePath, 10000);
125
+
126
+ return result;
127
+ } catch (error) {
128
+ if (tmpFilePath && fs.existsSync(tmpFilePath)) {
129
+ fs.unlinkSync(tmpFilePath);
130
+ }
131
+ throw error;
132
+ }
133
+ }
134
+
135
+ const handler = async (req, res) => {
136
+ try {
137
+ const { image_url, scale, key } = req.query;
138
+
139
+ if (!image_url) {
140
+ return res.status(400).json({
141
+ success: false,
142
+ error: 'Missing required parameter: image_url'
143
+ });
144
+ }
145
+
146
+ if (!scale) {
147
+ return res.status(400).json({
148
+ success: false,
149
+ error: 'Missing required parameter: scale'
150
+ });
151
+ }
152
+
153
+ const scaleNum = parseInt(scale);
154
+ if (![2, 4, 8, 16].includes(scaleNum)) {
155
+ return res.status(400).json({
156
+ success: false,
157
+ error: 'Scale must be 2, 4, 8, or 16'
158
+ });
159
+ }
160
+
161
+ const result = await upscaleImage(image_url, scaleNum);
162
+
163
+ return res.json({
164
+ author: "Herza",
165
+ success: true,
166
+ data: result
167
+ });
168
+
169
+ } catch (error) {
170
+ res.status(500).json({
171
+ success: false,
172
+ error: error.message,
173
+ timestamp: new Date().toISOString()
174
+ });
175
+ }
176
+ };
177
+
178
+ module.exports = {
179
+ name: 'Image Upscaler',
180
+ description: 'Upscale images to 2x, 4x, 8x, or 16x resolution',
181
+ type: 'GET',
182
+ routes: ['api/tools/upscale'],
183
+ tags: ['image', 'upscale', 'enhancement'],
184
+ parameters: ['image_url', 'scale', 'key'],
185
+ limit: 5,
186
+ enabled: true,
187
+ main: ['tools'],
188
+ handler
189
+ };