nodejs-insta-private-api-mqtt 1.3.40 → 1.3.42
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 +161 -0
- package/dist/realtime/commands/enhanced.direct.commands.js +332 -112
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -870,3 +870,164 @@ MIT
|
|
|
870
870
|
For issues, bugs, or feature requests: https://github.com/Kunboruto20/nodejs-insta-private-api/issues
|
|
871
871
|
|
|
872
872
|
Documentation: https://github.com/Kunboruto20/nodejs-insta-private-api
|
|
873
|
+
|
|
874
|
+
|
|
875
|
+
---
|
|
876
|
+
## Enhanced Location Usage — Practical Examples (English)
|
|
877
|
+
|
|
878
|
+
The `EnhancedDirectCommands` class (see `enhanced.direct.commands.js`) implements robust location sending for Instagram Direct by trying **story-with-location-sticker → share story to thread → fallback to link**. Below are ready-to-copy examples showing how to use the location-related methods and payloads exposed by the class.
|
|
879
|
+
|
|
880
|
+
> These examples assume:
|
|
881
|
+
> - `realtime` is an instance of `RealtimeClient`.
|
|
882
|
+
> - `realtime.directCommands` is an instance of `EnhancedDirectCommands`.
|
|
883
|
+
> - You have a valid `threadId` (target DM thread).
|
|
884
|
+
> - `realtime.ig` exists when examples require publishing a story via the private IG client.
|
|
885
|
+
|
|
886
|
+
### 1) Send a location when you already have a `venue` object (recommended)
|
|
887
|
+
|
|
888
|
+
```javascript
|
|
889
|
+
// venue shape expected by sendLocation:
|
|
890
|
+
// { id, name, address, lat, lng, facebook_places_id, external_source }
|
|
891
|
+
const venue = {
|
|
892
|
+
id: "213385402",
|
|
893
|
+
name: "McDonald's Unirii",
|
|
894
|
+
address: "Piața Unirii, Bucharest",
|
|
895
|
+
lat: 44.4268,
|
|
896
|
+
lng: 26.1025,
|
|
897
|
+
facebook_places_id: "213385402",
|
|
898
|
+
external_source: "facebook_places"
|
|
899
|
+
};
|
|
900
|
+
|
|
901
|
+
await realtime.directCommands.sendLocation({
|
|
902
|
+
threadId: "340282366841710300949128114477782749726",
|
|
903
|
+
venue,
|
|
904
|
+
text: "Meet me here at 18:00"
|
|
905
|
+
});
|
|
906
|
+
```
|
|
907
|
+
|
|
908
|
+
**What happens:**
|
|
909
|
+
1. The method attempts to publish a Story with a location sticker using `realtime.ig.publish.story`.
|
|
910
|
+
2. If the Story publish succeeds and a `storyId` is returned, `sendUserStory` (reel_share) is used to share the story to the thread.
|
|
911
|
+
3. If either step fails, the method falls back to sending a link to `https://www.instagram.com/explore/locations/{placeId}/` via `itemType: 'link'`.
|
|
912
|
+
|
|
913
|
+
---
|
|
914
|
+
|
|
915
|
+
### 2) Search for a place (instagram private search) and send it
|
|
916
|
+
|
|
917
|
+
Use `searchAndSendLocation()` when you only have a search query or coordinates:
|
|
918
|
+
|
|
919
|
+
```javascript
|
|
920
|
+
await realtime.directCommands.searchAndSendLocation({
|
|
921
|
+
threadId: "340282366841710300949128114477782749726",
|
|
922
|
+
query: "Starbucks Piata Unirii",
|
|
923
|
+
lat: 44.4268,
|
|
924
|
+
lng: 26.1025
|
|
925
|
+
});
|
|
926
|
+
```
|
|
927
|
+
|
|
928
|
+
This helper calls Instagram's `/fbsearch/places/` private endpoint (via `realtime.ig.request`) and then normalizes the first result into the `venue` shape before calling `sendLocation()`.
|
|
929
|
+
|
|
930
|
+
---
|
|
931
|
+
|
|
932
|
+
### 3) Build a location sticker manually & publish story (advanced)
|
|
933
|
+
|
|
934
|
+
If you want direct control over the sticker object or to publish your own image, you can use `createLocationStickerFromVenue()` and `realtime.ig.publish.story()` directly:
|
|
935
|
+
|
|
936
|
+
```javascript
|
|
937
|
+
const venue = {
|
|
938
|
+
id: "213385402",
|
|
939
|
+
name: "McDonald's Unirii",
|
|
940
|
+
address: "Piața Unirii, Bucharest",
|
|
941
|
+
lat: 44.4268,
|
|
942
|
+
lng: 26.1025,
|
|
943
|
+
facebook_places_id: "213385402"
|
|
944
|
+
};
|
|
945
|
+
|
|
946
|
+
// create sticker compatible with publish.story helpers
|
|
947
|
+
const sticker = realtime.directCommands.createLocationStickerFromVenue(venue);
|
|
948
|
+
|
|
949
|
+
// create a tiny placeholder image (1x1 PNG) or your real photo buffer
|
|
950
|
+
const SINGLE_PIXEL_PNG_BASE64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGNgYAAAAAMAAWgmWQ0AAAAASUVORK5CYII=";
|
|
951
|
+
const photoBuffer = Buffer.from(SINGLE_PIXEL_PNG_BASE64, 'base64');
|
|
952
|
+
|
|
953
|
+
// publish story with the sticker (if realtime.ig.publish.story exists)
|
|
954
|
+
const publishResult = await realtime.ig.publish.story({
|
|
955
|
+
file: photoBuffer,
|
|
956
|
+
stickers: [sticker]
|
|
957
|
+
});
|
|
958
|
+
|
|
959
|
+
// try to resolve returned story id and then share it
|
|
960
|
+
const storyId = publishResult?.media?.pk || publishResult?.item_id || publishResult?.upload_id;
|
|
961
|
+
if (storyId) {
|
|
962
|
+
await realtime.directCommands.sendUserStory({
|
|
963
|
+
threadId: "340282366841710300949128114477782749726",
|
|
964
|
+
storyId,
|
|
965
|
+
text: "Location for tonight"
|
|
966
|
+
});
|
|
967
|
+
} else {
|
|
968
|
+
// fallback: send explore link manually
|
|
969
|
+
await realtime.directCommands.sendLink({
|
|
970
|
+
threadId: "340282366841710300949128114477782749726",
|
|
971
|
+
link: `https://www.instagram.com/explore/locations/${venue.facebook_places_id || venue.id}/`,
|
|
972
|
+
text: venue.name
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
```
|
|
976
|
+
|
|
977
|
+
---
|
|
978
|
+
|
|
979
|
+
### 4) Force sending the explore-location link (explicit fallback)
|
|
980
|
+
|
|
981
|
+
If you don't want to publish a story and only need the location link in DM:
|
|
982
|
+
|
|
983
|
+
```javascript
|
|
984
|
+
const placeId = "213385402";
|
|
985
|
+
await realtime.directCommands.sendLink({
|
|
986
|
+
threadId: "340282366841710300949128114477782749726",
|
|
987
|
+
link: `https://www.instagram.com/explore/locations/${placeId}/`,
|
|
988
|
+
text: "Meet here"
|
|
989
|
+
});
|
|
990
|
+
```
|
|
991
|
+
|
|
992
|
+
---
|
|
993
|
+
|
|
994
|
+
### 5) Error handling & debug tips
|
|
995
|
+
|
|
996
|
+
```javascript
|
|
997
|
+
try {
|
|
998
|
+
await realtime.directCommands.sendLocation({ threadId, venue, text: "See you" });
|
|
999
|
+
console.log("Location sent!");
|
|
1000
|
+
} catch (err) {
|
|
1001
|
+
console.error("Failed to send location:", err);
|
|
1002
|
+
// fallback to explicit link if needed
|
|
1003
|
+
await realtime.directCommands.sendLink({
|
|
1004
|
+
threadId,
|
|
1005
|
+
link: `https://www.instagram.com/explore/locations/${venue.facebook_places_id || venue.id}/`,
|
|
1006
|
+
text: venue.name || "Location"
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
1009
|
+
```
|
|
1010
|
+
|
|
1011
|
+
If you need verbose logs, enable debug for the realtime/enhanced module:
|
|
1012
|
+
|
|
1013
|
+
```bash
|
|
1014
|
+
# in your environment (example)
|
|
1015
|
+
DEBUG="realtime:enhanced-commands" node your_bot.js
|
|
1016
|
+
# or to see broader realtime logs
|
|
1017
|
+
DEBUG="realtime:*" node your_bot.js
|
|
1018
|
+
```
|
|
1019
|
+
|
|
1020
|
+
---
|
|
1021
|
+
|
|
1022
|
+
### 6) Quick checklist (what the library needs to make story-with-sticker work)
|
|
1023
|
+
|
|
1024
|
+
- `realtime.ig` must exist and expose `publish.story(...)` (a private client publish helper).
|
|
1025
|
+
- The `venue` must include either `facebook_places_id` or `id`.
|
|
1026
|
+
- If `realtime.ig.publish.story` is unavailable or Instagram rejects the sticker, the library **automatically falls back** to sending a DM link to the Explore locations page.
|
|
1027
|
+
|
|
1028
|
+
---
|
|
1029
|
+
|
|
1030
|
+
## End of Location Examples
|
|
1031
|
+
|
|
1032
|
+
These examples are appended to the original README in order to keep the whole original file intact while adding clear, English examples for location flows.
|
|
1033
|
+
|
|
@@ -1,20 +1,29 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.EnhancedDirectCommands = void 0;
|
|
4
|
+
|
|
4
5
|
const shared_1 = require("../../shared");
|
|
5
6
|
const uuid_1 = require("uuid");
|
|
6
7
|
const constants_1 = require("../../constants");
|
|
7
8
|
const thrift_1 = require("../../thrift");
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
11
|
+
* EnhancedDirectCommands
|
|
12
|
+
*
|
|
13
|
+
* - Full, self-contained class that publishes correctly-formatted payloads to Instagram's
|
|
14
|
+
* Direct MQTT (Thrift + compressed payloads).
|
|
15
|
+
* - Updated sendLocation implementation:
|
|
16
|
+
* 1) try publish a story with a Location sticker (preferred, matches APK behavior)
|
|
17
|
+
* 2) share that story to the thread (reel/media_share)
|
|
18
|
+
* 3) fallback: send a link to /explore/locations/{placeId}/ if (1) fails
|
|
19
|
+
*
|
|
20
|
+
* Note: server-side validation may still reject location stickers in some contexts.
|
|
12
21
|
*/
|
|
13
22
|
class EnhancedDirectCommands {
|
|
14
23
|
constructor(client) {
|
|
15
24
|
this.realtimeClient = client;
|
|
16
25
|
this.enhancedDebug = (0, shared_1.debugChannel)('realtime', 'enhanced-commands');
|
|
17
|
-
|
|
26
|
+
|
|
18
27
|
// Foreground state config for Thrift encoding (matching instagram_mqtt)
|
|
19
28
|
this.foregroundStateConfig = [
|
|
20
29
|
thrift_1.ThriftDescriptors.boolean('inForegroundApp', 1),
|
|
@@ -29,10 +38,10 @@ class EnhancedDirectCommands {
|
|
|
29
38
|
}
|
|
30
39
|
|
|
31
40
|
/**
|
|
32
|
-
*
|
|
41
|
+
* Attempt to locate the MQTT client object on the realtime client.
|
|
42
|
+
* Many wrappers expose mqtt under different property names.
|
|
33
43
|
*/
|
|
34
44
|
getMqtt() {
|
|
35
|
-
// Try several known property names for mqtt client (some libs/wrappers expose differently)
|
|
36
45
|
const candidates = [
|
|
37
46
|
'mqtt',
|
|
38
47
|
'_mqtt',
|
|
@@ -43,7 +52,6 @@ class EnhancedDirectCommands {
|
|
|
43
52
|
];
|
|
44
53
|
let mqtt = null;
|
|
45
54
|
for (const key of candidates) {
|
|
46
|
-
// eslint-disable-next-line no-prototype-builtins
|
|
47
55
|
if (this.realtimeClient && Object.prototype.hasOwnProperty.call(this.realtimeClient, key) && this.realtimeClient[key]) {
|
|
48
56
|
mqtt = this.realtimeClient[key];
|
|
49
57
|
break;
|
|
@@ -67,7 +75,6 @@ class EnhancedDirectCommands {
|
|
|
67
75
|
* - mqtt.publish(topic, payload, { qos }, cb)
|
|
68
76
|
*/
|
|
69
77
|
async publishToMqtt(mqtt, publishObj) {
|
|
70
|
-
// publishObj: { topic, payload, qosLevel }
|
|
71
78
|
const topic = publishObj.topic;
|
|
72
79
|
const payload = publishObj.payload;
|
|
73
80
|
const qosLevel = typeof publishObj.qosLevel !== 'undefined' ? publishObj.qosLevel : 1;
|
|
@@ -132,10 +139,10 @@ class EnhancedDirectCommands {
|
|
|
132
139
|
*/
|
|
133
140
|
async sendForegroundState(state) {
|
|
134
141
|
this.enhancedDebug(`Updated foreground state: ${JSON.stringify(state)}`);
|
|
135
|
-
|
|
142
|
+
|
|
136
143
|
try {
|
|
137
144
|
const mqtt = this.getMqtt();
|
|
138
|
-
|
|
145
|
+
|
|
139
146
|
const thriftBuffer = (0, thrift_1.thriftWriteFromObject)(state, this.foregroundStateConfig);
|
|
140
147
|
const concat = Buffer.concat([
|
|
141
148
|
Buffer.alloc(1, 0),
|
|
@@ -144,18 +151,18 @@ class EnhancedDirectCommands {
|
|
|
144
151
|
|
|
145
152
|
// ensure we pass Buffer to compressDeflate
|
|
146
153
|
const payload = await (0, shared_1.compressDeflate)(concat);
|
|
147
|
-
|
|
154
|
+
|
|
148
155
|
const result = await this.publishToMqtt(mqtt, {
|
|
149
156
|
topic: constants_1.Topics.FOREGROUND_STATE.id,
|
|
150
157
|
payload: payload,
|
|
151
158
|
qosLevel: 1,
|
|
152
159
|
});
|
|
153
|
-
|
|
160
|
+
|
|
154
161
|
// Update keepAlive if provided
|
|
155
162
|
if ((0, shared_1.notUndefined)(state.keepAliveTimeout)) {
|
|
156
163
|
mqtt.keepAlive = state.keepAliveTimeout;
|
|
157
164
|
}
|
|
158
|
-
|
|
165
|
+
|
|
159
166
|
this.enhancedDebug(`✅ Foreground state updated via MQTT!`);
|
|
160
167
|
return result;
|
|
161
168
|
} catch (err) {
|
|
@@ -166,15 +173,16 @@ class EnhancedDirectCommands {
|
|
|
166
173
|
|
|
167
174
|
/**
|
|
168
175
|
* Base command sender (matching instagram_mqtt format)
|
|
176
|
+
* It encodes the command as JSON, compresses, and publishes to SEND_MESSAGE topic.
|
|
169
177
|
*/
|
|
170
178
|
async sendCommand({ action, data, threadId, clientContext }) {
|
|
171
179
|
try {
|
|
172
180
|
const mqtt = this.getMqtt();
|
|
173
|
-
|
|
181
|
+
|
|
174
182
|
if (clientContext) {
|
|
175
183
|
data.client_context = clientContext;
|
|
176
184
|
}
|
|
177
|
-
|
|
185
|
+
|
|
178
186
|
const json = JSON.stringify({
|
|
179
187
|
action,
|
|
180
188
|
thread_id: threadId,
|
|
@@ -183,7 +191,7 @@ class EnhancedDirectCommands {
|
|
|
183
191
|
|
|
184
192
|
// ensure Buffer (some compress implementations expect Buffer)
|
|
185
193
|
const payload = await (0, shared_1.compressDeflate)(Buffer.from(json));
|
|
186
|
-
|
|
194
|
+
|
|
187
195
|
return this.publishToMqtt(mqtt, {
|
|
188
196
|
topic: constants_1.Topics.SEND_MESSAGE.id,
|
|
189
197
|
qosLevel: 1,
|
|
@@ -211,11 +219,11 @@ class EnhancedDirectCommands {
|
|
|
211
219
|
}
|
|
212
220
|
|
|
213
221
|
/**
|
|
214
|
-
* Send text via MQTT
|
|
222
|
+
* Send text via MQTT
|
|
215
223
|
*/
|
|
216
224
|
async sendText({ text, clientContext, threadId }) {
|
|
217
225
|
this.enhancedDebug(`Sending text to ${threadId}: "${text}"`);
|
|
218
|
-
|
|
226
|
+
|
|
219
227
|
const result = await this.sendItem({
|
|
220
228
|
itemType: 'text',
|
|
221
229
|
threadId,
|
|
@@ -224,7 +232,7 @@ class EnhancedDirectCommands {
|
|
|
224
232
|
text,
|
|
225
233
|
},
|
|
226
234
|
});
|
|
227
|
-
|
|
235
|
+
|
|
228
236
|
this.enhancedDebug(`✅ Text sent via MQTT!`);
|
|
229
237
|
return result;
|
|
230
238
|
}
|
|
@@ -241,11 +249,11 @@ class EnhancedDirectCommands {
|
|
|
241
249
|
}
|
|
242
250
|
|
|
243
251
|
/**
|
|
244
|
-
* Send hashtag via MQTT
|
|
252
|
+
* Send hashtag via MQTT
|
|
245
253
|
*/
|
|
246
254
|
async sendHashtag({ text, threadId, hashtag, clientContext }) {
|
|
247
255
|
this.enhancedDebug(`Sending hashtag #${hashtag} to ${threadId}`);
|
|
248
|
-
|
|
256
|
+
|
|
249
257
|
const result = await this.sendItem({
|
|
250
258
|
itemType: 'hashtag',
|
|
251
259
|
threadId,
|
|
@@ -256,55 +264,264 @@ class EnhancedDirectCommands {
|
|
|
256
264
|
item_id: hashtag,
|
|
257
265
|
},
|
|
258
266
|
});
|
|
259
|
-
|
|
267
|
+
|
|
260
268
|
this.enhancedDebug(`✅ Hashtag sent via MQTT!`);
|
|
261
269
|
return result;
|
|
262
270
|
}
|
|
263
271
|
|
|
264
272
|
/**
|
|
265
|
-
* Send like via MQTT
|
|
273
|
+
* Send like via MQTT
|
|
266
274
|
*/
|
|
267
275
|
async sendLike({ threadId, clientContext }) {
|
|
268
276
|
this.enhancedDebug(`Sending like in thread ${threadId}`);
|
|
269
|
-
|
|
277
|
+
|
|
270
278
|
const result = await this.sendItem({
|
|
271
279
|
itemType: 'like',
|
|
272
280
|
threadId,
|
|
273
281
|
clientContext,
|
|
274
282
|
data: {},
|
|
275
283
|
});
|
|
276
|
-
|
|
284
|
+
|
|
277
285
|
this.enhancedDebug(`✅ Like sent via MQTT!`);
|
|
278
286
|
return result;
|
|
279
287
|
}
|
|
280
288
|
|
|
281
289
|
/**
|
|
282
|
-
* Send location via MQTT (
|
|
290
|
+
* Send location via MQTT (reworked)
|
|
291
|
+
*
|
|
292
|
+
* Now:
|
|
293
|
+
* - Tries to publish a Story with a Location sticker (preferred; matches APK behavior)
|
|
294
|
+
* - Shares that Story to the thread (reel_share / media_share)
|
|
295
|
+
* - If any step fails, falls back to sending a link to /explore/locations/{placeId}/
|
|
296
|
+
*
|
|
297
|
+
* venue shape expected:
|
|
298
|
+
* { id, name, address, lat, lng, facebook_places_id, external_source }
|
|
283
299
|
*/
|
|
284
|
-
async sendLocation({
|
|
285
|
-
this.enhancedDebug(`
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
this.
|
|
299
|
-
|
|
300
|
+
async sendLocation({ threadId, clientContext, venue, text = '' }) {
|
|
301
|
+
this.enhancedDebug(`Attempting to send location to ${threadId}. Venue: ${venue ? JSON.stringify(venue) : 'none'}`);
|
|
302
|
+
|
|
303
|
+
// Basic validation - need at least an id (or facebook_places_id)
|
|
304
|
+
const hasCoords = venue && typeof venue.lat === 'number' && typeof venue.lng === 'number';
|
|
305
|
+
const hasId = venue && (venue.facebook_places_id || venue.id);
|
|
306
|
+
|
|
307
|
+
// prefer facebook_places_id if present
|
|
308
|
+
const placeId = venue && (venue.facebook_places_id || venue.id);
|
|
309
|
+
|
|
310
|
+
// create sticker structure (format used by many reverse-engineered clients)
|
|
311
|
+
const sticker = this.createLocationStickerFromVenue(venue);
|
|
312
|
+
|
|
313
|
+
// If we have an ig client capable of publishing stories, attempt the sticker flow.
|
|
314
|
+
const ig = this.realtimeClient && this.realtimeClient.ig;
|
|
315
|
+
if (ig && typeof ig.publish === 'object' && typeof ig.publish.story === 'function') {
|
|
316
|
+
try {
|
|
317
|
+
// Use a tiny placeholder image if caller didn't provide one (1x1 PNG)
|
|
318
|
+
const SINGLE_PIXEL_PNG_BASE64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGNgYAAAAAMAAWgmWQ0AAAAASUVORK5CYII=";
|
|
319
|
+
const photoBuffer = Buffer.from(SINGLE_PIXEL_PNG_BASE64, 'base64');
|
|
320
|
+
|
|
321
|
+
this.enhancedDebug(`Publishing story with location sticker (venue id: ${placeId})...`);
|
|
322
|
+
|
|
323
|
+
// Build publish params. Many clients accept `file` and `stickers` array like this.
|
|
324
|
+
const publishParams = {
|
|
325
|
+
file: photoBuffer,
|
|
326
|
+
stickers: [sticker],
|
|
327
|
+
// optional: caption/text not always supported on story publish in the same way; keep minimal
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
const publishResult = await ig.publish.story(publishParams);
|
|
331
|
+
|
|
332
|
+
this.enhancedDebug(`Story publish result: ${publishResult ? JSON.stringify(publishResult).slice(0, 400) : 'no result'}`);
|
|
333
|
+
|
|
334
|
+
// Try to resolve story media id
|
|
335
|
+
let storyId = null;
|
|
336
|
+
if (publishResult) {
|
|
337
|
+
// common fields returned by private clients
|
|
338
|
+
storyId = publishResult.media && (publishResult.media.pk || publishResult.media.id || publishResult.media_id) ||
|
|
339
|
+
publishResult.item_id || publishResult.upload_id || publishResult.media_id;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// If we didn't get a story id, try common fallback fields
|
|
343
|
+
if (!storyId && publishResult && publishResult.params && publishResult.params.upload_id) {
|
|
344
|
+
storyId = publishResult.params.upload_id;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (!storyId) {
|
|
348
|
+
// If publish succeeded but no usable id found, still attempt best-effort: some clients return a "media" object later on pubsub
|
|
349
|
+
this.enhancedDebug(`Could not determine story id from publish result; continuing to fallback to link/share attempt.`);
|
|
350
|
+
throw new Error('Could not determine story id from publish result.');
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Now share the story to the thread (reel_share/media_share)
|
|
354
|
+
// Use the existing helper sendUserStory if available (it uses itemType: 'reel_share')
|
|
355
|
+
this.enhancedDebug(`Sharing published story ${storyId} to thread ${threadId}...`);
|
|
356
|
+
try {
|
|
357
|
+
const shareResult = await this.sendUserStory({
|
|
358
|
+
text: text || '',
|
|
359
|
+
storyId: storyId,
|
|
360
|
+
threadId,
|
|
361
|
+
clientContext: clientContext || (0, uuid_1.v4)(),
|
|
362
|
+
});
|
|
363
|
+
this.enhancedDebug(`✅ Location story shared to thread via MQTT! (storyId=${storyId})`);
|
|
364
|
+
return shareResult;
|
|
365
|
+
} catch (shareErr) {
|
|
366
|
+
// If sharing via MQTT fails, try a fallback: some clients expose direct send helper
|
|
367
|
+
this.enhancedDebug(`Sharing story to thread failed: ${shareErr && shareErr.message ? shareErr.message : String(shareErr)}`);
|
|
368
|
+
// fall through to fallback link below
|
|
369
|
+
throw shareErr;
|
|
370
|
+
}
|
|
371
|
+
} catch (err) {
|
|
372
|
+
this.enhancedDebug(`Story-with-sticker attempt failed: ${err && err.message ? err.message : String(err)} - falling back to link`);
|
|
373
|
+
// fallthrough to fallback block below
|
|
374
|
+
}
|
|
375
|
+
} else {
|
|
376
|
+
this.enhancedDebug(`ig.publish.story not available on realtimeClient.ig — will use fallback link if possible.`);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Fallback: send as a link to the location explore page (guaranteed to render in DM)
|
|
380
|
+
if (hasId) {
|
|
381
|
+
const link = `https://www.instagram.com/explore/locations/${placeId}/`;
|
|
382
|
+
this.enhancedDebug(`Sending location fallback link: ${link}`);
|
|
383
|
+
|
|
384
|
+
try {
|
|
385
|
+
const fallback = await this.sendItem({
|
|
386
|
+
itemType: 'link',
|
|
387
|
+
threadId,
|
|
388
|
+
clientContext: clientContext || (0, uuid_1.v4)(),
|
|
389
|
+
data: {
|
|
390
|
+
link_text: text || (venue && venue.name) || 'Location',
|
|
391
|
+
link_urls: [link],
|
|
392
|
+
},
|
|
393
|
+
});
|
|
394
|
+
this.enhancedDebug(`✅ Location fallback link sent via MQTT!`);
|
|
395
|
+
return fallback;
|
|
396
|
+
} catch (err) {
|
|
397
|
+
this.enhancedDebug(`Fallback link send failed: ${err && err.message ? err.message : String(err)}`);
|
|
398
|
+
throw err;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// If we don't have any usable info, throw an error
|
|
403
|
+
throw new Error('sendLocation requires a venue object with at least id (or facebook_places_id).');
|
|
300
404
|
}
|
|
301
405
|
|
|
302
406
|
/**
|
|
303
|
-
*
|
|
407
|
+
* Helper that returns a "location sticker" object compatible with many reverse-engineered
|
|
408
|
+
* clients / the publish.story helper. This mirrors the "LocationStickerClientModel" semantics.
|
|
409
|
+
*
|
|
410
|
+
* Format produced:
|
|
411
|
+
* {
|
|
412
|
+
* type: 'location',
|
|
413
|
+
* location_id: '12345',
|
|
414
|
+
* location: { lat, lng, name, address, external_source, facebook_places_id },
|
|
415
|
+
* x: 0.5,
|
|
416
|
+
* y: 0.5,
|
|
417
|
+
* width: 0.7,
|
|
418
|
+
* height: 0.15,
|
|
419
|
+
* rotation: 0,
|
|
420
|
+
* is_pinned: false
|
|
421
|
+
* }
|
|
422
|
+
*/
|
|
423
|
+
createLocationStickerFromVenue(venue) {
|
|
424
|
+
// Defensive defaults
|
|
425
|
+
if (!venue) {
|
|
426
|
+
throw new Error('venue required to create location sticker');
|
|
427
|
+
}
|
|
428
|
+
const placeId = venue.facebook_places_id || String(venue.id || '');
|
|
429
|
+
const lat = (typeof venue.lat === 'number') ? venue.lat : (venue.location && venue.location.lat) || null;
|
|
430
|
+
const lng = (typeof venue.lng === 'number') ? venue.lng : (venue.location && venue.location.lng) || null;
|
|
431
|
+
|
|
432
|
+
const locationObj = {
|
|
433
|
+
lat: lat,
|
|
434
|
+
lng: lng,
|
|
435
|
+
name: venue.name || '',
|
|
436
|
+
address: venue.address || '',
|
|
437
|
+
external_source: venue.external_source || 'facebook_places',
|
|
438
|
+
facebook_places_id: placeId || '',
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
// Sticker appearance / position defaults - caller may tweak later if needed
|
|
442
|
+
const sticker = {
|
|
443
|
+
type: 'location',
|
|
444
|
+
// some clients expect locationId, some expect venue_id or location_id
|
|
445
|
+
locationId: placeId,
|
|
446
|
+
venue_id: placeId,
|
|
447
|
+
location: locationObj,
|
|
448
|
+
x: 0.5,
|
|
449
|
+
y: 0.5,
|
|
450
|
+
width: 0.7,
|
|
451
|
+
height: 0.15,
|
|
452
|
+
rotation: 0,
|
|
453
|
+
isPinned: false,
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
return sticker;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Helper: search places via the Instagram client (optional).
|
|
461
|
+
* If your realtimeClient has an .ig.request helper, this will call the appropriate
|
|
462
|
+
* endpoint to fetch place metadata, and then call sendLocation with the full venue.
|
|
463
|
+
*
|
|
464
|
+
* This is optional — you can call sendLocation yourself with the venue object you already have.
|
|
465
|
+
*/
|
|
466
|
+
async searchAndSendLocation({ threadId, query, lat, lng, clientContext }) {
|
|
467
|
+
const ig = this.realtimeClient && this.realtimeClient.ig;
|
|
468
|
+
if (!ig || !ig.request) {
|
|
469
|
+
throw new Error('Instagram client (ig.request) not available on realtimeClient. Provide `venue` directly to sendLocation instead.');
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
this.enhancedDebug(`Searching location: ${query} at ${lat},${lng}`);
|
|
473
|
+
|
|
474
|
+
// Example endpoint - private API endpoints vary. If your client has a helper method,
|
|
475
|
+
// prefer that. This tries a common private endpoint pattern.
|
|
476
|
+
const url = '/fbsearch/places/';
|
|
477
|
+
const params = {
|
|
478
|
+
search_media_creation: false,
|
|
479
|
+
rank_token: (0, uuid_1.v4)(),
|
|
480
|
+
query: query,
|
|
481
|
+
latitude: lat,
|
|
482
|
+
longitude: lng,
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
try {
|
|
486
|
+
const res = await ig.request.send({
|
|
487
|
+
url: url,
|
|
488
|
+
method: 'GET',
|
|
489
|
+
qs: params,
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
// Parse response - different private API clients return different shapes.
|
|
493
|
+
// We try to find the first usable place with id/lat/lng/name.
|
|
494
|
+
const places = (res && (res.places || res.items || res.results)) || [];
|
|
495
|
+
const place = places.find(p => p && (p.pk || p.place || p.location || p.facebook_places_id)) || places[0];
|
|
496
|
+
|
|
497
|
+
if (!place) {
|
|
498
|
+
throw new Error('No places found from search.');
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Normalize to `venue` shape our sendLocation expects
|
|
502
|
+
const venue = {
|
|
503
|
+
id: String(place.pk || (place.place && place.place.id) || place.id || place.facebook_places_id || ''),
|
|
504
|
+
name: place.name || (place.place && place.place.name) || '',
|
|
505
|
+
address: place.address || (place.place && place.place.address) || '',
|
|
506
|
+
lat: (place.location && (place.location.lat || place.location.latitude)) || place.lat || null,
|
|
507
|
+
lng: (place.location && (place.location.lng || place.location.longitude)) || place.lng || null,
|
|
508
|
+
facebook_places_id: place.facebook_places_id || (place.place && place.place.id) || String(place.pk || ''),
|
|
509
|
+
external_source: place.external_source || 'facebook_places',
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
return await this.sendLocation({ threadId, clientContext, venue });
|
|
513
|
+
} catch (err) {
|
|
514
|
+
this.enhancedDebug(`place search/send failed: ${err && err.message ? err.message : String(err)}`);
|
|
515
|
+
throw err;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* Send media via MQTT (media_share)
|
|
304
521
|
*/
|
|
305
522
|
async sendMedia({ text, mediaId, threadId, clientContext }) {
|
|
306
523
|
this.enhancedDebug(`Sending media ${mediaId} to ${threadId}`);
|
|
307
|
-
|
|
524
|
+
|
|
308
525
|
const result = await this.sendItem({
|
|
309
526
|
itemType: 'media_share',
|
|
310
527
|
threadId,
|
|
@@ -314,17 +531,17 @@ class EnhancedDirectCommands {
|
|
|
314
531
|
media_id: mediaId,
|
|
315
532
|
},
|
|
316
533
|
});
|
|
317
|
-
|
|
534
|
+
|
|
318
535
|
this.enhancedDebug(`✅ Media sent via MQTT!`);
|
|
319
536
|
return result;
|
|
320
537
|
}
|
|
321
538
|
|
|
322
539
|
/**
|
|
323
|
-
* Send profile via MQTT
|
|
540
|
+
* Send profile via MQTT
|
|
324
541
|
*/
|
|
325
542
|
async sendProfile({ text, userId, threadId, clientContext }) {
|
|
326
543
|
this.enhancedDebug(`Sending profile ${userId} to ${threadId}`);
|
|
327
|
-
|
|
544
|
+
|
|
328
545
|
const result = await this.sendItem({
|
|
329
546
|
itemType: 'profile',
|
|
330
547
|
threadId,
|
|
@@ -335,17 +552,17 @@ class EnhancedDirectCommands {
|
|
|
335
552
|
item_id: userId,
|
|
336
553
|
},
|
|
337
554
|
});
|
|
338
|
-
|
|
555
|
+
|
|
339
556
|
this.enhancedDebug(`✅ Profile sent via MQTT!`);
|
|
340
557
|
return result;
|
|
341
558
|
}
|
|
342
559
|
|
|
343
560
|
/**
|
|
344
|
-
* Send reaction via MQTT
|
|
561
|
+
* Send reaction via MQTT
|
|
345
562
|
*/
|
|
346
563
|
async sendReaction({ itemId, reactionType, clientContext, threadId, reactionStatus, targetItemType, emoji }) {
|
|
347
564
|
this.enhancedDebug(`Sending ${reactionType || 'like'} reaction to message ${itemId}`);
|
|
348
|
-
|
|
565
|
+
|
|
349
566
|
const result = await this.sendItem({
|
|
350
567
|
itemType: 'reaction',
|
|
351
568
|
threadId,
|
|
@@ -359,17 +576,17 @@ class EnhancedDirectCommands {
|
|
|
359
576
|
emoji: emoji || '',
|
|
360
577
|
},
|
|
361
578
|
});
|
|
362
|
-
|
|
579
|
+
|
|
363
580
|
this.enhancedDebug(`✅ Reaction sent via MQTT!`);
|
|
364
581
|
return result;
|
|
365
582
|
}
|
|
366
583
|
|
|
367
584
|
/**
|
|
368
|
-
* Send user story via MQTT (
|
|
585
|
+
* Send user story via MQTT (reel_share)
|
|
369
586
|
*/
|
|
370
587
|
async sendUserStory({ text, storyId, threadId, clientContext }) {
|
|
371
588
|
this.enhancedDebug(`Sending story ${storyId} to ${threadId}`);
|
|
372
|
-
|
|
589
|
+
|
|
373
590
|
const result = await this.sendItem({
|
|
374
591
|
itemType: 'reel_share',
|
|
375
592
|
threadId,
|
|
@@ -380,17 +597,17 @@ class EnhancedDirectCommands {
|
|
|
380
597
|
media_id: storyId,
|
|
381
598
|
},
|
|
382
599
|
});
|
|
383
|
-
|
|
600
|
+
|
|
384
601
|
this.enhancedDebug(`✅ Story sent via MQTT!`);
|
|
385
602
|
return result;
|
|
386
603
|
}
|
|
387
604
|
|
|
388
605
|
/**
|
|
389
|
-
* Mark as seen via MQTT (
|
|
606
|
+
* Mark as seen via MQTT (mark_seen action)
|
|
390
607
|
*/
|
|
391
608
|
async markAsSeen({ threadId, itemId }) {
|
|
392
609
|
this.enhancedDebug(`Marking message ${itemId} as seen in thread ${threadId}`);
|
|
393
|
-
|
|
610
|
+
|
|
394
611
|
const result = await this.sendCommand({
|
|
395
612
|
action: 'mark_seen',
|
|
396
613
|
threadId,
|
|
@@ -398,18 +615,18 @@ class EnhancedDirectCommands {
|
|
|
398
615
|
item_id: itemId,
|
|
399
616
|
},
|
|
400
617
|
});
|
|
401
|
-
|
|
618
|
+
|
|
402
619
|
this.enhancedDebug(`✅ Message marked as seen via MQTT!`);
|
|
403
620
|
return result;
|
|
404
621
|
}
|
|
405
622
|
|
|
406
623
|
/**
|
|
407
|
-
* Indicate activity (typing) via MQTT (
|
|
624
|
+
* Indicate activity (typing) via MQTT (activity_status)
|
|
408
625
|
*/
|
|
409
626
|
async indicateActivity({ threadId, isActive, clientContext }) {
|
|
410
627
|
const active = typeof isActive === 'undefined' ? true : isActive;
|
|
411
628
|
this.enhancedDebug(`Indicating ${active ? 'typing' : 'stopped'} in thread ${threadId}`);
|
|
412
|
-
|
|
629
|
+
|
|
413
630
|
const result = await this.sendCommand({
|
|
414
631
|
action: 'indicate_activity',
|
|
415
632
|
threadId,
|
|
@@ -418,7 +635,7 @@ class EnhancedDirectCommands {
|
|
|
418
635
|
activity_status: active ? '1' : '0',
|
|
419
636
|
},
|
|
420
637
|
});
|
|
421
|
-
|
|
638
|
+
|
|
422
639
|
this.enhancedDebug(`✅ Activity indicator sent via MQTT!`);
|
|
423
640
|
return result;
|
|
424
641
|
}
|
|
@@ -428,7 +645,7 @@ class EnhancedDirectCommands {
|
|
|
428
645
|
*/
|
|
429
646
|
async deleteMessage(threadId, itemId) {
|
|
430
647
|
this.enhancedDebug(`Deleting message ${itemId} from thread ${threadId}`);
|
|
431
|
-
|
|
648
|
+
|
|
432
649
|
const result = await this.sendCommand({
|
|
433
650
|
action: 'delete_item',
|
|
434
651
|
threadId,
|
|
@@ -437,7 +654,7 @@ class EnhancedDirectCommands {
|
|
|
437
654
|
item_id: itemId,
|
|
438
655
|
},
|
|
439
656
|
});
|
|
440
|
-
|
|
657
|
+
|
|
441
658
|
this.enhancedDebug(`✅ Message deleted via MQTT!`);
|
|
442
659
|
return result;
|
|
443
660
|
}
|
|
@@ -447,7 +664,7 @@ class EnhancedDirectCommands {
|
|
|
447
664
|
*/
|
|
448
665
|
async editMessage(threadId, itemId, newText) {
|
|
449
666
|
this.enhancedDebug(`Editing message ${itemId}: "${newText}"`);
|
|
450
|
-
|
|
667
|
+
|
|
451
668
|
const result = await this.sendCommand({
|
|
452
669
|
action: 'edit_item',
|
|
453
670
|
threadId,
|
|
@@ -457,7 +674,7 @@ class EnhancedDirectCommands {
|
|
|
457
674
|
text: newText,
|
|
458
675
|
},
|
|
459
676
|
});
|
|
460
|
-
|
|
677
|
+
|
|
461
678
|
this.enhancedDebug(`✅ Message edited via MQTT!`);
|
|
462
679
|
return result;
|
|
463
680
|
}
|
|
@@ -467,7 +684,7 @@ class EnhancedDirectCommands {
|
|
|
467
684
|
*/
|
|
468
685
|
async replyToMessage(threadId, messageId, replyText) {
|
|
469
686
|
this.enhancedDebug(`Replying to ${messageId} in thread ${threadId}: "${replyText}"`);
|
|
470
|
-
|
|
687
|
+
|
|
471
688
|
const result = await this.sendItem({
|
|
472
689
|
itemType: 'text',
|
|
473
690
|
threadId,
|
|
@@ -477,7 +694,7 @@ class EnhancedDirectCommands {
|
|
|
477
694
|
replied_to_item_id: messageId,
|
|
478
695
|
},
|
|
479
696
|
});
|
|
480
|
-
|
|
697
|
+
|
|
481
698
|
this.enhancedDebug(`✅ Reply sent via MQTT!`);
|
|
482
699
|
return result;
|
|
483
700
|
}
|
|
@@ -487,7 +704,7 @@ class EnhancedDirectCommands {
|
|
|
487
704
|
*/
|
|
488
705
|
async addMemberToThread(threadId, userId) {
|
|
489
706
|
this.enhancedDebug(`Adding user ${userId} to thread ${threadId}`);
|
|
490
|
-
|
|
707
|
+
|
|
491
708
|
const result = await this.sendCommand({
|
|
492
709
|
action: 'add_users',
|
|
493
710
|
threadId,
|
|
@@ -496,7 +713,7 @@ class EnhancedDirectCommands {
|
|
|
496
713
|
user_ids: Array.isArray(userId) ? userId : [userId],
|
|
497
714
|
},
|
|
498
715
|
});
|
|
499
|
-
|
|
716
|
+
|
|
500
717
|
this.enhancedDebug(`✅ Member added to thread via MQTT!`);
|
|
501
718
|
return result;
|
|
502
719
|
}
|
|
@@ -506,7 +723,7 @@ class EnhancedDirectCommands {
|
|
|
506
723
|
*/
|
|
507
724
|
async removeMemberFromThread(threadId, userId) {
|
|
508
725
|
this.enhancedDebug(`Removing user ${userId} from thread ${threadId}`);
|
|
509
|
-
|
|
726
|
+
|
|
510
727
|
const result = await this.sendCommand({
|
|
511
728
|
action: 'remove_users',
|
|
512
729
|
threadId,
|
|
@@ -515,7 +732,7 @@ class EnhancedDirectCommands {
|
|
|
515
732
|
user_ids: Array.isArray(userId) ? userId : [userId],
|
|
516
733
|
},
|
|
517
734
|
});
|
|
518
|
-
|
|
735
|
+
|
|
519
736
|
this.enhancedDebug(`✅ Member removed from thread via MQTT!`);
|
|
520
737
|
return result;
|
|
521
738
|
}
|
|
@@ -525,14 +742,14 @@ class EnhancedDirectCommands {
|
|
|
525
742
|
*/
|
|
526
743
|
async leaveThread(threadId) {
|
|
527
744
|
this.enhancedDebug(`Leaving thread ${threadId}`);
|
|
528
|
-
|
|
745
|
+
|
|
529
746
|
const result = await this.sendCommand({
|
|
530
747
|
action: 'leave',
|
|
531
748
|
threadId,
|
|
532
749
|
clientContext: (0, uuid_1.v4)(),
|
|
533
750
|
data: {},
|
|
534
751
|
});
|
|
535
|
-
|
|
752
|
+
|
|
536
753
|
this.enhancedDebug(`✅ Left thread via MQTT!`);
|
|
537
754
|
return result;
|
|
538
755
|
}
|
|
@@ -542,7 +759,7 @@ class EnhancedDirectCommands {
|
|
|
542
759
|
*/
|
|
543
760
|
async muteThread(threadId, muteUntil = null) {
|
|
544
761
|
this.enhancedDebug(`Muting thread ${threadId}`);
|
|
545
|
-
|
|
762
|
+
|
|
546
763
|
const result = await this.sendCommand({
|
|
547
764
|
action: 'mute',
|
|
548
765
|
threadId,
|
|
@@ -551,7 +768,7 @@ class EnhancedDirectCommands {
|
|
|
551
768
|
mute_until: muteUntil,
|
|
552
769
|
},
|
|
553
770
|
});
|
|
554
|
-
|
|
771
|
+
|
|
555
772
|
this.enhancedDebug(`✅ Thread muted via MQTT!`);
|
|
556
773
|
return result;
|
|
557
774
|
}
|
|
@@ -561,14 +778,14 @@ class EnhancedDirectCommands {
|
|
|
561
778
|
*/
|
|
562
779
|
async unmuteThread(threadId) {
|
|
563
780
|
this.enhancedDebug(`Unmuting thread ${threadId}`);
|
|
564
|
-
|
|
781
|
+
|
|
565
782
|
const result = await this.sendCommand({
|
|
566
783
|
action: 'unmute',
|
|
567
784
|
threadId,
|
|
568
785
|
clientContext: (0, uuid_1.v4)(),
|
|
569
786
|
data: {},
|
|
570
787
|
});
|
|
571
|
-
|
|
788
|
+
|
|
572
789
|
this.enhancedDebug(`✅ Thread unmuted via MQTT!`);
|
|
573
790
|
return result;
|
|
574
791
|
}
|
|
@@ -578,7 +795,7 @@ class EnhancedDirectCommands {
|
|
|
578
795
|
*/
|
|
579
796
|
async updateThreadTitle(threadId, title) {
|
|
580
797
|
this.enhancedDebug(`Updating thread ${threadId} title to: "${title}"`);
|
|
581
|
-
|
|
798
|
+
|
|
582
799
|
const result = await this.sendCommand({
|
|
583
800
|
action: 'update_title',
|
|
584
801
|
threadId,
|
|
@@ -587,7 +804,7 @@ class EnhancedDirectCommands {
|
|
|
587
804
|
title: title,
|
|
588
805
|
},
|
|
589
806
|
});
|
|
590
|
-
|
|
807
|
+
|
|
591
808
|
this.enhancedDebug(`✅ Thread title updated via MQTT!`);
|
|
592
809
|
return result;
|
|
593
810
|
}
|
|
@@ -597,7 +814,7 @@ class EnhancedDirectCommands {
|
|
|
597
814
|
*/
|
|
598
815
|
async sendLink({ link, text, threadId, clientContext }) {
|
|
599
816
|
this.enhancedDebug(`Sending link ${link} to ${threadId}`);
|
|
600
|
-
|
|
817
|
+
|
|
601
818
|
const result = await this.sendItem({
|
|
602
819
|
itemType: 'link',
|
|
603
820
|
threadId,
|
|
@@ -608,7 +825,7 @@ class EnhancedDirectCommands {
|
|
|
608
825
|
link_urls: [link],
|
|
609
826
|
},
|
|
610
827
|
});
|
|
611
|
-
|
|
828
|
+
|
|
612
829
|
this.enhancedDebug(`✅ Link sent via MQTT!`);
|
|
613
830
|
return result;
|
|
614
831
|
}
|
|
@@ -618,7 +835,7 @@ class EnhancedDirectCommands {
|
|
|
618
835
|
*/
|
|
619
836
|
async sendAnimatedMedia({ id, isSticker, threadId, clientContext }) {
|
|
620
837
|
this.enhancedDebug(`Sending animated media ${id} to ${threadId}`);
|
|
621
|
-
|
|
838
|
+
|
|
622
839
|
const result = await this.sendItem({
|
|
623
840
|
itemType: 'animated_media',
|
|
624
841
|
threadId,
|
|
@@ -628,7 +845,7 @@ class EnhancedDirectCommands {
|
|
|
628
845
|
is_sticker: isSticker || false,
|
|
629
846
|
},
|
|
630
847
|
});
|
|
631
|
-
|
|
848
|
+
|
|
632
849
|
this.enhancedDebug(`✅ Animated media sent via MQTT!`);
|
|
633
850
|
return result;
|
|
634
851
|
}
|
|
@@ -638,7 +855,7 @@ class EnhancedDirectCommands {
|
|
|
638
855
|
*/
|
|
639
856
|
async sendVoice({ uploadId, waveform, waveformSamplingFrequencyHz, threadId, clientContext }) {
|
|
640
857
|
this.enhancedDebug(`Sending voice ${uploadId} to ${threadId}`);
|
|
641
|
-
|
|
858
|
+
|
|
642
859
|
const result = await this.sendItem({
|
|
643
860
|
itemType: 'voice_media',
|
|
644
861
|
threadId,
|
|
@@ -649,17 +866,18 @@ class EnhancedDirectCommands {
|
|
|
649
866
|
waveform_sampling_frequency_hz: waveformSamplingFrequencyHz || 10,
|
|
650
867
|
},
|
|
651
868
|
});
|
|
652
|
-
|
|
869
|
+
|
|
653
870
|
this.enhancedDebug(`✅ Voice sent via MQTT!`);
|
|
654
871
|
return result;
|
|
655
872
|
}
|
|
656
873
|
|
|
657
874
|
/**
|
|
658
875
|
* Send photo via Realtime (Upload + Broadcast)
|
|
876
|
+
* Note: depends on realtimeClient.ig.request for uploading
|
|
659
877
|
*/
|
|
660
878
|
async sendPhotoViaRealtime({ photoBuffer, threadId, caption = '', mimeType = 'image/jpeg', clientContext }) {
|
|
661
879
|
this.enhancedDebug(`Sending photo to thread ${threadId} via Realtime`);
|
|
662
|
-
|
|
880
|
+
|
|
663
881
|
try {
|
|
664
882
|
if (!photoBuffer || !Buffer.isBuffer(photoBuffer) || photoBuffer.length === 0) {
|
|
665
883
|
throw new Error('photoBuffer must be a non-empty Buffer');
|
|
@@ -674,10 +892,10 @@ class EnhancedDirectCommands {
|
|
|
674
892
|
}
|
|
675
893
|
|
|
676
894
|
this.enhancedDebug(`Step 1: Uploading photo (${photoBuffer.length} bytes)...`);
|
|
677
|
-
|
|
895
|
+
|
|
678
896
|
const uploadId = Date.now().toString();
|
|
679
897
|
const objectName = `${(0, uuid_1.v4)()}.${mimeType === 'image/png' ? 'png' : 'jpg'}`;
|
|
680
|
-
|
|
898
|
+
|
|
681
899
|
const isJpeg = mimeType === 'image/jpeg' || mimeType === 'image/jpg';
|
|
682
900
|
const compression = isJpeg
|
|
683
901
|
? '{"lib_name":"moz","lib_version":"3.1.m","quality":"80"}'
|
|
@@ -721,7 +939,7 @@ class EnhancedDirectCommands {
|
|
|
721
939
|
}
|
|
722
940
|
|
|
723
941
|
this.enhancedDebug(`Step 2: Broadcasting photo to thread ${threadId}...`);
|
|
724
|
-
|
|
942
|
+
|
|
725
943
|
const broadcastForm = {
|
|
726
944
|
upload_id: serverUploadId,
|
|
727
945
|
action: 'send_item',
|
|
@@ -761,10 +979,11 @@ class EnhancedDirectCommands {
|
|
|
761
979
|
|
|
762
980
|
/**
|
|
763
981
|
* Send video via Realtime (Upload + Broadcast)
|
|
982
|
+
* Note: depends on realtimeClient.ig.request for uploading
|
|
764
983
|
*/
|
|
765
984
|
async sendVideoViaRealtime({ videoBuffer, threadId, caption = '', duration = 0, width = 720, height = 1280, clientContext }) {
|
|
766
985
|
this.enhancedDebug(`Sending video to thread ${threadId} via Realtime`);
|
|
767
|
-
|
|
986
|
+
|
|
768
987
|
try {
|
|
769
988
|
if (!videoBuffer || !Buffer.isBuffer(videoBuffer) || videoBuffer.length === 0) {
|
|
770
989
|
throw new Error('videoBuffer must be a non-empty Buffer');
|
|
@@ -779,10 +998,10 @@ class EnhancedDirectCommands {
|
|
|
779
998
|
}
|
|
780
999
|
|
|
781
1000
|
this.enhancedDebug(`Step 1: Uploading video (${videoBuffer.length} bytes)...`);
|
|
782
|
-
|
|
1001
|
+
|
|
783
1002
|
const uploadId = Date.now().toString();
|
|
784
1003
|
const objectName = `${(0, uuid_1.v4)()}.mp4`;
|
|
785
|
-
|
|
1004
|
+
|
|
786
1005
|
const ruploadParams = {
|
|
787
1006
|
upload_id: uploadId,
|
|
788
1007
|
media_type: 2,
|
|
@@ -823,7 +1042,7 @@ class EnhancedDirectCommands {
|
|
|
823
1042
|
}
|
|
824
1043
|
|
|
825
1044
|
this.enhancedDebug(`Step 2: Broadcasting video to thread ${threadId}...`);
|
|
826
|
-
|
|
1045
|
+
|
|
827
1046
|
const broadcastForm = {
|
|
828
1047
|
upload_id: serverUploadId,
|
|
829
1048
|
action: 'send_item',
|
|
@@ -867,14 +1086,14 @@ class EnhancedDirectCommands {
|
|
|
867
1086
|
*/
|
|
868
1087
|
async approveThread(threadId) {
|
|
869
1088
|
this.enhancedDebug(`Approving thread ${threadId}`);
|
|
870
|
-
|
|
1089
|
+
|
|
871
1090
|
const result = await this.sendCommand({
|
|
872
1091
|
action: 'approve',
|
|
873
1092
|
threadId,
|
|
874
1093
|
clientContext: (0, uuid_1.v4)(),
|
|
875
1094
|
data: {},
|
|
876
1095
|
});
|
|
877
|
-
|
|
1096
|
+
|
|
878
1097
|
this.enhancedDebug(`✅ Thread approved via MQTT!`);
|
|
879
1098
|
return result;
|
|
880
1099
|
}
|
|
@@ -884,14 +1103,14 @@ class EnhancedDirectCommands {
|
|
|
884
1103
|
*/
|
|
885
1104
|
async declineThread(threadId) {
|
|
886
1105
|
this.enhancedDebug(`Declining thread ${threadId}`);
|
|
887
|
-
|
|
1106
|
+
|
|
888
1107
|
const result = await this.sendCommand({
|
|
889
1108
|
action: 'decline',
|
|
890
1109
|
threadId,
|
|
891
1110
|
clientContext: (0, uuid_1.v4)(),
|
|
892
1111
|
data: {},
|
|
893
1112
|
});
|
|
894
|
-
|
|
1113
|
+
|
|
895
1114
|
this.enhancedDebug(`✅ Thread declined via MQTT!`);
|
|
896
1115
|
return result;
|
|
897
1116
|
}
|
|
@@ -901,7 +1120,7 @@ class EnhancedDirectCommands {
|
|
|
901
1120
|
*/
|
|
902
1121
|
async blockUserInThread(threadId, userId) {
|
|
903
1122
|
this.enhancedDebug(`Blocking user ${userId} in thread ${threadId}`);
|
|
904
|
-
|
|
1123
|
+
|
|
905
1124
|
const result = await this.sendCommand({
|
|
906
1125
|
action: 'block',
|
|
907
1126
|
threadId,
|
|
@@ -910,7 +1129,7 @@ class EnhancedDirectCommands {
|
|
|
910
1129
|
user_id: userId,
|
|
911
1130
|
},
|
|
912
1131
|
});
|
|
913
|
-
|
|
1132
|
+
|
|
914
1133
|
this.enhancedDebug(`✅ User blocked in thread via MQTT!`);
|
|
915
1134
|
return result;
|
|
916
1135
|
}
|
|
@@ -920,7 +1139,7 @@ class EnhancedDirectCommands {
|
|
|
920
1139
|
*/
|
|
921
1140
|
async reportThread(threadId, reason) {
|
|
922
1141
|
this.enhancedDebug(`Reporting thread ${threadId}`);
|
|
923
|
-
|
|
1142
|
+
|
|
924
1143
|
const result = await this.sendCommand({
|
|
925
1144
|
action: 'report',
|
|
926
1145
|
threadId,
|
|
@@ -929,7 +1148,7 @@ class EnhancedDirectCommands {
|
|
|
929
1148
|
reason: reason || 'spam',
|
|
930
1149
|
},
|
|
931
1150
|
});
|
|
932
|
-
|
|
1151
|
+
|
|
933
1152
|
this.enhancedDebug(`✅ Thread reported via MQTT!`);
|
|
934
1153
|
return result;
|
|
935
1154
|
}
|
|
@@ -939,7 +1158,7 @@ class EnhancedDirectCommands {
|
|
|
939
1158
|
*/
|
|
940
1159
|
async removeReaction({ itemId, threadId, clientContext }) {
|
|
941
1160
|
this.enhancedDebug(`Removing reaction from message ${itemId}`);
|
|
942
|
-
|
|
1161
|
+
|
|
943
1162
|
const result = await this.sendItem({
|
|
944
1163
|
itemType: 'reaction',
|
|
945
1164
|
threadId,
|
|
@@ -951,7 +1170,7 @@ class EnhancedDirectCommands {
|
|
|
951
1170
|
reaction_status: 'deleted',
|
|
952
1171
|
},
|
|
953
1172
|
});
|
|
954
|
-
|
|
1173
|
+
|
|
955
1174
|
this.enhancedDebug(`✅ Reaction removed via MQTT!`);
|
|
956
1175
|
return result;
|
|
957
1176
|
}
|
|
@@ -961,7 +1180,7 @@ class EnhancedDirectCommands {
|
|
|
961
1180
|
*/
|
|
962
1181
|
async sendDisappearingPhoto({ uploadId, threadId, viewMode = 'once', clientContext }) {
|
|
963
1182
|
this.enhancedDebug(`Sending disappearing photo to ${threadId}`);
|
|
964
|
-
|
|
1183
|
+
|
|
965
1184
|
const result = await this.sendItem({
|
|
966
1185
|
itemType: 'expiring_media_message',
|
|
967
1186
|
threadId,
|
|
@@ -972,7 +1191,7 @@ class EnhancedDirectCommands {
|
|
|
972
1191
|
allow_replay: viewMode === 'replayable',
|
|
973
1192
|
},
|
|
974
1193
|
});
|
|
975
|
-
|
|
1194
|
+
|
|
976
1195
|
this.enhancedDebug(`✅ Disappearing photo sent via MQTT!`);
|
|
977
1196
|
return result;
|
|
978
1197
|
}
|
|
@@ -982,7 +1201,7 @@ class EnhancedDirectCommands {
|
|
|
982
1201
|
*/
|
|
983
1202
|
async sendDisappearingVideo({ uploadId, threadId, viewMode = 'once', clientContext }) {
|
|
984
1203
|
this.enhancedDebug(`Sending disappearing video to ${threadId}`);
|
|
985
|
-
|
|
1204
|
+
|
|
986
1205
|
const result = await this.sendItem({
|
|
987
1206
|
itemType: 'expiring_media_message',
|
|
988
1207
|
threadId,
|
|
@@ -994,7 +1213,7 @@ class EnhancedDirectCommands {
|
|
|
994
1213
|
media_type: 2,
|
|
995
1214
|
},
|
|
996
1215
|
});
|
|
997
|
-
|
|
1216
|
+
|
|
998
1217
|
this.enhancedDebug(`✅ Disappearing video sent via MQTT!`);
|
|
999
1218
|
return result;
|
|
1000
1219
|
}
|
|
@@ -1004,7 +1223,7 @@ class EnhancedDirectCommands {
|
|
|
1004
1223
|
*/
|
|
1005
1224
|
async markVisualMessageSeen({ threadId, itemId, clientContext }) {
|
|
1006
1225
|
this.enhancedDebug(`Marking visual message ${itemId} as seen`);
|
|
1007
|
-
|
|
1226
|
+
|
|
1008
1227
|
const result = await this.sendCommand({
|
|
1009
1228
|
action: 'mark_visual_item_seen',
|
|
1010
1229
|
threadId,
|
|
@@ -1013,7 +1232,7 @@ class EnhancedDirectCommands {
|
|
|
1013
1232
|
item_id: itemId,
|
|
1014
1233
|
},
|
|
1015
1234
|
});
|
|
1016
|
-
|
|
1235
|
+
|
|
1017
1236
|
this.enhancedDebug(`✅ Visual message marked as seen via MQTT!`);
|
|
1018
1237
|
return result;
|
|
1019
1238
|
}
|
|
@@ -1023,7 +1242,7 @@ class EnhancedDirectCommands {
|
|
|
1023
1242
|
*/
|
|
1024
1243
|
async sendScreenshotNotification({ threadId, itemId, clientContext }) {
|
|
1025
1244
|
this.enhancedDebug(`Sending screenshot notification for ${itemId}`);
|
|
1026
|
-
|
|
1245
|
+
|
|
1027
1246
|
const result = await this.sendCommand({
|
|
1028
1247
|
action: 'screenshot_notification',
|
|
1029
1248
|
threadId,
|
|
@@ -1032,7 +1251,7 @@ class EnhancedDirectCommands {
|
|
|
1032
1251
|
item_id: itemId,
|
|
1033
1252
|
},
|
|
1034
1253
|
});
|
|
1035
|
-
|
|
1254
|
+
|
|
1036
1255
|
this.enhancedDebug(`✅ Screenshot notification sent via MQTT!`);
|
|
1037
1256
|
return result;
|
|
1038
1257
|
}
|
|
@@ -1042,7 +1261,7 @@ class EnhancedDirectCommands {
|
|
|
1042
1261
|
*/
|
|
1043
1262
|
async sendReplayNotification({ threadId, itemId, clientContext }) {
|
|
1044
1263
|
this.enhancedDebug(`Sending replay notification for ${itemId}`);
|
|
1045
|
-
|
|
1264
|
+
|
|
1046
1265
|
const result = await this.sendCommand({
|
|
1047
1266
|
action: 'replay_notification',
|
|
1048
1267
|
threadId,
|
|
@@ -1051,9 +1270,10 @@ class EnhancedDirectCommands {
|
|
|
1051
1270
|
item_id: itemId,
|
|
1052
1271
|
},
|
|
1053
1272
|
});
|
|
1054
|
-
|
|
1273
|
+
|
|
1055
1274
|
this.enhancedDebug(`✅ Replay notification sent via MQTT!`);
|
|
1056
1275
|
return result;
|
|
1057
1276
|
}
|
|
1058
1277
|
}
|
|
1059
|
-
|
|
1278
|
+
|
|
1279
|
+
exports.EnhancedDirectCommands = EnhancedDirectCommands;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nodejs-insta-private-api-mqtt",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.42",
|
|
4
4
|
"description": "Complete Instagram MQTT protocol with FULL iOS + Android support. 33 device presets (21 iOS + 12 Android). iPhone 16/15/14/13/12, iPad Pro, Samsung, Pixel, Huawei. Real-time DM messaging, view-once media extraction, sub-500ms latency.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|