zona.mjs

javascriptCreated 26 Mar 2026, 11:3197 views
Ai song generator with lyrics or description, Wrapper from Zona apk
#ai#music#song
javascript
/*** 
    @ Base: https://play.google.com/store/apps/details?id=com.zona.aimusic
    @ Author: Shannz
    @ Note: Ai song generator with lyrics or description, Wrapper from Zona apk
***/

import jwt from 'jsonwebtoken';
import crypto from 'crypto';

const CONFIG = {
    BASE_URL: "https://zona-backend-production.onrender.com",
    SECRET_KEY: "c5933031d2b07fa4a3133cbd3f5a21fe8a0e0e9b6cb52d36e70402e81688d3b4",
    POLL_INTERVAL: 5000,
    MAX_RETRIES: 24,
    HEADERS: {
        'User-Agent': 'okhttp/4.12.0',
        'Accept': 'application/json',
        'Content-Type': 'application/json',
        'platform': 'android',
        'locale': 'en',
        'app-version': '7.5.7'
    }
};

const utils = {
    generateDeviceId: () => crypto.randomBytes(8).toString('hex'),
    
    generateAuthPayload: (deviceId) => jwt.sign({ device_id: deviceId }, CONFIG.SECRET_KEY, { noTimestamp: true }),
    
    sleep: (ms) => new Promise(resolve => setTimeout(resolve, ms)),
    
    filterResponse: (data) => {
        const transform = (item) => ({
            id: item.id,
            status: item.status,
            title: item.title || "Untitled",
            audio_url: item.audio_url,
            image_url: item.image_large_url || item.image_url,
            created_at: item.created_at
        });

        if (Array.isArray(data)) return data.map(transform);
        if (data && data.rows) return data.rows.map(transform);
        return data ? transform(data) : null;
    }
};

export const zona = {
    getToken: async (deviceId = utils.generateDeviceId()) => {
        try {
            const tokenJwt = utils.generateAuthPayload(deviceId);
            const response = await fetch(`${CONFIG.BASE_URL}/register`, {
                method: 'POST',
                headers: CONFIG.HEADERS,
                body: tokenJwt
            });
            const resData = await response.json();
            return resData.token;
        } catch (error) {
            return null;
        }
    },

    pollStatus: async (token, targetIds) => {
        console.log(`[wait] Sedang memproses musik (${targetIds.join('& ')})...`);
        let retries = 0;

        while (retries < CONFIG.MAX_RETRIES) {
            await utils.sleep(CONFIG.POLL_INTERVAL);            
            const library = await zona.getLibrary(token);
            const matches = library.filter(item => targetIds.includes(item.id));
            const isReady = matches.every(m => m.status === 'streaming' || m.audio_url);
            
            if (isReady && matches.length > 0) {
                console.log(`[✔] Musik siap!`);
                return matches;
            }

            retries++;
            console.log(`[..] Masih diproses... (Percobaan ${retries}/${CONFIG.MAX_RETRIES})`);
        }
        
        console.error("[-] Timeout: Musik memakan waktu terlalu lama.");
        return null;
    },

    genSmart: async (prompt, isInstrumental = false) => {
        const token = await zona.getToken();
        try {
            const response = await fetch(`${CONFIG.BASE_URL}/prediction/predict/smart`, {
                method: 'POST',
                headers: { ...CONFIG.HEADERS, 'authorization': `Bearer ${token}` },
                body: JSON.stringify({
                    gpt_description_prompt: prompt,
                    make_instrumental: isInstrumental
                })
            });

            const resData = await response.json();
            const initialData = utils.filterResponse(resData);
            const ids = initialData.map(item => item.id);
            return await zona.pollStatus(token, ids);
        } catch (error) {
            return null;
        }
    },

    genLyrics: async ({ title, lyrics, tags, isInstrumental = false }) => {
        const token = await zona.getToken();
        try {
            const response = await fetch(`${CONFIG.BASE_URL}/prediction/predict/custom`, {
                method: 'POST',
                headers: { ...CONFIG.HEADERS, 'authorization': `Bearer ${token}` },
                body: JSON.stringify({
                    prompt: lyrics,
                    tags: tags,
                    title: title,
                    instrumental: isInstrumental
                })
            });

            const resData = await response.json();
            const initialData = utils.filterResponse(resData);
            
            const ids = initialData.map(item => item.id);
            return await zona.pollStatus(token, ids);
        } catch (error) {
            return null;
        }
    },

    getLibrary: async (token, page = 1) => {
        try {
            const response = await fetch(`${CONFIG.BASE_URL}/users/library/prediction/list`, {
                method: 'POST',
                headers: { ...CONFIG.HEADERS, 'authorization': `Bearer ${token}` },
                body: JSON.stringify({ page: page, sort: "new_to_old" })
            });
            const resData = await response.json();
            return utils.filterResponse(resData);
        } catch (error) {
            return [];
        }
    }
};

/*
(async () => {
    // 1. Generate by prompt
    console.log('--- GENERATE MUSIC SMART BY PROMPT ---');
    const res1 = await zona.genSmart("Lagu galau akustik tentang kopi", false);
    console.log("Hasil Generate Smart:", res1);
    
    // 2. Generate by lyrics
    console.log('--- GENERATE MUSIC BY LYRICS ---');
    const res2 = await zona.genLyrics({
        prompt: "[Intro]\nWhispers of yesterday, echoes in my mind\nTrying to find peace, leaving you behind\n\n[Verse 1]\nWe danced through storms, glimpses of a brighter view\nNow I walk alone, trying to forget you\nMemories like shadows, flicker in the night\nHoping someday, I'll find the light\n\n[Pre-Chorus]\nStill feel your voice, in the silent air\nEvery word, a ghost that lingers there\nBut I know I must move on, set myself free\nFrom the love that used to be\n\n[Chorus]\nSurat cinta untuk mantan, words left unsaid\nLetters of longing, traces of what we had\nThough time has passed, your shadow still remains\nIn my heart, in my veins\n\n[Bridge]\nMaybe someday, I’ll read these lines again\nAnd smile at love’s bittersweet pain\nUntil then, I hold on to the past\nHoping it won’t last\n\n[Outro]\nGoodbye, my love, tears fall like rain\nSurat cinta untuk mantan, easing the pain\nFarewell to what we used to be\nYou set me free",
        tags: "Emotional pop ballad, acoustic guitar, piano, gentle drums, heartfelt vocals",
        title: "Surat Cinta untuk Mantan",
        isInstrumental: false
    });
    console.log("Hasil Generate By Lyrics:", res2);
})();
*/