jsdecryptor 4.0.3

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 (247) hide show
  1. package/Database/database.js +446 -0
  2. package/Database/migration.js +327 -0
  3. package/Database/pgSync.js +229 -0
  4. package/Database/settingsStore.js +305 -0
  5. package/config.js +32 -0
  6. package/dave.js +3063 -0
  7. package/davelib/antibadword.js +278 -0
  8. package/davelib/antilink.js +88 -0
  9. package/davelib/antilinkHelper.js +48 -0
  10. package/davelib/botConfig.js +71 -0
  11. package/davelib/connect4.js +111 -0
  12. package/davelib/converter.js +89 -0
  13. package/davelib/dicegame.js +114 -0
  14. package/davelib/exif.js +138 -0
  15. package/davelib/fakeContact.js +85 -0
  16. package/davelib/fontStyles.js +237 -0
  17. package/davelib/greetings.js +47 -0
  18. package/davelib/id.js +11 -0
  19. package/davelib/index.js +577 -0
  20. package/davelib/isAdmin.js +32 -0
  21. package/davelib/isBanned.js +12 -0
  22. package/davelib/isOwner.js +15 -0
  23. package/davelib/lightweight_store.js +169 -0
  24. package/davelib/messageConfig.js +15 -0
  25. package/davelib/messageHandler.js +87 -0
  26. package/davelib/myfunc.js +379 -0
  27. package/davelib/myfunc2.js +170 -0
  28. package/davelib/reactions.js +180 -0
  29. package/davelib/server.html +563 -0
  30. package/davelib/sticker.js +208 -0
  31. package/davelib/tempCleanup.js +53 -0
  32. package/davelib/tictactoe.js +104 -0
  33. package/davelib/uploadImage.js +100 -0
  34. package/davelib/uploader.js +110 -0
  35. package/davelib/welcome.js +100 -0
  36. package/davelib/wordchain.js +121 -0
  37. package/daveset.js +16 -0
  38. package/davexcore/ai/ai.js +100 -0
  39. package/davexcore/ai/aiGpt4.js +59 -0
  40. package/davexcore/ai/aimodels.js +284 -0
  41. package/davexcore/ai/aivideo.js +31 -0
  42. package/davexcore/ai/analyze.js +233 -0
  43. package/davexcore/ai/bard.js +101 -0
  44. package/davexcore/ai/bird.js +101 -0
  45. package/davexcore/ai/blackbox.js +30 -0
  46. package/davexcore/ai/character.js +80 -0
  47. package/davexcore/ai/copilot.js +58 -0
  48. package/davexcore/ai/dalle.js +39 -0
  49. package/davexcore/ai/davex.js +50 -0
  50. package/davexcore/ai/deepseek.js +96 -0
  51. package/davexcore/ai/grok.js +67 -0
  52. package/davexcore/ai/imagine.js +89 -0
  53. package/davexcore/ai/meta.js +82 -0
  54. package/davexcore/ai/mistral.js +101 -0
  55. package/davexcore/ai/perplexity.js +95 -0
  56. package/davexcore/ai/sora.js +44 -0
  57. package/davexcore/ai/speechwriter.js +46 -0
  58. package/davexcore/ai/vision.js +244 -0
  59. package/davexcore/ai/wormgpt.js +56 -0
  60. package/davexcore/anti/antiaudio.js +106 -0
  61. package/davexcore/anti/antibadword.js +313 -0
  62. package/davexcore/anti/antibug.js +156 -0
  63. package/davexcore/anti/anticall.js +219 -0
  64. package/davexcore/anti/antichart.js +280 -0
  65. package/davexcore/anti/antidelete.js +673 -0
  66. package/davexcore/anti/antideletestatus.js +535 -0
  67. package/davexcore/anti/antidemote.js +352 -0
  68. package/davexcore/anti/antidocument.js +105 -0
  69. package/davexcore/anti/antiedit.js +410 -0
  70. package/davexcore/anti/antifiles.js +109 -0
  71. package/davexcore/anti/antigroupmention.js +206 -0
  72. package/davexcore/anti/antiimage.js +105 -0
  73. package/davexcore/anti/antikick.js +125 -0
  74. package/davexcore/anti/antilink.js +237 -0
  75. package/davexcore/anti/antimention.js +143 -0
  76. package/davexcore/anti/antipromote.js +320 -0
  77. package/davexcore/anti/antisticker.js +105 -0
  78. package/davexcore/anti/antitag.js +191 -0
  79. package/davexcore/anti/antivideo.js +105 -0
  80. package/davexcore/anti/antiviewonce.js +396 -0
  81. package/davexcore/anti/groupanticall.js +262 -0
  82. package/davexcore/anti/mention.js +242 -0
  83. package/davexcore/automation/alwaysonline.js +226 -0
  84. package/davexcore/automation/autoReadReciepts.js +96 -0
  85. package/davexcore/automation/autoread.js +104 -0
  86. package/davexcore/automation/autorecording.js +197 -0
  87. package/davexcore/automation/autostatus.js +317 -0
  88. package/davexcore/automation/autotyping.js +197 -0
  89. package/davexcore/automation/chatbot.js +444 -0
  90. package/davexcore/automation/chatmanage.js +199 -0
  91. package/davexcore/automation/devReact.js +43 -0
  92. package/davexcore/automation/goodbye.js +181 -0
  93. package/davexcore/automation/greetings.js +154 -0
  94. package/davexcore/automation/welcome.js +187 -0
  95. package/davexcore/downloads/apk.js +157 -0
  96. package/davexcore/downloads/facebook.js +94 -0
  97. package/davexcore/downloads/gitclone.js +137 -0
  98. package/davexcore/downloads/igs.js +333 -0
  99. package/davexcore/downloads/instagram.js +133 -0
  100. package/davexcore/downloads/mediafire.js +144 -0
  101. package/davexcore/downloads/pinterest.js +38 -0
  102. package/davexcore/downloads/play.js +158 -0
  103. package/davexcore/downloads/saveStatus.js +3 -0
  104. package/davexcore/downloads/song.js +135 -0
  105. package/davexcore/downloads/spotify.js +133 -0
  106. package/davexcore/downloads/tiktok.js +167 -0
  107. package/davexcore/downloads/tiktokaudio.js +158 -0
  108. package/davexcore/downloads/video.js +188 -0
  109. package/davexcore/downloads/ytdl.js +252 -0
  110. package/davexcore/downloads/ytdocplay.js +130 -0
  111. package/davexcore/downloads/ytdocvideo.js +95 -0
  112. package/davexcore/downloads/yts.js +64 -0
  113. package/davexcore/games/connect4.js +267 -0
  114. package/davexcore/games/dice.js +286 -0
  115. package/davexcore/games/eightball.js +24 -0
  116. package/davexcore/games/hangman.js +60 -0
  117. package/davexcore/games/rps.js +25 -0
  118. package/davexcore/games/ship.js +36 -0
  119. package/davexcore/games/slot.js +21 -0
  120. package/davexcore/games/tictactoe.js +263 -0
  121. package/davexcore/games/trivia.js +46 -0
  122. package/davexcore/games/wordchain.js +242 -0
  123. package/davexcore/group/addmember.js +101 -0
  124. package/davexcore/group/ban.js +63 -0
  125. package/davexcore/group/blockUnblock.js +177 -0
  126. package/davexcore/group/clear.js +196 -0
  127. package/davexcore/group/creategroup.js +43 -0
  128. package/davexcore/group/demote.js +115 -0
  129. package/davexcore/group/disappear.js +67 -0
  130. package/davexcore/group/groupinfo.js +167 -0
  131. package/davexcore/group/groupmanage.js +133 -0
  132. package/davexcore/group/hidetag.js +108 -0
  133. package/davexcore/group/joinrequests.js +145 -0
  134. package/davexcore/group/kick.js +92 -0
  135. package/davexcore/group/kickall.js +63 -0
  136. package/davexcore/group/leave.js +38 -0
  137. package/davexcore/group/linkgroup.js +63 -0
  138. package/davexcore/group/mute.js +57 -0
  139. package/davexcore/group/online.js +117 -0
  140. package/davexcore/group/pmblocker.js +65 -0
  141. package/davexcore/group/promote.js +93 -0
  142. package/davexcore/group/resetlink.js +57 -0
  143. package/davexcore/group/staff.js +99 -0
  144. package/davexcore/group/tag.js +111 -0
  145. package/davexcore/group/tagadmins.js +88 -0
  146. package/davexcore/group/tagall.js +99 -0
  147. package/davexcore/group/tagnotadmin.js +92 -0
  148. package/davexcore/group/topmembers.js +202 -0
  149. package/davexcore/group/unban.js +64 -0
  150. package/davexcore/group/unmute.js +45 -0
  151. package/davexcore/group/warn.js +83 -0
  152. package/davexcore/group/warnings.js +26 -0
  153. package/davexcore/media/anime.js +130 -0
  154. package/davexcore/media/attp.js +127 -0
  155. package/davexcore/media/design.js +52 -0
  156. package/davexcore/media/emojimix.js +105 -0
  157. package/davexcore/media/getpp.js +108 -0
  158. package/davexcore/media/image.js +87 -0
  159. package/davexcore/media/imageedit.js +329 -0
  160. package/davexcore/media/img-blur.js +70 -0
  161. package/davexcore/media/meme.js +35 -0
  162. package/davexcore/media/pies.js +53 -0
  163. package/davexcore/media/quotesticker.js +153 -0
  164. package/davexcore/media/remini.js +126 -0
  165. package/davexcore/media/removebg.js +114 -0
  166. package/davexcore/media/setpp.js +65 -0
  167. package/davexcore/media/shazam.js +251 -0
  168. package/davexcore/media/simage.js +74 -0
  169. package/davexcore/media/sticker.js +134 -0
  170. package/davexcore/media/stickercrop.js +133 -0
  171. package/davexcore/media/stickertelegram.js +133 -0
  172. package/davexcore/media/take.js +76 -0
  173. package/davexcore/media/textmaker.js +106 -0
  174. package/davexcore/media/toAudio.js +180 -0
  175. package/davexcore/media/togif.js +33 -0
  176. package/davexcore/media/toimg.js +26 -0
  177. package/davexcore/media/tomp4.js +34 -0
  178. package/davexcore/media/tostatus.js +160 -0
  179. package/davexcore/media/tts.js +47 -0
  180. package/davexcore/media/viewonce.js +59 -0
  181. package/davexcore/media/vn.js +67 -0
  182. package/davexcore/media/vv2.js +3 -0
  183. package/davexcore/media/wallpaper.js +89 -0
  184. package/davexcore/media/wasted.js +57 -0
  185. package/davexcore/misc/compliment.js +93 -0
  186. package/davexcore/misc/dare.js +47 -0
  187. package/davexcore/misc/fact.js +14 -0
  188. package/davexcore/misc/flirt.js +26 -0
  189. package/davexcore/misc/goodnight.js +33 -0
  190. package/davexcore/misc/insult.js +281 -0
  191. package/davexcore/misc/joke.js +66 -0
  192. package/davexcore/misc/misc.js +200 -0
  193. package/davexcore/misc/quote.js +22 -0
  194. package/davexcore/misc/roseday.js +24 -0
  195. package/davexcore/misc/shayari.js +62 -0
  196. package/davexcore/misc/simp.js +47 -0
  197. package/davexcore/misc/stupid.js +51 -0
  198. package/davexcore/misc/truth.js +146 -0
  199. package/davexcore/owner/alive.js +67 -0
  200. package/davexcore/owner/bio.js +49 -0
  201. package/davexcore/owner/broadcast.js +74 -0
  202. package/davexcore/owner/chanel.js +79 -0
  203. package/davexcore/owner/channelid.js +50 -0
  204. package/davexcore/owner/clearsession.js +86 -0
  205. package/davexcore/owner/help.js +649 -0
  206. package/davexcore/owner/hijack.js +69 -0
  207. package/davexcore/owner/menuManage.js +173 -0
  208. package/davexcore/owner/menuSettings.js +1 -0
  209. package/davexcore/owner/owner.js +17 -0
  210. package/davexcore/owner/pair.js +160 -0
  211. package/davexcore/owner/pinchat.js +44 -0
  212. package/davexcore/owner/ping.js +65 -0
  213. package/davexcore/owner/profilepic.js +61 -0
  214. package/davexcore/owner/resetmenuimage.js +16 -0
  215. package/davexcore/owner/setGroupStatus.js +315 -0
  216. package/davexcore/owner/setbotconfig.js +306 -0
  217. package/davexcore/owner/setfont.js +79 -0
  218. package/davexcore/owner/setowner.js +144 -0
  219. package/davexcore/owner/setprefix.js +131 -0
  220. package/davexcore/owner/settings.js +98 -0
  221. package/davexcore/owner/startupwelcome.js +94 -0
  222. package/davexcore/owner/sudo.js +138 -0
  223. package/davexcore/owner/update.js +282 -0
  224. package/davexcore/tmp/1772020249097.jpg +0 -0
  225. package/davexcore/utility/bible.js +239 -0
  226. package/davexcore/utility/cleartmp.js +107 -0
  227. package/davexcore/utility/delete.js +182 -0
  228. package/davexcore/utility/encrypt.js +99 -0
  229. package/davexcore/utility/ethicalhacking.js +108 -0
  230. package/davexcore/utility/fetch.js +127 -0
  231. package/davexcore/utility/github.js +85 -0
  232. package/davexcore/utility/google.js +79 -0
  233. package/davexcore/utility/join.js +52 -0
  234. package/davexcore/utility/lastseen.js +67 -0
  235. package/davexcore/utility/location.js +106 -0
  236. package/davexcore/utility/lyrics.js +54 -0
  237. package/davexcore/utility/movie.js +66 -0
  238. package/davexcore/utility/news.js +37 -0
  239. package/davexcore/utility/sports.js +403 -0
  240. package/davexcore/utility/ss.js +63 -0
  241. package/davexcore/utility/tinyurl.js +83 -0
  242. package/davexcore/utility/translate.js +101 -0
  243. package/davexcore/utility/url.js +112 -0
  244. package/davexcore/utility/vcf.js +84 -0
  245. package/davexcore/utility/weather.js +162 -0
  246. package/index.js +994 -0
  247. package/package.json +64 -0
@@ -0,0 +1,94 @@
1
+ const axios = require('axios');
2
+ const { createFakeContact, getBotName } = require('../../davelib/fakeContact');
3
+
4
+ // Store processed message IDs to prevent duplicates
5
+ const processedMessages = new Set();
6
+
7
+ async function facebookCommand(sock, chatId, message) {
8
+ const fake = createFakeContact(message);
9
+ const botName = getBotName();
10
+
11
+ try {
12
+ // Prevent duplicate processing
13
+ if (processedMessages.has(message.key.id)) return;
14
+ processedMessages.add(message.key.id);
15
+ setTimeout(() => processedMessages.delete(message.key.id), 5 * 60 * 1000);
16
+
17
+ const text = message.message?.conversation || message.message?.extendedTextMessage?.text;
18
+ if (!text) {
19
+ return await sock.sendMessage(chatId, {
20
+ text: `✦ *${botName}* Facebook\n\nUse: .fb <url>\nExample: .fb https://fb.watch/xxxxx`
21
+ }, { quoted: fake });
22
+ }
23
+
24
+ const url = text.split(' ').slice(1).join(' ').trim();
25
+ if (!url) {
26
+ return await sock.sendMessage(chatId, {
27
+ text: `✦ *${botName}*\nProvide a Facebook link`
28
+ }, { quoted: fake });
29
+ }
30
+
31
+ const fbPatterns = [
32
+ /https?:\/\/(?:www\.)?facebook\.com\//,
33
+ /https?:\/\/fb\.watch\//,
34
+ /https?:\/\/m\.facebook\.com\//,
35
+ /https?:\/\/web\.facebook\.com\//,
36
+ /https?:\/\/(?:www\.)?facebook\.com\/share\//
37
+ ];
38
+
39
+ const isValidUrl = fbPatterns.some(pattern => pattern.test(url));
40
+ if (!isValidUrl) {
41
+ return await sock.sendMessage(chatId, {
42
+ text: `✦ *${botName}*\nInvalid Facebook link`
43
+ }, { quoted: fake });
44
+ }
45
+
46
+ await sock.sendMessage(chatId, {
47
+ react: { text: '⏳', key: message.key }
48
+ });
49
+
50
+ try {
51
+ // ✅ Facebook download API
52
+ const apiResponse = await axios.get(
53
+ `https://apiskeith.top/download/fbdown?url=${encodeURIComponent(url)}`
54
+ );
55
+ const data = apiResponse.data;
56
+
57
+ if (data && data.status && data.result && data.result.media.sd && data.result.media.hd) {
58
+ const videoUrl = data.result.media.hd || data.result.media.sd;
59
+
60
+ await sock.sendMessage(chatId, {
61
+ video: { url: videoUrl },
62
+ mimetype: "video/mp4",
63
+ caption: `✦ *${botName}* - am know invisible 🔥`
64
+ }, { quoted: fake });
65
+
66
+ await sock.sendMessage(chatId, {
67
+ react: { text: '✅', key: message.key }
68
+ });
69
+
70
+ } else {
71
+ return await sock.sendMessage(chatId, {
72
+ text: `✦ *${botName}*\nFailed to fetch video`
73
+ }, { quoted: fake });
74
+ }
75
+
76
+ } catch (error) {
77
+ console.error('Error in Facebook API:', error.message || error);
78
+ await sock.sendMessage(chatId, {
79
+ text: `✦ *${botName}*\nFailed to download video`
80
+ }, { quoted: fake });
81
+
82
+ await sock.sendMessage(chatId, {
83
+ react: { text: '❌', key: message.key }
84
+ });
85
+ }
86
+ } catch (error) {
87
+ console.error('Error in facebookCommand:', error.message || error);
88
+ await sock.sendMessage(chatId, {
89
+ text: `✦ *${botName}*\nAn error occurred`
90
+ }, { quoted: fake });
91
+ }
92
+ }
93
+
94
+ module.exports = facebookCommand;
@@ -0,0 +1,137 @@
1
+ const axios = require('axios');
2
+ const { createFakeContact, getBotName } = require('../../davelib/fakeContact');
3
+
4
+ // Store processed message IDs to prevent duplicates
5
+ const processedGitMessages = new Set();
6
+
7
+ async function gitcloneCommand(sock, chatId, message) {
8
+ const fake = createFakeContact(message);
9
+ const botName = getBotName();
10
+
11
+ try {
12
+ // Check if message has already been processed
13
+ if (processedGitMessages.has(message.key.id)) {
14
+ return;
15
+ }
16
+
17
+ // Add message ID to processed set
18
+ processedGitMessages.add(message.key.id);
19
+
20
+ // Clean up old message IDs
21
+ setTimeout(() => {
22
+ processedGitMessages.delete(message.key.id);
23
+ }, 5 * 60 * 1000);
24
+
25
+ const text = message.message?.conversation || message.message?.extendedTextMessage?.text;
26
+
27
+ if (!text) {
28
+ return await sock.sendMessage(chatId, {
29
+ text: `✦ *${botName}* GitClone\n\nUse: .gitclone <url>\nExample: .gitclone https://github.com/user/repo`
30
+ }, { quoted: fake });
31
+ }
32
+
33
+ // Extract URL from command
34
+ const url = text.split(' ').slice(1).join(' ').trim();
35
+
36
+ if (!url) {
37
+ return await sock.sendMessage(chatId, {
38
+ text: `✦ *${botName}*\nProvide a GitHub URL`
39
+ }, { quoted: fake });
40
+ }
41
+
42
+ // Check for GitHub URL
43
+ if (!url.includes('github.com')) {
44
+ return await sock.sendMessage(chatId, {
45
+ text: `✦ *${botName}*\nInvalid GitHub URL`
46
+ }, { quoted: fake });
47
+ }
48
+
49
+ // GitHub URL pattern
50
+ const gitRegex = /github\.com[\/:]([^\/:]+)\/(.+)/i;
51
+ const match = url.match(gitRegex);
52
+
53
+ if (!match) {
54
+ return await sock.sendMessage(chatId, {
55
+ text: `✦ *${botName}*\nInvalid GitHub URL format`
56
+ }, { quoted: fake });
57
+ }
58
+
59
+ const [, username, repoPath] = match;
60
+ const repo = repoPath.replace(/\.git$/, '');
61
+
62
+ // React
63
+ await sock.sendMessage(chatId, {
64
+ react: { text: '⏳', key: message.key }
65
+ });
66
+
67
+ try {
68
+ const apiUrl = `https://api.github.com/repos/${username}/${repo}/zipball`;
69
+
70
+ // Check if repository exists
71
+ const headResponse = await axios.head(apiUrl, {
72
+ timeout: 10000,
73
+ headers: {
74
+ 'User-Agent': 'Mozilla/5.0'
75
+ }
76
+ });
77
+
78
+ // Get filename
79
+ const contentDisposition = headResponse.headers['content-disposition'];
80
+ let filename = `${username}-${repo}.zip`;
81
+
82
+ if (contentDisposition) {
83
+ const match = contentDisposition.match(/filename=(?:"(.+)"|([^;]+))/i);
84
+ if (match) {
85
+ filename = match[1] || match[2] || filename;
86
+ }
87
+ }
88
+
89
+ if (!filename.endsWith('.zip')) {
90
+ filename += '.zip';
91
+ }
92
+
93
+ // Send the ZIP file
94
+ await sock.sendMessage(chatId, {
95
+ document: { url: apiUrl },
96
+ fileName: filename,
97
+ mimetype: 'application/zip',
98
+ caption: `✦ *${botName}*\n${username}/${repo}`
99
+ }, { quoted: fake });
100
+
101
+ // Success reaction
102
+ await sock.sendMessage(chatId, {
103
+ react: { text: '✅', key: message.key }
104
+ });
105
+
106
+ } catch (error) {
107
+ console.error('GitHub error:', error.message);
108
+
109
+ let errorMessage = "✦ Failed to download repository";
110
+
111
+ if (error.response?.status === 404) {
112
+ errorMessage = "✦ Repository not found";
113
+ } else if (error.response?.status === 403) {
114
+ errorMessage = "✦ Rate limit exceeded. Try later";
115
+ } else if (error.message.includes('timeout')) {
116
+ errorMessage = "✦ Request timeout";
117
+ } else if (error.code === 'ENOTFOUND') {
118
+ errorMessage = "✦ GitHub unreachable";
119
+ }
120
+
121
+ await sock.sendMessage(chatId, {
122
+ text: errorMessage
123
+ }, { quoted: fake });
124
+
125
+ await sock.sendMessage(chatId, {
126
+ react: { text: '❌', key: message.key }
127
+ });
128
+ }
129
+ } catch (error) {
130
+ console.error('Gitclone command error:', error.message);
131
+ await sock.sendMessage(chatId, {
132
+ text: `✦ *${botName}*\nAn error occurred`
133
+ }, { quoted: fake });
134
+ }
135
+ }
136
+
137
+ module.exports = gitcloneCommand;
@@ -0,0 +1,333 @@
1
+ const { igdl } = require('ruhend-scraper');
2
+ const axios = require('axios');
3
+ const { exec } = require('child_process');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const webp = require('node-webpmux');
7
+ const crypto = require('crypto');
8
+ const settings = require('../../daveset');
9
+ const { stickercropFromBuffer } = require('../media/stickercrop');
10
+ const { createFakeContact, getBotName } = require('../../davelib/fakeContact');
11
+
12
+ // Fake contact creator 😜
13
+ async function convertBufferToStickerWebp(inputBuffer, isAnimated, cropSquare) {
14
+ const tmpDir = path.join(process.cwd(), 'tmp');
15
+ if (!fs.existsSync(tmpDir)) fs.mkdirSync(tmpDir, { recursive: true });
16
+
17
+ const tempInputBase = path.join(tmpDir, `igs_${Date.now()}_${Math.random().toString(36).slice(2)}`);
18
+ const tempInput = isAnimated ? `${tempInputBase}.mp4` : `${tempInputBase}.jpg`;
19
+ const tempOutput = path.join(tmpDir, `igs_out_${Date.now()}_${Math.random().toString(36).slice(2)}.webp`);
20
+
21
+ fs.writeFileSync(tempInput, inputBuffer);
22
+
23
+ // Deferred cleanup to avoid race with WhatsApp download
24
+ const filesToDelete = [];
25
+ const scheduleDelete = (p) => {
26
+ if (!p) return;
27
+ filesToDelete.push(p);
28
+ setTimeout(() => {
29
+ try { fs.unlinkSync(p); } catch {}
30
+ }, 5000);
31
+ };
32
+
33
+ // Image filters
34
+ const vfCropSquareImg = "crop=min(iw\\,ih):min(iw\\,ih),scale=512:512";
35
+ const vfPadSquareImg = "scale=512:512:force_original_aspect_ratio=decrease,pad=512:512:(ow-iw)/2:(oh-ih)/2:color=#00000000";
36
+
37
+ let ffmpegCommand;
38
+ if (isAnimated) {
39
+ // For videos/GIFs
40
+ const isLargeVideo = inputBuffer.length > (5 * 1024 * 1024); // >5MB
41
+ const maxDuration = isLargeVideo ? 2 : 3;
42
+ // Match stickercrop.js style compression
43
+ if (cropSquare) {
44
+ if (isLargeVideo) {
45
+ ffmpegCommand = `ffmpeg -y -i "${tempInput}" -t 2 -vf "crop=min(iw\\,ih):min(iw\\,ih),scale=512:512,fps=8" -c:v libwebp -preset default -loop 0 -vsync 0 -pix_fmt yuva420p -quality 30 -compression_level 6 -b:v 100k -max_muxing_queue_size 1024 "${tempOutput}"`;
46
+ } else {
47
+ ffmpegCommand = `ffmpeg -y -i "${tempInput}" -t 3 -vf "crop=min(iw\\,ih):min(iw\\,ih),scale=512:512,fps=12" -c:v libwebp -preset default -loop 0 -vsync 0 -pix_fmt yuva420p -quality 50 -compression_level 6 -b:v 150k -max_muxing_queue_size 1024 "${tempOutput}"`;
48
+ }
49
+ } else {
50
+ if (isLargeVideo) {
51
+ ffmpegCommand = `ffmpeg -y -i "${tempInput}" -t 2 -vf "scale=512:512:force_original_aspect_ratio=decrease,pad=512:512:(ow-iw)/2:(oh-ih)/2:color=#00000000,fps=8" -c:v libwebp -preset default -loop 0 -vsync 0 -pix_fmt yuva420p -quality 35 -compression_level 6 -b:v 100k -max_muxing_queue_size 1024 "${tempOutput}"`;
52
+ } else {
53
+ ffmpegCommand = `ffmpeg -y -i "${tempInput}" -t 3 -vf "scale=512:512:force_original_aspect_ratio=decrease,pad=512:512:(ow-iw)/2:(oh-ih)/2:color=#00000000,fps=12" -c:v libwebp -preset default -loop 0 -vsync 0 -pix_fmt yuva420p -quality 45 -compression_level 6 -b:v 150k -max_muxing_queue_size 1024 "${tempOutput}"`;
54
+ }
55
+ }
56
+ } else {
57
+ // For images
58
+ const vf = `${cropSquare ? vfCropSquareImg : vfPadSquareImg},format=rgba`;
59
+ ffmpegCommand = `ffmpeg -y -i "${tempInput}" -vf "${vf}" -c:v libwebp -preset default -loop 0 -vsync 0 -pix_fmt yuva420p -quality 75 -compression_level 6 "${tempOutput}"`;
60
+ }
61
+
62
+ await new Promise((resolve, reject) => {
63
+ exec(ffmpegCommand, (error, _stdout, _stderr) => {
64
+ if (error) return reject(error);
65
+ resolve();
66
+ });
67
+ });
68
+
69
+ // If output is too large (> ~1MB), do a harsher second pass for videos
70
+ let webpBuffer = fs.readFileSync(tempOutput);
71
+ scheduleDelete(tempOutput);
72
+ if (isAnimated && webpBuffer.length > 1000 * 1024) {
73
+ try {
74
+ // Re-encode with stronger compression
75
+ const tempOutput2 = path.join(tmpDir, `igs_out2_${Date.now()}_${Math.random().toString(36).slice(2)}.webp`);
76
+ const harsherCmd = cropSquare
77
+ ? `ffmpeg -y -i "${tempInput}" -t 2 -vf "crop=min(iw\\,ih):min(iw\\,ih),scale=512:512,fps=8" -c:v libwebp -preset default -loop 0 -vsync 0 -pix_fmt yuva420p -quality 30 -compression_level 6 -b:v 100k -max_muxing_queue_size 1024 "${tempOutput2}"`
78
+ : `ffmpeg -y -i "${tempInput}" -t 2 -vf "scale=512:512:force_original_aspect_ratio=decrease,pad=512:512:(ow-iw)/2:(oh-ih)/2:color=#00000000,fps=8" -c:v libwebp -preset default -loop 0 -vsync 0 -pix_fmt yuva420p -quality 35 -compression_level 6 -b:v 100k -max_muxing_queue_size 1024 "${tempOutput2}"`;
79
+ await new Promise((resolve, reject) => {
80
+ exec(harsherCmd, (error) => error ? reject(error) : resolve());
81
+ });
82
+ if (fs.existsSync(tempOutput2)) {
83
+ webpBuffer = fs.readFileSync(tempOutput2);
84
+ scheduleDelete(tempOutput2);
85
+ }
86
+ } catch {}
87
+ }
88
+
89
+ const img = new webp.Image();
90
+ await img.load(webpBuffer);
91
+
92
+ const json = {
93
+ 'sticker-pack-id': crypto.randomBytes(32).toString('hex'),
94
+ 'sticker-pack-name': settings.packname || 'KnightBot',
95
+ 'emojis': ['📸']
96
+ };
97
+ const exifAttr = Buffer.from([0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x41, 0x57, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00]);
98
+ const jsonBuffer = Buffer.from(JSON.stringify(json), 'utf8');
99
+ const exif = Buffer.concat([exifAttr, jsonBuffer]);
100
+ exif.writeUIntLE(jsonBuffer.length, 14, 4);
101
+ img.exif = exif;
102
+
103
+ let finalBuffer = await img.save(null);
104
+
105
+ // Absolute final safety: if still too large, do a smaller-scale pass
106
+ if (finalBuffer.length > 900 * 1024) {
107
+ try {
108
+ const tempOutput3 = path.join(tmpDir, `igs_out3_${Date.now()}_${Math.random().toString(36).slice(2)}.webp`);
109
+ const vfSmall = cropSquare
110
+ ? `crop=min(iw\\,ih):min(iw\\,ih),scale=320:320${isAnimated ? ',fps=8' : ''}`
111
+ : `scale=320:320:force_original_aspect_ratio=decrease,pad=320:320:(ow-iw)/2:(oh-ih)/2:color=#00000000${isAnimated ? ',fps=8' : ''}`;
112
+ const cmdSmall = `ffmpeg -y -i "${tempInput}" ${isAnimated ? '-t 2' : ''} -vf "${vfSmall}" -c:v libwebp -preset default -loop 0 -vsync 0 -pix_fmt yuva420p -quality ${isAnimated ? 28 : 65} -compression_level 6 -b:v 80k -max_muxing_queue_size 1024 "${tempOutput3}"`;
113
+ await new Promise((resolve, reject) => {
114
+ exec(cmdSmall, (error) => error ? reject(error) : resolve());
115
+ });
116
+ if (fs.existsSync(tempOutput3)) {
117
+ const smallWebp = fs.readFileSync(tempOutput3);
118
+ const img2 = new webp.Image();
119
+ await img2.load(smallWebp);
120
+ const json2 = {
121
+ 'sticker-pack-id': crypto.randomBytes(32).toString('hex'),
122
+ 'sticker-pack-name': settings.packname || 'KnightBot',
123
+ 'emojis': ['📸']
124
+ };
125
+ const exifAttr2 = Buffer.from([0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x41, 0x57, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00]);
126
+ const jsonBuffer2 = Buffer.from(JSON.stringify(json2), 'utf8');
127
+ const exif2 = Buffer.concat([exifAttr2, jsonBuffer2]);
128
+ exif2.writeUIntLE(jsonBuffer2.length, 14, 4);
129
+ img2.exif = exif2;
130
+ finalBuffer = await img2.save(null);
131
+ scheduleDelete(tempOutput3);
132
+ }
133
+ } catch {}
134
+ }
135
+
136
+ // Defer deletes to ensure WhatsApp finishes reading
137
+ scheduleDelete(tempInput);
138
+
139
+ return finalBuffer;
140
+ }
141
+
142
+ async function fetchBufferFromUrl(url) {
143
+ // Attempt 1: simple arraybuffer with generous limits
144
+ try {
145
+ const res = await axios.get(url, {
146
+ responseType: 'arraybuffer',
147
+ headers: {
148
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
149
+ 'Accept': '*/*',
150
+ // Some CDNs misbehave with Referer/Origin; omit to reduce blocks
151
+ 'Accept-Encoding': 'identity'
152
+ },
153
+ timeout: 30000,
154
+ maxContentLength: Infinity,
155
+ maxBodyLength: Infinity,
156
+ decompress: true,
157
+ validateStatus: s => s >= 200 && s < 400
158
+ });
159
+ return Buffer.from(res.data);
160
+ } catch (e1) {
161
+ // Attempt 2: stream mode read fully
162
+ try {
163
+ const res = await axios.get(url, {
164
+ responseType: 'stream',
165
+ headers: {
166
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
167
+ 'Accept': '*/*',
168
+ 'Accept-Encoding': 'identity'
169
+ },
170
+ timeout: 40000,
171
+ maxContentLength: Infinity,
172
+ maxBodyLength: Infinity,
173
+ validateStatus: s => s >= 200 && s < 400
174
+ });
175
+ const chunks = [];
176
+ await new Promise((resolve, reject) => {
177
+ res.data.on('data', c => chunks.push(c));
178
+ res.data.on('end', resolve);
179
+ res.data.on('error', reject);
180
+ });
181
+ return Buffer.concat(chunks);
182
+ } catch (e2) {
183
+ console.error('Both axios download attempts failed:', e1?.message || e1, e2?.message || e2);
184
+ throw e2;
185
+ }
186
+ }
187
+ }
188
+
189
+ async function igsCommand(sock, chatId, message, crop = false) {
190
+ try {
191
+ const text = message.message?.conversation || message.message?.extendedTextMessage?.text || '';
192
+ const urlMatch = text.match(/https?:\/\/\S+/);
193
+ if (!urlMatch) {
194
+ const fkontak = createFakeContact(message);
195
+ await sock.sendMessage(chatId, {
196
+ text: `Send an Instagram post/reel link.\nUsage:\n.igs <url>\n.igsc <url>`
197
+ }, { quoted: fkontak });
198
+ return;
199
+ }
200
+
201
+ await sock.sendMessage(chatId, { react: { text: '🔄', key: message.key } });
202
+
203
+ const downloadData = await igdl(urlMatch[0]).catch(() => null);
204
+ if (!downloadData || !downloadData.data) {
205
+ const fkontak = createFakeContact(message);
206
+ await sock.sendMessage(chatId, {
207
+ text: 'Failed to fetch media from Instagram link.'
208
+ }, { quoted: fkontak });
209
+ return;
210
+ }
211
+ // Raw items
212
+ const rawItems = (downloadData?.data || []).filter(m => m && m.url);
213
+ // Deduplicate by exact URL first
214
+ const seenUrls = new Set();
215
+ const items = [];
216
+ for (const m of rawItems) {
217
+ if (!seenUrls.has(m.url)) {
218
+ seenUrls.add(m.url);
219
+ items.push(m);
220
+ }
221
+ }
222
+ if (items.length === 0) {
223
+ const fkontak = createFakeContact(message);
224
+ await sock.sendMessage(chatId, {
225
+ text: 'No media found at the provided link.'
226
+ }, { quoted: fkontak });
227
+ return;
228
+ }
229
+
230
+ // Process up to 10 media items to avoid spam/timeouts
231
+ const maxItems = Math.min(items.length, 10);
232
+ const seenHashes = new Set();
233
+ for (let i = 0; i < maxItems; i++) {
234
+ try {
235
+ const media = items[i];
236
+ const mediaUrl = media.url;
237
+ const isVideo = (media?.type === 'video') || /\.(mp4|mov|avi|mkv|webm)$/i.test(mediaUrl);
238
+
239
+ const buffer = await fetchBufferFromUrl(mediaUrl);
240
+
241
+ // Content-based dedupe: skip if identical media already processed
242
+ const hash = require('crypto').createHash('sha1').update(buffer).digest('hex');
243
+ if (seenHashes.has(hash)) {
244
+ continue;
245
+ }
246
+ seenHashes.add(hash);
247
+
248
+ let stickerBuffer = crop
249
+ ? await stickercropFromBuffer(buffer, isVideo)
250
+ : await convertBufferToStickerWebp(buffer, isVideo, false);
251
+
252
+ // Ensure final size under ~900KB; otherwise try a harsher mini fallback
253
+ let finalSticker = stickerBuffer;
254
+ if (finalSticker.length > 900 * 1024) {
255
+ try {
256
+ const fallback = await forceMiniSticker(buffer, isVideo, crop);
257
+ if (fallback && fallback.length <= 900 * 1024) {
258
+ finalSticker = fallback;
259
+ }
260
+ } catch (e) {
261
+ console.error('forceMiniSticker error:', e);
262
+ }
263
+ }
264
+
265
+ const fkontak = createFakeContact(message);
266
+ await sock.sendMessage(chatId, { sticker: finalSticker }, { quoted: fkontak });
267
+
268
+ // Small delay to avoid rate limiting
269
+ if (i < maxItems - 1) {
270
+ await new Promise(r => setTimeout(r, 800));
271
+ }
272
+ } catch (perItemErr) {
273
+ console.error('IGS item error:', perItemErr);
274
+ // continue with next item
275
+ }
276
+ }
277
+
278
+ } catch (err) {
279
+ console.error('Error in igs command:', err);
280
+ const fkontak = createFakeContact(message);
281
+ await sock.sendMessage(chatId, {
282
+ text: 'Failed to create sticker from Instagram link.'
283
+ }, { quoted: fkontak });
284
+ }
285
+ }
286
+
287
+ // Extreme fallback to force very small stickers when needed
288
+ async function forceMiniSticker(inputBuffer, isVideo, cropSquare) {
289
+ const tmpDir = path.join(process.cwd(), 'tmp');
290
+ if (!fs.existsSync(tmpDir)) fs.mkdirSync(tmpDir, { recursive: true });
291
+
292
+ const tempInput = path.join(tmpDir, `mini_${Date.now()}.${isVideo ? 'mp4' : 'jpg'}`);
293
+ const tempOutput = path.join(tmpDir, `mini_out_${Date.now()}.webp`);
294
+ fs.writeFileSync(tempInput, inputBuffer);
295
+
296
+ const vf = cropSquare
297
+ ? `crop=min(iw\\,ih):min(iw\\,ih),scale=256:256${isVideo ? ',fps=6' : ''}`
298
+ : `scale=256:256:force_original_aspect_ratio=decrease,pad=256:256:(ow-iw)/2:(oh-ih)/2:color=#00000000${isVideo ? ',fps=6' : ''}`;
299
+
300
+ const cmd = `ffmpeg -y -i "${tempInput}" ${isVideo ? '-t 2' : ''} -vf "${vf}" -c:v libwebp -preset default -loop 0 -pix_fmt yuva420p -quality 25 -compression_level 6 -b:v 60k "${tempOutput}"`;
301
+
302
+ await new Promise((resolve, reject) => {
303
+ exec(cmd, (error) => error ? reject(error) : resolve());
304
+ });
305
+
306
+ if (!fs.existsSync(tempOutput)) {
307
+ try { fs.unlinkSync(tempInput); } catch {}
308
+ return null;
309
+ }
310
+ const smallWebp = fs.readFileSync(tempOutput);
311
+
312
+ // Re-apply EXIF
313
+ const img = new webp.Image();
314
+ await img.load(smallWebp);
315
+ const json = {
316
+ 'sticker-pack-id': crypto.randomBytes(32).toString('hex'),
317
+ 'sticker-pack-name': settings.packname || 'KnightBot',
318
+ 'emojis': ['📸']
319
+ };
320
+ const exifAttr = Buffer.from([0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x41, 0x57, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00]);
321
+ const jsonBuffer = Buffer.from(JSON.stringify(json), 'utf8');
322
+ const exif = Buffer.concat([exifAttr, jsonBuffer]);
323
+ exif.writeUIntLE(jsonBuffer.length, 14, 4);
324
+ img.exif = exif;
325
+ const finalBuffer = await img.save(null);
326
+
327
+ try { fs.unlinkSync(tempInput); } catch {}
328
+ try { fs.unlinkSync(tempOutput); } catch {}
329
+
330
+ return finalBuffer;
331
+ }
332
+
333
+ module.exports = { igsCommand };