Jadianime

by @fuadxyro
71 Raw
/**
© ZENITH
ᘎ https://whatsapp.com/channel/0029Vai9MMj5vKABWrYzIJ2Z
*/

import axios from "axios"
import CryptoJS from "crypto-js"
import fs from "fs"

let handler = async(m, { conn, text, usedPrefix: prefix, command: cmd }) => {
    let q = m.quoted ? m.quoted : m
    let mime = (q.msg || q).mimetype || q.mediaType || ''
    if (!/image/.test(mime)) return await conn.reply(m.chat, `*\`Kirim atau balas pesan gambar dengan caption:\`*\n> _*${prefix+cmd} [1/2/3/4] (untuk menentukan style nya)*_`, m)
    let style
    try {
        if (Number(text)) style = Number(text)
        else style = 2
        await m.reply(wait)
        const aieaseInstance = new Aiease({ debug: true })    
        const image = await q.download()
        await aieaseInstance.generateImage('filter', image, { style: style })       
            if (!res) await conn.reply(m.chat, "Gagal membuat anime pada foto anda!", m).then(async() => {
                return await conn.sendMessage(m.chat, { react: { delete: m.key, key: m.key }})
            })
            const { nsfw, origin, thumb } = res[0]
            await conn.sendMessage(m.chat, {
                image: { url: origin },
                mimetype: "image/jpeg",
                caption: "Berhasil",
            }, { quoted: m }) 
       
    } catch(err) {
        return await conn.reply(m.chat, `Maaf terjadi kesalahan...\n> _Log Error:_ \`\`\`${err?.message}\`\`\``, m)
    }
}
handler.help = ["jadianime"]
handler.tags = ["tools"]
handler.command = ["jadianime", "toanime"]

export default handler

class Aiease {
    constructor({ debug = false } = {}) {
        this.DEBUG = debug
        this.AUTH_TOKEN = null
        this.api = {
            uploader: 'https://www.aiease.ai/api/api/id_photo/s',
            genImg2Img: 'https://www.aiease.ai/api/api/gen/img2img',
            gentext2img: 'https://www.aiease.ai/api/api/gen/text2img',
            taskInfo: 'https://www.aiease.ai/api/api/id_photo/task-info',
            styleList: ' https://www.aiease.ai/api/api/common/',
            token: 'https://www.aiease.ai/api/api/user/visit',
        }
        this.headers = {
            json: {
                'Content-Type': 'application/json',
                'User-Agent': 'Mozilla/5.0',
                'Authorization': null,
                'Accept': 'application/json'
            },
            image: {
                'Content-Type': 'image/jpeg',
                'Host': 'pub-static.aiease.ai',
                'Origin': 'https://www.aiease.ai',
                'Referer': 'https://www.aiease.ai/',
                'User-Agent': 'Mozilla/5.0',
                'Accept': '*/*'
            }
        }
        this.default_payload = {
            enhance: {
                gen_type: "enhance",
                enhance_extra_data: {
                    img_url: null,
                    mode: null, // general || anime || old_photo
                    size: "4",
                    restore: 1
                }
            },
            filter: {
                gen_type: 'ai_filter',
                ai_filter_extra_data: { 
                    img_url: null,
                    style_id: null
                }
            },
            watermark: {
                gen_type: "text_remove",
                text_remove_extra_data: {
                    img_url: null,
                    mask_url: ""
                }
            },
            rembg: {
                gen_type: "rembg",
                rembg_extra_data: {
                    img_url: null
                }
            },
            retouch: {
                gen_type: "ai_skin_repair",
                ai_skin_repair_extra_data: {
                    img_url: null
                }
            }
        }
        this.constants = {
            maxRetry: 40,
            retryDelay: 3000,
        }
        const { useEncrypt, useDecrypt } = this._setupEncryption()
        this.useEncrypt = useEncrypt
        this.useDecrypt = useDecrypt
    }

    _setupEncryption() {
        const encryptionKeyPhrase = ["Q", "@", "D", "2", "4", "=", "o", "u", "e", "V", "%", "]", "O", "B", "S", "8", "i", ",", "%", "e", "K", "=", "5", "I", "|", "7", "W", "U", "$", "P", "e", "E"]
            .map((char) => {
                const charCode = char.charCodeAt(0)
                return String.fromCharCode(charCode)
            }).join("")
        const hashHex = CryptoJS.SHA256(encryptionKeyPhrase).toString(CryptoJS.enc.Hex)
        const encryptionKey = CryptoJS.enc.Hex.parse(hashHex)
        return {
            useEncrypt: function (plainText) {
                const encodedText = encodeURIComponent(plainText)
                const iv = CryptoJS.lib.WordArray.random(16)
                const encrypted = CryptoJS.AES.encrypt(encodedText, encryptionKey, {
                    iv: iv,
                    mode: CryptoJS.mode.CFB,
                    padding: CryptoJS.pad.NoPadding
                })
                const combined = iv.concat(encrypted.ciphertext)
                const encryptedStr = CryptoJS.enc.Base64.stringify(combined)
                return encryptedStr
            },
            useDecrypt: function (base64EncryptedText) {
                const encryptedBytes = CryptoJS.enc.Base64.parse(base64EncryptedText)
                const iv = CryptoJS.lib.WordArray.create(encryptedBytes.words.slice(0, 4), 16)
                const ciphertext = CryptoJS.lib.WordArray.create(encryptedBytes.words.slice(4), encryptedBytes.sigBytes - 16)
                const decrypted = CryptoJS.AES.decrypt({ ciphertext: ciphertext }, encryptionKey, {
                    iv: iv,
                    mode: CryptoJS.mode.CFB,
                    padding: CryptoJS.pad.NoPadding
                })
                const decryptedText = decodeURIComponent(decrypted.toString(CryptoJS.enc.Utf8))
                return decryptedText
            }
        }
    }

    async uploadImage(input) {
        if (!this.AUTH_TOKEN) await this.getToken()
        try {
            const fileBuffer = Buffer.isBuffer(input) ? input : /^data:.*?\/.*?;base64,/i.test(input) ? Buffer.from(input.split`,`[1], 'base64') : /^https?:\/\//.test(input) ? Buffer.from(new Uint8Array((await (await fetch(input)).arrayBuffer()))) : fs.existsSync(input) ? fs.readFileSync(input) : typeof input === 'string' ? input : Buffer.alloc(0)
            const metadata = {
                length: fileBuffer.length,
                filetype: 'image/jpeg',
                filename: "IMG-" + Date.now() + "-WA" + ["0012", "0034", "00371", "0018", "1120", "0045", "0038"].getRandom() + ".jpg"
            }
            const metadataJsonString = JSON.stringify(metadata)
            const encryptedMetadata = this.useEncrypt(metadataJsonString)
            const tValue = encryptedMetadata
            const apiUrl = `${this.api.uploader}?time=${Date.now()}`
            const payload = { t: tValue }
            const response = await axios.post(apiUrl, payload, { headers: this.headers.json })
            const uploadUrl = this.useDecrypt(response.data.result)
            const imageSizeInBytes = fileBuffer.length
            await axios.put(uploadUrl, fileBuffer, { headers: { 'Content-Length': imageSizeInBytes, ...this.headers.image } })
            console.log('Upload success!', `Image uploaded to ${uploadUrl.split('?')[0]}`)
            return uploadUrl.split('?')[0]
        } catch (error) {
            console.error('Image Upload Error:', error.message)
            throw error
        }
    }

    async generateImage(type, input, { style = 4, mode = 'general' } = {}) {
        if (!this.AUTH_TOKEN) await this.getToken()
        try {
            const payload = this.default_payload[type]
            if (!payload) {
                throw new Error(`Invalid type: ${type}\nSupported types: ${Object.keys(this.default_payload).join(', ')}`)
            }
            const imgUrl = await this.uploadImage(input)
            const dataKey = Object.keys(payload).find(key => key.endsWith("_extra_data"))
            if (dataKey) {
                payload[dataKey].img_url = imgUrl
            }
            if (type === 'filter') {
                payload[dataKey].style_id = style
            } else if (type === 'enhance') {
                payload[dataKey].mode = mode
            }
            const response = await axios.post(this.api.genImg2Img, payload, {
                headers: this.headers.json
            })
            if (response.data && response.data.result && response.data.result.task_id) {
                const taskId = response.data.result.task_id
                console.log(`Task ID received: ${taskId}`)
                return await this.checkTaskStatus(taskId)
            } else {
                throw new Error(response.data.message || 'Task ID not found in response')
            }
        } catch (error) {
            console.error('Image Generation Error:', error.message)
            throw error
        }
    }

    async text2img(prompt, { style = 1, size = '1-1' } = {}) {
        if (!this.AUTH_TOKEN) await this.getToken()
        try {
            if (!prompt) throw new Error('Please provide a prompt.')
            const payload = {
                gen_type: "art_v1",
                art_v1_extra_data: {
                    prompt: prompt,
                    style_id: style,
                    size: size
                }
            }
            const response = await axios.post(this.api.gentext2img, payload, {
                headers: this.headers.json
            })
            if (response.data && response.data.result && response.data.result.task_id) {
                const taskId = response.data.result.task_id
                console.log(`Task ID received: ${taskId}`)
                return await this.checkTaskStatus(taskId)
            } else {
                throw new Error(response.data.message || 'Task ID not found in response')
            }
        } catch (error) {
            console.error('Image Generation Error:', error.message)
            throw error
        }
    }

    async checkTaskStatus(taskId, maxRetry = this.constants.maxRetry) {
        let status = ''
        let attempts = 0
        while (status !== 'success' && attempts < maxRetry) {
            try {
                const response = await axios.get(`${this.api.taskInfo}?task_id=${taskId}`, {
                    headers: this.headers.json
                })

                if (response.data.code === 450) {
                    throw new Error(response.data.message)
                }
                if (response.data && response.data.result && response.data.result.data) {
                    status = response.data.result.data.queue_info.status
                    console.log(`Task ${taskId} status: ${status}`)
                    if (status === 'success') {
                        console.log(`Task ${taskId} succeeded!`)
                        return response.data.result.data.results
                    }
                }
            } catch (error) {
                console.error('Task Status Check Error:', error.message)
                if (error.message.includes('Image generation failed')) {
                    throw new Error(error.message)
                }
            }
            attempts++;
            if (attempts >= maxRetry) {
                console.error('Task Status Check Error:', `Max retry limit reached (${maxRetry}) for task ${taskId}`)
                throw new Error(`Max retry limit reached (${maxRetry}) for task ${taskId}`)
            }
            await new Promise(resolve => setTimeout(resolve, this.constants.retryDelay))
        }
    }

    async getStyle(type) {
        if (!this.AUTH_TOKEN) await this.getToken()
        try {
            const end = {
                art: 'ai_art_style',
                filter: 'ai_filter_style'
            }[type]
            if (!end) {
                throw new Error(`Invalid type: ${type}\nSupported types: ${Object.keys(end).join(', ')}`)
            }
            const response = await axios.get(this.api.styleList + end, {
                headers: this.headers.json
            })
            if (response.data.code === 200) {
                console.log('Style list fetched successfully.')
                return response.data.result
            } else {
                console.error('Failed to fetch style list:', response.data.message || 'Unknown error')
                throw new Error(response.data.message || 'Failed to fetch style list')
            }
        } catch (error) {
            console.error('Error fetching style list:', error.message)
            throw error
        }
    }

    async getToken() {
        try {
            const response = await axios.post(this.api.token, {}, {
                headers: {
                    'Content-Type': 'application/json',
                    'Accept': 'application/json',
                    'User-Agent': 'Mozilla/5.0'
                }
            })
            if (response.data.code === 200) {
                console.log('Token fetched successfully.')
                const jwt = `JWT ${response.data.result.user.token}`
                this.AUTH_TOKEN = jwt
                this.headers.json.Authorization = this.AUTH_TOKEN
                return
            } else {
                console.error('Failed to fetch token:', response.data.message || 'Unknown error')
                throw new Error(response.data.message || 'Failed to fetch token')
            }
        } catch (error) {
            console.error('Error fetching token:', error.message)
            throw error
        }
    }
}