deepnude.mjs

Live3D cloth remover generator

#ai#image#nsfw
26
27 Des 2025, 03:34
RawEdit
javascript0 lines
/***
  @ Base: https://live3d.io/deepnude-ai-generator/
  @ Author: Shannz
  @ Note: Live3D cloth remover generator
***/

import axios from 'axios';
import FormData from 'form-data';
import fs from 'fs';
import crypto from 'crypto';
import path from 'path';

const CONFIG = {
    BASE_URL: 'https://app.live3d.io',
    CDN_URL: 'https://temp.live3d.io/',
    ENDPOINTS: {
        UPLOAD: '/aitools/upload-img',
        CREATE: '/aitools/of/create',
        STATUS: '/aitools/of/check-status'
    },
    SECRETS: {
        FP: '78dc286eaeb7fb88586e07f0d18bf61b',
        APP_ID: 'aifaceswap',
        PUBLIC_KEY: `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwlO+boC6cwRo3UfXVBadaYwcX
0zKS2fuVNY2qZ0dgwb1NJ+/Q9FeAosL4ONiosD71on3PVYqRUlL5045mvH2K9i8b
AFVMEip7E6RMK6tKAAif7xzZrXnP1GZ5Rijtqdgwh+YmzTo39cuBCsZqK9oEoeQ3
r/myG9S+9cR5huTuFQIDAQAB
-----END PUBLIC KEY-----`
    },
    HEADERS: {
        'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Mobile Safari/537.36',
        'Accept': 'application/json, text/plain, */*',
        'sec-ch-ua-platform': '"Android"',
        'theme-version': '83EmcUoQTUv50LhNx0VrdcK8rcGexcP35FcZDcpgWsAXEyO4xqL5shCY6sFIWB2Q',
        'origin': 'https://live3d.io',
        'referer': 'https://live3d.io/',
        'priority': 'u=1, i'
    }
};

const utils = {
    genHex: (bytes) => crypto.randomBytes(bytes).toString('hex'),
    
    genRandomString: (length) => {
        const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        let result = "";
        for (let i = 0; i < length; i++) result += chars.charAt(Math.floor(Math.random() * chars.length));
        return result;
    },

    aesEncrypt: (plaintext, keyStr, ivStr) => {
        const key = Buffer.from(keyStr, 'utf8');
        const iv = Buffer.from(ivStr, 'utf8');
        const cipher = crypto.createCipheriv('aes-128-cbc', key, iv);
        let encrypted = cipher.update(plaintext, 'utf8', 'base64');
        encrypted += cipher.final('base64');
        return encrypted;
    },

    rsaEncrypt: (data) => {
        const buffer = Buffer.from(data, 'utf8');
        const encrypted = crypto.publicEncrypt({
            key: CONFIG.SECRETS.PUBLIC_KEY,
            padding: crypto.constants.RSA_PKCS1_PADDING,
        }, buffer);
        return encrypted.toString('base64');
    },

    generateHeaders: () => {
        const aesKey = utils.genRandomString(16);
        const xCode = Date.now().toString();
        const xGuide = utils.rsaEncrypt(aesKey);
        const plaintextFp = `${CONFIG.SECRETS.APP_ID}:${CONFIG.SECRETS.FP}`;
        const fp1 = utils.aesEncrypt(plaintextFp, aesKey, aesKey);

        return {
            ...CONFIG.HEADERS,
            'x-code': xCode,
            'x-guide': xGuide,
            'fp': CONFIG.SECRETS.FP,
            'fp1': fp1
        };
    }
};

export const live3d = {
    generate: async (imagePath) => {
        const originFrom = utils.genHex(8);
        const requestFrom = 9;

        console.log(`\n=== Live3D Generator [Hex: ${originFrom}] ===`);

        try {
            if (!fs.existsSync(imagePath)) return console.log(`[!] File ${imagePath} tidak ditemukan.`);
            
            process.stdout.write(`[1/3] Uploading image... `);
            
            const form = new FormData();
            form.append('file', fs.createReadStream(imagePath));
            form.append('fn_name', 'cloth-change');
            form.append('request_from', requestFrom.toString());
            form.append('origin_from', originFrom);

            const uploadHeaders = { ...utils.generateHeaders(), ...form.getHeaders() };
            
            const uploadRes = await axios.post(CONFIG.BASE_URL + CONFIG.ENDPOINTS.UPLOAD, form, { headers: uploadHeaders });
            let serverPath = uploadRes.data?.data;
            if (typeof serverPath === 'object' && serverPath.path) serverPath = serverPath.path;

            if (!serverPath) throw new Error("Gagal mendapatkan path server.");
            console.log(`Done.`);

            process.stdout.write(`[2/3] Submitting task... `);
            
            const submitPayload = {
                "fn_name": "cloth-change",
                "call_type": 3,
                "input": {
                    "source_image": serverPath,
                    "prompt": "best quality, naked, nude",
                    "cloth_type": "full_outfits",
                    "request_from": requestFrom,
                    "type": 1
                },
                "request_from": requestFrom,
                "origin_from": originFrom
            };

            const submitRes = await axios.post(CONFIG.BASE_URL + CONFIG.ENDPOINTS.CREATE, submitPayload, {
                headers: { ...utils.generateHeaders(), 'Content-Type': 'application/json' }
            });

            const taskId = submitRes.data?.data?.task_id;
            if (!taskId) throw new Error("Gagal mendapatkan Task ID.");
            console.log(`Done (ID: ${taskId})`);

            let isCompleted = false;
            let attempts = 0;
            let resultUrl = null;
            const maxAttempts = 40;

            while (!isCompleted && attempts < maxAttempts) {
                attempts++;
                await new Promise(r => setTimeout(r, 3000));

                const statusPayload = {
                    "task_id": taskId,
                    "fn_name": "cloth-change",
                    "call_type": 3,
                    "consume_type": 0,
                    "request_from": requestFrom,
                    "origin_from": originFrom
                };

                const statusRes = await axios.post(CONFIG.BASE_URL + CONFIG.ENDPOINTS.STATUS, statusPayload, {
                    headers: { ...utils.generateHeaders(), 'Content-Type': 'application/json' }
                });

                const data = statusRes.data?.data;
                if (!data) continue;

                const status = data.status;

                process.stdout.clearLine();
                process.stdout.cursorTo(0);
                
                if (status === 2) {
                    resultUrl = data.result_image;
                    if (resultUrl && !resultUrl.startsWith('http')) {
                        resultUrl = CONFIG.CDN_URL + resultUrl;
                    }
                    process.stdout.write(`[3/3] Status: Success!\n`);
                    isCompleted = true;
                } else if (status === 1) {
                    const dots = ".".repeat((attempts % 3) + 1);
                    process.stdout.write(`[3/3] Status: Generating${dots} `);
                } else {
                    process.stdout.write(`[3/3] Status: Queue (Rank ${data.rank})... `);
                }
            }

            if (!resultUrl) throw new Error("Timeout generating image.");

            console.log(`\n[RESULT] ${resultUrl}\n`);
            return resultUrl;

        } catch (error) {
            console.log(`\n[X] Error: ${error.message}`);
            if (error.response) console.log(`    Server Msg: ${JSON.stringify(error.response.data)}`);
            return null;
        }
    }
};