@vielhuber/wahelper 1.8.6 → 1.8.7
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/package.json +1 -1
- package/wahelper-daemon.js +42 -15
- package/wahelper.js +26 -6
package/package.json
CHANGED
package/wahelper-daemon.js
CHANGED
|
@@ -276,6 +276,11 @@ export default class wahelperDaemon {
|
|
|
276
276
|
this.log('storeDataToDatabase');
|
|
277
277
|
|
|
278
278
|
let messages = Array.isArray(data?.messages) ? data.messages : [];
|
|
279
|
+
if (Array.isArray(data?.updates)) {
|
|
280
|
+
messages = data.updates
|
|
281
|
+
.filter(({ update }) => update?.message?.editedMessage)
|
|
282
|
+
.map(({ key, update }) => ({ ...update, key }));
|
|
283
|
+
}
|
|
279
284
|
let chats = Array.isArray(data) ? data : Array.isArray(data?.chats) ? data.chats : [];
|
|
280
285
|
if (messages.length === 0 && chats.length === 0) {
|
|
281
286
|
return;
|
|
@@ -301,14 +306,24 @@ export default class wahelperDaemon {
|
|
|
301
306
|
let query = this.db.prepare(`
|
|
302
307
|
INSERT OR IGNORE INTO messages
|
|
303
308
|
(id, \`from\`, \`to\`, content, media_data, media_filename, timestamp)
|
|
304
|
-
VALUES (
|
|
309
|
+
VALUES ($id, $from, $to, $content, $mediaData, $mediaFilename, $timestamp)
|
|
310
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
311
|
+
\`from\` = excluded.\`from\`,
|
|
312
|
+
\`to\` = excluded.\`to\`,
|
|
313
|
+
content = CASE WHEN $preserveContent THEN messages.content ELSE excluded.content END,
|
|
314
|
+
media_data = COALESCE(excluded.media_data, messages.media_data),
|
|
315
|
+
media_filename = COALESCE(excluded.media_filename, messages.media_filename),
|
|
316
|
+
timestamp = CASE WHEN $preserveTimestamp THEN messages.timestamp ELSE excluded.timestamp END
|
|
305
317
|
`);
|
|
306
318
|
|
|
307
319
|
for (let messages__value of messages) {
|
|
308
320
|
let id = messages__value.key?.id,
|
|
309
321
|
chatId = messages__value.key?.remoteJid,
|
|
310
322
|
fromMe = messages__value.key?.fromMe ? 1 : 0,
|
|
311
|
-
timestamp = messages__value.messageTimestamp;
|
|
323
|
+
timestamp = Number(messages__value.messageTimestamp ?? NaN);
|
|
324
|
+
let isEdited = messages__value.message?.editedMessage !== undefined;
|
|
325
|
+
// Edit events carry the edit time, not the original send time.
|
|
326
|
+
let preserveTimestamp = isEdited || isNaN(timestamp);
|
|
312
327
|
|
|
313
328
|
// status posts and newsletter items are not conversations. they carry
|
|
314
329
|
// their author in remoteJidAlt, so without this they would be stored
|
|
@@ -317,12 +332,7 @@ export default class wahelperDaemon {
|
|
|
317
332
|
continue;
|
|
318
333
|
}
|
|
319
334
|
|
|
320
|
-
if (timestamp
|
|
321
|
-
timestamp = Number(timestamp);
|
|
322
|
-
if (isNaN(timestamp)) {
|
|
323
|
-
timestamp = Math.floor(Date.now() / 1000);
|
|
324
|
-
}
|
|
325
|
-
} else {
|
|
335
|
+
if (isNaN(timestamp)) {
|
|
326
336
|
timestamp = Math.floor(Date.now() / 1000);
|
|
327
337
|
}
|
|
328
338
|
|
|
@@ -365,6 +375,7 @@ export default class wahelperDaemon {
|
|
|
365
375
|
}
|
|
366
376
|
|
|
367
377
|
let content = null,
|
|
378
|
+
preserveContent = false,
|
|
368
379
|
mediaFilename = null,
|
|
369
380
|
mediaData = null,
|
|
370
381
|
mediaBufferInput = null;
|
|
@@ -484,8 +495,9 @@ export default class wahelperDaemon {
|
|
|
484
495
|
}
|
|
485
496
|
|
|
486
497
|
// skip media download on first run (initial history sync after fresh pairing)
|
|
487
|
-
if (this.isFirstRun) {
|
|
498
|
+
if (this.isFirstRun && !isEdited) {
|
|
488
499
|
if (content === null || content === '') {
|
|
500
|
+
preserveContent = true;
|
|
489
501
|
content = '[Media message not downloaded on first run]';
|
|
490
502
|
}
|
|
491
503
|
mediaFilename = null;
|
|
@@ -506,12 +518,21 @@ export default class wahelperDaemon {
|
|
|
506
518
|
mediaData = buffer.toString('base64');
|
|
507
519
|
this.log('✅ Downloaded media ' + mediaFilename);
|
|
508
520
|
} catch (error) {
|
|
509
|
-
|
|
510
|
-
this.log('⚠️ Failed to download media: ' + error.message + '. Storing URL instead.');
|
|
521
|
+
this.log('⚠️ Failed to download media: ' + error.message + '. Leaving media data empty.');
|
|
511
522
|
}
|
|
512
523
|
}
|
|
513
524
|
|
|
514
|
-
query.run(
|
|
525
|
+
query.run({
|
|
526
|
+
id,
|
|
527
|
+
from,
|
|
528
|
+
to,
|
|
529
|
+
content,
|
|
530
|
+
mediaData,
|
|
531
|
+
mediaFilename,
|
|
532
|
+
timestamp,
|
|
533
|
+
preserveContent: Number(preserveContent),
|
|
534
|
+
preserveTimestamp: Number(preserveTimestamp)
|
|
535
|
+
});
|
|
515
536
|
count++;
|
|
516
537
|
|
|
517
538
|
if (length < 100 || count % 100 === 0) {
|
|
@@ -526,11 +547,11 @@ export default class wahelperDaemon {
|
|
|
526
547
|
this.db.exec('COMMIT');
|
|
527
548
|
this.log('END TRANSACTION');
|
|
528
549
|
if (count > 0) {
|
|
529
|
-
this.log('Stored ' + count + '
|
|
550
|
+
this.log('Stored ' + count + ' messages to database (' + length + ' total received)');
|
|
530
551
|
process.stdout.write(
|
|
531
552
|
'\r✅ Stored ' +
|
|
532
553
|
count +
|
|
533
|
-
'
|
|
554
|
+
' messages to database (' +
|
|
534
555
|
length +
|
|
535
556
|
' total received)' +
|
|
536
557
|
' '.repeat(10) +
|
|
@@ -830,6 +851,7 @@ export default class wahelperDaemon {
|
|
|
830
851
|
|
|
831
852
|
socket.ev.on('messages.update', async updates => {
|
|
832
853
|
try {
|
|
854
|
+
await this.storeDataToDatabase({ updates });
|
|
833
855
|
await this.markMessagesRead(updates);
|
|
834
856
|
} catch (error) {
|
|
835
857
|
this.log('⛔ messages.update handler failed: ' + error.message);
|
|
@@ -1173,7 +1195,12 @@ export default class wahelperDaemon {
|
|
|
1173
1195
|
}
|
|
1174
1196
|
}
|
|
1175
1197
|
|
|
1176
|
-
|
|
1198
|
+
// Importing the class must not start the daemon or connect to WhatsApp.
|
|
1199
|
+
if (
|
|
1200
|
+
process.argv[1] &&
|
|
1201
|
+
fs.existsSync(process.argv[1]) &&
|
|
1202
|
+
fs.realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)
|
|
1203
|
+
) {
|
|
1177
1204
|
let daemon = new wahelperDaemon();
|
|
1178
1205
|
daemon.init();
|
|
1179
1206
|
}
|
package/wahelper.js
CHANGED
|
@@ -26,7 +26,11 @@ export default class wahelper {
|
|
|
26
26
|
this.authFolder = 'auth_' + this.formatNumber(this.args.device);
|
|
27
27
|
this.dbPath = 'whatsapp_' + this.formatNumber(this.args.device) + '.sqlite';
|
|
28
28
|
this.logPath = 'whatsapp_' + this.formatNumber(this.args.device) + '.log';
|
|
29
|
-
this.
|
|
29
|
+
if (this.args.request_id !== undefined && !/^[a-f0-9]{32}$/.test(this.args.request_id)) {
|
|
30
|
+
throw new Error('Invalid request id');
|
|
31
|
+
}
|
|
32
|
+
let requestSuffix = this.args.request_id === undefined ? '' : '_' + this.args.request_id;
|
|
33
|
+
this.dataPath = 'whatsapp_' + this.formatNumber(this.args.device) + requestSuffix + '.json';
|
|
30
34
|
this.port = this.computePort(this.formatNumber(this.args.device));
|
|
31
35
|
this.authToken = this.getAuthToken();
|
|
32
36
|
}
|
|
@@ -199,6 +203,7 @@ export default class wahelper {
|
|
|
199
203
|
};
|
|
200
204
|
} catch (error) {
|
|
201
205
|
this.log('⛔ Error fetching database: ' + error.message + ' (code: ' + error.code + ')');
|
|
206
|
+
this.write({ success: false, message: 'error', data: null }, true);
|
|
202
207
|
}
|
|
203
208
|
return null;
|
|
204
209
|
}
|
|
@@ -269,6 +274,7 @@ export default class wahelper {
|
|
|
269
274
|
};
|
|
270
275
|
} catch (error) {
|
|
271
276
|
this.log('⛔ Error fetching message from database: ' + error.message + ' (code: ' + error.code + ')');
|
|
277
|
+
this.write({ success: false, message: 'error', data: null }, true);
|
|
272
278
|
}
|
|
273
279
|
return null;
|
|
274
280
|
}
|
|
@@ -576,7 +582,14 @@ export default class wahelper {
|
|
|
576
582
|
this.writeOnEnd = msg;
|
|
577
583
|
return;
|
|
578
584
|
}
|
|
579
|
-
|
|
585
|
+
let responsePath = this.dirname + '/' + this.dataPath;
|
|
586
|
+
let temporaryPath = responsePath + '.' + crypto.randomUUID() + '.tmp';
|
|
587
|
+
try {
|
|
588
|
+
fs.writeFileSync(temporaryPath, JSON.stringify(msg), { flag: 'wx' });
|
|
589
|
+
fs.renameSync(temporaryPath, responsePath);
|
|
590
|
+
} finally {
|
|
591
|
+
fs.rmSync(temporaryPath, { force: true });
|
|
592
|
+
}
|
|
580
593
|
}
|
|
581
594
|
|
|
582
595
|
initDatabase() {
|
|
@@ -621,7 +634,14 @@ export default class wahelper {
|
|
|
621
634
|
}
|
|
622
635
|
}
|
|
623
636
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
.
|
|
627
|
-
.
|
|
637
|
+
// Importing the class must not start the CLI or terminate the caller.
|
|
638
|
+
if (
|
|
639
|
+
process.argv[1] &&
|
|
640
|
+
fs.existsSync(process.argv[1]) &&
|
|
641
|
+
fs.realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)
|
|
642
|
+
) {
|
|
643
|
+
let wa = new wahelper();
|
|
644
|
+
wa.init()
|
|
645
|
+
.then(() => process.exit(0))
|
|
646
|
+
.catch(() => process.exit(1));
|
|
647
|
+
}
|