satanic-release 0.0.0-stage → 2.4.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.
Files changed (244) hide show
  1. package/RUN NODE 20 - 21 +0 -0
  2. package/assets/fishing/LICENSE.txt +1 -0
  3. package/assets/fishing/SOURCES.md +8 -0
  4. package/assets/fishing/angler.svg +16 -0
  5. package/assets/fishing/background.svg +1 -0
  6. package/assets/fishing/bait.svg +1 -0
  7. package/assets/fishing/birds.svg +1 -0
  8. package/assets/fishing/boat.svg +1 -0
  9. package/assets/fishing/bobber.svg +1 -0
  10. package/assets/fishing/cloud.svg +1 -0
  11. package/assets/fishing/coin.svg +1 -0
  12. package/assets/fishing/coral.svg +1 -0
  13. package/assets/fishing/crate.svg +1 -0
  14. package/assets/fishing/fish-bass.svg +1 -0
  15. package/assets/fishing/fish-catfish.svg +1 -0
  16. package/assets/fishing/fish-koi.svg +1 -0
  17. package/assets/fishing/fish-perch.svg +1 -0
  18. package/assets/fishing/fish-trout.svg +1 -0
  19. package/assets/fishing/hook.svg +1 -0
  20. package/assets/fishing/lilypad.svg +1 -0
  21. package/assets/fishing/manifest.json +48 -0
  22. package/assets/fishing/net.svg +1 -0
  23. package/assets/fishing/reeds.svg +1 -0
  24. package/assets/fishing/rod.svg +1 -0
  25. package/assets/fishing/spark.svg +1 -0
  26. package/assets/fishing/splash.svg +5 -0
  27. package/assets/fishing/watergrass.svg +1 -0
  28. package/assets/fonts/qiro-nulis.ttf +0 -0
  29. package/assets/rpg/CC0_SOURCES.txt +23 -0
  30. package/assets/rpg/cc0/SOURCES.md +18 -0
  31. package/assets/rpg/items/antidote.svg +1 -0
  32. package/assets/rpg/items/armor.svg +1 -0
  33. package/assets/rpg/items/axe.svg +1 -0
  34. package/assets/rpg/items/bag.svg +1 -0
  35. package/assets/rpg/items/bear.svg +1 -0
  36. package/assets/rpg/items/boar.svg +1 -0
  37. package/assets/rpg/items/book.svg +1 -0
  38. package/assets/rpg/items/bow.svg +1 -0
  39. package/assets/rpg/items/car.svg +1 -0
  40. package/assets/rpg/items/cherry.svg +1 -0
  41. package/assets/rpg/items/chest.svg +1 -0
  42. package/assets/rpg/items/coal.svg +1 -0
  43. package/assets/rpg/items/coin.svg +1 -0
  44. package/assets/rpg/items/compass.svg +1 -0
  45. package/assets/rpg/items/crate.svg +1 -0
  46. package/assets/rpg/items/deer.svg +1 -0
  47. package/assets/rpg/items/demon.svg +1 -0
  48. package/assets/rpg/items/diamond.svg +5 -0
  49. package/assets/rpg/items/diamondchest.svg +1 -0
  50. package/assets/rpg/items/dice.svg +1 -0
  51. package/assets/rpg/items/dice1.svg +1 -0
  52. package/assets/rpg/items/dice2.svg +1 -0
  53. package/assets/rpg/items/dice3.svg +1 -0
  54. package/assets/rpg/items/dice4.svg +1 -0
  55. package/assets/rpg/items/dice5.svg +1 -0
  56. package/assets/rpg/items/dice6.svg +1 -0
  57. package/assets/rpg/items/dragon.svg +1 -0
  58. package/assets/rpg/items/dumbbell.svg +1 -0
  59. package/assets/rpg/items/egg.svg +1 -0
  60. package/assets/rpg/items/elixir.svg +1 -0
  61. package/assets/rpg/items/emerald.svg +1 -0
  62. package/assets/rpg/items/fish.svg +1 -0
  63. package/assets/rpg/items/fishingrod.svg +1 -0
  64. package/assets/rpg/items/flower.svg +1 -0
  65. package/assets/rpg/items/food.svg +1 -0
  66. package/assets/rpg/items/fox.svg +1 -0
  67. package/assets/rpg/items/frost.svg +1 -0
  68. package/assets/rpg/items/gold.svg +1 -0
  69. package/assets/rpg/items/goldchest.svg +1 -0
  70. package/assets/rpg/items/grape.svg +1 -0
  71. package/assets/rpg/items/hammer.svg +1 -0
  72. package/assets/rpg/items/helmet.svg +1 -0
  73. package/assets/rpg/items/herb.svg +1 -0
  74. package/assets/rpg/items/house.svg +1 -0
  75. package/assets/rpg/items/iron.svg +1 -0
  76. package/assets/rpg/items/key.svg +1 -0
  77. package/assets/rpg/items/kraken.svg +1 -0
  78. package/assets/rpg/items/kunai.svg +1 -0
  79. package/assets/rpg/items/leather.svg +1 -0
  80. package/assets/rpg/items/lemon.svg +1 -0
  81. package/assets/rpg/items/lion.svg +1 -0
  82. package/assets/rpg/items/map.svg +1 -0
  83. package/assets/rpg/items/meat.svg +1 -0
  84. package/assets/rpg/items/mpotion.svg +1 -0
  85. package/assets/rpg/items/octopus.svg +1 -0
  86. package/assets/rpg/items/orange.svg +1 -0
  87. package/assets/rpg/items/ore.svg +1 -0
  88. package/assets/rpg/items/parking.svg +1 -0
  89. package/assets/rpg/items/pearl.svg +1 -0
  90. package/assets/rpg/items/pet.svg +1 -0
  91. package/assets/rpg/items/pickaxe.svg +1 -0
  92. package/assets/rpg/items/potion.svg +1 -0
  93. package/assets/rpg/items/prawn.svg +1 -0
  94. package/assets/rpg/items/rabbit.svg +1 -0
  95. package/assets/rpg/items/ramen.svg +1 -0
  96. package/assets/rpg/items/rice.svg +1 -0
  97. package/assets/rpg/items/rock.svg +1 -0
  98. package/assets/rpg/items/scroll.svg +1 -0
  99. package/assets/rpg/items/seven.svg +1 -0
  100. package/assets/rpg/items/shark.svg +1 -0
  101. package/assets/rpg/items/shield.svg +1 -0
  102. package/assets/rpg/items/shuriken.svg +1 -0
  103. package/assets/rpg/items/slot.svg +1 -0
  104. package/assets/rpg/items/staminapotion.svg +1 -0
  105. package/assets/rpg/items/sword.svg +1 -0
  106. package/assets/rpg/items/tent.svg +1 -0
  107. package/assets/rpg/items/thunder.svg +1 -0
  108. package/assets/rpg/items/titan.svg +1 -0
  109. package/assets/rpg/items/trash.svg +1 -0
  110. package/assets/rpg/items/undead.svg +1 -0
  111. package/assets/rpg/items/whale.svg +1 -0
  112. package/assets/rpg/items/wheat.svg +1 -0
  113. package/assets/rpg/items/wood.svg +1 -0
  114. package/assets/rpg/ui/SOURCES.md +12 -0
  115. package/assets/rpg/ui/compass.svg +1 -0
  116. package/assets/rpg/ui/diamond.svg +1 -0
  117. package/assets/rpg/ui/soft-frame.svg +6 -0
  118. package/buypanel.js +37 -0
  119. package/cara ambil apikey.js +26 -0
  120. package/data/assets/Caveat-Bold.ttf +0 -0
  121. package/data/assets/FontsFree-Net-SFProDisplay-Bold.ttf +0 -0
  122. package/data/assets/FontsFree-Net-SFProDisplay-Regular.ttf +0 -0
  123. package/data/assets/Indie-Flower.ttf +0 -0
  124. package/database/absen.json +1 -0
  125. package/database/absen_status.json +1 -0
  126. package/database/admin.json +1 -0
  127. package/database/adminvip.json +1 -0
  128. package/database/afk.json +1 -0
  129. package/database/antiaudio.json +1 -0
  130. package/database/antibadword.json +1 -0
  131. package/database/antibot-settings.json +1 -0
  132. package/database/antibot.json +1 -0
  133. package/database/antidelete.json +3 -0
  134. package/database/antiig.json +1 -0
  135. package/database/antiimage.json +1 -0
  136. package/database/antilink.json +1 -0
  137. package/database/antilinkall.json +1 -0
  138. package/database/antilinkkick.json +1 -0
  139. package/database/antirvo.json +1 -0
  140. package/database/antispam-counter.json +1 -0
  141. package/database/antispam-groups.json +1 -0
  142. package/database/antispam-warn.json +1 -0
  143. package/database/antisticker.json +1 -0
  144. package/database/antiswgc.json +1 -0
  145. package/database/antitagsw.json +1 -0
  146. package/database/antitoxic.json +1 -0
  147. package/database/antitt.json +1 -0
  148. package/database/antivideo.json +1 -0
  149. package/database/antiyt.json +1 -0
  150. package/database/autojoingc.json +1 -0
  151. package/database/autosholat.json +3 -0
  152. package/database/bad.json +73 -0
  153. package/database/badword.json +7 -0
  154. package/database/banchat.json +1 -0
  155. package/database/bannedfitur.json +1 -0
  156. package/database/banuser.json +1 -0
  157. package/database/blacklist.json +1 -0
  158. package/database/blacklistgroup.json +1 -0
  159. package/database/broadcast.json +3 -0
  160. package/database/chatsNotif.json +1 -0
  161. package/database/config.json +1 -0
  162. package/database/database.json +1 -0
  163. package/database/expiredpanel.json +1 -0
  164. package/database/expiredpanel2.json +1 -0
  165. package/database/fiturmember.json +1 -0
  166. package/database/groupadd.json +1 -0
  167. package/database/groups.json +6 -0
  168. package/database/gruplist.json +5 -0
  169. package/database/idgrup.json +1 -0
  170. package/database/jpmgroup.json +1 -0
  171. package/database/kata-kata.json +28309 -0
  172. package/database/left.json +1 -0
  173. package/database/list-message.json +51 -0
  174. package/database/maintenance.json +4 -0
  175. package/database/mutegc.json +1 -0
  176. package/database/nilai.json +3 -0
  177. package/database/onlyadmin.json +1 -0
  178. package/database/onlygc.json +6 -0
  179. package/database/onlyprivate.json +3 -0
  180. package/database/openaigc.json +3 -0
  181. package/database/owner.json +1 -0
  182. package/database/panelexpired2.json +1 -0
  183. package/database/payment.json +1 -0
  184. package/database/pending.json +1 -0
  185. package/database/pendingSewa.json +1 -0
  186. package/database/prefix.json +4 -0
  187. package/database/premium.json +1 -0
  188. package/database/qris.json +3 -0
  189. package/database/registered.json +2 -0
  190. package/database/schedule.json +1 -0
  191. package/database/set_done.json +1 -0
  192. package/database/set_left.json +1 -0
  193. package/database/set_proses.json +1 -0
  194. package/database/set_welcome.json +1 -0
  195. package/database/setting.json +1 -0
  196. package/database/sewa.json +1 -0
  197. package/database/sewabot.json +3 -0
  198. package/database/transaksi.json +1 -0
  199. package/database/uservip.json +1 -0
  200. package/database/warning.json +2 -0
  201. package/database/welcome.json +1 -0
  202. package/helper.js +461 -0
  203. package/index.js +19 -0
  204. package/lib/AGENCYB.TTF +0 -0
  205. package/lib/CallDur.ttf +0 -0
  206. package/lib/CallName.ttf +0 -0
  207. package/lib/DanaFont.otf +0 -0
  208. package/lib/DevFont.ttf +0 -0
  209. package/lib/antidelete.js +196 -0
  210. package/lib/arialnarrow.ttf +0 -0
  211. package/lib/cekban.js +14 -0
  212. package/lib/color.js +19 -0
  213. package/lib/connection.js +12 -0
  214. package/lib/converter.js +85 -0
  215. package/lib/exif.js +171 -0
  216. package/lib/function.js +407 -0
  217. package/lib/gemmy.js +433 -0
  218. package/lib/groupManager.js +75 -0
  219. package/lib/helper-bails.js +19 -0
  220. package/lib/myfunction.js +384 -0
  221. package/lib/respon-list.js +95 -0
  222. package/lib/sambungkata.js +117 -0
  223. package/lib/savetube.js +1 -0
  224. package/lib/setwelcome.js +66 -0
  225. package/lib/sewa.js +109 -0
  226. package/lib/sewabot.js +40 -0
  227. package/lib/store.js +94 -0
  228. package/lib/surprisedeal.js +120 -0
  229. package/lib/thumb.jpg +0 -0
  230. package/lib/tictactoe.js +94 -0
  231. package/lib/tiktoksearch.js +83 -0
  232. package/lib/uploader.js +324 -0
  233. package/lib/videothumb.mp4 +0 -0
  234. package/lib/welcome.js +129 -0
  235. package/license.md +17 -0
  236. package/no developer.js +2 -0
  237. package/package.json +61 -5
  238. package/plugins/crm.js +309 -0
  239. package/plugins/douyinsearch.js +166 -0
  240. package/plugins/runcrm.js +124 -0
  241. package/plugins/spotifylirik.js +130 -0
  242. package/satanic.js +37922 -0
  243. package/settings.js +173 -0
  244. package/README.md +0 -3
package/lib/gemmy.js ADDED
@@ -0,0 +1,433 @@
1
+ const https = require('https')
2
+ const fs = require('fs')
3
+
4
+ const agent = new https.Agent({ keepAlive: true })
5
+
6
+ const randomUUID = () => 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
7
+ const r = Math.random() * 16 | 0
8
+ return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16)
9
+ })
10
+
11
+ function syncCookies(jar, setCookies = []) {
12
+ const list = Array.isArray(setCookies) ? setCookies : [setCookies]
13
+ for (const item of list) {
14
+ const pair = item.split(';')[0].split('=')
15
+ if (pair.length >= 2) {
16
+ jar[pair[0].trim()] = pair.slice(1).join('=').trim()
17
+ }
18
+ }
19
+ }
20
+
21
+ const buildCookieString = (jar) => Object.entries(jar).map(([k, v]) => `${k}=${v}`).join('; ')
22
+
23
+ function cleanText(text) {
24
+ if (!text) return ''
25
+ text = text.replace(/https?:\/\/[a-z0-9.-]*googleusercontent\.com\/[^\s\n"<>]+/gi, '')
26
+ return text
27
+ .replace(/&#(\d+);/g, (_, n) => String.fromCodePoint(parseInt(n, 10)))
28
+ .replace(/&#x([0-9a-f]+);/gi, (_, h) => String.fromCodePoint(parseInt(h, 16)))
29
+ .replace(/&amp;/g, '&')
30
+ .replace(/&lt;/g, '<')
31
+ .replace(/&gt;/g, '>')
32
+ .replace(/&quot;/g, '"')
33
+ .replace(/&apos;/g, "'")
34
+ .replace(/&nbsp;/g, ' ')
35
+ .trim()
36
+ }
37
+
38
+ function request(url, { method = 'GET', headers = {}, body = null, stream = false } = {}) {
39
+ return new Promise((resolve, reject) => {
40
+ const u = new URL(url)
41
+ const opts = {
42
+ hostname: u.hostname,
43
+ path: u.pathname + u.search,
44
+ method,
45
+ headers: body ? { ...headers, 'content-length': Buffer.byteLength(body) } : headers,
46
+ agent,
47
+ maxHeaderSize: 1048576
48
+ }
49
+
50
+ const req = https.request(opts, res => {
51
+ if (stream) return resolve({ res, headers: res.headers })
52
+ const chunks = []
53
+ res.on('data', c => chunks.push(c))
54
+ res.on('end', () => resolve({ text: Buffer.concat(chunks).toString(), headers: res.headers }))
55
+ })
56
+
57
+ req.on('error', reject)
58
+ if (body) req.write(body)
59
+ req.end()
60
+ })
61
+ }
62
+
63
+ function download(url, cookieStr = null, hops = 0) {
64
+ return new Promise((resolve, reject) => {
65
+ if (hops > 5) return reject(new Error('Too many redirects'))
66
+ const safeUrl = url.startsWith('http:') ? url.replace('http:', 'https:') : url
67
+ const u = new URL(safeUrl)
68
+ const headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' }
69
+ if (cookieStr) headers['cookie'] = cookieStr
70
+ https.get({ hostname: u.hostname, path: u.pathname + u.search, headers, maxHeaderSize: 1048576, agent }, res => {
71
+ if ([301, 302, 303, 307, 308].includes(res.statusCode) && res.headers.location) {
72
+ res.resume()
73
+ return download(res.headers.location, cookieStr, hops + 1).then(resolve).catch(reject)
74
+ }
75
+ const chunks = []
76
+ res.on('data', c => chunks.push(c))
77
+ res.on('end', () => resolve(Buffer.concat(chunks)))
78
+ }).on('error', reject)
79
+ })
80
+ }
81
+
82
+ function parseFrames(buffer) {
83
+ const frames = []
84
+ let remaining = buffer
85
+
86
+ if (remaining.startsWith(")]}'")) remaining = remaining.substring(4).trimStart()
87
+
88
+ while (true) {
89
+ const nl = remaining.indexOf('\n')
90
+ if (nl === -1) break
91
+
92
+ const sizeStr = remaining.substring(0, nl).trim()
93
+ const size = parseInt(sizeStr, 10)
94
+
95
+ if (isNaN(size)) {
96
+ remaining = remaining.substring(nl + 1)
97
+ continue
98
+ }
99
+
100
+ if (remaining.length < nl + size) break
101
+
102
+ const framePayload = remaining.substring(nl, nl + size)
103
+ remaining = remaining.substring(nl + size)
104
+
105
+ try {
106
+ const frameData = JSON.parse(framePayload)
107
+ for (const item of (Array.isArray(frameData) ? frameData : [frameData])) {
108
+ const innerStr = item?.[2]
109
+ if (!innerStr) continue
110
+ try { frames.push(JSON.parse(innerStr)) } catch (_) {}
111
+ }
112
+ } catch (_) {}
113
+ }
114
+
115
+ return { frames, remaining }
116
+ }
117
+
118
+ async function startSession(cookieStr = null) {
119
+ const cookies = {}
120
+
121
+ if (!cookieStr) {
122
+ try {
123
+ const fs = require('fs');
124
+ if (fs.existsSync('cookies.json')) {
125
+ const cookieData = JSON.parse(fs.readFileSync('cookies.json', 'utf8'));
126
+ if (cookieData && Array.isArray(cookieData.cookies)) {
127
+ cookieData.cookies.forEach(c => cookies[c.name] = c.value);
128
+ }
129
+ }
130
+ } catch (err) {
131
+ console.error('Failed to load cookies.json:', err.message);
132
+ }
133
+ } else {
134
+ for (const pair of cookieStr.split(';')) {
135
+ const idx = pair.indexOf('=')
136
+ if (idx > 0) cookies[pair.slice(0, idx).trim()] = pair.slice(idx + 1).trim()
137
+ }
138
+ }
139
+
140
+ const pageRes = await request('https://gemini.google.com/app', {
141
+ headers: {
142
+ 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
143
+ ...(Object.keys(cookies).length > 0 ? { 'cookie': buildCookieString(cookies) } : {})
144
+ }
145
+ })
146
+ syncCookies(cookies, pageRes.headers['set-cookie'])
147
+
148
+
149
+ const cfb2hMatch = pageRes.text.match(/"cfb2h":\s*"(.*?)"/)
150
+ const buildLabel = cfb2hMatch ? cfb2hMatch[1] : 'boq_assistant-bard-web-server_20260709.09_p0'
151
+
152
+ const atMatch = pageRes.text.match(/"SNlM0e":"([^"]+)"/)
153
+ const sidMatch = pageRes.text.match(/"FdrFJe":"(-?\d+)"/)
154
+ const atToken = atMatch ? atMatch[1] : null
155
+ const fSid = sidMatch ? sidMatch[1] : null
156
+
157
+ const batchRes = await request('https://gemini.google.com/_/BardChatUi/data/batchexecute?rpcids=maGuAc&source-path=%2F&hl=en-US&_reqid=1&rt=c', {
158
+ method: 'POST',
159
+ headers: {
160
+ 'content-type': 'application/x-www-form-urlencoded;charset=UTF-8',
161
+ 'cookie': buildCookieString(cookies)
162
+ },
163
+ body: 'f.req=[[["maGuAc","[0]",null,"generic"]]]&'
164
+ })
165
+ syncCookies(cookies, batchRes.headers['set-cookie'])
166
+
167
+ const sessionId = Array.from({ length: 19 }, () => Math.floor(Math.random() * 10)).join('')
168
+
169
+ return {
170
+ cookies,
171
+ buildLabel,
172
+ sessionId,
173
+ atToken,
174
+ fSid,
175
+ reqId: Math.floor(Math.random() * 90000) + 10000
176
+ }
177
+ }
178
+
179
+ function buildStreamRequest(prompt, tokens, metadata, auth, imageParam = null) {
180
+ const traceId = randomUUID().toUpperCase()
181
+ const queryParams = new URLSearchParams({ hl: 'en-US', _reqid: String(auth.reqId), rt: 'c' })
182
+ if (auth.buildLabel) queryParams.set('bl', auth.buildLabel)
183
+ if (auth.fSid) queryParams.set('f.sid', auth.fSid)
184
+ else if (auth.sessionId) queryParams.set('f.sid', auth.sessionId)
185
+
186
+ const payload = [
187
+ [prompt, 0, null, imageParam, null, null, 0], ['en-US'],
188
+ metadata, null, null, null, [1], 1, null, null, 1, 0, null, null, null, null, null, [[0]], 1,
189
+ null, null, null, null, null,
190
+ ['', '', '', null, null, null, null, null, 0, null, 1, null, null, null, []],
191
+ null, null, 1, null, null, null, null, null, null, null,
192
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
193
+ 1, null, null, null, null, [1]
194
+ ]
195
+
196
+ const bodyParams = new URLSearchParams({ 'f.req': JSON.stringify([null, JSON.stringify(payload)]) })
197
+ if (auth.atToken) bodyParams.set('at', auth.atToken)
198
+ const body = bodyParams.toString()
199
+
200
+ return {
201
+ url: `https://gemini.google.com/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate?${queryParams}`,
202
+ headers: {
203
+ 'content-type': 'application/x-www-form-urlencoded;charset=UTF-8',
204
+ 'x-goog-ext-525001261-jspb': '[1,null,null,null,"fbb127bbb056c959",null,null,0,[4,6],null,null,1,null,null,1]',
205
+ 'x-goog-ext-525005358-jspb': `["${traceId}",1]`,
206
+ 'x-goog-ext-73010989-jspb': '[0]',
207
+ 'x-goog-ext-73010990-jspb': '[0,0,0]',
208
+ 'x-same-domain': '1',
209
+ 'origin': 'https://gemini.google.com',
210
+ 'referer': 'https://gemini.google.com/',
211
+ 'cookie': buildCookieString(auth.cookies)
212
+ },
213
+ body
214
+ }
215
+ }
216
+
217
+ async function chat(prompt, auth = null, chatId = null, onChunk = null) {
218
+ auth = auth || await startSession()
219
+ auth.reqId = (auth.reqId || 10000) + 100000
220
+
221
+ let metadata = ['', '', '', null, null, null, null, null, null, '']
222
+ if (chatId) {
223
+ try {
224
+ metadata = typeof chatId === 'string' ? JSON.parse(chatId) : chatId
225
+ } catch (_) {}
226
+ }
227
+
228
+ const req = buildStreamRequest(prompt, null, metadata, auth)
229
+ const { res, headers: resHeaders } = await request(req.url, { method: 'POST', headers: req.headers, body: req.body, stream: true })
230
+
231
+ syncCookies(auth.cookies, resHeaders['set-cookie'])
232
+
233
+ return new Promise((resolve, reject) => {
234
+ let accumulatedText = ''
235
+ let lastSentText = ''
236
+ let buf = ''
237
+ let updatedMetadata = metadata
238
+
239
+ res.on('data', chunk => {
240
+ try {
241
+ buf += chunk.toString('utf8')
242
+ const { frames, remaining } = parseFrames(buf)
243
+ buf = remaining
244
+
245
+ for (const pj of frames) {
246
+ if (pj?.[1]) updatedMetadata = pj[1]
247
+ if (typeof pj?.[25] === 'string') updatedMetadata[9] = pj[25]
248
+ for (const cand of (pj?.[4] || [])) {
249
+ const cleaned = cleanText(cand?.[1]?.[0] || '')
250
+ if (cleaned) {
251
+ accumulatedText = cleaned
252
+ const delta = cleaned.substring(lastSentText.length)
253
+ if (delta && onChunk) {
254
+ onChunk(delta)
255
+ lastSentText = cleaned
256
+ }
257
+ }
258
+ }
259
+ }
260
+ } catch (err) { reject(err) }
261
+ })
262
+
263
+ res.on('end', () => {
264
+ const finalDelta = accumulatedText.substring(lastSentText.length)
265
+ if (finalDelta && onChunk) onChunk(finalDelta)
266
+ resolve({ reply: accumulatedText, chatId: updatedMetadata, auth })
267
+ })
268
+
269
+ res.on('error', reject)
270
+ })
271
+ }
272
+
273
+ async function uploadImage(filePath) {
274
+ const fileData = fs.readFileSync(filePath)
275
+ const fileName = filePath.split('/').pop()
276
+
277
+ const startHeaders = {
278
+ 'host': 'push.clients6.google.com',
279
+ 'x-goog-upload-protocol': 'resumable',
280
+ 'x-goog-upload-command': 'start',
281
+ 'x-goog-upload-header-content-length': String(fileData.length),
282
+ 'push-id': 'feeds/mcudyrk2a4khkz',
283
+ 'x-client-pctx': 'CgcSBWjK7pYx',
284
+ 'x-tenant-id': 'bard-storage',
285
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
286
+ 'origin': 'https://gemini.google.com',
287
+ 'referer': 'https://gemini.google.com/',
288
+ 'content-type': 'application/x-www-form-urlencoded;charset=UTF-8'
289
+ }
290
+ const startRes = await request('https://push.clients6.google.com/upload/', { method: 'POST', headers: startHeaders, body: `File name: ${fileName}` })
291
+ const uploadUrl = startRes.headers['x-goog-upload-url']
292
+
293
+ const uploadHeaders = {
294
+ 'host': 'push.clients6.google.com',
295
+ 'x-goog-upload-command': 'upload, finalize',
296
+ 'x-goog-upload-offset': '0',
297
+ 'x-tenant-id': 'bard-storage',
298
+ 'push-id': 'feeds/mcudyrk2a4khkz',
299
+ 'x-client-pctx': 'CgcSBWjK7pYx',
300
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
301
+ 'origin': 'https://gemini.google.com',
302
+ 'referer': 'https://gemini.google.com/',
303
+ 'content-length': String(fileData.length)
304
+ }
305
+ const uploadRes = await request(uploadUrl, { method: 'POST', headers: uploadHeaders, body: fileData })
306
+ return uploadRes.text.trim()
307
+ }
308
+
309
+ async function generateImageToImage(prompt, imagePath, auth = null, chatId = null, outputPath = 'output.png') {
310
+ auth = auth || await startSession()
311
+ auth.reqId = (auth.reqId || 10000) + 100000
312
+
313
+ const imgUrl = await uploadImage(imagePath)
314
+ const imageParam = [
315
+ [[imgUrl, 1], imagePath.split('/').pop()]
316
+ ]
317
+
318
+ let metadata = ['', '', '', null, null, null, null, null, null, '']
319
+ if (chatId) {
320
+ try {
321
+ metadata = typeof chatId === 'string' ? JSON.parse(chatId) : chatId
322
+ } catch (_) {}
323
+ }
324
+
325
+ const req = buildStreamRequest(prompt, null, metadata, auth, imageParam)
326
+ const { res, headers: resHeaders } = await request(req.url, { method: 'POST', headers: req.headers, body: req.body, stream: true })
327
+
328
+ syncCookies(auth.cookies, resHeaders['set-cookie'])
329
+
330
+ return new Promise((resolve, reject) => {
331
+ let rawText = ''
332
+ let fullRawText = ''
333
+ let buf = ''
334
+ let updatedMetadata = metadata
335
+
336
+ res.on('data', chunk => {
337
+ try {
338
+ const chunkStr = chunk.toString('utf8')
339
+ fullRawText += chunkStr
340
+ buf += chunkStr
341
+ const { frames, remaining } = parseFrames(buf)
342
+ buf = remaining
343
+
344
+ for (const pj of frames) {
345
+ if (pj?.[1]) updatedMetadata = pj[1]
346
+ if (typeof pj?.[25] === 'string') updatedMetadata[9] = pj[25]
347
+ for (const cand of (pj?.[4] || [])) {
348
+ const raw = cand?.[1]?.[0] || ''
349
+ if (raw) rawText += raw
350
+ }
351
+ }
352
+ } catch (err) { reject(err) }
353
+ })
354
+
355
+ res.on('end', async () => {
356
+ try {
357
+ const urlMatch = fullRawText.match(/https?:\/\/[a-z0-9.-]*googleusercontent\.com\/(?:rd-)?gg-dl\/[^\s\n"<>'\\]+/i)
358
+ if (!urlMatch) {
359
+ return resolve({ imageUrl: null, reply: cleanText(rawText), chatId: updatedMetadata, auth })
360
+ }
361
+
362
+ const imageUrl = urlMatch[0]
363
+ const imgBuf = await download(imageUrl, buildCookieString(auth.cookies))
364
+ fs.writeFileSync(outputPath, imgBuf)
365
+ resolve({ imageUrl, savedTo: outputPath, chatId: updatedMetadata, auth })
366
+ } catch (err) { reject(err) }
367
+ })
368
+
369
+ res.on('error', reject)
370
+ })
371
+ }
372
+
373
+ async function generateImage(prompt, auth = null, chatId = null, outputPath = 'output.png') {
374
+ auth = auth || await startSession()
375
+ auth.reqId = (auth.reqId || 10000) + 100000
376
+
377
+ let metadata = ['', '', '', null, null, null, null, null, null, '']
378
+ if (chatId) {
379
+ try {
380
+ metadata = typeof chatId === 'string' ? JSON.parse(chatId) : chatId
381
+ } catch (_) {}
382
+ }
383
+
384
+ const req = buildStreamRequest(prompt, null, metadata, auth)
385
+ const { res, headers: resHeaders } = await request(req.url, { method: 'POST', headers: req.headers, body: req.body, stream: true })
386
+
387
+ syncCookies(auth.cookies, resHeaders['set-cookie'])
388
+
389
+ return new Promise((resolve, reject) => {
390
+ let rawText = ''
391
+ let fullRawText = ''
392
+ let buf = ''
393
+ let updatedMetadata = metadata
394
+
395
+ res.on('data', chunk => {
396
+ try {
397
+ const chunkStr = chunk.toString('utf8')
398
+ fullRawText += chunkStr
399
+ buf += chunkStr
400
+ const { frames, remaining } = parseFrames(buf)
401
+ buf = remaining
402
+
403
+ for (const pj of frames) {
404
+ if (pj?.[1]) updatedMetadata = pj[1]
405
+ if (typeof pj?.[25] === 'string') updatedMetadata[9] = pj[25]
406
+ for (const cand of (pj?.[4] || [])) {
407
+ const raw = cand?.[1]?.[0] || ''
408
+ if (raw) rawText += raw
409
+ }
410
+
411
+ }
412
+ } catch (err) { reject(err) }
413
+ })
414
+
415
+ res.on('end', async () => {
416
+ try {
417
+ const urlMatch = fullRawText.match(/https?:\/\/[a-z0-9.-]*googleusercontent\.com\/(?:rd-)?gg-dl\/[^\s\n"<>'\\]+/i)
418
+ if (!urlMatch) {
419
+ return resolve({ imageUrl: null, reply: cleanText(rawText), chatId: updatedMetadata, auth })
420
+ }
421
+
422
+ const imageUrl = urlMatch[0]
423
+ const imgBuf = await download(imageUrl, buildCookieString(auth.cookies))
424
+ fs.writeFileSync(outputPath, imgBuf)
425
+ resolve({ imageUrl, savedTo: outputPath, chatId: updatedMetadata, auth })
426
+ } catch (err) { reject(err) }
427
+ })
428
+
429
+ res.on('error', reject)
430
+ })
431
+ }
432
+
433
+ module.exports = { startSession, chat, generateImage, generateImageToImage, buildCookieString, uploadImage }
@@ -0,0 +1,75 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ // Konfigurasi
5
+ const GROUP_FILE = './database/groups.json'; // Sesuaikan path
6
+
7
+ function loadGroupList() {
8
+ try {
9
+ const fileExists = fs.existsSync(GROUP_FILE);
10
+
11
+ if (!fileExists) {
12
+ const dbDir = path.dirname(GROUP_FILE);
13
+
14
+ if (!fs.existsSync(dbDir)) {
15
+ fs.mkdirSync(dbDir, { recursive: true });
16
+ }
17
+
18
+ const defaultData = JSON.stringify({ groups: [] }, null, 2);
19
+ fs.writeFileSync(GROUP_FILE, defaultData);
20
+ return [];
21
+ }
22
+ const data = fs.readFileSync(GROUP_FILE, 'utf8');
23
+ const parsed = JSON.parse(data);
24
+
25
+ if (parsed && parsed.groups && Array.isArray(parsed.groups)) {
26
+ return parsed.groups;
27
+ }
28
+
29
+ fs.writeFileSync(GROUP_FILE, JSON.stringify({ groups: [] }, null, 2));
30
+
31
+ return [];
32
+
33
+ } catch (e) {
34
+ try {
35
+ fs.writeFileSync(GROUP_FILE, JSON.stringify({ groups: [] }, null, 2));
36
+ } catch (err) {
37
+ }
38
+ return [];
39
+ }
40
+ }
41
+
42
+ function saveGroupList(list) {
43
+ try {
44
+ console.log(`📊 [saveGroupList] List yang akan disimpan:`, list);
45
+
46
+ if (!Array.isArray(list)) {
47
+ list = [];
48
+ }
49
+
50
+ const dbDir = path.dirname(GROUP_FILE);
51
+ console.log(`📁 [saveGroupList] Directory: ${dbDir}`);
52
+
53
+ if (!fs.existsSync(dbDir)) {
54
+ console.log(`📁 [saveGroupList] Membuat directory: ${dbDir}`);
55
+ fs.mkdirSync(dbDir, { recursive: true });
56
+ }
57
+
58
+ const dataToSave = JSON.stringify({ groups: list }, null, 2);
59
+ fs.writeFileSync(GROUP_FILE, dataToSave);
60
+ console.log(`💾 [saveGroupList] Data tersimpan:`, dataToSave);
61
+ console.log(`✅ [saveGroupList] Berhasil menyimpan ${list.length} grup`);
62
+ return true;
63
+
64
+ } catch (e) {
65
+ console.log(`❌ [saveGroupList] ERROR:`, e.message);
66
+ console.log(`❌ [saveGroupList] Stack:`, e.stack);
67
+ return false;
68
+ }
69
+ }
70
+
71
+ // Ekspor fungsi
72
+ module.exports = {
73
+ loadGroupList,
74
+ saveGroupList
75
+ };