jagproject 26.3.22 → 26.3.23
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/lib/Defaults/index.js +7 -3
- package/lib/Defaults/wileys-version.json +2 -2
- package/lib/Socket/messages-send.js +3 -0
- package/lib/Utils/messages.js +348 -0
- package/package.json +5 -4
- package/readme.md +97 -0
package/lib/Defaults/index.js
CHANGED
|
@@ -9,7 +9,7 @@ const libsignal_1 = require("../Signal/libsignal");
|
|
|
9
9
|
const browser_utils_1 = require("../Utils/browser-utils");
|
|
10
10
|
const logger_1 = __importDefault(require("../Utils/logger"));
|
|
11
11
|
const waVer = require("./wileys-version.json");
|
|
12
|
-
exports.version = waVer?.version || [2, 3000,
|
|
12
|
+
exports.version = waVer?.version || [2, 3000, 1036687490];
|
|
13
13
|
exports.UNAUTHORIZED_CODES = [401, 403, 419];
|
|
14
14
|
exports.DEFAULT_ORIGIN = 'https://web.whatsapp.com';
|
|
15
15
|
exports.CALL_VIDEO_PREFIX = 'https://call.whatsapp.com/video/';
|
|
@@ -85,7 +85,9 @@ exports.MEDIA_PATH_MAP = {
|
|
|
85
85
|
'product-catalog-image': '/product/image',
|
|
86
86
|
'md-app-state': '',
|
|
87
87
|
'md-msg-hist': '/mms/md-app-state',
|
|
88
|
-
'biz-cover-photo': '/pps/biz-cover-photo'
|
|
88
|
+
'biz-cover-photo': '/pps/biz-cover-photo',
|
|
89
|
+
'sticker-pack': '/mms/sticker',
|
|
90
|
+
'thumbnail-sticker-pack': '/mms/image'
|
|
89
91
|
};
|
|
90
92
|
exports.MEDIA_HKDF_KEY_MAPPING = {
|
|
91
93
|
audio: 'Audio',
|
|
@@ -106,7 +108,9 @@ exports.MEDIA_HKDF_KEY_MAPPING = {
|
|
|
106
108
|
'product-catalog-image': '',
|
|
107
109
|
'payment-bg-image': 'Payment Background',
|
|
108
110
|
ptv: 'Video',
|
|
109
|
-
'biz-cover-photo': 'Image'
|
|
111
|
+
'biz-cover-photo': 'Image',
|
|
112
|
+
'sticker-pack': 'Sticker Pack',
|
|
113
|
+
'thumbnail-sticker-pack': 'Image Thumbnail'
|
|
110
114
|
};
|
|
111
115
|
exports.MEDIA_KEYS = Object.keys(exports.MEDIA_PATH_MAP);
|
|
112
116
|
exports.MIN_PREKEY_COUNT = 5;
|
|
@@ -634,6 +634,9 @@ const userDevicesCache = config.userDevicesCache || new node_cache_1.default({
|
|
|
634
634
|
else if (message.stickerMessage) {
|
|
635
635
|
return 'sticker';
|
|
636
636
|
}
|
|
637
|
+
else if (message.stickerPackMessage) {
|
|
638
|
+
return 'sticker_pack';
|
|
639
|
+
}
|
|
637
640
|
else if (message.listMessage) {
|
|
638
641
|
return 'list';
|
|
639
642
|
}
|
package/lib/Utils/messages.js
CHANGED
|
@@ -444,6 +444,354 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
444
444
|
}
|
|
445
445
|
}
|
|
446
446
|
}
|
|
447
|
+
else if ('stickerPack' in message && !!message.stickerPack) {
|
|
448
|
+
const { zip } = require('fflate');
|
|
449
|
+
const { stickers, cover, name, publisher, packId, description } = message.stickerPack;
|
|
450
|
+
const coverSource = cover || ((stickers[0] && (stickers[0].data || stickers[0].sticker)) || null);
|
|
451
|
+
if (!Array.isArray(stickers)) {
|
|
452
|
+
throw new boom_1.Boom('stickerPack.stickers must be an array', { statusCode: 400 });
|
|
453
|
+
}
|
|
454
|
+
if (stickers.length > 60) {
|
|
455
|
+
throw new boom_1.Boom('Sticker pack exceeds the maximum limit of 60 stickers', { statusCode: 400 });
|
|
456
|
+
}
|
|
457
|
+
if (stickers.length === 0) {
|
|
458
|
+
throw new boom_1.Boom('Sticker pack must contain at least one sticker', { statusCode: 400 });
|
|
459
|
+
}
|
|
460
|
+
const stickerPackId = packId || (0, generics_1.generateMessageIDV2)();
|
|
461
|
+
let sharpLib = null;
|
|
462
|
+
let jimpLib = null;
|
|
463
|
+
try {
|
|
464
|
+
sharpLib = require('sharp');
|
|
465
|
+
}
|
|
466
|
+
catch (_sharpError) { }
|
|
467
|
+
try {
|
|
468
|
+
jimpLib = require('jimp');
|
|
469
|
+
}
|
|
470
|
+
catch (_jimpError) { }
|
|
471
|
+
if (!sharpLib && !jimpLib) {
|
|
472
|
+
throw new boom_1.Boom('No image processing library available (install sharp or jimp)', { statusCode: 400 });
|
|
473
|
+
}
|
|
474
|
+
const isWebPBuffer = (buf) => (buf.length >= 12
|
|
475
|
+
&& buf[0] === 0x52
|
|
476
|
+
&& buf[1] === 0x49
|
|
477
|
+
&& buf[2] === 0x46
|
|
478
|
+
&& buf[3] === 0x46
|
|
479
|
+
&& buf[8] === 0x57
|
|
480
|
+
&& buf[9] === 0x45
|
|
481
|
+
&& buf[10] === 0x42
|
|
482
|
+
&& buf[11] === 0x50);
|
|
483
|
+
const isAnimatedWebP = (buf) => {
|
|
484
|
+
if (!isWebPBuffer(buf)) {
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
let offset = 12;
|
|
488
|
+
while (offset < buf.length - 8) {
|
|
489
|
+
const fourCC = buf.toString('ascii', offset, offset + 4);
|
|
490
|
+
const chunkSize = buf.readUInt32LE(offset + 4);
|
|
491
|
+
if (fourCC === 'VP8X') {
|
|
492
|
+
const flagsOffset = offset + 8;
|
|
493
|
+
if (flagsOffset < buf.length && (buf[flagsOffset] & 0x02)) {
|
|
494
|
+
return true;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
else if (fourCC === 'ANIM' || fourCC === 'ANMF') {
|
|
498
|
+
return true;
|
|
499
|
+
}
|
|
500
|
+
offset += 8 + chunkSize + (chunkSize % 2);
|
|
501
|
+
}
|
|
502
|
+
return false;
|
|
503
|
+
};
|
|
504
|
+
const getJimpBuffer = async (image, mime) => {
|
|
505
|
+
if (typeof image.getBufferAsync === 'function') {
|
|
506
|
+
return await image.getBufferAsync(mime);
|
|
507
|
+
}
|
|
508
|
+
return await new Promise((resolve, reject) => {
|
|
509
|
+
image.getBuffer(mime, (err, result) => {
|
|
510
|
+
if (err) {
|
|
511
|
+
reject(err);
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
resolve(result);
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
});
|
|
518
|
+
};
|
|
519
|
+
const { spawn } = require('child_process');
|
|
520
|
+
const { promises: fsPromises } = require('fs');
|
|
521
|
+
const { join } = require('path');
|
|
522
|
+
const { tmpdir } = require('os');
|
|
523
|
+
const isPngBuffer = (buf) => (buf.length >= 8
|
|
524
|
+
&& buf[0] === 0x89
|
|
525
|
+
&& buf[1] === 0x50
|
|
526
|
+
&& buf[2] === 0x4e
|
|
527
|
+
&& buf[3] === 0x47);
|
|
528
|
+
const isJpegBuffer = (buf) => (buf.length >= 3
|
|
529
|
+
&& buf[0] === 0xff
|
|
530
|
+
&& buf[1] === 0xd8
|
|
531
|
+
&& buf[2] === 0xff);
|
|
532
|
+
const isGifBuffer = (buf) => (buf.length >= 4 && buf.slice(0, 4).toString() === 'GIF8');
|
|
533
|
+
const isWebmBuffer = (buf) => (buf.length >= 4
|
|
534
|
+
&& buf[0] === 0x1a
|
|
535
|
+
&& buf[1] === 0x45
|
|
536
|
+
&& buf[2] === 0xdf
|
|
537
|
+
&& buf[3] === 0xa3);
|
|
538
|
+
const isMp4Buffer = (buf) => (buf.length >= 8
|
|
539
|
+
&& buf[4] === 0x66
|
|
540
|
+
&& buf[5] === 0x74
|
|
541
|
+
&& buf[6] === 0x79
|
|
542
|
+
&& buf[7] === 0x70);
|
|
543
|
+
const looksLikeGzip = (buf) => (buf.length >= 2 && buf[0] === 0x1f && buf[1] === 0x8b);
|
|
544
|
+
const inferSourceKind = (buffer, source, stickerItem) => {
|
|
545
|
+
var _c, _d, _e, _f;
|
|
546
|
+
if (isAnimatedWebP(buffer)) {
|
|
547
|
+
return 'animated-webp';
|
|
548
|
+
}
|
|
549
|
+
if (isWebPBuffer(buffer)) {
|
|
550
|
+
return 'webp';
|
|
551
|
+
}
|
|
552
|
+
if (isPngBuffer(buffer)) {
|
|
553
|
+
return 'png';
|
|
554
|
+
}
|
|
555
|
+
if (isJpegBuffer(buffer)) {
|
|
556
|
+
return 'jpg';
|
|
557
|
+
}
|
|
558
|
+
if (isGifBuffer(buffer)) {
|
|
559
|
+
return 'gif';
|
|
560
|
+
}
|
|
561
|
+
if (isWebmBuffer(buffer)) {
|
|
562
|
+
return 'webm';
|
|
563
|
+
}
|
|
564
|
+
if (isMp4Buffer(buffer)) {
|
|
565
|
+
return 'mp4';
|
|
566
|
+
}
|
|
567
|
+
if (looksLikeGzip(buffer)) {
|
|
568
|
+
return 'tgs';
|
|
569
|
+
}
|
|
570
|
+
const hint = String(((_c = stickerItem === null || stickerItem === void 0 ? void 0 : stickerItem.format) !== null && _c !== void 0 ? _c : ((_d = stickerItem === null || stickerItem === void 0 ? void 0 : stickerItem.mimetype) !== null && _d !== void 0 ? _d : ((_f = (_e = source) === null || _e === void 0 ? void 0 : _e.url) === null || _f === void 0 ? void 0 : _f.toString()))) || '').toLowerCase();
|
|
571
|
+
if (hint.includes('webm')) {
|
|
572
|
+
return 'webm';
|
|
573
|
+
}
|
|
574
|
+
if (hint.includes('mp4') || hint.includes('mov') || hint.includes('mkv') || hint.includes('avi')) {
|
|
575
|
+
return 'mp4';
|
|
576
|
+
}
|
|
577
|
+
if (hint.includes('gif')) {
|
|
578
|
+
return 'gif';
|
|
579
|
+
}
|
|
580
|
+
if (hint.includes('png')) {
|
|
581
|
+
return 'png';
|
|
582
|
+
}
|
|
583
|
+
if (hint.includes('jpg') || hint.includes('jpeg')) {
|
|
584
|
+
return 'jpg';
|
|
585
|
+
}
|
|
586
|
+
if (hint.includes('tgs') || hint.includes('lottie') || hint.includes('json')) {
|
|
587
|
+
return 'tgs';
|
|
588
|
+
}
|
|
589
|
+
return 'unknown';
|
|
590
|
+
};
|
|
591
|
+
const convertStaticToWebp = async (buffer, label) => {
|
|
592
|
+
if (isWebPBuffer(buffer)) {
|
|
593
|
+
return buffer;
|
|
594
|
+
}
|
|
595
|
+
if (sharpLib) {
|
|
596
|
+
return await sharpLib(buffer)
|
|
597
|
+
.resize(512, 512, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } })
|
|
598
|
+
.webp({ quality: 80, lossless: false })
|
|
599
|
+
.toBuffer();
|
|
600
|
+
}
|
|
601
|
+
if (jimpLib) {
|
|
602
|
+
const JimpCtor = jimpLib.Jimp || jimpLib.default || jimpLib;
|
|
603
|
+
const image = await JimpCtor.read(buffer);
|
|
604
|
+
image.contain(512, 512);
|
|
605
|
+
return await getJimpBuffer(image, 'image/webp');
|
|
606
|
+
}
|
|
607
|
+
throw new boom_1.Boom(`No image processing library available for converting ${label} to WebP`, { statusCode: 400 });
|
|
608
|
+
};
|
|
609
|
+
const runFfmpegToWebp = async (inputBuffer, inputExt, animated, label) => {
|
|
610
|
+
const baseName = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
611
|
+
const inputPath = join(tmpdir(), `sticker-pack-${baseName}.${inputExt || 'bin'}`);
|
|
612
|
+
const outputPath = join(tmpdir(), `sticker-pack-${baseName}.webp`);
|
|
613
|
+
await fsPromises.writeFile(inputPath, inputBuffer);
|
|
614
|
+
const args = animated
|
|
615
|
+
? [
|
|
616
|
+
'-y',
|
|
617
|
+
'-i', inputPath,
|
|
618
|
+
'-vf', 'fps=12,scale=512:512:force_original_aspect_ratio=decrease:flags=lanczos,pad=512:512:-1:-1:color=0x00000000',
|
|
619
|
+
'-loop', '0',
|
|
620
|
+
'-an',
|
|
621
|
+
'-vsync', '0',
|
|
622
|
+
'-s', '512:512',
|
|
623
|
+
'-vcodec', 'libwebp_anim',
|
|
624
|
+
'-lossless', '0',
|
|
625
|
+
'-compression_level', '6',
|
|
626
|
+
'-q:v', '55',
|
|
627
|
+
outputPath,
|
|
628
|
+
]
|
|
629
|
+
: [
|
|
630
|
+
'-y',
|
|
631
|
+
'-i', inputPath,
|
|
632
|
+
'-vf', 'scale=512:512:force_original_aspect_ratio=decrease:flags=lanczos,pad=512:512:-1:-1:color=0x00000000',
|
|
633
|
+
'-frames:v', '1',
|
|
634
|
+
'-vcodec', 'libwebp',
|
|
635
|
+
'-lossless', '0',
|
|
636
|
+
'-compression_level', '6',
|
|
637
|
+
'-q:v', '70',
|
|
638
|
+
outputPath,
|
|
639
|
+
];
|
|
640
|
+
await new Promise((resolve, reject) => {
|
|
641
|
+
const ff = spawn('ffmpeg', args);
|
|
642
|
+
let stderr = '';
|
|
643
|
+
ff.stderr.on('data', (chunk) => {
|
|
644
|
+
stderr += chunk.toString();
|
|
645
|
+
});
|
|
646
|
+
ff.on('error', (err) => reject(new boom_1.Boom(`ffmpeg not available for ${label}: ${err.message}`, { statusCode: 400 })));
|
|
647
|
+
ff.on('close', (code) => {
|
|
648
|
+
if (code === 0) {
|
|
649
|
+
resolve(undefined);
|
|
650
|
+
}
|
|
651
|
+
else {
|
|
652
|
+
reject(new boom_1.Boom(`ffmpeg failed while converting ${label} (code ${code})\n${stderr}`, { statusCode: 400 }));
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
});
|
|
656
|
+
try {
|
|
657
|
+
return await fsPromises.readFile(outputPath);
|
|
658
|
+
}
|
|
659
|
+
finally {
|
|
660
|
+
await Promise.allSettled([
|
|
661
|
+
fsPromises.unlink(inputPath),
|
|
662
|
+
fsPromises.unlink(outputPath)
|
|
663
|
+
]);
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
const toWebpBuffer = async (buffer, label, source, stickerItem) => {
|
|
667
|
+
const sourceKind = inferSourceKind(buffer, source, stickerItem);
|
|
668
|
+
if (sourceKind === 'animated-webp' || sourceKind === 'webp') {
|
|
669
|
+
return buffer;
|
|
670
|
+
}
|
|
671
|
+
if (sourceKind === 'png' || sourceKind === 'jpg') {
|
|
672
|
+
return await convertStaticToWebp(buffer, label);
|
|
673
|
+
}
|
|
674
|
+
if (sourceKind === 'gif' || sourceKind === 'webm' || sourceKind === 'mp4') {
|
|
675
|
+
return await runFfmpegToWebp(buffer, sourceKind, true, label);
|
|
676
|
+
}
|
|
677
|
+
if (sourceKind === 'tgs') {
|
|
678
|
+
throw new boom_1.Boom(`TGS/Lottie source for ${label} is not supported in this runtime`, { statusCode: 400 });
|
|
679
|
+
}
|
|
680
|
+
return await convertStaticToWebp(buffer, label);
|
|
681
|
+
};
|
|
682
|
+
const toStaticWebpCoverBuffer = async (buffer, label, source, stickerItem) => {
|
|
683
|
+
const sourceKind = inferSourceKind(buffer, source, stickerItem);
|
|
684
|
+
if (sourceKind === 'gif' || sourceKind === 'webm' || sourceKind === 'mp4' || sourceKind === 'animated-webp') {
|
|
685
|
+
return await runFfmpegToWebp(buffer, sourceKind === 'animated-webp' ? 'webp' : sourceKind, false, label);
|
|
686
|
+
}
|
|
687
|
+
return await convertStaticToWebp(buffer, label);
|
|
688
|
+
};
|
|
689
|
+
const stickerData = {};
|
|
690
|
+
const stickerMetadata = await Promise.all(stickers.map(async (stickerItem, index) => {
|
|
691
|
+
const mediaSource = (stickerItem === null || stickerItem === void 0 ? void 0 : stickerItem.data) || (stickerItem === null || stickerItem === void 0 ? void 0 : stickerItem.sticker);
|
|
692
|
+
if (!mediaSource) {
|
|
693
|
+
throw new boom_1.Boom(`Sticker at index ${index} is missing data/sticker`, { statusCode: 400 });
|
|
694
|
+
}
|
|
695
|
+
const { stream } = await (0, messages_media_1.getStream)(mediaSource);
|
|
696
|
+
const buffer = await (0, messages_media_1.toBuffer)(stream);
|
|
697
|
+
const webpBuffer = await toWebpBuffer(buffer, `sticker at index ${index}`, mediaSource, stickerItem);
|
|
698
|
+
if (webpBuffer.length > 1024 * 1024) {
|
|
699
|
+
throw new boom_1.Boom(`Sticker at index ${index} exceeds the 1MB size limit`, { statusCode: 400 });
|
|
700
|
+
}
|
|
701
|
+
const hash = (0, crypto_2.sha256)(webpBuffer).toString('base64').replace(/\//g, '-');
|
|
702
|
+
const fileName = `${hash}.webp`;
|
|
703
|
+
stickerData[fileName] = [new Uint8Array(webpBuffer), { level: 0 }];
|
|
704
|
+
return {
|
|
705
|
+
fileName,
|
|
706
|
+
mimetype: 'image/webp',
|
|
707
|
+
isAnimated: isAnimatedWebP(webpBuffer),
|
|
708
|
+
emojis: stickerItem.emojis || [],
|
|
709
|
+
accessibilityLabel: stickerItem.accessibilityLabel || ''
|
|
710
|
+
};
|
|
711
|
+
}));
|
|
712
|
+
const trayIconFileName = `${stickerPackId}.webp`;
|
|
713
|
+
if (!coverSource) {
|
|
714
|
+
throw new boom_1.Boom('stickerPack.cover is required when no valid sticker media is available', { statusCode: 400 });
|
|
715
|
+
}
|
|
716
|
+
const { stream: coverStream } = await (0, messages_media_1.getStream)(coverSource);
|
|
717
|
+
const coverBuffer = await (0, messages_media_1.toBuffer)(coverStream);
|
|
718
|
+
const coverWebpBuffer = await toStaticWebpCoverBuffer(coverBuffer, 'cover', coverSource, stickers[0]);
|
|
719
|
+
stickerData[trayIconFileName] = [new Uint8Array(coverWebpBuffer), { level: 0 }];
|
|
720
|
+
const zipBuffer = await new Promise((resolve, reject) => {
|
|
721
|
+
zip(stickerData, (err, data) => {
|
|
722
|
+
if (err) {
|
|
723
|
+
reject(err);
|
|
724
|
+
}
|
|
725
|
+
else {
|
|
726
|
+
resolve(Buffer.from(data));
|
|
727
|
+
}
|
|
728
|
+
});
|
|
729
|
+
});
|
|
730
|
+
const stickerPackUpload = await (0, messages_media_1.encryptedStream)(zipBuffer, 'sticker-pack', {
|
|
731
|
+
logger: options.logger,
|
|
732
|
+
opts: options.options
|
|
733
|
+
});
|
|
734
|
+
const stickerPackUploadResult = await options.upload(stickerPackUpload.encWriteStream, {
|
|
735
|
+
fileEncSha256B64: stickerPackUpload.fileEncSha256.toString('base64'),
|
|
736
|
+
mediaType: 'sticker-pack',
|
|
737
|
+
timeoutMs: options.mediaUploadTimeoutMs
|
|
738
|
+
});
|
|
739
|
+
m.stickerPackMessage = {
|
|
740
|
+
name,
|
|
741
|
+
publisher,
|
|
742
|
+
stickerPackId,
|
|
743
|
+
packDescription: description,
|
|
744
|
+
stickerPackOrigin: WAProto_1.proto.Message.StickerPackMessage.StickerPackOrigin.THIRD_PARTY,
|
|
745
|
+
stickerPackSize: zipBuffer.length,
|
|
746
|
+
stickers: stickerMetadata,
|
|
747
|
+
fileSha256: stickerPackUpload.fileSha256,
|
|
748
|
+
fileEncSha256: stickerPackUpload.fileEncSha256,
|
|
749
|
+
mediaKey: stickerPackUpload.mediaKey,
|
|
750
|
+
directPath: stickerPackUploadResult.directPath,
|
|
751
|
+
fileLength: stickerPackUpload.fileLength,
|
|
752
|
+
mediaKeyTimestamp: (0, generics_1.unixTimestampSeconds)(),
|
|
753
|
+
trayIconFileName
|
|
754
|
+
};
|
|
755
|
+
try {
|
|
756
|
+
let thumbnailBuffer;
|
|
757
|
+
if (sharpLib) {
|
|
758
|
+
thumbnailBuffer = await sharpLib(coverWebpBuffer).resize(252, 252).jpeg().toBuffer();
|
|
759
|
+
}
|
|
760
|
+
else if (jimpLib) {
|
|
761
|
+
const JimpCtor = jimpLib.Jimp || jimpLib.default || jimpLib;
|
|
762
|
+
const image = await JimpCtor.read(coverWebpBuffer);
|
|
763
|
+
thumbnailBuffer = await getJimpBuffer(image.resize({ w: 252, h: 252 }), 'image/jpeg');
|
|
764
|
+
}
|
|
765
|
+
if (thumbnailBuffer && thumbnailBuffer.length) {
|
|
766
|
+
const thumbUpload = await (0, messages_media_1.encryptedStream)(thumbnailBuffer, 'thumbnail-sticker-pack', {
|
|
767
|
+
logger: options.logger,
|
|
768
|
+
opts: options.options,
|
|
769
|
+
mediaKey: stickerPackUpload.mediaKey
|
|
770
|
+
});
|
|
771
|
+
const thumbUploadResult = await options.upload(thumbUpload.encWriteStream, {
|
|
772
|
+
fileEncSha256B64: thumbUpload.fileEncSha256.toString('base64'),
|
|
773
|
+
mediaType: 'thumbnail-sticker-pack',
|
|
774
|
+
timeoutMs: options.mediaUploadTimeoutMs
|
|
775
|
+
});
|
|
776
|
+
Object.assign(m.stickerPackMessage, {
|
|
777
|
+
thumbnailDirectPath: thumbUploadResult.directPath,
|
|
778
|
+
thumbnailSha256: thumbUpload.fileSha256,
|
|
779
|
+
thumbnailEncSha256: thumbUpload.fileEncSha256,
|
|
780
|
+
thumbnailHeight: 252,
|
|
781
|
+
thumbnailWidth: 252,
|
|
782
|
+
imageDataHash: (0, crypto_2.sha256)(thumbnailBuffer).toString('base64')
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
catch (error) {
|
|
787
|
+
var _r, _s;
|
|
788
|
+
(_s = (_r = options.logger) === null || _r === void 0 ? void 0 : _r.warn) === null || _s === void 0 ? void 0 : _s.call(_r, { err: error }, 'sticker pack thumbnail generation failed');
|
|
789
|
+
}
|
|
790
|
+
m.stickerPackMessage.contextInfo = {
|
|
791
|
+
...((message.contextInfo) || {}),
|
|
792
|
+
...((message.mentions) ? { mentionedJid: message.mentions } : {})
|
|
793
|
+
};
|
|
794
|
+
}
|
|
447
795
|
else if ('event' in message) {
|
|
448
796
|
m.messageContextInfo = {
|
|
449
797
|
messageSecret: message.event.messageSecret || (0, crypto_1.randomBytes)(32),
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jagproject",
|
|
3
|
-
"version": "26.03.
|
|
4
|
-
|
|
3
|
+
"version": "26.03.23",
|
|
4
|
+
"update": "22 Maret 2026",
|
|
5
5
|
"description": "WhatsApp Web API Library",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"jagoan",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"automation",
|
|
13
13
|
"multi-device"
|
|
14
14
|
],
|
|
15
|
-
"homepage": "https://whatsapp.com/channel/0029VanhMDo42DcjiRGJOc2m",
|
|
15
|
+
"homepage": "https://whatsapp.com/channel/0029VanhMDo42DcjiRGJOc2m",
|
|
16
16
|
"repository": {
|
|
17
17
|
"type": "git",
|
|
18
18
|
"url": "git+https://github.com/ChandraGO/jagoans.git"
|
|
@@ -65,7 +65,8 @@
|
|
|
65
65
|
"pino": "^9.6",
|
|
66
66
|
"protobufjs": "^6.11.3",
|
|
67
67
|
"uuid": "^10.0.0",
|
|
68
|
-
"ws": "^8.13.0"
|
|
68
|
+
"ws": "^8.13.0",
|
|
69
|
+
"fflate": "^0.8.2"
|
|
69
70
|
},
|
|
70
71
|
"devDependencies": {
|
|
71
72
|
"@adiwajshing/eslint-config": "github:adiwajshing/eslint-config",
|
package/readme.md
CHANGED
|
@@ -68,6 +68,78 @@ yarn add jagproject
|
|
|
68
68
|
---
|
|
69
69
|
|
|
70
70
|
|
|
71
|
+
# Cara Pakai Cepat
|
|
72
|
+
|
|
73
|
+
## Instalasi
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npm install jagproject
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Pemakaian Dasar
|
|
80
|
+
|
|
81
|
+
```javascript
|
|
82
|
+
const { default: makeWASocket, useMultiFileAuthState } = require('jagproject')
|
|
83
|
+
|
|
84
|
+
async function startBot() {
|
|
85
|
+
const { state, saveCreds } = await useMultiFileAuthState('./session')
|
|
86
|
+
|
|
87
|
+
const sock = makeWASocket({
|
|
88
|
+
auth: state,
|
|
89
|
+
printQRInTerminal: true
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
sock.ev.on('creds.update', saveCreds)
|
|
93
|
+
|
|
94
|
+
sock.ev.on('connection.update', ({ connection }) => {
|
|
95
|
+
if (connection === 'open') {
|
|
96
|
+
console.log('Bot connected')
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
startBot()
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Kirim Sticker Pack
|
|
105
|
+
|
|
106
|
+
```javascript
|
|
107
|
+
await sock.sendMessage('6281234567890@s.whatsapp.net', {
|
|
108
|
+
stickerPack: {
|
|
109
|
+
name: 'Baileys Wileyss',
|
|
110
|
+
publisher: 'Project Pemuda',
|
|
111
|
+
description: 'Sticker pack custom dari Wileyss',
|
|
112
|
+
cover: { url: './assets/cover.png' },
|
|
113
|
+
stickers: [
|
|
114
|
+
{ sticker: { url: './assets/sticker-1.webp' }, emojis: ['😀'] },
|
|
115
|
+
{ sticker: { url: './assets/sticker-2.webp' }, emojis: ['🔥'] },
|
|
116
|
+
{ sticker: { url: './assets/sticker-3.png' }, emojis: ['🚀'] }
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
})
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Format object `stickerPack`
|
|
123
|
+
|
|
124
|
+
- `name`: nama pack sticker
|
|
125
|
+
- `publisher`: nama author/publisher
|
|
126
|
+
- `description`: deskripsi pack
|
|
127
|
+
- `cover`: cover/tray icon, bisa file path, buffer, stream, atau URL
|
|
128
|
+
- `stickers`: array isi sticker, minimal 1 maksimal 60
|
|
129
|
+
- `sticker`: media tiap sticker, bisa WebP/PNG/JPG. Jika bukan WebP akan dicoba dikonversi otomatis
|
|
130
|
+
- `emojis`: emoji untuk sticker terkait
|
|
131
|
+
- `accessibilityLabel`: label opsional
|
|
132
|
+
- `packId`: opsional, jika tidak diisi akan dibuat otomatis
|
|
133
|
+
|
|
134
|
+
### Catatan
|
|
135
|
+
|
|
136
|
+
- Sangat disarankan install `sharp` agar konversi gambar ke WebP lebih stabil.
|
|
137
|
+
- Jika `sharp` tidak ada, library akan mencoba memakai `jimp`.
|
|
138
|
+
- Ukuran tiap sticker maksimal 1 MB.
|
|
139
|
+
- Jumlah sticker maksimal 60 per pack.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
71
143
|
# Documentation
|
|
72
144
|
|
|
73
145
|
- [Connecting Account](#connecting-account)
|
|
@@ -119,6 +191,7 @@ yarn add jagproject
|
|
|
119
191
|
- [Audio Message](#audio-message)
|
|
120
192
|
- [Image Message](#image-message)
|
|
121
193
|
- [ViewOnce Message](#view-once-message)
|
|
194
|
+
- [Sticker Pack Message](#kirim-sticker-pack)
|
|
122
195
|
- [Modify Messages](#modify-messages)
|
|
123
196
|
- [Delete Messages (for everyone)](#deleting-messages-for-everyone)
|
|
124
197
|
- [Edit Messages](#editing-messages)
|
|
@@ -1873,3 +1946,27 @@ Gunakan secara bertanggung jawab dan hindari aktivitas ilegal atau penyalahgunaa
|
|
|
1873
1946
|
|
|
1874
1947
|
📘 *Documentation powered by jagoan project*
|
|
1875
1948
|
🧑💻 **Modified and Presented by Jagoan Project**
|
|
1949
|
+
|
|
1950
|
+
<a id="kirim-sticker-pack"></a>
|
|
1951
|
+
## Sticker Pack Message
|
|
1952
|
+
|
|
1953
|
+
Gunakan field `stickerPack` pada `sendMessage` untuk mengirim satu paket sticker sekaligus.
|
|
1954
|
+
|
|
1955
|
+
Catatan penting: `stickerPack` sekarang bisa menerima campuran sticker statis dan video/animated (`webp/png/jpg/jpeg/gif/webm/mp4`) lalu mengonversinya ke WebP otomatis saat proses kirim, selama `ffmpeg` tersedia di server. Format `tgs`/Lottie tetap butuh preview/konverter tambahan di luar runtime ini.
|
|
1956
|
+
|
|
1957
|
+
```javascript
|
|
1958
|
+
await sock.sendMessage(jid, {
|
|
1959
|
+
stickerPack: {
|
|
1960
|
+
name: 'Nama Pack',
|
|
1961
|
+
publisher: 'Nama Publisher',
|
|
1962
|
+
description: 'Deskripsi singkat',
|
|
1963
|
+
cover: { url: './cover.png' },
|
|
1964
|
+
stickers: [
|
|
1965
|
+
{ sticker: { url: './1.webp' }, emojis: ['🙂'] },
|
|
1966
|
+
{ sticker: { url: './2.png' }, emojis: ['🎉'] }
|
|
1967
|
+
]
|
|
1968
|
+
}
|
|
1969
|
+
})
|
|
1970
|
+
```
|
|
1971
|
+
|
|
1972
|
+
`cover` dan setiap item `sticker` menerima format media yang sama seperti pengiriman media biasa: path lokal, URL, Buffer, atau stream.
|