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/package.json CHANGED
@@ -1,6 +1,62 @@
1
1
  {
2
- "name": "satanic-release",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
2
+ "name": "satanic-release",
3
+ "version": "v2.4.0",
4
+ "description": "Multi-Device",
5
+ "main": "index.js",
6
+ "type": "commonjs",
7
+ "scripts": {
8
+ "start": "node index.js"
9
+ },
10
+ "keywords": [
11
+ "whiskeysockets",
12
+ "multi-device"
13
+ ],
14
+ "author": "Satanic Project",
15
+ "license": "MIT",
16
+ "dependencies": {
17
+ "@adiwajshing/keyed-db": "^0.2.4",
18
+ "@ffmpeg-installer/ffmpeg": "^1.1.0",
19
+ "@hapi/boom": "^10.0.1",
20
+ "@napi-rs/canvas": "^1.0.6",
21
+ "anita-baileys": "npm:anitabaileys@^9.11.22",
22
+ "anitabaileys": "npm:anitabaileys@^9.0.22",
23
+ "awesome-phonenumber": "^5.9.0",
24
+ "axios": "^1.18.1",
25
+ "cfonts": "^3.3.0",
26
+ "chalk": "^4.1.2",
27
+ "cheerio": "^1.2.0",
28
+ "child_process": "^1.0.2",
29
+ "colors": "latest",
30
+ "crypto": "^1.0.1",
31
+ "crypto-js": "^4.2.0",
32
+ "cycletls": "^2.0.5",
33
+ "didyoumean": "^1.2.2",
34
+ "file-type": "^16.5.3",
35
+ "fluent-ffmpeg": "^2.1.2",
36
+ "form-data": "^4.0.0",
37
+ "fs": "^0.0.1-security",
38
+ "human-readable": "^0.2.1",
39
+ "jimp": "^0.16.1",
40
+ "jszip": "^3.10.1",
41
+ "libphonenumber-js": "^1.13.14",
42
+ "moment-timezone": "^0.5.43",
43
+ "ms": "^2.1.3",
44
+ "node-cron": "^3.0.0",
45
+ "node-fetch": "^2.7.0",
46
+ "node-webpmux": "^3.1.1",
47
+ "os": "^0.1.2",
48
+ "path": "^0.12.7",
49
+ "performance-now": "^2.1.0",
50
+ "pino": "^8.14.1",
51
+ "request": "^2.88.2",
52
+ "rimraf": "^3.0.2",
53
+ "scrape-primbon": "^1.1.0",
54
+ "sharp": "^0.32.6",
55
+ "similarity": "^1.2.1",
56
+ "skia-canvas": "^3.0.8",
57
+ "stream": "^0.0.3",
58
+ "twemoji": "^14.0.2",
59
+ "util": "^0.12.4",
60
+ "yt-search": "^2.12.1"
61
+ }
62
+ }
package/plugins/crm.js ADDED
@@ -0,0 +1,309 @@
1
+ // plugins/crm.js
2
+ const fs = require('fs')
3
+ const path = require('path')
4
+ const { generateWAMessageFromContent } = require('@whiskeysockets/baileys')
5
+
6
+ function unwrap(content) {
7
+ if (!content || typeof content !== 'object') return content
8
+ if (content.ephemeralMessage?.message) return unwrap(content.ephemeralMessage.message)
9
+ if (content.viewOnceMessage?.message) return unwrap(content.viewOnceMessage.message)
10
+ if (content.viewOnceMessageV2?.message) return unwrap(content.viewOnceMessageV2.message)
11
+ if (content.viewOnceMessageV2Extension?.message) return unwrap(content.viewOnceMessageV2Extension.message)
12
+ if (content.documentWithCaptionMessage?.message) return unwrap(content.documentWithCaptionMessage.message)
13
+ return content
14
+ }
15
+
16
+ function normalizeForRelay(rawContent) {
17
+ const content = unwrap(rawContent)
18
+ if (typeof content?.conversation === 'string') {
19
+ const { conversation, ...rest } = content
20
+ return { ...rest, extendedTextMessage: { text: conversation } }
21
+ }
22
+ return content
23
+ }
24
+
25
+ function toJsLiteral(value, indent = 2, seen = new WeakSet(), depth = 0) {
26
+ if (value === null) return 'null'
27
+ if (value === undefined) return 'undefined'
28
+ if (typeof value === 'string') return JSON.stringify(value)
29
+ if (typeof value === 'number' || typeof value === 'boolean') return String(value)
30
+ if (typeof value === 'bigint') return value.toString()
31
+ if (Buffer.isBuffer(value) || value instanceof Uint8Array) {
32
+ return JSON.stringify(Buffer.from(value).toString('base64'))
33
+ }
34
+ if (typeof value !== 'object') return JSON.stringify(value)
35
+ if (depth > 40) return '"[MaxDepth]"'
36
+ if (seen.has(value)) return '"[Circular]"'
37
+ seen.add(value)
38
+ const pad = ' '.repeat(indent)
39
+ const padClose = ' '.repeat(Math.max(indent - 2, 0))
40
+ let result
41
+ if (Array.isArray(value)) {
42
+ if (!value.length) {
43
+ result = '[]'
44
+ } else {
45
+ const items = value.map((v) => pad + toJsLiteral(v, indent + 2, seen, depth + 1))
46
+ result = `[\n${items.join(',\n')}\n${padClose}]`
47
+ }
48
+ } else {
49
+ const keys = Object.keys(value).filter((k) => typeof value[k] !== 'function' && value[k] !== undefined)
50
+ if (!keys.length) {
51
+ result = '{}'
52
+ } else {
53
+ const lines = keys.map((k) => {
54
+ const keyStr = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(k) ? k : JSON.stringify(k)
55
+ return `${pad}${keyStr}: ${toJsLiteral(value[k], indent + 2, seen, depth + 1)}`
56
+ })
57
+ result = `{\n${lines.join(',\n')}\n${padClose}}`
58
+ }
59
+ }
60
+ seen.delete(value)
61
+ return result
62
+ }
63
+
64
+ const FRAMEWORK_DECORATED_KEYS = new Set([
65
+ 'mtype', 'id', 'chat', 'isBaileys', 'sender', 'fromMe', 'mentionedJid',
66
+ 'fakeObj', 'delete', 'copyNForward', 'download', 'key', 'participant',
67
+ 'text', 'body', 'name', 'pushName', 'viewonce', 'download1',
68
+ ])
69
+
70
+ function stripFrameworkProps(content) {
71
+ if (!content || typeof content !== 'object') return content
72
+ const out = {}
73
+ for (const k of Object.keys(content)) {
74
+ if (FRAMEWORK_DECORATED_KEYS.has(k)) continue
75
+ if (typeof content[k] === 'function') continue
76
+ out[k] = content[k]
77
+ }
78
+ return out
79
+ }
80
+
81
+ function buildReadableSendCode(content) {
82
+ try {
83
+ const clean = stripFrameworkProps(content)
84
+ return `satanic.relayMessage(\n m.chat,\n ${toJsLiteral(clean)},\n {}\n)`
85
+ } catch (err) {
86
+ return `// Gagal generate relay_code: ${err?.message || err}`
87
+ }
88
+ }
89
+
90
+ function typeNameFromContent(content) {
91
+ const clean = stripFrameworkProps(content)
92
+ const key = Object.keys(clean)[0] || 'UnknownMessage'
93
+ return key.charAt(0).toUpperCase() + key.slice(1)
94
+ }
95
+
96
+ function buildRelayCodeFile(rawQuotedContent) {
97
+ const dir = path.join(process.cwd(), 'debug')
98
+ if (!fs.existsSync(dir)) {
99
+ fs.mkdirSync(dir, { recursive: true })
100
+ }
101
+ const typeName = typeNameFromContent(rawQuotedContent)
102
+ const filename = `${typeName}.js`
103
+ const filepath = path.join(dir, filename)
104
+ const code = buildReadableSendCode(rawQuotedContent)
105
+ fs.writeFileSync(filepath, code, 'utf-8')
106
+ return { filepath, filename }
107
+ }
108
+
109
+ let handler = async (m, { satanic, text, command, prefix, isCreator }) => {
110
+ const from = m.chat
111
+
112
+ if (!isCreator) {
113
+ return m.reply('❌ Fitur khusus owner/pemilik saja ya kak~ 🌸')
114
+ }
115
+
116
+ if (!m.quoted) {
117
+ return m.reply(
118
+ `⚠️ *Cara penggunaan:*\n\n` +
119
+ `Reply pesan yang mau di-relay, lalu kirim *${prefix}${command}*\n\n` +
120
+ `📌 Contoh: Reply pesan button/list/location lalu ketik ${prefix}crm\n\n` +
121
+ `📌 Mode:\n` +
122
+ `• ${prefix}crm - Mode JSON (file relay.js)\n` +
123
+ `• ${prefix}crm2 - Mode JS (file ${typeNameFromContent}.js)`
124
+ )
125
+ }
126
+
127
+ function crmHasViewOnce(obj, visited = new WeakSet()) {
128
+ if (!obj || typeof obj !== 'object') return false
129
+ if (visited.has(obj)) return false
130
+ visited.add(obj)
131
+ if (
132
+ obj.viewOnceMessage ||
133
+ obj.viewOnceMessageV2 ||
134
+ obj.viewOnceMessageV2Extension
135
+ ) {
136
+ return true
137
+ }
138
+ for (const value of Object.values(obj)) {
139
+ if (crmHasViewOnce(value, visited)) {
140
+ return true
141
+ }
142
+ }
143
+ return false
144
+ }
145
+
146
+ if (crmHasViewOnce(m.quoted)) {
147
+ return m.reply('❌ Pesan view-once tidak bisa disimpan.')
148
+ }
149
+
150
+ try {
151
+ const quotedMsg = m.quoted
152
+ const rawQuoted = quotedMsg.message || quotedMsg.msg || m.msg?.contextInfo?.quotedMessage
153
+
154
+ if (!rawQuoted || typeof rawQuoted !== 'object' || !Object.keys(rawQuoted).length) {
155
+ return m.reply('❌ Tidak ada pesan yang bisa di-relay.')
156
+ }
157
+
158
+ const unwrapped = unwrap(rawQuoted)
159
+
160
+ if (!unwrapped || typeof unwrapped !== 'object' || !Object.keys(unwrapped).length) {
161
+ return m.reply('❌ Jenis pesan ini belum didukung untuk di-relay.')
162
+ }
163
+
164
+ let fullData = {}
165
+ let messageType = 'unknown'
166
+ let hasButtons = false
167
+ let buttonData = null
168
+ let locationData = null
169
+
170
+ if (quotedMsg.quoted) {
171
+ fullData = quotedMsg.quoted
172
+ messageType = fullData.mtype || 'unknown'
173
+ if (fullData.buttonsMessage) {
174
+ hasButtons = true
175
+ buttonData = fullData.buttonsMessage
176
+ if (buttonData.locationMessage) {
177
+ locationData = buttonData.locationMessage
178
+ }
179
+ }
180
+ } else if (quotedMsg.message) {
181
+ fullData = quotedMsg.message
182
+ const keys = Object.keys(fullData)
183
+ if (keys.length > 0) {
184
+ messageType = keys[0]
185
+ if (messageType === 'buttonsMessage') {
186
+ hasButtons = true
187
+ buttonData = fullData[messageType]
188
+ if (buttonData.locationMessage) {
189
+ locationData = buttonData.locationMessage
190
+ }
191
+ }
192
+ }
193
+ } else if (quotedMsg.msg) {
194
+ fullData = quotedMsg.msg
195
+ const keys = Object.keys(fullData)
196
+ if (keys.length > 0) {
197
+ messageType = keys[0]
198
+ if (messageType === 'buttonsMessage') {
199
+ hasButtons = true
200
+ buttonData = fullData[messageType]
201
+ if (buttonData.locationMessage) {
202
+ locationData = buttonData.locationMessage
203
+ }
204
+ }
205
+ }
206
+ }
207
+
208
+ const isCrm2 = command === 'crm2'
209
+
210
+ if (isCrm2) {
211
+ const relayContent = normalizeForRelay(rawQuoted)
212
+ const relayMsg = generateWAMessageFromContent(m.chat, relayContent, {
213
+ userJid: satanic.user.id,
214
+ quoted: m,
215
+ })
216
+ await satanic.relayMessage(relayMsg.key.remoteJid, relayMsg.message, {
217
+ messageId: relayMsg.key.id,
218
+ })
219
+ const { filepath, filename } = buildRelayCodeFile(unwrapped)
220
+ await satanic.sendMessage(
221
+ m.chat,
222
+ {
223
+ document: fs.readFileSync(filepath),
224
+ fileName: filename,
225
+ mimetype: 'text/javascript',
226
+ caption: `✅ *Relay berhasil (CRM2)*\n\n📄 ${filename}\n📝 Tipe: ${typeNameFromContent(unwrapped)}`
227
+ },
228
+ { quoted: m }
229
+ )
230
+ } else {
231
+ const crmPayload = {
232
+ key: quotedMsg.key || {},
233
+ sender: quotedMsg.sender || m.sender,
234
+ timestamp: quotedMsg.timestamp || Date.now(),
235
+ text: quotedMsg.text || quotedMsg.body || '',
236
+ caption: quotedMsg.caption || '',
237
+ type: messageType,
238
+ hasButtons: hasButtons,
239
+ hasLocation: !!locationData,
240
+ fullData: fullData,
241
+ buttonData: buttonData,
242
+ locationData: locationData,
243
+ rawMessage: fullData
244
+ }
245
+
246
+ const crmData = {
247
+ type: 'satanic-crm-relay',
248
+ version: 2,
249
+ createdAt: new Date().toISOString(),
250
+ creator: global.config?.botname || 'Rinn MD',
251
+ payload: crmPayload
252
+ }
253
+
254
+ const crmCode = `module.exports = ${JSON.stringify(crmData, null, 2)};\n`
255
+
256
+ let infoText = `✅ *CRM berhasil dibuat (JSON)*\n\n`
257
+ infoText += `📝 Tipe: ${messageType}\n`
258
+ infoText += `🔘 Button: ${hasButtons ? '✅ Ada' : '❌ Tidak'}\n`
259
+ if (locationData) {
260
+ infoText += `📍 Location: ${locationData.name || 'Ada'}\n`
261
+ }
262
+ infoText += `📅 Waktu: ${crmData.createdAt}\n\n`
263
+ infoText += `Reply file ini lalu kirim:\n`
264
+ infoText += `*${prefix}runcrm*`
265
+
266
+ await satanic.sendMessage(
267
+ m.chat,
268
+ {
269
+ document: Buffer.from(crmCode),
270
+ mimetype: 'application/javascript',
271
+ fileName: 'relay.js',
272
+ caption: infoText
273
+ },
274
+ { quoted: m }
275
+ )
276
+ }
277
+
278
+ await satanic.sendMessage(from, {
279
+ react: {
280
+ text: '✅',
281
+ key: m.key
282
+ }
283
+ })
284
+
285
+ } catch (e) {
286
+ console.error('CRM ERROR:', e)
287
+ try {
288
+ if (typeof global.sendAdminLog === 'function') {
289
+ await global.sendAdminLog(
290
+ satanic,
291
+ 'crm',
292
+ m.sender?.split('@')[0] || m.sender,
293
+ e
294
+ )
295
+ }
296
+ } catch {}
297
+ return m.reply(
298
+ '❌ Gagal membuat CRM.\n\n' +
299
+ (e?.message || String(e))
300
+ )
301
+ }
302
+ }
303
+
304
+ handler.help = ['crm', 'crm2']
305
+ handler.tags = ['owner']
306
+ handler.command = /^(crm|crm2)$/i
307
+ handler.owner = true
308
+
309
+ module.exports = handler
@@ -0,0 +1,166 @@
1
+ const axios = require('axios');
2
+ const cheerio = require('cheerio');
3
+
4
+ class DouyinSearch {
5
+ constructor() {
6
+ this.baseURL = 'https://so.douyin.com/';
7
+ this.defaultParams = {
8
+ search_entrance: 'aweme',
9
+ enter_method: 'normal_search',
10
+ innerWidth: '431',
11
+ innerHeight: '814',
12
+ reloadNavStart: String(Date.now()),
13
+ is_no_width_reload: '1',
14
+ keyword: '',
15
+ };
16
+ this.cookies = {};
17
+ this.api = axios.create({
18
+ baseURL: this.baseURL,
19
+ headers: {
20
+ accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
21
+ 'accept-language': 'id-ID,id;q=0.9',
22
+ referer: 'https://so.douyin.com/',
23
+ 'upgrade-insecure-requests': '1',
24
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Mobile Safari/537.36',
25
+ },
26
+ });
27
+
28
+ this.api.interceptors.response.use((res) => {
29
+ const setCookies = res.headers['set-cookie'];
30
+ if (setCookies) {
31
+ setCookies.forEach((c) => {
32
+ const [name, value] = c.split(';')[0].split('=');
33
+ if (name && value) this.cookies[name] = value;
34
+ });
35
+ }
36
+ return res;
37
+ });
38
+
39
+ this.api.interceptors.request.use((config) => {
40
+ if (Object.keys(this.cookies).length) {
41
+ config.headers['Cookie'] = Object.entries(this.cookies)
42
+ .map(([k, v]) => `${k}=${v}`)
43
+ .join('; ');
44
+ }
45
+ return config;
46
+ });
47
+ }
48
+
49
+ async initialize() {
50
+ try {
51
+ await this.api.get('/');
52
+ return true;
53
+ } catch (error) {
54
+ console.error('Initialize error:', error.message);
55
+ return false;
56
+ }
57
+ }
58
+
59
+ async search({ query }) {
60
+ try {
61
+ await this.initialize();
62
+
63
+ const params = {
64
+ ...this.defaultParams,
65
+ keyword: query,
66
+ reloadNavStart: String(Date.now()),
67
+ };
68
+
69
+ const res = await this.api.get('s', { params });
70
+ const html = res.data;
71
+ const $ = cheerio.load(html);
72
+
73
+ let scriptWithData = '';
74
+ $('script').each((_, el) => {
75
+ const text = $(el).html();
76
+ if (text.includes('let data =') && text.includes('"business_data":')) {
77
+ scriptWithData = text;
78
+ }
79
+ });
80
+
81
+ if (!scriptWithData) {
82
+ throw new Error('Script containing data not found.');
83
+ }
84
+
85
+ const match = scriptWithData.match(/let\s+data\s*=\s*(\{[\s\S]+?\});/);
86
+ if (!match) {
87
+ throw new Error('Unable to match data object.');
88
+ }
89
+
90
+ let fullData;
91
+ try {
92
+ fullData = new Function(`${match[0]}; return data`)();
93
+ } catch (e) {
94
+ throw new Error('Failed to evaluate Douyin data: ' + e.message);
95
+ }
96
+
97
+ const awemeInfos = fullData?.business_data
98
+ ?.map((entry) => entry?.data?.aweme_info)
99
+ .filter(Boolean) || [];
100
+
101
+ return awemeInfos;
102
+
103
+ } catch (error) {
104
+ console.error('Search error:', error.message);
105
+ throw error;
106
+ }
107
+ }
108
+ }
109
+
110
+ let handler = async (m, { satanic, text, prefix, command }) => {
111
+ if (!text) return m.reply(`Contoh: ${prefix + command} kata kunci`);
112
+
113
+ await satanic.sendMessage(m.chat, {
114
+ react: { text: '⏳', key: m.key },
115
+ });
116
+
117
+ try {
118
+ const client = new DouyinSearch();
119
+ const results = await client.search({ query: text });
120
+
121
+ if (!results || !results.length) {
122
+ await satanic.sendMessage(m.chat, {
123
+ react: { text: '❌', key: m.key },
124
+ });
125
+ return m.reply('Tidak ditemukan.');
126
+ }
127
+
128
+ const first = results[0];
129
+ const videoUrl = first.video?.play_addr?.url_list?.[0];
130
+ const caption = `${first.desc || 'Tanpa deskripsi'}\nhttps://www.douyin.com/video/${first.aweme_id}`;
131
+
132
+ if (!videoUrl) {
133
+ await satanic.sendMessage(m.chat, {
134
+ react: { text: '⚠️', key: m.key },
135
+ });
136
+ return m.reply('Video tidak tersedia.');
137
+ }
138
+
139
+ await satanic.sendMessage(m.chat, {
140
+ react: { text: '✅', key: m.key },
141
+ });
142
+
143
+ await satanic.sendMessage(
144
+ m.chat,
145
+ {
146
+ video: { url: videoUrl },
147
+ caption: caption,
148
+ },
149
+ { quoted: m }
150
+ );
151
+
152
+ } catch (err) {
153
+ console.error('Error:', err);
154
+ await satanic.sendMessage(m.chat, {
155
+ react: { text: '⚠️', key: m.key },
156
+ });
157
+ m.reply('Gagal mengambil data:\n' + err.message);
158
+ }
159
+ }
160
+
161
+ handler.help = ['douyinsearch <query>'];
162
+ handler.tags = ['download'];
163
+ handler.command = /^douyinsearch$/i;
164
+ handler.limit = true;
165
+
166
+ module.exports = handler;
@@ -0,0 +1,124 @@
1
+ // plugins/runcrm.js
2
+ const fs = require('fs')
3
+ const path = require('path')
4
+
5
+ let handler = async (m, { satanic, text, command, prefix, isCreator }) => {
6
+ const from = m.chat
7
+
8
+ if (!isCreator) {
9
+ return m.reply('❌ Fitur khusus owner/pemilik saja ya kak~ 🌸')
10
+ }
11
+
12
+ if (!m.quoted) {
13
+ return m.reply(
14
+ `⚠️ *Cara penggunaan:*\n\n` +
15
+ `Reply ke file *relay.js* yang sudah dibuat, lalu kirim *${prefix}${command}*\n\n` +
16
+ `📌 Contoh: Reply file relay.js lalu ketik ${prefix}runcrm`
17
+ )
18
+ }
19
+
20
+ const quotedMsg = m.quoted
21
+
22
+ const isDocument = quotedMsg.mimetype === 'application/javascript' ||
23
+ quotedMsg.fileName === 'relay.js' ||
24
+ quotedMsg.documentMessage ||
25
+ quotedMsg.msg?.documentMessage
26
+
27
+ if (!isDocument) {
28
+ return m.reply(
29
+ `❌ Bukan file yang valid!\n\n` +
30
+ `📌 Reply ke file *relay.js* yang dikirim bot`
31
+ )
32
+ }
33
+
34
+ try {
35
+ const media = await satanic.downloadMediaMessage(m.quoted)
36
+ if (!media) {
37
+ return m.reply('❌ Gagal mendownload file')
38
+ }
39
+
40
+ const fileContent = media.toString('utf8')
41
+ let crmData
42
+
43
+ try {
44
+ const tempFile = path.join(process.cwd(), 'temp', `crm_${Date.now()}.js`)
45
+
46
+ if (!fs.existsSync(path.join(process.cwd(), 'temp'))) {
47
+ fs.mkdirSync(path.join(process.cwd(), 'temp'), { recursive: true })
48
+ }
49
+
50
+ fs.writeFileSync(tempFile, fileContent)
51
+
52
+ const loadedData = require(tempFile)
53
+ crmData = loadedData
54
+
55
+ fs.unlinkSync(tempFile)
56
+
57
+ } catch (e) {
58
+ return m.reply(`❌ Gagal parsing CRM:\n${e.message}`)
59
+ }
60
+
61
+ if (!crmData || !crmData.payload) {
62
+ return m.reply('❌ CRM tidak valid atau payload kosong')
63
+ }
64
+
65
+ const payload = crmData.payload
66
+
67
+ if (payload.hasButtons && payload.buttonData) {
68
+ const buttonMsg = {
69
+ text: payload.buttonData.contentText || payload.text || '',
70
+ footer: payload.buttonData.footerText || '',
71
+ buttons: payload.buttonData.buttons || [],
72
+ headerType: payload.buttonData.headerType || 6
73
+ }
74
+ if (payload.locationData) {
75
+ buttonMsg.location = payload.locationData
76
+ }
77
+ await satanic.sendMessage(from, buttonMsg, {
78
+ quoted: m
79
+ })
80
+ } else if (payload.rawMessage && Object.keys(payload.rawMessage).length > 0) {
81
+ await satanic.sendMessage(from, payload.rawMessage, {
82
+ quoted: m
83
+ })
84
+ } else if (payload.text) {
85
+ await satanic.sendMessage(from, { text: payload.text }, { quoted: m })
86
+ } else {
87
+ return m.reply('❌ Tidak ada konten yang bisa dikirim dari CRM')
88
+ }
89
+
90
+ await satanic.sendMessage(from, {
91
+ react: {
92
+ text: '✅',
93
+ key: m.key
94
+ }
95
+ })
96
+
97
+ let infoText = `✅ *CRM berhasil dijalankan*\n\n`
98
+ infoText += `📅 Dibuat: ${crmData.createdAt || 'Tidak diketahui'}\n`
99
+ infoText += `👤 Creator: ${crmData.creator || 'Tidak diketahui'}\n`
100
+ infoText += `📝 Tipe: ${payload.type || 'Tidak diketahui'}\n`
101
+ infoText += `🔘 Button: ${payload.hasButtons ? '✅ Ada' : '❌ Tidak'}\n`
102
+ if (payload.hasLocation) {
103
+ infoText += `📍 Location: ✅ Ada\n`
104
+ }
105
+
106
+ await satanic.sendMessage(from, {
107
+ text: infoText
108
+ }, { quoted: m })
109
+
110
+ } catch (e) {
111
+ console.error('RUNCRM ERROR:', e)
112
+ return m.reply(
113
+ '❌ Gagal menjalankan CRM.\n\n' +
114
+ (e?.message || String(e))
115
+ )
116
+ }
117
+ }
118
+
119
+ handler.help = ['runcrm']
120
+ handler.tags = ['owner']
121
+ handler.command = /^(runcrm)$/i
122
+ handler.owner = true
123
+
124
+ module.exports = handler