nodejs-insta-private-api-mqtt 1.3.14 → 1.3.15
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/README.md +280 -29
- package/dist/core/request.js +127 -53
- package/dist/realtime/commands/enhanced.direct.commands.js +86 -71
- package/dist/repositories/direct-thread.repository.js +108 -15
- package/dist/sendmedia/sendPhoto.js +115 -66
- package/package.json +1 -1
|
@@ -39,8 +39,7 @@ class EnhancedDirectCommands {
|
|
|
39
39
|
|
|
40
40
|
// Compress JSON payload
|
|
41
41
|
const json = JSON.stringify(command);
|
|
42
|
-
const
|
|
43
|
-
const payload = await compressDeflate(json);
|
|
42
|
+
const payload = await (0, shared_1.compressDeflate)(json);
|
|
44
43
|
|
|
45
44
|
// Send to MQTT
|
|
46
45
|
this.enhancedDebug(`Publishing to MQTT topic ${constants_1.Topics.SEND_MESSAGE.id}`);
|
|
@@ -80,8 +79,7 @@ class EnhancedDirectCommands {
|
|
|
80
79
|
};
|
|
81
80
|
|
|
82
81
|
const json = JSON.stringify(command);
|
|
83
|
-
const
|
|
84
|
-
const payload = await compressDeflate(json);
|
|
82
|
+
const payload = await (0, shared_1.compressDeflate)(json);
|
|
85
83
|
|
|
86
84
|
this.enhancedDebug(`Publishing delete command to MQTT topic ${constants_1.Topics.SEND_MESSAGE.id}`);
|
|
87
85
|
const result = await mqtt.publish({
|
|
@@ -121,8 +119,7 @@ class EnhancedDirectCommands {
|
|
|
121
119
|
};
|
|
122
120
|
|
|
123
121
|
const json = JSON.stringify(command);
|
|
124
|
-
const
|
|
125
|
-
const payload = await compressDeflate(json);
|
|
122
|
+
const payload = await (0, shared_1.compressDeflate)(json);
|
|
126
123
|
|
|
127
124
|
this.enhancedDebug(`Publishing edit command to MQTT topic ${constants_1.Topics.SEND_MESSAGE.id}`);
|
|
128
125
|
const result = await mqtt.publish({
|
|
@@ -163,8 +160,7 @@ class EnhancedDirectCommands {
|
|
|
163
160
|
};
|
|
164
161
|
|
|
165
162
|
const json = JSON.stringify(command);
|
|
166
|
-
const
|
|
167
|
-
const payload = await compressDeflate(json);
|
|
163
|
+
const payload = await (0, shared_1.compressDeflate)(json);
|
|
168
164
|
|
|
169
165
|
this.enhancedDebug(`Publishing reply command to MQTT topic ${constants_1.Topics.SEND_MESSAGE.id}`);
|
|
170
166
|
const result = await mqtt.publish({
|
|
@@ -202,8 +198,7 @@ class EnhancedDirectCommands {
|
|
|
202
198
|
};
|
|
203
199
|
|
|
204
200
|
const json = JSON.stringify(command);
|
|
205
|
-
const
|
|
206
|
-
const payload = await compressDeflate(json);
|
|
201
|
+
const payload = await (0, shared_1.compressDeflate)(json);
|
|
207
202
|
|
|
208
203
|
this.enhancedDebug(`Publishing follow subscription to MQTT`);
|
|
209
204
|
const result = await mqtt.publish({
|
|
@@ -241,8 +236,7 @@ class EnhancedDirectCommands {
|
|
|
241
236
|
};
|
|
242
237
|
|
|
243
238
|
const json = JSON.stringify(command);
|
|
244
|
-
const
|
|
245
|
-
const payload = await compressDeflate(json);
|
|
239
|
+
const payload = await (0, shared_1.compressDeflate)(json);
|
|
246
240
|
|
|
247
241
|
this.enhancedDebug(`Publishing mention subscription to MQTT`);
|
|
248
242
|
const result = await mqtt.publish({
|
|
@@ -280,8 +274,7 @@ class EnhancedDirectCommands {
|
|
|
280
274
|
};
|
|
281
275
|
|
|
282
276
|
const json = JSON.stringify(command);
|
|
283
|
-
const
|
|
284
|
-
const payload = await compressDeflate(json);
|
|
277
|
+
const payload = await (0, shared_1.compressDeflate)(json);
|
|
285
278
|
|
|
286
279
|
this.enhancedDebug(`Publishing call subscription to MQTT`);
|
|
287
280
|
const result = await mqtt.publish({
|
|
@@ -320,8 +313,7 @@ class EnhancedDirectCommands {
|
|
|
320
313
|
};
|
|
321
314
|
|
|
322
315
|
const json = JSON.stringify(command);
|
|
323
|
-
const
|
|
324
|
-
const payload = await compressDeflate(json);
|
|
316
|
+
const payload = await (0, shared_1.compressDeflate)(json);
|
|
325
317
|
|
|
326
318
|
this.enhancedDebug(`Publishing add member command to MQTT`);
|
|
327
319
|
const result = await mqtt.publish({
|
|
@@ -360,8 +352,7 @@ class EnhancedDirectCommands {
|
|
|
360
352
|
};
|
|
361
353
|
|
|
362
354
|
const json = JSON.stringify(command);
|
|
363
|
-
const
|
|
364
|
-
const payload = await compressDeflate(json);
|
|
355
|
+
const payload = await (0, shared_1.compressDeflate)(json);
|
|
365
356
|
|
|
366
357
|
this.enhancedDebug(`Publishing remove member command to MQTT`);
|
|
367
358
|
const result = await mqtt.publish({
|
|
@@ -403,8 +394,7 @@ class EnhancedDirectCommands {
|
|
|
403
394
|
};
|
|
404
395
|
|
|
405
396
|
const json = JSON.stringify(command);
|
|
406
|
-
const
|
|
407
|
-
const payload = await compressDeflate(json);
|
|
397
|
+
const payload = await (0, shared_1.compressDeflate)(json);
|
|
408
398
|
|
|
409
399
|
this.enhancedDebug(`Publishing reaction to MQTT`);
|
|
410
400
|
const result = await mqtt.publish({
|
|
@@ -443,8 +433,7 @@ class EnhancedDirectCommands {
|
|
|
443
433
|
};
|
|
444
434
|
|
|
445
435
|
const json = JSON.stringify(command);
|
|
446
|
-
const
|
|
447
|
-
const payload = await compressDeflate(json);
|
|
436
|
+
const payload = await (0, shared_1.compressDeflate)(json);
|
|
448
437
|
|
|
449
438
|
this.enhancedDebug(`Publishing mark as seen to MQTT`);
|
|
450
439
|
const result = await mqtt.publish({
|
|
@@ -483,8 +472,7 @@ class EnhancedDirectCommands {
|
|
|
483
472
|
};
|
|
484
473
|
|
|
485
474
|
const json = JSON.stringify(command);
|
|
486
|
-
const
|
|
487
|
-
const payload = await compressDeflate(json);
|
|
475
|
+
const payload = await (0, shared_1.compressDeflate)(json);
|
|
488
476
|
|
|
489
477
|
this.enhancedDebug(`Publishing activity indicator to MQTT`);
|
|
490
478
|
const result = await mqtt.publish({
|
|
@@ -503,11 +491,18 @@ class EnhancedDirectCommands {
|
|
|
503
491
|
|
|
504
492
|
/**
|
|
505
493
|
* Send media (image/video) via MQTT
|
|
494
|
+
* If uploadId present or item_type indicates photo, delegate to MQTT photo path.
|
|
506
495
|
*/
|
|
507
496
|
async sendMedia({ text, mediaId, threadId, clientContext, uploadId }) {
|
|
508
497
|
this.enhancedDebug(`Sending media ${mediaId} (uploadId: ${uploadId}) to ${threadId} via MQTT`);
|
|
509
498
|
|
|
510
499
|
try {
|
|
500
|
+
// If an uploadId exists, this is a DM upload flow — use photo MQTT path
|
|
501
|
+
if (uploadId) {
|
|
502
|
+
return this.sendPhotoMqtt({ uploadId: String(uploadId), threadId: String(threadId), caption: text || '', clientContext });
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Otherwise continue with existing generic media publish (share/post style)
|
|
511
506
|
const mqtt = this.realtimeClient.mqtt || this.realtimeClient._mqtt;
|
|
512
507
|
if (!mqtt || typeof mqtt.publish !== 'function') {
|
|
513
508
|
throw new Error('MQTT client not available');
|
|
@@ -529,8 +524,7 @@ class EnhancedDirectCommands {
|
|
|
529
524
|
this.enhancedDebug(`Payload: ${JSON.stringify(command)}`);
|
|
530
525
|
|
|
531
526
|
const json = JSON.stringify(command);
|
|
532
|
-
const
|
|
533
|
-
const payload = await compressDeflate(json);
|
|
527
|
+
const payload = await (0, shared_1.compressDeflate)(json);
|
|
534
528
|
|
|
535
529
|
this.enhancedDebug(`Publishing media to MQTT topic ${constants_1.Topics.SEND_MESSAGE.id}`);
|
|
536
530
|
const result = await mqtt.publish({
|
|
@@ -547,6 +541,48 @@ class EnhancedDirectCommands {
|
|
|
547
541
|
}
|
|
548
542
|
}
|
|
549
543
|
|
|
544
|
+
/**
|
|
545
|
+
* Proper MQTT photo send. This publishes the minimal payload Instagram expects
|
|
546
|
+
* for Direct Message photos (upload_id + thread_id). Must be called after rupload.
|
|
547
|
+
*/
|
|
548
|
+
async sendPhotoMqtt({ uploadId, threadId, caption = '', clientContext }) {
|
|
549
|
+
this.enhancedDebug(`Sending photo via MQTT uploadId=${uploadId} to thread=${threadId}`);
|
|
550
|
+
try {
|
|
551
|
+
const mqtt = this.realtimeClient.mqtt || this.realtimeClient._mqtt;
|
|
552
|
+
if (!mqtt || typeof mqtt.publish !== 'function') {
|
|
553
|
+
throw new Error('MQTT client not available');
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
const ctx = clientContext || (0, uuid_1.v4)();
|
|
557
|
+
const command = {
|
|
558
|
+
action: 'send_item',
|
|
559
|
+
thread_id: String(threadId),
|
|
560
|
+
item_type: 'photo',
|
|
561
|
+
upload_id: String(uploadId),
|
|
562
|
+
text: caption || '',
|
|
563
|
+
timestamp: Date.now(),
|
|
564
|
+
client_context: ctx,
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
this.enhancedDebug(`Photo payload: ${JSON.stringify(command)}`);
|
|
568
|
+
const json = JSON.stringify(command);
|
|
569
|
+
const payload = await (0, shared_1.compressDeflate)(json);
|
|
570
|
+
|
|
571
|
+
this.enhancedDebug(`Publishing photo to MQTT topic ${constants_1.Topics.SEND_MESSAGE.id}`);
|
|
572
|
+
const result = await mqtt.publish({
|
|
573
|
+
topic: constants_1.Topics.SEND_MESSAGE.id,
|
|
574
|
+
qosLevel: 1,
|
|
575
|
+
payload: payload,
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
this.enhancedDebug(`✅ Photo published via MQTT!`);
|
|
579
|
+
return result;
|
|
580
|
+
} catch (err) {
|
|
581
|
+
this.enhancedDebug(`Photo MQTT publish failed: ${err.message}`);
|
|
582
|
+
throw err;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
550
586
|
/**
|
|
551
587
|
* Send location via MQTT
|
|
552
588
|
*/
|
|
@@ -571,8 +607,7 @@ class EnhancedDirectCommands {
|
|
|
571
607
|
};
|
|
572
608
|
|
|
573
609
|
const json = JSON.stringify(command);
|
|
574
|
-
const
|
|
575
|
-
const payload = await compressDeflate(json);
|
|
610
|
+
const payload = await (0, shared_1.compressDeflate)(json);
|
|
576
611
|
|
|
577
612
|
this.enhancedDebug(`Publishing location to MQTT`);
|
|
578
613
|
const result = await mqtt.publish({
|
|
@@ -613,8 +648,7 @@ class EnhancedDirectCommands {
|
|
|
613
648
|
};
|
|
614
649
|
|
|
615
650
|
const json = JSON.stringify(command);
|
|
616
|
-
const
|
|
617
|
-
const payload = await compressDeflate(json);
|
|
651
|
+
const payload = await (0, shared_1.compressDeflate)(json);
|
|
618
652
|
|
|
619
653
|
this.enhancedDebug(`Publishing profile to MQTT`);
|
|
620
654
|
const result = await mqtt.publish({
|
|
@@ -655,8 +689,7 @@ class EnhancedDirectCommands {
|
|
|
655
689
|
};
|
|
656
690
|
|
|
657
691
|
const json = JSON.stringify(command);
|
|
658
|
-
const
|
|
659
|
-
const payload = await compressDeflate(json);
|
|
692
|
+
const payload = await (0, shared_1.compressDeflate)(json);
|
|
660
693
|
|
|
661
694
|
this.enhancedDebug(`Publishing hashtag to MQTT`);
|
|
662
695
|
const result = await mqtt.publish({
|
|
@@ -695,8 +728,7 @@ class EnhancedDirectCommands {
|
|
|
695
728
|
};
|
|
696
729
|
|
|
697
730
|
const json = JSON.stringify(command);
|
|
698
|
-
const
|
|
699
|
-
const payload = await compressDeflate(json);
|
|
731
|
+
const payload = await (0, shared_1.compressDeflate)(json);
|
|
700
732
|
|
|
701
733
|
this.enhancedDebug(`Publishing like to MQTT`);
|
|
702
734
|
const result = await mqtt.publish({
|
|
@@ -737,8 +769,7 @@ class EnhancedDirectCommands {
|
|
|
737
769
|
};
|
|
738
770
|
|
|
739
771
|
const json = JSON.stringify(command);
|
|
740
|
-
const
|
|
741
|
-
const payload = await compressDeflate(json);
|
|
772
|
+
const payload = await (0, shared_1.compressDeflate)(json);
|
|
742
773
|
|
|
743
774
|
this.enhancedDebug(`Publishing story to MQTT`);
|
|
744
775
|
const result = await mqtt.publish({
|
|
@@ -756,8 +787,9 @@ class EnhancedDirectCommands {
|
|
|
756
787
|
}
|
|
757
788
|
|
|
758
789
|
/**
|
|
759
|
-
* Send photo via Realtime (Upload + Broadcast)
|
|
760
|
-
* This method uploads the photo first
|
|
790
|
+
* Send photo via Realtime (Upload + Broadcast via MQTT)
|
|
791
|
+
* This method uploads the photo first (rupload) then publishes the MQTT photo command (send_item item_type=photo).
|
|
792
|
+
* Returns the MQTT publish result.
|
|
761
793
|
*
|
|
762
794
|
* @param {Object} options - Photo sending options
|
|
763
795
|
* @param {Buffer} options.photoBuffer - Image buffer (JPEG/PNG)
|
|
@@ -767,7 +799,7 @@ class EnhancedDirectCommands {
|
|
|
767
799
|
* @param {string} [options.clientContext] - Optional client context
|
|
768
800
|
*/
|
|
769
801
|
async sendPhotoViaRealtime({ photoBuffer, threadId, caption = '', mimeType = 'image/jpeg', clientContext }) {
|
|
770
|
-
this.enhancedDebug(`Sending photo to thread ${threadId} via Realtime`);
|
|
802
|
+
this.enhancedDebug(`Sending photo to thread ${threadId} via Realtime (upload -> MQTT)`);
|
|
771
803
|
|
|
772
804
|
try {
|
|
773
805
|
// Validate inputs
|
|
@@ -823,8 +855,8 @@ class EnhancedDirectCommands {
|
|
|
823
855
|
body: photoBuffer,
|
|
824
856
|
});
|
|
825
857
|
|
|
826
|
-
if (uploadResponse && typeof uploadResponse === 'object' && uploadResponse.upload_id) {
|
|
827
|
-
serverUploadId = uploadResponse.upload_id;
|
|
858
|
+
if (uploadResponse && typeof uploadResponse === 'object' && (uploadResponse.upload_id || uploadResponse.body?.upload_id || uploadResponse.data?.upload_id)) {
|
|
859
|
+
serverUploadId = uploadResponse.upload_id || (uploadResponse.body && uploadResponse.body.upload_id) || (uploadResponse.data && uploadResponse.data.upload_id) || serverUploadId;
|
|
828
860
|
}
|
|
829
861
|
this.enhancedDebug(`✅ Photo uploaded! upload_id: ${serverUploadId}`);
|
|
830
862
|
} catch (uploadErr) {
|
|
@@ -832,32 +864,11 @@ class EnhancedDirectCommands {
|
|
|
832
864
|
throw new Error(`Photo upload failed: ${uploadErr.message}`);
|
|
833
865
|
}
|
|
834
866
|
|
|
835
|
-
// Step 2:
|
|
836
|
-
this.enhancedDebug(`Step 2:
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
action: 'send_item',
|
|
841
|
-
thread_ids: JSON.stringify([String(threadId)]),
|
|
842
|
-
};
|
|
843
|
-
|
|
844
|
-
if (caption) {
|
|
845
|
-
broadcastForm.caption = caption;
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
try {
|
|
849
|
-
const broadcastResponse = await ig.request.send({
|
|
850
|
-
url: '/direct_v2/threads/broadcast/upload_photo/',
|
|
851
|
-
method: 'POST',
|
|
852
|
-
form: broadcastForm,
|
|
853
|
-
});
|
|
854
|
-
|
|
855
|
-
this.enhancedDebug(`✅ Photo sent successfully to thread ${threadId}!`);
|
|
856
|
-
return broadcastResponse;
|
|
857
|
-
} catch (broadcastErr) {
|
|
858
|
-
this.enhancedDebug(`Broadcast error: ${broadcastErr.message}`);
|
|
859
|
-
throw new Error(`Photo broadcast failed: ${broadcastErr.message}`);
|
|
860
|
-
}
|
|
867
|
+
// Step 2: Publish photo via MQTT (correct path)
|
|
868
|
+
this.enhancedDebug(`Step 2: Publishing photo via MQTT to thread ${threadId}...`);
|
|
869
|
+
const mqttResult = await this.sendPhotoMqtt({ uploadId: serverUploadId, threadId: String(threadId), caption, clientContext });
|
|
870
|
+
this.enhancedDebug(`✅ Photo MQTT publish result: ${JSON.stringify(mqttResult)}`);
|
|
871
|
+
return mqttResult;
|
|
861
872
|
|
|
862
873
|
} catch (err) {
|
|
863
874
|
this.enhancedDebug(`sendPhotoViaRealtime failed: ${err.message}`);
|
|
@@ -875,6 +886,9 @@ class EnhancedDirectCommands {
|
|
|
875
886
|
/**
|
|
876
887
|
* Send video via Realtime (Upload + Broadcast)
|
|
877
888
|
*
|
|
889
|
+
* NOTE: Video via MQTT is more complex; for now this continues to use existing rupload + REST broadcast path.
|
|
890
|
+
* If you want MQTT video publish, we can add similar sendVideoMqtt that publishes item_type 'video' with upload_id.
|
|
891
|
+
*
|
|
878
892
|
* @param {Object} options - Video sending options
|
|
879
893
|
* @param {Buffer} options.videoBuffer - Video buffer (MP4)
|
|
880
894
|
* @param {string} options.threadId - Thread ID to send to
|
|
@@ -938,8 +952,8 @@ class EnhancedDirectCommands {
|
|
|
938
952
|
body: videoBuffer,
|
|
939
953
|
});
|
|
940
954
|
|
|
941
|
-
if (uploadResponse && typeof uploadResponse === 'object' && uploadResponse.upload_id) {
|
|
942
|
-
serverUploadId = uploadResponse.upload_id;
|
|
955
|
+
if (uploadResponse && typeof uploadResponse === 'object' && (uploadResponse.upload_id || uploadResponse.body?.upload_id || uploadResponse.data?.upload_id)) {
|
|
956
|
+
serverUploadId = uploadResponse.upload_id || (uploadResponse.body && uploadResponse.body.upload_id) || (uploadResponse.data && uploadResponse.data.upload_id) || serverUploadId;
|
|
943
957
|
}
|
|
944
958
|
this.enhancedDebug(`✅ Video uploaded! upload_id: ${serverUploadId}`);
|
|
945
959
|
} catch (uploadErr) {
|
|
@@ -947,8 +961,8 @@ class EnhancedDirectCommands {
|
|
|
947
961
|
throw new Error(`Video upload failed: ${uploadErr.message}`);
|
|
948
962
|
}
|
|
949
963
|
|
|
950
|
-
// Step 2: Broadcast the uploaded video to the thread
|
|
951
|
-
this.enhancedDebug(`Step 2: Broadcasting video to thread ${threadId}...`);
|
|
964
|
+
// Step 2: Broadcast the uploaded video to the thread via REST (legacy)
|
|
965
|
+
this.enhancedDebug(`Step 2: Broadcasting video to thread ${threadId} via REST upload_video endpoint...`);
|
|
952
966
|
|
|
953
967
|
const broadcastForm = {
|
|
954
968
|
upload_id: serverUploadId,
|
|
@@ -989,3 +1003,4 @@ class EnhancedDirectCommands {
|
|
|
989
1003
|
}
|
|
990
1004
|
}
|
|
991
1005
|
exports.EnhancedDirectCommands = EnhancedDirectCommands;
|
|
1006
|
+
|
|
@@ -20,12 +20,15 @@ class DirectThreadRepository extends Repository {
|
|
|
20
20
|
} catch (error) {
|
|
21
21
|
const shouldRetry =
|
|
22
22
|
(error.data?.error_type === 'server_error' ||
|
|
23
|
-
error.data?.error_type === 'rate_limited'
|
|
23
|
+
error.data?.error_type === 'rate_limited' ||
|
|
24
|
+
error.name === 'IgActionSpamError' ||
|
|
25
|
+
error.status === 503 ||
|
|
26
|
+
error.status === 429) &&
|
|
24
27
|
retries < this.maxRetries;
|
|
25
28
|
|
|
26
29
|
if (shouldRetry) {
|
|
27
30
|
const delay = 1000 * (retries + 1);
|
|
28
|
-
if (process.env.DEBUG) console.log(`[DEBUG] Retrying after ${delay}ms due to ${error.data?.error_type}`);
|
|
31
|
+
if (process.env.DEBUG) console.log(`[DEBUG] Retrying after ${delay}ms due to ${error.data?.error_type || error.message || error.name || error.status}`);
|
|
29
32
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
30
33
|
return this.requestWithRetry(requestFn, retries + 1);
|
|
31
34
|
}
|
|
@@ -59,7 +62,7 @@ class DirectThreadRepository extends Repository {
|
|
|
59
62
|
method: 'GET',
|
|
60
63
|
url: `/api/v1/direct_v2/threads/${threadId}/`,
|
|
61
64
|
});
|
|
62
|
-
return response.body;
|
|
65
|
+
return response.body || response.data || response;
|
|
63
66
|
});
|
|
64
67
|
}
|
|
65
68
|
|
|
@@ -74,7 +77,7 @@ class DirectThreadRepository extends Repository {
|
|
|
74
77
|
url: '/api/v1/direct_v2/threads/get_by_participants/',
|
|
75
78
|
qs: { recipient_users: JSON.stringify(recipientUsers) },
|
|
76
79
|
});
|
|
77
|
-
return response.body;
|
|
80
|
+
return response.body || response.data || response;
|
|
78
81
|
});
|
|
79
82
|
}
|
|
80
83
|
|
|
@@ -99,13 +102,102 @@ class DirectThreadRepository extends Repository {
|
|
|
99
102
|
};
|
|
100
103
|
|
|
101
104
|
return this.requestWithRetry(async () => {
|
|
105
|
+
const payloadForm = options.signed && this.client.request && typeof this.client.request.sign === 'function'
|
|
106
|
+
? this.client.request.sign(form)
|
|
107
|
+
: form;
|
|
108
|
+
|
|
102
109
|
const response = await this.client.request.send({
|
|
103
110
|
url: `/api/v1/direct_v2/threads/broadcast/${options.item}/`,
|
|
104
111
|
method: 'POST',
|
|
105
|
-
form:
|
|
112
|
+
form: payloadForm,
|
|
106
113
|
qs: options.qs,
|
|
107
114
|
});
|
|
108
|
-
return response.body;
|
|
115
|
+
return response.body || response.data || response;
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Broadcast a photo to one or more threads (uses REST configure_photo)
|
|
121
|
+
* Options:
|
|
122
|
+
* - uploadId (required) : upload_id returned from rupload
|
|
123
|
+
* - threadIds or threadId (required) : target thread id(s)
|
|
124
|
+
* - caption (optional) : caption/text to attach
|
|
125
|
+
* - signed (optional, default true) : whether to sign the form (if client.request.sign available)
|
|
126
|
+
*/
|
|
127
|
+
async broadcastPhoto(options) {
|
|
128
|
+
// normalize inputs
|
|
129
|
+
const uploadId = options.uploadId || options.upload_id || options.uploadIdStr;
|
|
130
|
+
const threadIds = options.threadIds || (options.threadId ? [options.threadId] : []);
|
|
131
|
+
const caption = options.caption || options.text || '';
|
|
132
|
+
const signed = (options.signed === undefined) ? true : !!options.signed; // default to true for media
|
|
133
|
+
const mutationToken = new Chance().guid();
|
|
134
|
+
const clientContext = mutationToken;
|
|
135
|
+
|
|
136
|
+
if (!uploadId) throw new Error('broadcastPhoto: uploadId is required');
|
|
137
|
+
if (!threadIds || !Array.isArray(threadIds) || threadIds.length === 0) throw new Error('broadcastPhoto: at least one threadId is required');
|
|
138
|
+
|
|
139
|
+
// Build the form closely matching instagram-private-api / official client expectations
|
|
140
|
+
const form = {
|
|
141
|
+
action: 'send_item', // must be send_item for DM photo
|
|
142
|
+
upload_id: uploadId.toString(),
|
|
143
|
+
thread_ids: JSON.stringify(threadIds),
|
|
144
|
+
client_context: clientContext,
|
|
145
|
+
mutation_token: mutationToken,
|
|
146
|
+
offline_threading_id: clientContext,
|
|
147
|
+
_csrftoken: this.client.state.cookieCsrfToken,
|
|
148
|
+
device_id: this.client.state.deviceId,
|
|
149
|
+
_uuid: this.client.state.uuid,
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
if (caption) {
|
|
153
|
+
// Instagram often expects 'text' for the message body
|
|
154
|
+
form.text = caption;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// perform request with retry wrapper
|
|
158
|
+
return this.requestWithRetry(async () => {
|
|
159
|
+
const payloadForm = (signed && this.client.request && typeof this.client.request.sign === 'function')
|
|
160
|
+
? this.client.request.sign(form)
|
|
161
|
+
: form;
|
|
162
|
+
|
|
163
|
+
const response = await this.client.request.send({
|
|
164
|
+
url: `/api/v1/direct_v2/threads/broadcast/configure_photo/`,
|
|
165
|
+
method: 'POST',
|
|
166
|
+
form: payloadForm,
|
|
167
|
+
qs: {
|
|
168
|
+
use_unified_inbox: true,
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// normalize: some wrappers return { body } or axios response
|
|
173
|
+
const body = response && (response.body || response.data || response);
|
|
174
|
+
|
|
175
|
+
if (!body) {
|
|
176
|
+
const err = new Error('broadcastPhoto: empty response');
|
|
177
|
+
throw err;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// parse if string
|
|
181
|
+
let parsed = null;
|
|
182
|
+
if (typeof body === 'string') {
|
|
183
|
+
try {
|
|
184
|
+
parsed = JSON.parse(body);
|
|
185
|
+
} catch (e) {
|
|
186
|
+
parsed = null;
|
|
187
|
+
}
|
|
188
|
+
} else if (typeof body === 'object') {
|
|
189
|
+
parsed = body;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Typical success: parsed.status === 'ok' OR parsed.media/parsed.result/payload present
|
|
193
|
+
const ok = parsed && (parsed.status === 'ok' || parsed.media || parsed.result || parsed.payload || parsed.items || parsed.thread);
|
|
194
|
+
if (ok) return parsed;
|
|
195
|
+
|
|
196
|
+
// If we reach here, treat as error to trigger retry logic
|
|
197
|
+
const error = new Error('broadcastPhoto: Request failed');
|
|
198
|
+
error.response = response;
|
|
199
|
+
if (parsed) error.data = parsed;
|
|
200
|
+
throw error;
|
|
109
201
|
});
|
|
110
202
|
}
|
|
111
203
|
|
|
@@ -126,7 +218,7 @@ class DirectThreadRepository extends Repository {
|
|
|
126
218
|
item_id: threadItemId,
|
|
127
219
|
},
|
|
128
220
|
});
|
|
129
|
-
return response.body;
|
|
221
|
+
return response.body || response.data || response;
|
|
130
222
|
});
|
|
131
223
|
}
|
|
132
224
|
|
|
@@ -140,7 +232,7 @@ class DirectThreadRepository extends Repository {
|
|
|
140
232
|
method: 'POST',
|
|
141
233
|
form: { _csrftoken: this.client.state.cookieCsrfToken, _uuid: this.client.state.uuid },
|
|
142
234
|
});
|
|
143
|
-
return response.body;
|
|
235
|
+
return response.body || response.data || response;
|
|
144
236
|
});
|
|
145
237
|
}
|
|
146
238
|
|
|
@@ -154,7 +246,7 @@ class DirectThreadRepository extends Repository {
|
|
|
154
246
|
method: 'POST',
|
|
155
247
|
form: { _csrftoken: this.client.state.cookieCsrfToken, _uuid: this.client.state.uuid },
|
|
156
248
|
});
|
|
157
|
-
return response.body;
|
|
249
|
+
return response.body || response.data || response;
|
|
158
250
|
});
|
|
159
251
|
}
|
|
160
252
|
|
|
@@ -168,7 +260,7 @@ class DirectThreadRepository extends Repository {
|
|
|
168
260
|
method: 'POST',
|
|
169
261
|
form: { _csrftoken: this.client.state.cookieCsrfToken, _uuid: this.client.state.uuid },
|
|
170
262
|
});
|
|
171
|
-
return response.body;
|
|
263
|
+
return response.body || response.data || response;
|
|
172
264
|
});
|
|
173
265
|
}
|
|
174
266
|
|
|
@@ -182,7 +274,7 @@ class DirectThreadRepository extends Repository {
|
|
|
182
274
|
method: 'POST',
|
|
183
275
|
form: { _csrftoken: this.client.state.cookieCsrfToken, _uuid: this.client.state.uuid },
|
|
184
276
|
});
|
|
185
|
-
return response.body;
|
|
277
|
+
return response.body || response.data || response;
|
|
186
278
|
});
|
|
187
279
|
}
|
|
188
280
|
|
|
@@ -196,7 +288,7 @@ class DirectThreadRepository extends Repository {
|
|
|
196
288
|
method: 'POST',
|
|
197
289
|
form: { _csrftoken: this.client.state.cookieCsrfToken, _uuid: this.client.state.uuid },
|
|
198
290
|
});
|
|
199
|
-
return response.body;
|
|
291
|
+
return response.body || response.data || response;
|
|
200
292
|
});
|
|
201
293
|
}
|
|
202
294
|
|
|
@@ -211,7 +303,7 @@ class DirectThreadRepository extends Repository {
|
|
|
211
303
|
method: 'POST',
|
|
212
304
|
form: { _csrftoken: this.client.state.cookieCsrfToken, user_ids: JSON.stringify(userIds), _uuid: this.client.state.uuid },
|
|
213
305
|
});
|
|
214
|
-
return response.body;
|
|
306
|
+
return response.body || response.data || response;
|
|
215
307
|
});
|
|
216
308
|
}
|
|
217
309
|
|
|
@@ -225,7 +317,7 @@ class DirectThreadRepository extends Repository {
|
|
|
225
317
|
method: 'POST',
|
|
226
318
|
form: { _csrftoken: this.client.state.cookieCsrfToken, _uuid: this.client.state.uuid },
|
|
227
319
|
});
|
|
228
|
-
return response.body;
|
|
320
|
+
return response.body || response.data || response;
|
|
229
321
|
});
|
|
230
322
|
}
|
|
231
323
|
|
|
@@ -239,9 +331,10 @@ class DirectThreadRepository extends Repository {
|
|
|
239
331
|
method: 'POST',
|
|
240
332
|
form: { _csrftoken: this.client.state.cookieCsrfToken, _uuid: this.client.state.uuid, title },
|
|
241
333
|
});
|
|
242
|
-
return response.body;
|
|
334
|
+
return response.body || response.data || response;
|
|
243
335
|
});
|
|
244
336
|
}
|
|
245
337
|
}
|
|
246
338
|
|
|
247
339
|
module.exports = DirectThreadRepository;
|
|
340
|
+
|