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.
- package/RUN NODE 20 - 21 +0 -0
- package/assets/fishing/LICENSE.txt +1 -0
- package/assets/fishing/SOURCES.md +8 -0
- package/assets/fishing/angler.svg +16 -0
- package/assets/fishing/background.svg +1 -0
- package/assets/fishing/bait.svg +1 -0
- package/assets/fishing/birds.svg +1 -0
- package/assets/fishing/boat.svg +1 -0
- package/assets/fishing/bobber.svg +1 -0
- package/assets/fishing/cloud.svg +1 -0
- package/assets/fishing/coin.svg +1 -0
- package/assets/fishing/coral.svg +1 -0
- package/assets/fishing/crate.svg +1 -0
- package/assets/fishing/fish-bass.svg +1 -0
- package/assets/fishing/fish-catfish.svg +1 -0
- package/assets/fishing/fish-koi.svg +1 -0
- package/assets/fishing/fish-perch.svg +1 -0
- package/assets/fishing/fish-trout.svg +1 -0
- package/assets/fishing/hook.svg +1 -0
- package/assets/fishing/lilypad.svg +1 -0
- package/assets/fishing/manifest.json +48 -0
- package/assets/fishing/net.svg +1 -0
- package/assets/fishing/reeds.svg +1 -0
- package/assets/fishing/rod.svg +1 -0
- package/assets/fishing/spark.svg +1 -0
- package/assets/fishing/splash.svg +5 -0
- package/assets/fishing/watergrass.svg +1 -0
- package/assets/fonts/qiro-nulis.ttf +0 -0
- package/assets/rpg/CC0_SOURCES.txt +23 -0
- package/assets/rpg/cc0/SOURCES.md +18 -0
- package/assets/rpg/items/antidote.svg +1 -0
- package/assets/rpg/items/armor.svg +1 -0
- package/assets/rpg/items/axe.svg +1 -0
- package/assets/rpg/items/bag.svg +1 -0
- package/assets/rpg/items/bear.svg +1 -0
- package/assets/rpg/items/boar.svg +1 -0
- package/assets/rpg/items/book.svg +1 -0
- package/assets/rpg/items/bow.svg +1 -0
- package/assets/rpg/items/car.svg +1 -0
- package/assets/rpg/items/cherry.svg +1 -0
- package/assets/rpg/items/chest.svg +1 -0
- package/assets/rpg/items/coal.svg +1 -0
- package/assets/rpg/items/coin.svg +1 -0
- package/assets/rpg/items/compass.svg +1 -0
- package/assets/rpg/items/crate.svg +1 -0
- package/assets/rpg/items/deer.svg +1 -0
- package/assets/rpg/items/demon.svg +1 -0
- package/assets/rpg/items/diamond.svg +5 -0
- package/assets/rpg/items/diamondchest.svg +1 -0
- package/assets/rpg/items/dice.svg +1 -0
- package/assets/rpg/items/dice1.svg +1 -0
- package/assets/rpg/items/dice2.svg +1 -0
- package/assets/rpg/items/dice3.svg +1 -0
- package/assets/rpg/items/dice4.svg +1 -0
- package/assets/rpg/items/dice5.svg +1 -0
- package/assets/rpg/items/dice6.svg +1 -0
- package/assets/rpg/items/dragon.svg +1 -0
- package/assets/rpg/items/dumbbell.svg +1 -0
- package/assets/rpg/items/egg.svg +1 -0
- package/assets/rpg/items/elixir.svg +1 -0
- package/assets/rpg/items/emerald.svg +1 -0
- package/assets/rpg/items/fish.svg +1 -0
- package/assets/rpg/items/fishingrod.svg +1 -0
- package/assets/rpg/items/flower.svg +1 -0
- package/assets/rpg/items/food.svg +1 -0
- package/assets/rpg/items/fox.svg +1 -0
- package/assets/rpg/items/frost.svg +1 -0
- package/assets/rpg/items/gold.svg +1 -0
- package/assets/rpg/items/goldchest.svg +1 -0
- package/assets/rpg/items/grape.svg +1 -0
- package/assets/rpg/items/hammer.svg +1 -0
- package/assets/rpg/items/helmet.svg +1 -0
- package/assets/rpg/items/herb.svg +1 -0
- package/assets/rpg/items/house.svg +1 -0
- package/assets/rpg/items/iron.svg +1 -0
- package/assets/rpg/items/key.svg +1 -0
- package/assets/rpg/items/kraken.svg +1 -0
- package/assets/rpg/items/kunai.svg +1 -0
- package/assets/rpg/items/leather.svg +1 -0
- package/assets/rpg/items/lemon.svg +1 -0
- package/assets/rpg/items/lion.svg +1 -0
- package/assets/rpg/items/map.svg +1 -0
- package/assets/rpg/items/meat.svg +1 -0
- package/assets/rpg/items/mpotion.svg +1 -0
- package/assets/rpg/items/octopus.svg +1 -0
- package/assets/rpg/items/orange.svg +1 -0
- package/assets/rpg/items/ore.svg +1 -0
- package/assets/rpg/items/parking.svg +1 -0
- package/assets/rpg/items/pearl.svg +1 -0
- package/assets/rpg/items/pet.svg +1 -0
- package/assets/rpg/items/pickaxe.svg +1 -0
- package/assets/rpg/items/potion.svg +1 -0
- package/assets/rpg/items/prawn.svg +1 -0
- package/assets/rpg/items/rabbit.svg +1 -0
- package/assets/rpg/items/ramen.svg +1 -0
- package/assets/rpg/items/rice.svg +1 -0
- package/assets/rpg/items/rock.svg +1 -0
- package/assets/rpg/items/scroll.svg +1 -0
- package/assets/rpg/items/seven.svg +1 -0
- package/assets/rpg/items/shark.svg +1 -0
- package/assets/rpg/items/shield.svg +1 -0
- package/assets/rpg/items/shuriken.svg +1 -0
- package/assets/rpg/items/slot.svg +1 -0
- package/assets/rpg/items/staminapotion.svg +1 -0
- package/assets/rpg/items/sword.svg +1 -0
- package/assets/rpg/items/tent.svg +1 -0
- package/assets/rpg/items/thunder.svg +1 -0
- package/assets/rpg/items/titan.svg +1 -0
- package/assets/rpg/items/trash.svg +1 -0
- package/assets/rpg/items/undead.svg +1 -0
- package/assets/rpg/items/whale.svg +1 -0
- package/assets/rpg/items/wheat.svg +1 -0
- package/assets/rpg/items/wood.svg +1 -0
- package/assets/rpg/ui/SOURCES.md +12 -0
- package/assets/rpg/ui/compass.svg +1 -0
- package/assets/rpg/ui/diamond.svg +1 -0
- package/assets/rpg/ui/soft-frame.svg +6 -0
- package/buypanel.js +37 -0
- package/cara ambil apikey.js +26 -0
- package/data/assets/Caveat-Bold.ttf +0 -0
- package/data/assets/FontsFree-Net-SFProDisplay-Bold.ttf +0 -0
- package/data/assets/FontsFree-Net-SFProDisplay-Regular.ttf +0 -0
- package/data/assets/Indie-Flower.ttf +0 -0
- package/database/absen.json +1 -0
- package/database/absen_status.json +1 -0
- package/database/admin.json +1 -0
- package/database/adminvip.json +1 -0
- package/database/afk.json +1 -0
- package/database/antiaudio.json +1 -0
- package/database/antibadword.json +1 -0
- package/database/antibot-settings.json +1 -0
- package/database/antibot.json +1 -0
- package/database/antidelete.json +3 -0
- package/database/antiig.json +1 -0
- package/database/antiimage.json +1 -0
- package/database/antilink.json +1 -0
- package/database/antilinkall.json +1 -0
- package/database/antilinkkick.json +1 -0
- package/database/antirvo.json +1 -0
- package/database/antispam-counter.json +1 -0
- package/database/antispam-groups.json +1 -0
- package/database/antispam-warn.json +1 -0
- package/database/antisticker.json +1 -0
- package/database/antiswgc.json +1 -0
- package/database/antitagsw.json +1 -0
- package/database/antitoxic.json +1 -0
- package/database/antitt.json +1 -0
- package/database/antivideo.json +1 -0
- package/database/antiyt.json +1 -0
- package/database/autojoingc.json +1 -0
- package/database/autosholat.json +3 -0
- package/database/bad.json +73 -0
- package/database/badword.json +7 -0
- package/database/banchat.json +1 -0
- package/database/bannedfitur.json +1 -0
- package/database/banuser.json +1 -0
- package/database/blacklist.json +1 -0
- package/database/blacklistgroup.json +1 -0
- package/database/broadcast.json +3 -0
- package/database/chatsNotif.json +1 -0
- package/database/config.json +1 -0
- package/database/database.json +1 -0
- package/database/expiredpanel.json +1 -0
- package/database/expiredpanel2.json +1 -0
- package/database/fiturmember.json +1 -0
- package/database/groupadd.json +1 -0
- package/database/groups.json +6 -0
- package/database/gruplist.json +5 -0
- package/database/idgrup.json +1 -0
- package/database/jpmgroup.json +1 -0
- package/database/kata-kata.json +28309 -0
- package/database/left.json +1 -0
- package/database/list-message.json +51 -0
- package/database/maintenance.json +4 -0
- package/database/mutegc.json +1 -0
- package/database/nilai.json +3 -0
- package/database/onlyadmin.json +1 -0
- package/database/onlygc.json +6 -0
- package/database/onlyprivate.json +3 -0
- package/database/openaigc.json +3 -0
- package/database/owner.json +1 -0
- package/database/panelexpired2.json +1 -0
- package/database/payment.json +1 -0
- package/database/pending.json +1 -0
- package/database/pendingSewa.json +1 -0
- package/database/prefix.json +4 -0
- package/database/premium.json +1 -0
- package/database/qris.json +3 -0
- package/database/registered.json +2 -0
- package/database/schedule.json +1 -0
- package/database/set_done.json +1 -0
- package/database/set_left.json +1 -0
- package/database/set_proses.json +1 -0
- package/database/set_welcome.json +1 -0
- package/database/setting.json +1 -0
- package/database/sewa.json +1 -0
- package/database/sewabot.json +3 -0
- package/database/transaksi.json +1 -0
- package/database/uservip.json +1 -0
- package/database/warning.json +2 -0
- package/database/welcome.json +1 -0
- package/helper.js +461 -0
- package/index.js +19 -0
- package/lib/AGENCYB.TTF +0 -0
- package/lib/CallDur.ttf +0 -0
- package/lib/CallName.ttf +0 -0
- package/lib/DanaFont.otf +0 -0
- package/lib/DevFont.ttf +0 -0
- package/lib/antidelete.js +196 -0
- package/lib/arialnarrow.ttf +0 -0
- package/lib/cekban.js +14 -0
- package/lib/color.js +19 -0
- package/lib/connection.js +12 -0
- package/lib/converter.js +85 -0
- package/lib/exif.js +171 -0
- package/lib/function.js +407 -0
- package/lib/gemmy.js +433 -0
- package/lib/groupManager.js +75 -0
- package/lib/helper-bails.js +19 -0
- package/lib/myfunction.js +384 -0
- package/lib/respon-list.js +95 -0
- package/lib/sambungkata.js +117 -0
- package/lib/savetube.js +1 -0
- package/lib/setwelcome.js +66 -0
- package/lib/sewa.js +109 -0
- package/lib/sewabot.js +40 -0
- package/lib/store.js +94 -0
- package/lib/surprisedeal.js +120 -0
- package/lib/thumb.jpg +0 -0
- package/lib/tictactoe.js +94 -0
- package/lib/tiktoksearch.js +83 -0
- package/lib/uploader.js +324 -0
- package/lib/videothumb.mp4 +0 -0
- package/lib/welcome.js +129 -0
- package/license.md +17 -0
- package/no developer.js +2 -0
- package/package.json +61 -5
- package/plugins/crm.js +309 -0
- package/plugins/douyinsearch.js +166 -0
- package/plugins/runcrm.js +124 -0
- package/plugins/spotifylirik.js +130 -0
- package/satanic.js +37922 -0
- package/settings.js +173 -0
- package/README.md +0 -3
package/package.json
CHANGED
|
@@ -1,6 +1,62 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|