imageditor.js

Editing images is easier with ai nanobanana.

#ai#image#tools
106
4 Des 2025, 10:16
RawEdit
javascript0 lines
/***
  @ Base: https://imgeditor.co/
  @ Author: Shannz
  @ Note: image edit with nanobanana ai
***/

import axios from 'axios';
import { readFileSync } from 'fs';
import { basename } from 'path';

const BASE_URL = 'https://imgeditor.co';
const HEADERS = {
  'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Mobile Safari/537.36',
  'Accept-Encoding': 'gzip, deflate, br, zstd',
  'sec-ch-ua-platform': '"Android"',
  'sec-ch-ua': '"Chromium";v="142", "Google Chrome";v="142", "Not_A Brand";v="99"',
  'dnt': '1',
  'sec-ch-ua-mobile': '?1',
  'origin': BASE_URL,
  'sec-fetch-site': 'same-origin',
  'sec-fetch-mode': 'cors',
  'sec-fetch-dest': 'empty',
  'referer': `${BASE_URL}/generator`,
  'accept-language': 'id,en-US;q=0.9,en;q=0.8,ja;q=0.7',
  'priority': 'u=1, i'
};

export const imgeditor = {
  getPresign: async (fileName, contentType = 'image/jpeg', fileSize) => {
    try {
      const response = await axios.post(
        `${BASE_URL}/api/get-upload-url`,
        {
          fileName,
          contentType,
          fileSize
        },
        {
          headers: {
            ...HEADERS,
            'Content-Type': 'application/json'
          }
        }
      );
      return response.data;
    } catch (error) {
      throw new Error(`Failed to get presigned URL: ${error.message}`);
    }
  },

  upload: async (uploadUrl, fileData, contentType = 'image/jpeg') => {
    try {
      const data = typeof fileData === 'string' ? readFileSync(fileData) : fileData;
      
      const response = await axios.put(uploadUrl, data, {
        headers: {
          'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Mobile Safari/537.36',
          'Accept-Encoding': 'gzip, deflate, br, zstd',
          'Content-Type': contentType,
          'sec-ch-ua-platform': '"Android"',
          'sec-ch-ua': '"Chromium";v="142", "Google Chrome";v="142", "Not_A Brand";v="99"',
          'DNT': '1',
          'sec-ch-ua-mobile': '?1',
          'Origin': BASE_URL,
          'Sec-Fetch-Site': 'cross-site',
          'Sec-Fetch-Mode': 'cors',
          'Sec-Fetch-Dest': 'empty',
          'Referer': `${BASE_URL}/`,
          'Accept-Language': 'id,en-US;q=0.9,en;q=0.8,ja;q=0.7'
        }
      });

      return {
        success: response.status === 200,
        etag: response.headers.etag
      };
    } catch (error) {
      throw new Error(`Failed to upload file: ${error.message}`);
    }
  },

  submit: async (options) => {
    const {
      prompt,
      imageUrl,
      styleId = 'realistic',
      mode = 'image',
      imageSize = 'auto',
      quality = 'standard',
      numImages = 1,
      outputFormat = 'png',
      model = 'nano-banana'
    } = options;

    try {
      const response = await axios.post(
        `${BASE_URL}/api/generate-image`,
        {
          prompt,
          styleId,
          mode,
          imageUrl,
          imageUrls: [imageUrl],
          imageSize,
          quality,
          numImages,
          outputFormat,
          model
        },
        {
          headers: {
            ...HEADERS,
            'Content-Type': 'application/json'
          }
        }
      );
      return response.data;
    } catch (error) {
      throw new Error(`Failed to submit generation: ${error.message}`);
    }
  },

  status: async (taskId) => {
    try {
      const response = await axios.get(
        `${BASE_URL}/api/generate-image/status`,
        {
          params: { taskId },
          headers: HEADERS
        }
      );
      return response.data;
    } catch (error) {
      throw new Error(`Failed to check status: ${error.message}`);
    }
  },

  create: async (filePath, prompt, options = {}, pollInterval = 5000) => {
    try {
      const fileData = readFileSync(filePath);
      const fileName = basename(filePath);
      const contentType = fileName.endsWith('.png') ? 'image/png' : 'image/jpeg';
      const fileSize = fileData.length;
      const presignData = await imgeditor.getPresign(fileName, contentType, fileSize);
      await imgeditor.upload(presignData.uploadUrl, fileData, contentType);
      
      const submitData = await imgeditor.submit({
        prompt,
        imageUrl: presignData.publicUrl,
        ...options
      });

      let statusData;
      let attempts = 0;
      const maxAttempts = 60;

      while (attempts < maxAttempts) {
        statusData = await imgeditor.status(submitData.taskId);
        
        if (statusData.status === 'completed') {
          return {
            imageUrl: statusData.imageUrl,
            taskId: submitData.taskId,
            completedAt: statusData.completedAt
          };
        } else if (statusData.status === 'failed') {
          throw new Error(`Generation failed: ${statusData.error || 'Unknown error'}`);
        }

        await new Promise(resolve => setTimeout(resolve, pollInterval));
        attempts++;
      }

      throw new Error('Generation timeout after 5 minutes');
    } catch (error) {
      throw new Error(`Create failed: ${error.message}`);
    }
  }
};