@danonino/moon 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,390 @@
1
+ /*
2
+ Source : https://whatsapp.com/channel/0029VbCHRSDAzNboLatr0W0o/471
3
+ */
4
+
5
+ const { createCanvas, loadImage, GlobalFonts } = require('@napi-rs/canvas');
6
+ const { writeFile, readFile, mkdir } = require('node:fs/promises');
7
+ const { existsSync } = require('node:fs');
8
+ const { join } = require('node:path');
9
+
10
+ const BG_URL = "https://raw.githubusercontent.com/ryyntwx/allimagerin/refs/heads/main/Iqcbyrin.png";
11
+ const BG_LOCAL = join(__dirname, 'Iqcbyrin.png');
12
+
13
+ const INTER_FONTS = [
14
+ { url: 'https://fonts.gstatic.com/s/inter/v18/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuLyfAZ9hiJ-Ek-_EeA.woff2', file: 'Inter-Regular.ttf' },
15
+ { url: 'https://fonts.gstatic.com/s/inter/v18/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuI6fAZ9hiJ-Ek-_EeA.woff2', file: 'Inter-Medium.ttf' },
16
+ { url: 'https://fonts.gstatic.com/s/inter/v18/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuFuYAZ9hiJ-Ek-_EeA.woff2', file: 'Inter-SemiBold.ttf' },
17
+ ];
18
+
19
+ const APPLE_EMOJI_JSON_URL = 'https://media.githubusercontent.com/media/Ditzzx-vibecoder/entahlah/main/emoji-apple.json';
20
+ const APPLE_EMOJI_JSON_LOCAL = join(__dirname, 'fonts', 'emoji-apple-image.json');
21
+
22
+ const BG_W = 906;
23
+ const BG_H = 1736;
24
+ const SX = BG_W / 1080;
25
+ const SY = BG_H / 2280;
26
+
27
+ const state = {
28
+ text: "Kesendirian adalah teman terbaik ku😂😂",
29
+ time: "22.54",
30
+ bubbleColor: "#ffc5d5",
31
+ textColor: "#111111",
32
+ timeColor: "#5e4146",
33
+ tickColor: "#8c1d2c",
34
+ fontSize: Math.round(45 * SX),
35
+ bubbleWidth: Math.round(746 * SX),
36
+ showReaction: true,
37
+ emojiSize: Math.round(90 * SX),
38
+ emojiSpacing: Math.round(110 * SX),
39
+ emojiXOffset: Math.round(15 * SX),
40
+ emojiYOffset: -15,
41
+ reactionScale: 1.0,
42
+ emojis: ["👍", "❤️", "😂", "😮", "😢", "🙏"],
43
+ offsetX: 20,
44
+ offsetY: 0,
45
+ };
46
+
47
+ let appleEmojiMap = null;
48
+
49
+ async function downloadFile(url) {
50
+ const axios = require('axios');
51
+ const res = await axios.get(url, {
52
+ responseType: 'arraybuffer',
53
+ headers: { 'User-Agent': 'Mozilla/5.0' },
54
+ maxRedirects: 5,
55
+ });
56
+ return Buffer.from(res.data);
57
+ }
58
+
59
+ function emojiToUnicode(emoji) {
60
+ return [...emoji].map(c => c.codePointAt(0).toString(16)).join('-');
61
+ }
62
+
63
+ async function loadAppleEmojiMap() {
64
+ if (appleEmojiMap) return appleEmojiMap;
65
+ if (!existsSync(APPLE_EMOJI_JSON_LOCAL)) {
66
+ const buf = await downloadFile(APPLE_EMOJI_JSON_URL);
67
+ await writeFile(APPLE_EMOJI_JSON_LOCAL, buf);
68
+ }
69
+ const raw = await readFile(APPLE_EMOJI_JSON_LOCAL, 'utf-8');
70
+ appleEmojiMap = JSON.parse(raw);
71
+ return appleEmojiMap;
72
+ }
73
+
74
+ async function drawAppleEmoji(ctx, emoji, x, y, size) {
75
+ const map = await loadAppleEmojiMap();
76
+ const base = emojiToUnicode(emoji);
77
+ const variants = [
78
+ base,
79
+ base.replace(/-fe0f/g, ''),
80
+ base.toUpperCase(),
81
+ base.replace(/-fe0f/g, '').toUpperCase(),
82
+ ];
83
+ let b64 = null;
84
+ for (const v of variants) {
85
+ if (map[v]) { b64 = map[v]; break; }
86
+ }
87
+ if (!b64) {
88
+ ctx.fillText(emoji, x, y);
89
+ return;
90
+ }
91
+ const buf = Buffer.from(b64, 'base64');
92
+ const img = await loadImage(buf);
93
+ ctx.drawImage(img, x - size / 2, y - size / 2, size, size);
94
+ }
95
+
96
+ async function ensureAssets() {
97
+ await mkdir(join(__dirname, 'fonts'), { recursive: true });
98
+
99
+ for (const f of INTER_FONTS) {
100
+ const dest = join(__dirname, 'fonts', f.file);
101
+ if (!existsSync(dest)) {
102
+ const buf = await downloadFile(f.url);
103
+ await writeFile(dest, buf);
104
+ }
105
+ GlobalFonts.registerFromPath(dest, 'Inter');
106
+ }
107
+
108
+ await loadAppleEmojiMap();
109
+
110
+ if (!existsSync(BG_LOCAL)) {
111
+ const buf = await downloadFile(BG_URL);
112
+ await writeFile(BG_LOCAL, buf);
113
+ }
114
+ }
115
+
116
+ function drawRoundedRect(ctx, x, y, w, h, r) {
117
+ ctx.beginPath();
118
+ ctx.moveTo(x + r, y);
119
+ ctx.lineTo(x + w - r, y);
120
+ ctx.quadraticCurveTo(x + w, y, x + w, y + r);
121
+ ctx.lineTo(x + w, y + h - r);
122
+ ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
123
+ ctx.lineTo(x + r, y + h);
124
+ ctx.quadraticCurveTo(x, y + h, x, y + h - r);
125
+ ctx.lineTo(x, y + r);
126
+ ctx.quadraticCurveTo(x, y, x + r, y);
127
+ ctx.closePath();
128
+ }
129
+
130
+ function measureTextCustom(ctx, text, fontSize) {
131
+ const parts = text.split(/(\p{Extended_Pictographic})/gu);
132
+ let totalWidth = 0;
133
+ for (const part of parts) {
134
+ if (!part) continue;
135
+ if (/\p{Extended_Pictographic}/u.test(part)) {
136
+ totalWidth += fontSize * 1.05;
137
+ } else {
138
+ totalWidth += ctx.measureText(part).width;
139
+ }
140
+ }
141
+ return totalWidth;
142
+ }
143
+
144
+ async function drawTextWithEmojis(ctx, text, x, y, fontSize) {
145
+ const parts = text.split(/(\p{Extended_Pictographic})/gu);
146
+ let currentX = x;
147
+
148
+ for (const part of parts) {
149
+ if (!part) continue;
150
+ if (/\p{Extended_Pictographic}/u.test(part)) {
151
+ const emojiSize = fontSize * 1.05;
152
+ const emojiCX = currentX + emojiSize / 2;
153
+ const emojiCY = y;
154
+ await drawAppleEmoji(ctx, part, emojiCX, emojiCY, emojiSize);
155
+ currentX += emojiSize;
156
+ } else {
157
+ ctx.fillText(part, currentX, y);
158
+ currentX += ctx.measureText(part).width;
159
+ }
160
+ }
161
+ }
162
+
163
+ function wrapText(ctx, text, maxWidth, fontSize) {
164
+ ctx.font = `500 ${fontSize}px Inter`;
165
+ const words = text.split(" ");
166
+ const lines = [];
167
+ let cur = "";
168
+ for (let i = 0; i < words.length; i++) {
169
+ const word = words[i];
170
+ if (word.includes('\n')) {
171
+ const parts = word.split('\n');
172
+ for (let j = 0; j < parts.length; j++) {
173
+ const test = cur + (cur ? " " : "") + parts[j];
174
+ if (measureTextCustom(ctx, test, fontSize) > maxWidth && cur) {
175
+ lines.push(cur); cur = parts[j];
176
+ } else { cur = test; }
177
+ if (j < parts.length - 1) { lines.push(cur); cur = ""; }
178
+ }
179
+ continue;
180
+ }
181
+ const test = cur + (cur ? " " : "") + word;
182
+ if (measureTextCustom(ctx, test, fontSize) > maxWidth && i > 0) {
183
+ lines.push(cur); cur = word;
184
+ } else { cur = test; }
185
+ }
186
+ if (cur) lines.push(cur);
187
+ return lines;
188
+ }
189
+
190
+ async function render(text, time, outputPath) {
191
+ await ensureAssets();
192
+
193
+ const s = { ...state, text: text ?? state.text, time: time ?? state.time };
194
+
195
+ const canvas = createCanvas(BG_W, BG_H);
196
+ const ctx = canvas.getContext('2d');
197
+
198
+ const bgImg = await loadImage(BG_LOCAL);
199
+ ctx.drawImage(bgImg, 0, 0, BG_W, BG_H);
200
+
201
+ const rightPadding = Math.round(80 * SX);
202
+ const textPaddingX = Math.round(36 * SX);
203
+ const paddingTop = Math.round(28 * SY);
204
+ const paddingBottom = Math.round(28 * SY);
205
+ const bRadius = Math.round(32 * SX);
206
+ const menuTopBorderY = Math.round(1276 * SY);
207
+ const timeFontSize = Math.round(23 * SX);
208
+
209
+ ctx.font = `600 ${timeFontSize}px Inter`;
210
+ const timeMetrics = ctx.measureText(s.time);
211
+ const ticksWidth = Math.round(34 * SX);
212
+ const timestampWidth = timeMetrics.width + ticksWidth + Math.round(12 * SX);
213
+ const timestampHeight = timeFontSize;
214
+
215
+ const textLimitW = s.bubbleWidth - (textPaddingX * 2);
216
+ ctx.font = `500 ${s.fontSize}px Inter`;
217
+ const textLines = wrapText(ctx, s.text, textLimitW, s.fontSize);
218
+
219
+ const lineWidths = textLines.map(line => measureTextCustom(ctx, line, s.fontSize));
220
+ const maxLineWidth = Math.max(...lineWidths, 0);
221
+
222
+ let bubbleActualW = 0;
223
+ let timestampOnNewRow = false;
224
+ const minBubbleW = Math.round(280 * SX);
225
+
226
+ if (textLines.length === 1) {
227
+ bubbleActualW = maxLineWidth + (textPaddingX * 2) + timestampWidth + Math.round(35 * SX);
228
+ } else {
229
+ const lastLineWidth = lineWidths[textLines.length - 1] || 0;
230
+
231
+ if (lastLineWidth + timestampWidth + Math.round(35 * SX) <= maxLineWidth) {
232
+ bubbleActualW = maxLineWidth + (textPaddingX * 2);
233
+ } else if (lastLineWidth + timestampWidth + Math.round(35 * SX) <= textLimitW) {
234
+ bubbleActualW = lastLineWidth + timestampWidth + Math.round(35 * SX) + (textPaddingX * 2);
235
+ } else {
236
+ bubbleActualW = maxLineWidth + (textPaddingX * 2);
237
+ timestampOnNewRow = true;
238
+ }
239
+ }
240
+
241
+ if (bubbleActualW < minBubbleW) bubbleActualW = minBubbleW;
242
+ if (bubbleActualW > s.bubbleWidth) bubbleActualW = s.bubbleWidth;
243
+
244
+ const bubbleX = BG_W - bubbleActualW - rightPadding;
245
+
246
+ const lineGap = Math.round(12 * SY);
247
+ const textTotalHeight = (textLines.length * s.fontSize) + ((textLines.length - 1) * lineGap);
248
+
249
+ let bubbleHeight = 0;
250
+ if (timestampOnNewRow) {
251
+ bubbleHeight = paddingTop + textTotalHeight + Math.round(16 * SY) + timestampHeight + paddingBottom;
252
+ } else {
253
+ bubbleHeight = paddingTop + textTotalHeight + paddingBottom;
254
+ }
255
+
256
+ const currentBubbleY = menuTopBorderY - bubbleHeight - Math.round(28 * SY);
257
+
258
+ ctx.save();
259
+ ctx.translate(s.offsetX, s.offsetY);
260
+
261
+ ctx.save();
262
+ ctx.shadowColor = "rgba(0,0,0,0.05)";
263
+ ctx.shadowBlur = 20;
264
+ ctx.shadowOffsetY = 6;
265
+ ctx.fillStyle = s.bubbleColor;
266
+ drawRoundedRect(ctx, bubbleX, currentBubbleY, bubbleActualW, bubbleHeight, bRadius);
267
+ ctx.fill();
268
+ ctx.restore();
269
+
270
+ ctx.save();
271
+ ctx.beginPath();
272
+ ctx.moveTo(bubbleX + bubbleActualW - Math.round(15 * SX), currentBubbleY + bubbleHeight - 5);
273
+ ctx.lineTo(bubbleX + bubbleActualW + Math.round(10 * SX), currentBubbleY + bubbleHeight - 5);
274
+ ctx.quadraticCurveTo(
275
+ bubbleX + bubbleActualW + Math.round(2 * SX),
276
+ currentBubbleY + bubbleHeight - Math.round(20 * SY),
277
+ bubbleX + bubbleActualW - Math.round(1 * SX),
278
+ currentBubbleY + bubbleHeight - Math.round(32 * SY)
279
+ );
280
+ ctx.closePath();
281
+ ctx.fillStyle = s.bubbleColor;
282
+ ctx.fill();
283
+ ctx.restore();
284
+
285
+ ctx.save();
286
+ ctx.fillStyle = s.textColor;
287
+ ctx.font = `400 ${s.fontSize}px Inter`;
288
+ ctx.textAlign = "left";
289
+ ctx.textBaseline = "middle";
290
+ for (let i = 0; i < textLines.length; i++) {
291
+ const lineY = currentBubbleY + paddingTop + (i * (s.fontSize + lineGap)) + (s.fontSize / 2);
292
+ await drawTextWithEmojis(ctx, textLines[i], bubbleX + textPaddingX, lineY, s.fontSize);
293
+ }
294
+ ctx.restore();
295
+
296
+ ctx.save();
297
+ let timeX = bubbleX + bubbleActualW - textPaddingX - timestampWidth;
298
+ let timeY = 0;
299
+
300
+ if (timestampOnNewRow) {
301
+ timeY = currentBubbleY + bubbleHeight - paddingBottom - timestampHeight + Math.round(4 * SY);
302
+ } else {
303
+ const lastLineTop = currentBubbleY + paddingTop + ((textLines.length - 1) * (s.fontSize + lineGap));
304
+ timeY = lastLineTop + s.fontSize - timestampHeight + Math.round(2 * SY);
305
+ }
306
+
307
+ ctx.fillStyle = s.timeColor;
308
+ ctx.font = `600 ${timeFontSize}px Inter`;
309
+ ctx.textBaseline = "top";
310
+ ctx.fillText(s.time, timeX, timeY);
311
+
312
+ const tickX = timeX + timeMetrics.width + Math.round(10 * SX);
313
+ const t = (n) => Math.round(n * SX);
314
+ const tickY = timeY + (timeFontSize / 2) - t(8);
315
+
316
+ ctx.strokeStyle = s.tickColor;
317
+ ctx.lineWidth = 3.6 * SX;
318
+ ctx.lineCap = "round";
319
+ ctx.lineJoin = "round";
320
+
321
+ ctx.beginPath();
322
+ ctx.moveTo(tickX, tickY + t(8));
323
+ ctx.lineTo(tickX + t(6), tickY + t(14));
324
+ ctx.lineTo(tickX + t(16), tickY + t(2));
325
+ ctx.stroke();
326
+
327
+ ctx.beginPath();
328
+ ctx.moveTo(tickX + t(7), tickY + t(8));
329
+ ctx.lineTo(tickX + t(7) + t(6), tickY + t(14));
330
+ ctx.lineTo(tickX + t(7) + t(16), tickY + t(2));
331
+ ctx.stroke();
332
+ ctx.restore();
333
+
334
+ if (s.showReaction) {
335
+ ctx.save();
336
+ const emojiNum = s.emojis.length;
337
+ const startPad = Math.round(52 * SX);
338
+ const plusBtnW = Math.round(80 * SX);
339
+ const rxHeight = Math.round(160 * SX);
340
+ const rxWidth = startPad + ((emojiNum - 1) * s.emojiSpacing) + s.emojiSpacing * 0.5 + plusBtnW + startPad * 0.5;
341
+
342
+ const rxX = bubbleX + bubbleActualW - rxWidth + s.emojiXOffset;
343
+ const rxY = currentBubbleY - rxHeight + s.emojiYOffset;
344
+ const rxRadius = rxHeight / 2;
345
+
346
+ const rxPivotX = rxX + rxWidth - Math.round(80 * SX);
347
+ const rxPivotY = rxY + rxHeight / 2;
348
+ ctx.translate(rxPivotX, rxPivotY);
349
+ ctx.scale(s.reactionScale, s.reactionScale);
350
+ ctx.translate(-rxPivotX, -rxPivotY);
351
+
352
+ ctx.save();
353
+ ctx.shadowColor = "rgba(0,0,0,0.10)";
354
+ ctx.shadowBlur = 36;
355
+ ctx.shadowOffsetY = 16;
356
+ ctx.fillStyle = "#FFFFFF";
357
+ drawRoundedRect(ctx, rxX, rxY, rxWidth, rxHeight, rxRadius);
358
+ ctx.fill();
359
+ ctx.restore();
360
+
361
+ const emojiCY = rxY + rxHeight / 2;
362
+ for (let i = 0; i < emojiNum; i++) {
363
+ await drawAppleEmoji(ctx, s.emojis[i], rxX + startPad + (i * s.emojiSpacing), emojiCY, s.emojiSize);
364
+ }
365
+
366
+ const plusX = rxX + startPad + (emojiNum - 1) * s.emojiSpacing + Math.round(90 * SX);
367
+ const plusY = emojiCY;
368
+ const plusR = Math.round(38 * SX);
369
+ const arm = Math.round(13 * SX);
370
+ ctx.beginPath();
371
+ ctx.arc(plusX, plusY, plusR, 0, Math.PI * 2);
372
+ ctx.fillStyle = "#E5E5EA";
373
+ ctx.fill();
374
+ ctx.strokeStyle = "#8E8E93";
375
+ ctx.lineWidth = 4.5 * SX;
376
+ ctx.lineCap = "round";
377
+ ctx.beginPath();
378
+ ctx.moveTo(plusX - arm, plusY); ctx.lineTo(plusX + arm, plusY);
379
+ ctx.moveTo(plusX, plusY - arm); ctx.lineTo(plusX, plusY + arm);
380
+ ctx.stroke();
381
+ ctx.restore();
382
+ }
383
+
384
+ ctx.restore();
385
+
386
+ const pngData = await canvas.encode('png');
387
+ return pngData;
388
+ }
389
+
390
+ module.exports = render;
@@ -0,0 +1,144 @@
1
+ const cheerio = require('cheerio')
2
+ const axios = require("axios")
3
+
4
+ const regex_ = {
5
+ folder: /\.com\/folder\/([^\/]+)\/?/,
6
+ file: /\.com\/(view|file)\/([a-zA-Z0-9]+)/
7
+ }
8
+
9
+ async function extractFromWeb(is, link) {
10
+ try {
11
+ const lnk = link.replace('.com/view', '.com/file');
12
+ const f = await is.get(lnk)
13
+ const $ = cheerio.load(f.data)
14
+ const url = $('.input.popsok').attr('href')
15
+
16
+ if (!url || !/\/\/download\d+\.mediafire\.com\//.test(url)) throw Error ('Failed to find download url on the web')
17
+
18
+ const [name, date, size, type] = [
19
+ $('.intro .filename').text(),
20
+ $('.details li:nth-child(2) span').text(),
21
+ $('.details li:nth-child(1) span').text(),
22
+ $('.intro .filetype').text()
23
+ ]
24
+
25
+ const cont = {
26
+ 'af': 'Africa',
27
+ 'an': 'Antarctica',
28
+ 'as': 'Asia',
29
+ 'eu': 'Europe',
30
+ 'na': 'North America',
31
+ 'oc': 'Oceania',
32
+ 'sa': 'South America'
33
+ }
34
+
35
+ const $lo = $('.DLExtraInfo-uploadLocation')
36
+
37
+ const [continent, location, flag] = [
38
+ $lo.find('.DLExtraInfo-uploadLocationRegion').attr('data-lazyclass')?.replace('continent-', ''),
39
+ $lo.find('.DLExtraInfo-sectionDetails p').text().match(/from (.*?) on/)?.[1],
40
+ $lo.find('div.lazyload.flag').attr('data-lazyclass')?.replace('flag-', '')
41
+ ];
42
+
43
+ return {
44
+ size_format: size,
45
+ continent: cont[continent] || 'Unkown',
46
+ flag,
47
+ location,
48
+ url,
49
+ }
50
+ } catch (e) {
51
+ throw e
52
+ }
53
+ }
54
+
55
+ async function mediafire(link) {
56
+ try {
57
+ const is = axios.create({
58
+ baseURL: "https://www.mediafire.com",
59
+ headers: {
60
+ 'accept-encoding' : 'gzip, deflate, br, zstd',
61
+ 'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36',
62
+ }
63
+ });
64
+
65
+ if (regex_.folder.test(link)) {
66
+ const ab = link.match(regex_.folder)
67
+ const getId = ab ? ab[1] : null;
68
+
69
+ const { data: info } = await is.get('/api/1.4/folder/get_info.php', {
70
+ params: {
71
+ recursive: 'yes',
72
+ folder_key: getId,
73
+ response_format: 'json'
74
+ }
75
+ })
76
+
77
+ let files_ = [], chunk = 1;
78
+
79
+ while (true) {
80
+ const { data: files } = await is.get('/api/1.4/folder/get_content.php', {
81
+ params: {
82
+ r: 'hrdd',
83
+ content_type: 'files',
84
+ filter: 'all',
85
+ order_by: 'name',
86
+ order_direction: 'asc',
87
+ chunk: chunk,
88
+ version: '1.5',
89
+ folder_key: getId,
90
+ response_format: 'json'
91
+ },
92
+ })
93
+ files.response.folder_content.files.map(p => files_.push({
94
+ ...p,
95
+ links: p.links.normal_download,
96
+ }));
97
+ if (files.response.folder_content.more_chunks === 'no') break;
98
+ chunk++;
99
+ await new Promise(r => setTimeout(r, 2e3));
100
+ }
101
+
102
+ return {
103
+ status: true,
104
+ type: 'folder',
105
+ ...info.response.folder_info,
106
+ files: files_
107
+ }
108
+ };
109
+
110
+ const match = link.match(regex_.file);
111
+ const ab = match ? match[2] : null;
112
+
113
+ let { data: info } = await is.get('/api/1.5/file/get_info.php', {
114
+ params: {
115
+ quick_key: ab,
116
+ response_format: 'json'
117
+ }
118
+ })
119
+
120
+ let inf = info.response.file_info, wb = await extractFromWeb(is, link);
121
+ if (!wb.type) wb = await extractFromWeb(is, link);
122
+
123
+ return {
124
+ status: true,
125
+ type: 'file',
126
+ ...inf,
127
+ links: inf.links.normal_download,
128
+ ...wb,
129
+ ...(!!inf.links.view ? {
130
+ preview: is.defaults.baseURL + '/convkey/' + inf.hash.substr(0, 4) + '/' + inf.quickkey + '9g.' + inf.filename.split('.').pop()
131
+ } : {}),
132
+ }
133
+ } catch(e) {
134
+ if (e.status === 404) {
135
+ return {
136
+ status: false,
137
+ msg: "Page not found or invalid link"
138
+ }
139
+ }
140
+ throw e.response ? e.response.data : e.message
141
+ }
142
+ }
143
+
144
+ module.exports = mediafire;
@@ -0,0 +1,115 @@
1
+ const axios = require('axios');
2
+ const crypto = require('crypto');
3
+ const FormData = require('form-data');
4
+
5
+ async function live3d(buffer, prompt) {
6
+ const config = {
7
+ pkey: "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHZk1BMEdDU3FHU0liM0RRRUJBUVVBQTRHTkFEQ0JpUUtCZ1FDd2xPK2JvQzZjd1JvM1VmWFZCYWRhWXdjWDB6S1MyZnVWTlkycVowZGd3YjFOSisvUTlGZUFvc0w0T05pb3NENzFvbjNQVllxUlVsTDUwNDVtdkgySzlpOGJBRlZNRWlwN0U2Uk1LNnRLQUFpZjd4elpyWG5QMUdaNVJpanRxZGd3aCtZbXpUbzM5Y3VCQ3NacUs5b0VvZVEzci9teUc5Uys5Y1I1aHVUdUZRSURBUUFCCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ==",
8
+ aid: "aifaceswap",
9
+ uid: "1H5tRtzsBkqXcaJ",
10
+ origin: "8f3f0c7387123ae0",
11
+ theme_version: '83EmcUoQTUv50LhNx0VrdcK8rcGexcP35FcZDcpgWsAXEyO4xqL5shCY6sFIWB2Q',
12
+ model: 'nano_banana_2',
13
+ }
14
+
15
+ let currentFp = crypto.randomBytes(16).toString('hex');
16
+
17
+ const crypt = {
18
+ aes: (data, key) => {
19
+ const cipher = crypto.createCipheriv('aes-128-cbc', key, key);
20
+ return Buffer.concat([cipher.update(data, 'utf8'), cipher.final()]).toString('base64')
21
+ },
22
+ rsa: (data) => {
23
+ return crypto.publicEncrypt({
24
+ key: Buffer.from(config.pkey, "base64").toString(),
25
+ padding: crypto.constants.RSA_PKCS1_PADDING,
26
+ }, Buffer.from(data, 'utf8')).toString('base64');
27
+ }
28
+ };
29
+
30
+ const api = axios.create({
31
+ baseURL: 'https://app-v1.live3d.io',
32
+ headers: {
33
+ 'User-Agent': 'Mozilla/5.0 (Linux; Android 16; NX729J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.34 Mobile Safari/537.36',
34
+ 'origin': 'https://live3d.io',
35
+ 'referer': 'https://live3d.io/',
36
+ 'theme-version': config.theme_version
37
+ }
38
+ });
39
+
40
+ api.interceptors.request.use((cfg) => {
41
+ const [i, d, n] = [
42
+ crypto.randomBytes(8).toString('hex'),
43
+ crypto.randomUUID(),
44
+ Math.floor(Date.now() / 1000)
45
+ ]
46
+
47
+ const s = crypt.rsa(i);
48
+ const signStr = cfg.url.includes('upload-img') ? `${config.aid}:${d}:${s}` : `${config.aid}:${config.uid}:${n}:${d}:${s}`;
49
+
50
+ Object.assign(cfg.headers, {
51
+ 'fp': currentFp,
52
+ 'fp1': crypt.aes(`${config.aid}:${currentFp}`, i),
53
+ 'x-guide': s,
54
+ 'x-sign': crypt.aes(signStr, i),
55
+ 'x-code': Date.now().toString()
56
+ });
57
+
58
+ return cfg;
59
+ });
60
+
61
+ try {
62
+ const form = new FormData();
63
+ form.append('file', buffer, { filename: 'input.jpg', contentType: 'image/jpeg' });
64
+ form.append('fn_name', 'demo-image-editor');
65
+ form.append('request_from', '9');
66
+ form.append('origin_from', config.origin);
67
+
68
+ const { data: upRes } = await api.post('/aitools/upload-img', form, {
69
+ headers: form.getHeaders()
70
+ });
71
+
72
+ const { data: job } = await api.post('/aitools/of/create', {
73
+ fn_name: 'demo-image-editor',
74
+ call_type: 3,
75
+ input: {
76
+ model: config.model,
77
+ source_images: [upRes.data.path],
78
+ prompt: prompt,
79
+ aspect_radio: 'auto',
80
+ request_from: 9
81
+ },
82
+ data: '',
83
+ request_from: 9,
84
+ origin_from: config.origin
85
+ });
86
+
87
+
88
+ const taskId = job.data.task_id;
89
+ if (!taskId) throw new Error("TaskId cannot be found")
90
+
91
+ while (true) {
92
+ const { data: status } = await api.post('/aitools/of/check-status', {
93
+ task_id: taskId,
94
+ fn_name: 'demo-image-editor',
95
+ call_type: 3,
96
+ request_from: 9,
97
+ origin_from: config.origin
98
+ });
99
+
100
+ if (status.data.status === 2) {
101
+ return {
102
+ status: 'success',
103
+ image_url: 'https://temp.live3d.io/' + status.data.result_image
104
+ };
105
+ } else if (status.data.status === 3) {
106
+ return status.data
107
+ }
108
+ await new Promise(r => setTimeout(r, 3000));
109
+ }
110
+ } catch (error) {
111
+ throw new Error(`Process failed: ${error.message}`);
112
+ }
113
+ }
114
+
115
+ module.exports = live3d;
package/src/novaai.js ADDED
@@ -0,0 +1,34 @@
1
+ /*
2
+ Base : https://play.google.com/store/apps/details?id=com.apporigins.NovaAI
3
+ By : ZennzXD
4
+ Created : 1 Mei 2026
5
+ */
6
+
7
+ const headers = {
8
+ 'User-Agent': 'okhttp/4.10.0',
9
+ 'Accept-Encoding': 'gzip',
10
+ 'platform': 'Android',
11
+ 'version': '1.4.0',
12
+ 'language': 'in',
13
+ 'content-type': 'application/json; charset=utf-8'
14
+ }
15
+
16
+ async function novaAi(text) {
17
+ const payload = {
18
+ question_text: text,
19
+ conversation: {
20
+ conversation_items: []
21
+ }
22
+ }
23
+
24
+ const res = await fetch('https://us-central1-nova-ai---android.cloudfunctions.net/app/ai-response/v2', {
25
+ method: 'POST',
26
+ headers: headers,
27
+ body: JSON.stringify(payload)
28
+ })
29
+
30
+ const data = await res.json()
31
+ return data
32
+ }
33
+
34
+ module.exports = novaAi