web2apk
JavaScriptPublicby zx-apiAug 23, 2026, 02:44 AMExpires: Never60 views
1/**
2 * Name Scrape: Web2Apk
3 * Credit By Zx
4 * Description: Website To Apk
5 * Sumber Kode: https://whatsapp.com/channel/0029VbDLqe7EquiSF4STU13o
6 * Note: Kalau Mau di sher lagi harap jangan hapus credit atau sumber saluran
7 *
8**/
9
10import fs from 'fs'
11import path from 'path'
12import os from 'os'
13import axios from 'axios'
14
15class Web2Apk {
16 constructor({ apiUrl = 'https://webappcreator.amethystlab.org/api/build-apk', baseUrl = 'https://webappcreator.amethystlab.org' } = {}) {
17 this.apiUrl = apiUrl
18 this.baseUrl = baseUrl
19 }
20
21 isValidUrl(url) {
22 return /^https?:\/\//i.test(url)
23 }
24
25 buildPackageName(appName) {
26 const cleaned = appName.toLowerCase().replace(/[^a-z0-9]/g, '')
27 return `com.${cleaned || 'app'}.web2apk`
28 }
29
30 saveIconBuffer(buffer) {
31 const tempDir = path.join(os.tmpdir(), 'web2apk')
32 if (!fs.existsSync(tempDir)) fs.mkdirSync(tempDir, { recursive: true })
33
34 const iconPath = path.join(tempDir, `icon_${Date.now()}.png`)
35 fs.writeFileSync(iconPath, buffer)
36 return iconPath
37 }
38
39 async build({ url, appName, iconBuffer, versionName = '1.0.0', versionCode = 1 }) {
40 if (!this.isValidUrl(url)) throw new Error('URL harus diawali dengan http:// atau https://')
41 if (!appName) throw new Error('Nama aplikasi tidak boleh kosong.')
42 if (!iconBuffer) throw new Error('Icon aplikasi wajib disertakan.')
43
44 const packageName = this.buildPackageName(appName)
45 const iconPath = this.saveIconBuffer(iconBuffer)
46 let projectId = null
47
48 try {
49 const FormDataNode = (await import('form-data')).default
50 const form = new FormDataNode()
51
52 form.append('websiteUrl', url)
53 form.append('appName', appName)
54 form.append('icon', fs.createReadStream(iconPath), {
55 filename: 'icon.png',
56 contentType: 'image/png'
57 })
58 form.append('packageName', packageName)
59 form.append('versionName', versionName)
60 form.append('versionCode', String(versionCode)) // Pastikan string
61
62 console.log('๐ค Mengirim file ke server (Server lambat, mohon tunggu 1-5 menit)...')
63
64 const response = await axios.post(this.apiUrl, form, {
65 headers: {
66 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36',
67 'Accept': 'application/json, text/plain, */*',
68 'Origin': this.baseUrl,
69 'Referer': `${this.baseUrl}/`,
70 ...form.getHeaders()
71 },
72 maxContentLength: Infinity,
73 maxBodyLength: Infinity,
74 timeout: 600000,
75 validateStatus: (status) => status >= 200 && status < 600
76 })
77
78 const data = response.data
79 console.log(`โ
Server merespons dengan status HTTP ${response.status}`)
80
81 if (response.status >= 400) {
82 const errorMsg = (data && (data.error || data.message)) || `Server mengembalikan error HTTP ${response.status}`
83 throw new Error(errorMsg)
84 }
85
86 if (data.success && data.downloadUrl) {
87 return {
88 success: true,
89 appName,
90 packageName,
91 downloadUrl: data.downloadUrl.startsWith('http') ? data.downloadUrl : `${this.baseUrl}${data.downloadUrl}`
92 }
93 }
94
95 if (data.queued || data.projectId) {
96 projectId = data.projectId
97 console.log(`โ
Request diterima! Project ID: ${projectId}`)
98 } else {
99 throw new Error('Respon tidak dikenali dari server: ' + JSON.stringify(data))
100 }
101
102 console.log(`โณ Build masuk antrian. Memulai polling status...`)
103 const statusUrl = `${this.baseUrl}/api/build-status/${projectId}`
104 const maxAttempts = 120 // Maksimal polling 10 menit
105 let attempt = 0
106
107 while (attempt < maxAttempts) {
108 await new Promise(resolve => setTimeout(resolve, 5000)) // Tunggu 5 detik
109 attempt++
110
111 try {
112 const statusResponse = await axios.get(statusUrl, {
113 headers: {
114 'Accept': 'application/json',
115 'Origin': this.baseUrl,
116 'Referer': `${this.baseUrl}/`,
117 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36'
118 },
119 timeout: 15000
120 })
121
122 const status = statusResponse.data
123
124 if (status.status === 'completed') {
125 console.log('\nโ
Build Selesai!')
126 const downloadPath = status.downloadUrl || `/download/${projectId}.apk`
127 return {
128 success: true,
129 appName,
130 packageName,
131 downloadUrl: downloadPath.startsWith('http') ? downloadPath : `${this.baseUrl}${downloadPath}`
132 }
133 }
134 else if (status.status === 'failed') {
135 throw new Error(status.error || 'Build gagal di server.')
136 }
137 else {
138 const queueInfo = status.queueInfo ? `(${status.queueInfo.currentBuilds}/${status.queueInfo.maxConcurrent} slot)` : ''
139 const pos = status.position ? `Posisi: ${status.position}` : 'Sedang diproses'
140
141 process.stdout.write(
142 `\rโณ Status: ${status.status.toUpperCase().padEnd(10)} | ` +
143 `${pos.padEnd(15)} | ${queueInfo.padEnd(20)} | Cek ke-${attempt} `
144 )
145 }
146 } catch (err) {
147 console.warn(`\nโ ๏ธ Gagal cek status (percobaan ${attempt}): ${err.message}`)
148 }
149 }
150
151 throw new Error('Timeout: Build memakan waktu lebih dari 10 menit.')
152
153 } finally {
154 if (fs.existsSync(iconPath)) fs.unlinkSync(iconPath)
155 }
156 }
157}
158
159export default Web2Apk
160
161async function run() {
162 console.log('โณ Memulai proses pembuatan APK...\n');
163
164 try {
165 const web2apk = new Web2Apk();
166
167 console.log('๐ฅ Mengunduh icon aplikasi');
168 const iconResponse = await axios.get(
169 'https://placehold.co/512x512/4285F4/FFFFFF/png?text=GoogleKu',
170 { responseType: 'arraybuffer', timeout: 30000 }
171 );
172 const iconBuffer = Buffer.from(iconResponse.data);
173
174 const appConfig = {
175 url: 'https://google.com',
176 appName: 'GoogleKu',
177 iconBuffer: iconBuffer,
178 versionName: '1.0.0',
179 versionCode: 1
180 };
181
182 console.log('๐ Mengirim request build ke server AmethystLab...');
183 const result = await web2apk.build(appConfig);
184
185 console.log('\n\nโ
Build Berhasil!');
186 console.log('-------------------');
187 console.log(`๐ฑ Nama Aplikasi : ${result.appName}`);
188 console.log(`๐ฆ Package Name : ${result.packageName}`);
189 console.log(`๐ Link Download : ${result.downloadUrl}`);
190 console.log('-------------------');
191
192 } catch (error) {
193 console.error('\n\nโ Terjadi kesalahan saat mem-build APK:');
194 console.error(error.message);
195 if (error.response) {
196 console.error('Response status:', error.response.status);
197 console.error('Response data:', error.response.data);
198 }
199 }
200}
201
202run();202 linesยท6,906 charsยท6.8 KB
WwrapยทFfullscreen