nodejs-insta-private-api-mqtt 1.0.0
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 +1650 -0
- package/dist/constants/constants.js +280 -0
- package/dist/constants/index.js +41 -0
- package/dist/core/client.js +243 -0
- package/dist/core/repository.js +7 -0
- package/dist/core/request.js +212 -0
- package/dist/core/state.js +1456 -0
- package/dist/core/utils.js +786 -0
- package/dist/downloadMedia.js +381 -0
- package/dist/errors/index.d.ts +16 -0
- package/dist/errors/index.js +30 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/fbns/fbns.client.d.ts +32 -0
- package/dist/fbns/fbns.client.events.d.ts +41 -0
- package/dist/fbns/fbns.client.events.js +3 -0
- package/dist/fbns/fbns.client.events.js.map +1 -0
- package/dist/fbns/fbns.client.js +179 -0
- package/dist/fbns/fbns.client.js.map +1 -0
- package/dist/fbns/fbns.device-auth.d.ts +17 -0
- package/dist/fbns/fbns.device-auth.js +54 -0
- package/dist/fbns/fbns.device-auth.js.map +1 -0
- package/dist/fbns/fbns.types.d.ts +83 -0
- package/dist/fbns/fbns.types.js +3 -0
- package/dist/fbns/fbns.types.js.map +1 -0
- package/dist/fbns/fbns.utilities.d.ts +2 -0
- package/dist/fbns/fbns.utilities.js +79 -0
- package/dist/fbns/fbns.utilities.js.map +1 -0
- package/dist/fbns/index.d.ts +4 -0
- package/dist/fbns/index.js +21 -0
- package/dist/fbns/index.js.map +1 -0
- package/dist/index.js +39 -0
- package/dist/mqttot/index.d.ts +4 -0
- package/dist/mqttot/index.js +21 -0
- package/dist/mqttot/index.js.map +1 -0
- package/dist/mqttot/mqttot.client.d.ts +39 -0
- package/dist/mqttot/mqttot.client.js +120 -0
- package/dist/mqttot/mqttot.client.js.map +1 -0
- package/dist/mqttot/mqttot.connect.request.packet.d.ts +7 -0
- package/dist/mqttot/mqttot.connect.request.packet.js +9 -0
- package/dist/mqttot/mqttot.connect.request.packet.js.map +1 -0
- package/dist/mqttot/mqttot.connect.response.packet.d.ts +7 -0
- package/dist/mqttot/mqttot.connect.response.packet.js +24 -0
- package/dist/mqttot/mqttot.connect.response.packet.js.map +1 -0
- package/dist/mqttot/mqttot.connection.d.ts +57 -0
- package/dist/mqttot/mqttot.connection.js +56 -0
- package/dist/mqttot/mqttot.connection.js.map +1 -0
- package/dist/package.json +59 -0
- package/dist/realtime/commands/commands.d.ts +15 -0
- package/dist/realtime/commands/commands.js +21 -0
- package/dist/realtime/commands/commands.js.map +1 -0
- package/dist/realtime/commands/direct.commands.d.ts +75 -0
- package/dist/realtime/commands/direct.commands.js +186 -0
- package/dist/realtime/commands/direct.commands.js.map +1 -0
- package/dist/realtime/commands/enhanced.direct.commands.js +987 -0
- package/dist/realtime/commands/index.d.ts +2 -0
- package/dist/realtime/commands/index.js +19 -0
- package/dist/realtime/commands/index.js.map +1 -0
- package/dist/realtime/delta-sync.manager.js +293 -0
- package/dist/realtime/features/dm-sender.js +88 -0
- package/dist/realtime/features/error-handler.js +73 -0
- package/dist/realtime/features/gap-handler.js +61 -0
- package/dist/realtime/features/presence.manager.js +66 -0
- package/dist/realtime/index.js +30 -0
- package/dist/realtime/messages/app-presence.event.d.ts +9 -0
- package/dist/realtime/messages/app-presence.event.js +3 -0
- package/dist/realtime/messages/app-presence.event.js.map +1 -0
- package/dist/realtime/messages/index.d.ts +3 -0
- package/dist/realtime/messages/index.js +20 -0
- package/dist/realtime/messages/index.js.map +1 -0
- package/dist/realtime/messages/message-sync.message.d.ts +222 -0
- package/dist/realtime/messages/message-sync.message.js +43 -0
- package/dist/realtime/messages/message-sync.message.js.map +1 -0
- package/dist/realtime/messages/realtime-sub.direct.data.d.ts +11 -0
- package/dist/realtime/messages/realtime-sub.direct.data.js +3 -0
- package/dist/realtime/messages/realtime-sub.direct.data.js.map +1 -0
- package/dist/realtime/messages/thread-update.message.d.ts +68 -0
- package/dist/realtime/messages/thread-update.message.js +3 -0
- package/dist/realtime/messages/thread-update.message.js.map +1 -0
- package/dist/realtime/mixins/index.d.ts +3 -0
- package/dist/realtime/mixins/index.js +20 -0
- package/dist/realtime/mixins/index.js.map +1 -0
- package/dist/realtime/mixins/message-sync.mixin.d.ts +8 -0
- package/dist/realtime/mixins/message-sync.mixin.js +381 -0
- package/dist/realtime/mixins/message-sync.mixin.js.map +1 -0
- package/dist/realtime/mixins/mixin.d.ts +19 -0
- package/dist/realtime/mixins/mixin.js +41 -0
- package/dist/realtime/mixins/mixin.js.map +1 -0
- package/dist/realtime/mixins/presence-typing.mixin.js +33 -0
- package/dist/realtime/mixins/realtime-sub.mixin.d.ts +8 -0
- package/dist/realtime/mixins/realtime-sub.mixin.js +55 -0
- package/dist/realtime/mixins/realtime-sub.mixin.js.map +1 -0
- package/dist/realtime/parsers/graphql-parser.js +43 -0
- package/dist/realtime/parsers/graphql.parser.d.ts +15 -0
- package/dist/realtime/parsers/graphql.parser.js +22 -0
- package/dist/realtime/parsers/graphql.parser.js.map +1 -0
- package/dist/realtime/parsers/index.d.ts +6 -0
- package/dist/realtime/parsers/index.js +23 -0
- package/dist/realtime/parsers/index.js.map +1 -0
- package/dist/realtime/parsers/iris-parser.js +43 -0
- package/dist/realtime/parsers/iris.parser.d.ts +17 -0
- package/dist/realtime/parsers/iris.parser.js +10 -0
- package/dist/realtime/parsers/iris.parser.js.map +1 -0
- package/dist/realtime/parsers/json-parser.js +43 -0
- package/dist/realtime/parsers/json.parser.d.ts +6 -0
- package/dist/realtime/parsers/json.parser.js +10 -0
- package/dist/realtime/parsers/json.parser.js.map +1 -0
- package/dist/realtime/parsers/parser.d.ts +9 -0
- package/dist/realtime/parsers/parser.js +3 -0
- package/dist/realtime/parsers/parser.js.map +1 -0
- package/dist/realtime/parsers/region-hint-parser.js +43 -0
- package/dist/realtime/parsers/region-hint.parser.d.ts +12 -0
- package/dist/realtime/parsers/region-hint.parser.js +15 -0
- package/dist/realtime/parsers/region-hint.parser.js.map +1 -0
- package/dist/realtime/parsers/skywalker-parser.js +43 -0
- package/dist/realtime/parsers/skywalker.parser.d.ts +12 -0
- package/dist/realtime/parsers/skywalker.parser.js +15 -0
- package/dist/realtime/parsers/skywalker.parser.js.map +1 -0
- package/dist/realtime/parsers-advanced.js +158 -0
- package/dist/realtime/proto/common.proto +38 -0
- package/dist/realtime/proto/direct.proto +65 -0
- package/dist/realtime/proto/ig-messages.proto +83 -0
- package/dist/realtime/proto/iris.proto +188 -0
- package/dist/realtime/proto-parser.js +195 -0
- package/dist/realtime/protocols/iris.handshake.js +74 -0
- package/dist/realtime/protocols/proto-definitions.js +80 -0
- package/dist/realtime/protocols/skywalker.protocol.js +91 -0
- package/dist/realtime/realtime.client.events.js +3 -0
- package/dist/realtime/realtime.client.js +449 -0
- package/dist/realtime/realtime.service.js +462 -0
- package/dist/realtime/reconnect.manager.js +94 -0
- package/dist/realtime/session.manager.js +121 -0
- package/dist/realtime/subscriptions/graphql.subscription.d.ts +47 -0
- package/dist/realtime/subscriptions/graphql.subscription.js +99 -0
- package/dist/realtime/subscriptions/graphql.subscription.js.map +1 -0
- package/dist/realtime/subscriptions/index.d.ts +2 -0
- package/dist/realtime/subscriptions/index.js +19 -0
- package/dist/realtime/subscriptions/index.js.map +1 -0
- package/dist/realtime/subscriptions/skywalker.subscription.d.ts +4 -0
- package/dist/realtime/subscriptions/skywalker.subscription.js +13 -0
- package/dist/realtime/subscriptions/skywalker.subscription.js.map +1 -0
- package/dist/realtime/topic-map.js +71 -0
- package/dist/realtime/topic.js +80 -0
- package/dist/repositories/account.repository.js +261 -0
- package/dist/repositories/direct-thread.repository.js +247 -0
- package/dist/repositories/direct.repository.js +153 -0
- package/dist/repositories/feed.repository.js +233 -0
- package/dist/repositories/friendship.repository.js +190 -0
- package/dist/repositories/hashtag.repository.js +101 -0
- package/dist/repositories/highlights.repository.js +127 -0
- package/dist/repositories/location.repository.js +84 -0
- package/dist/repositories/media.repository.js +165 -0
- package/dist/repositories/story.repository.js +156 -0
- package/dist/repositories/upload.repository.js +167 -0
- package/dist/repositories/user.repository.js +94 -0
- package/dist/sendmedia/index.js +11 -0
- package/dist/sendmedia/sendFile.js +154 -0
- package/dist/sendmedia/sendPhoto.js +145 -0
- package/dist/sendmedia/uploadPhoto.js +175 -0
- package/dist/sendmedia/uploadfFile.js +264 -0
- package/dist/services/live.service.js +147 -0
- package/dist/services/search.service.js +116 -0
- package/dist/shared/index.js +35 -0
- package/dist/shared/shared.js +86 -0
- package/dist/thrift/index.d.ts +3 -0
- package/dist/thrift/index.js +20 -0
- package/dist/thrift/index.js.map +1 -0
- package/dist/thrift/thrift.d.ts +59 -0
- package/dist/thrift/thrift.js +101 -0
- package/dist/thrift/thrift.js.map +1 -0
- package/dist/thrift/thrift.reading.d.ts +41 -0
- package/dist/thrift/thrift.reading.js +327 -0
- package/dist/thrift/thrift.reading.js.map +1 -0
- package/dist/thrift/thrift.writing.d.ts +44 -0
- package/dist/thrift/thrift.writing.js +342 -0
- package/dist/thrift/thrift.writing.js.map +1 -0
- package/dist/types/index.js +285 -0
- package/dist/useMultiFileAuthState.js +437 -0
- package/dist/utils/helper-1.js +1 -0
- package/dist/utils/helper-10.js +1 -0
- package/dist/utils/helper-11.js +1 -0
- package/dist/utils/helper-12.js +1 -0
- package/dist/utils/helper-13.js +1 -0
- package/dist/utils/helper-14.js +1 -0
- package/dist/utils/helper-15.js +1 -0
- package/dist/utils/helper-16.js +1 -0
- package/dist/utils/helper-17.js +1 -0
- package/dist/utils/helper-18.js +1 -0
- package/dist/utils/helper-19.js +1 -0
- package/dist/utils/helper-2.js +1 -0
- package/dist/utils/helper-20.js +1 -0
- package/dist/utils/helper-21.js +1 -0
- package/dist/utils/helper-22.js +1 -0
- package/dist/utils/helper-23.js +1 -0
- package/dist/utils/helper-24.js +1 -0
- package/dist/utils/helper-25.js +1 -0
- package/dist/utils/helper-26.js +1 -0
- package/dist/utils/helper-27.js +1 -0
- package/dist/utils/helper-28.js +1 -0
- package/dist/utils/helper-29.js +1 -0
- package/dist/utils/helper-3.js +1 -0
- package/dist/utils/helper-30.js +1 -0
- package/dist/utils/helper-4.js +1 -0
- package/dist/utils/helper-5.js +1 -0
- package/dist/utils/helper-6.js +1 -0
- package/dist/utils/helper-7.js +1 -0
- package/dist/utils/helper-8.js +1 -0
- package/dist/utils/helper-9.js +1 -0
- package/dist/utils/index.js +280 -0
- package/examples/listen-to-messages.js +86 -0
- package/package.json +79 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
const Repository = require('../core/repository');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
|
|
4
|
+
class StoryRepository extends Repository {
|
|
5
|
+
async react(options) {
|
|
6
|
+
const { storyId, reaction } = options;
|
|
7
|
+
|
|
8
|
+
const response = await this.client.request.send({
|
|
9
|
+
url: `/api/v1/media/${storyId}/story_react/`,
|
|
10
|
+
method: 'POST',
|
|
11
|
+
form: this.client.request.sign({
|
|
12
|
+
_csrftoken: this.client.state.cookieCsrfToken,
|
|
13
|
+
_uid: this.client.state.cookieUserId,
|
|
14
|
+
_uuid: this.client.state.uuid,
|
|
15
|
+
reaction_type: 'like',
|
|
16
|
+
emoji: reaction || '❤️',
|
|
17
|
+
}),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
return response.body;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async getFeed() {
|
|
24
|
+
const response = await this.client.request.send({
|
|
25
|
+
method: 'GET',
|
|
26
|
+
url: '/api/v1/feed/reels_tray/',
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
return response.body;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async getUser(userId) {
|
|
33
|
+
const response = await this.client.request.send({
|
|
34
|
+
method: 'GET',
|
|
35
|
+
url: `/api/v1/feed/user/${userId}/reel_media/`,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
return response.body;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async upload(options) {
|
|
42
|
+
const { imagePath, caption } = options;
|
|
43
|
+
|
|
44
|
+
// Read image file
|
|
45
|
+
const imageBuffer = fs.readFileSync(imagePath);
|
|
46
|
+
|
|
47
|
+
// Upload image first
|
|
48
|
+
const uploadResult = await this.client.upload.photo({
|
|
49
|
+
file: imageBuffer,
|
|
50
|
+
uploadId: Date.now()
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Configure as story
|
|
54
|
+
const configureResult = await this.client.upload.configure({
|
|
55
|
+
uploadId: uploadResult.upload_id,
|
|
56
|
+
source_type: '4',
|
|
57
|
+
configure_mode: 1, // Story mode
|
|
58
|
+
caption: caption || '',
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
return configureResult;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async uploadVideo(options) {
|
|
65
|
+
const { videoPath, caption } = options;
|
|
66
|
+
|
|
67
|
+
// Read video file
|
|
68
|
+
const videoBuffer = fs.readFileSync(videoPath);
|
|
69
|
+
|
|
70
|
+
// Upload video first
|
|
71
|
+
const uploadResult = await this.client.upload.video({
|
|
72
|
+
video: videoBuffer,
|
|
73
|
+
uploadId: Date.now(),
|
|
74
|
+
duration_ms: options.duration_ms || 15000,
|
|
75
|
+
width: options.width || 720,
|
|
76
|
+
height: options.height || 1280,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Configure as story
|
|
80
|
+
const configureResult = await this.client.upload.configureVideo({
|
|
81
|
+
uploadId: uploadResult.upload_id,
|
|
82
|
+
source_type: '4',
|
|
83
|
+
configure_mode: 1, // Story mode
|
|
84
|
+
caption: caption || '',
|
|
85
|
+
length: options.duration_ms || 15000,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
return configureResult;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async seen(input, sourceId = null) {
|
|
92
|
+
let items = [];
|
|
93
|
+
|
|
94
|
+
if (Array.isArray(input)) {
|
|
95
|
+
items = input;
|
|
96
|
+
} else {
|
|
97
|
+
// Flatten reels object to items array
|
|
98
|
+
items = Object.values(input).reduce((acc, reel) => acc.concat(reel.items), []);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const reels = {};
|
|
102
|
+
const maxSeenAt = Math.floor(Date.now() / 1000);
|
|
103
|
+
let seenAt = maxSeenAt - items.length;
|
|
104
|
+
|
|
105
|
+
for (const item of items) {
|
|
106
|
+
const itemTakenAt = item.taken_at;
|
|
107
|
+
|
|
108
|
+
if (seenAt < itemTakenAt) {
|
|
109
|
+
seenAt = itemTakenAt + 1;
|
|
110
|
+
}
|
|
111
|
+
if (seenAt > maxSeenAt) {
|
|
112
|
+
seenAt = maxSeenAt;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const itemSourceId = sourceId === null ? item.user.pk : sourceId;
|
|
116
|
+
const reelId = `${item.id}_${itemSourceId}`;
|
|
117
|
+
reels[reelId] = [`${itemTakenAt}_${seenAt}`];
|
|
118
|
+
|
|
119
|
+
seenAt += 1;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return this.client.media.seen(reels);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async getHighlights(userId) {
|
|
126
|
+
const response = await this.client.request.send({
|
|
127
|
+
method: 'GET',
|
|
128
|
+
url: `/api/v1/highlights/${userId}/highlights_tray/`,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
return response.body;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async getHighlight(highlightId) {
|
|
135
|
+
const response = await this.client.request.send({
|
|
136
|
+
method: 'GET',
|
|
137
|
+
url: `/api/v1/feed/reels_media/`,
|
|
138
|
+
qs: {
|
|
139
|
+
reel_ids: highlightId
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
return response.body;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async viewers(storyId) {
|
|
147
|
+
const response = await this.client.request.send({
|
|
148
|
+
method: 'GET',
|
|
149
|
+
url: `/api/v1/media/${storyId}/list_reel_media_viewer/`,
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
return response.body;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
module.exports = StoryRepository;
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
const Repository = require('../core/repository');
|
|
2
|
+
const Chance = require('chance');
|
|
3
|
+
const { random } = require('lodash');
|
|
4
|
+
const FormData = require('form-data');
|
|
5
|
+
|
|
6
|
+
class UploadRepository extends Repository {
|
|
7
|
+
constructor(client) {
|
|
8
|
+
super(client);
|
|
9
|
+
this.chance = new Chance();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async photo(options) {
|
|
13
|
+
const uploadId = options.uploadId || Date.now();
|
|
14
|
+
const name = `${uploadId}_0_${random(1000000000, 9999999999)}`;
|
|
15
|
+
const waterfallId = options.waterfallId || this.chance.guid();
|
|
16
|
+
|
|
17
|
+
const ruploadParams = this.createPhotoRuploadParams(options, uploadId);
|
|
18
|
+
|
|
19
|
+
const formData = new FormData();
|
|
20
|
+
formData.append('photo', options.file, { filename: 'photo.jpg' });
|
|
21
|
+
|
|
22
|
+
const response = await this.client.request.send({
|
|
23
|
+
url: `/rupload_igphoto/${name}`,
|
|
24
|
+
method: 'POST',
|
|
25
|
+
headers: {
|
|
26
|
+
'X-FB-Photo-Waterfall-ID': waterfallId,
|
|
27
|
+
'X-Entity-Type': 'image/jpeg',
|
|
28
|
+
'Offset': '0',
|
|
29
|
+
'X-Instagram-Rupload-Params': JSON.stringify(ruploadParams),
|
|
30
|
+
'X-Entity-Name': name,
|
|
31
|
+
'X-Entity-Length': options.file.length.toString(),
|
|
32
|
+
'Content-Type': 'application/octet-stream',
|
|
33
|
+
'Content-Length': options.file.length.toString(),
|
|
34
|
+
'Accept-Encoding': 'gzip',
|
|
35
|
+
...formData.getHeaders(),
|
|
36
|
+
},
|
|
37
|
+
data: options.file,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return response.body;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async video(options) {
|
|
44
|
+
const uploadId = options.uploadId || Date.now();
|
|
45
|
+
const name = options.uploadName || `${uploadId}_0_${random(1000000000, 9999999999)}`;
|
|
46
|
+
const waterfallId = options.waterfallId || this.chance.guid();
|
|
47
|
+
|
|
48
|
+
const ruploadParams = this.createVideoRuploadParams(options, uploadId);
|
|
49
|
+
|
|
50
|
+
const response = await this.client.request.send({
|
|
51
|
+
url: `/rupload_igvideo/${name}`,
|
|
52
|
+
method: 'POST',
|
|
53
|
+
headers: {
|
|
54
|
+
'X-FB-Video-Waterfall-ID': waterfallId,
|
|
55
|
+
'X-Entity-Type': 'video/mp4',
|
|
56
|
+
'Offset': options.offset || '0',
|
|
57
|
+
'X-Instagram-Rupload-Params': JSON.stringify(ruploadParams),
|
|
58
|
+
'X-Entity-Name': name,
|
|
59
|
+
'X-Entity-Length': options.video.length.toString(),
|
|
60
|
+
'Content-Type': 'application/octet-stream',
|
|
61
|
+
'Content-Length': options.video.length.toString(),
|
|
62
|
+
'Accept-Encoding': 'gzip',
|
|
63
|
+
},
|
|
64
|
+
data: options.video,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return response.body;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
createPhotoRuploadParams(options, uploadId) {
|
|
71
|
+
return {
|
|
72
|
+
retry_context: JSON.stringify({
|
|
73
|
+
num_step_auto_retry: 0,
|
|
74
|
+
num_reupload: 0,
|
|
75
|
+
num_step_manual_retry: 0,
|
|
76
|
+
}),
|
|
77
|
+
media_type: '1',
|
|
78
|
+
xsharing_user_ids: JSON.stringify([]),
|
|
79
|
+
upload_id: uploadId.toString(),
|
|
80
|
+
image_compression: JSON.stringify({
|
|
81
|
+
lib_name: 'moz',
|
|
82
|
+
lib_version: '3.1.m',
|
|
83
|
+
quality: '95',
|
|
84
|
+
}),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
createVideoRuploadParams(options, uploadId) {
|
|
89
|
+
return {
|
|
90
|
+
retry_context: JSON.stringify({
|
|
91
|
+
num_step_auto_retry: 0,
|
|
92
|
+
num_reupload: 0,
|
|
93
|
+
num_step_manual_retry: 0,
|
|
94
|
+
}),
|
|
95
|
+
media_type: '2',
|
|
96
|
+
xsharing_user_ids: JSON.stringify([]),
|
|
97
|
+
upload_id: uploadId.toString(),
|
|
98
|
+
upload_media_duration_ms: options.duration_ms || '0',
|
|
99
|
+
upload_media_width: options.width || '720',
|
|
100
|
+
upload_media_height: options.height || '1280',
|
|
101
|
+
for_album: options.for_album || false,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async configure(options) {
|
|
106
|
+
const basePayload = {
|
|
107
|
+
upload_id: options.uploadId,
|
|
108
|
+
source_type: options.source_type || '4',
|
|
109
|
+
camera_position: options.camera_position || 'back',
|
|
110
|
+
_csrftoken: this.client.state.cookieCsrfToken,
|
|
111
|
+
_uid: this.client.state.cookieUserId,
|
|
112
|
+
_uuid: this.client.state.uuid,
|
|
113
|
+
creation_logger_session_id: this.chance.guid(),
|
|
114
|
+
device: {
|
|
115
|
+
manufacturer: this.client.state.devicePayload.manufacturer,
|
|
116
|
+
model: this.client.state.devicePayload.model,
|
|
117
|
+
android_version: this.client.state.devicePayload.android_version,
|
|
118
|
+
android_release: this.client.state.devicePayload.android_release,
|
|
119
|
+
},
|
|
120
|
+
length: options.length || 0,
|
|
121
|
+
audio_muted: options.audio_muted || false,
|
|
122
|
+
poster_frame_index: options.poster_frame_index || 0,
|
|
123
|
+
filter_type: options.filter_type || '0',
|
|
124
|
+
video_result: options.video_result || '',
|
|
125
|
+
composition_id: this.chance.guid(),
|
|
126
|
+
clips: options.clips || [
|
|
127
|
+
{
|
|
128
|
+
length: options.length || 0,
|
|
129
|
+
source_type: '4',
|
|
130
|
+
camera_position: 'back',
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
if (options.caption) {
|
|
136
|
+
basePayload.caption = options.caption;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (options.location) {
|
|
140
|
+
basePayload.location = JSON.stringify(options.location);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const response = await this.client.request.send({
|
|
144
|
+
url: '/api/v1/media/configure/',
|
|
145
|
+
method: 'POST',
|
|
146
|
+
form: this.client.request.sign(basePayload),
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
return response.body;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async configureVideo(options) {
|
|
153
|
+
return this.configure({
|
|
154
|
+
...options,
|
|
155
|
+
video_result: 'deprecated',
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async configurePhoto(options) {
|
|
160
|
+
return this.configure({
|
|
161
|
+
...options,
|
|
162
|
+
source_type: '4',
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
module.exports = UploadRepository;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
const Repository = require('../core/repository');
|
|
2
|
+
|
|
3
|
+
class UserRepository extends Repository {
|
|
4
|
+
async infoByUsername(username) {
|
|
5
|
+
const response = await this.client.request.send({
|
|
6
|
+
method: 'GET',
|
|
7
|
+
url: `/api/v1/users/${username}/usernameinfo/`,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
return response.body.user;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async info(userId) {
|
|
14
|
+
const response = await this.client.request.send({
|
|
15
|
+
method: 'GET',
|
|
16
|
+
url: `/api/v1/users/${userId}/info/`,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
return response.body.user;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async search(query) {
|
|
23
|
+
const response = await this.client.request.send({
|
|
24
|
+
method: 'GET',
|
|
25
|
+
url: '/api/v1/users/search/',
|
|
26
|
+
qs: {
|
|
27
|
+
q: query,
|
|
28
|
+
count: 50
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return response.body.users;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async follow(userId) {
|
|
36
|
+
const response = await this.client.request.send({
|
|
37
|
+
method: 'POST',
|
|
38
|
+
url: `/api/v1/friendships/create/${userId}/`,
|
|
39
|
+
form: this.client.request.sign({
|
|
40
|
+
_csrftoken: this.client.state.cookieCsrfToken,
|
|
41
|
+
_uid: this.client.state.cookieUserId,
|
|
42
|
+
_uuid: this.client.state.uuid,
|
|
43
|
+
user_id: userId,
|
|
44
|
+
}),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return response.body;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async unfollow(userId) {
|
|
51
|
+
const response = await this.client.request.send({
|
|
52
|
+
method: 'POST',
|
|
53
|
+
url: `/api/v1/friendships/destroy/${userId}/`,
|
|
54
|
+
form: this.client.request.sign({
|
|
55
|
+
_csrftoken: this.client.state.cookieCsrfToken,
|
|
56
|
+
_uid: this.client.state.cookieUserId,
|
|
57
|
+
_uuid: this.client.state.uuid,
|
|
58
|
+
user_id: userId,
|
|
59
|
+
}),
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
return response.body;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async getFollowers(userId, maxId = null) {
|
|
66
|
+
const qs = {
|
|
67
|
+
max_id: maxId
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const response = await this.client.request.send({
|
|
71
|
+
method: 'GET',
|
|
72
|
+
url: `/api/v1/friendships/${userId}/followers/`,
|
|
73
|
+
qs
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
return response.body;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async getFollowing(userId, maxId = null) {
|
|
80
|
+
const qs = {
|
|
81
|
+
max_id: maxId
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const response = await this.client.request.send({
|
|
85
|
+
method: 'GET',
|
|
86
|
+
url: `/api/v1/friendships/${userId}/following/`,
|
|
87
|
+
qs
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
return response.body;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
module.exports = UserRepository;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const sendPhoto = require('./sendPhoto');
|
|
2
|
+
const sendFile = require('./sendFile');
|
|
3
|
+
const uploadPhoto = require('./uploadPhoto');
|
|
4
|
+
const uploadFile = require('./uploadfFile');
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
sendPhoto,
|
|
8
|
+
sendFile,
|
|
9
|
+
uploadPhoto,
|
|
10
|
+
uploadFile
|
|
11
|
+
};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sendFile.js
|
|
3
|
+
* High-level helper to send uploaded video/audio/image files to Instagram Direct (DM or existing thread).
|
|
4
|
+
*
|
|
5
|
+
* Requires:
|
|
6
|
+
* - uploadFile(session, fileBuffer, options) from ./uploadFile
|
|
7
|
+
*
|
|
8
|
+
* Supports:
|
|
9
|
+
* - Send to a single user by userId (recipient_users)
|
|
10
|
+
* - Send to an existing thread (group or DM) by threadId
|
|
11
|
+
* - Optional caption
|
|
12
|
+
* - Optional mentions (array of userIds) embedded in caption
|
|
13
|
+
* - Custom mimeType/fileName/chunkSize/isClipsMedia forwarded to uploadFile
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
* const sendFile = require('./sendFile');
|
|
17
|
+
* await sendFile(session, {
|
|
18
|
+
* fileBuffer: fs.readFileSync('./clip.mp4'),
|
|
19
|
+
* mimeType: 'video/mp4',
|
|
20
|
+
* fileName: 'clip.mp4',
|
|
21
|
+
* userId: '123456789', // or threadId: '340282366841710300949128123456789'
|
|
22
|
+
* caption: 'Uite clipul!',
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* Notes:
|
|
26
|
+
* - Exactly one of { userId, threadId } must be provided.
|
|
27
|
+
* - For photos (JPEG/PNG), you can still use this with mimeType 'image/jpeg' or 'image/png',
|
|
28
|
+
* but uploadPhoto.js + sendPhoto.js is preferred for image-specific flows.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
const uploadFile = require('./uploadfFile');
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @typedef {Object} SendFileOptions
|
|
35
|
+
* @property {Buffer} fileBuffer - Required Buffer data
|
|
36
|
+
* @property {string} [mimeType='video/mp4'] - e.g., 'video/mp4', 'audio/mpeg', 'image/jpeg'
|
|
37
|
+
* @property {string} [fileName] - Optional file name; sanitized based on mime
|
|
38
|
+
* @property {number} [chunkSize] - Optional chunk size for uploadFile
|
|
39
|
+
* @property {boolean} [isClipsMedia=false] - Hint for reels-like uploads (if your flow supports it)
|
|
40
|
+
* @property {string} [caption] - Optional caption text
|
|
41
|
+
* @property {string} [userId] - Send to user (DM) — exactly one of userId or threadId
|
|
42
|
+
* @property {string} [threadId] - Send to existing thread (group or DM) — exactly one of userId or threadId
|
|
43
|
+
* @property {string[]} [mentions] - Optional array of userIds mentioned in caption
|
|
44
|
+
* @property {AbortSignal} [signal] - Optional AbortSignal to cancel
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Send a file (video/audio/image) to Instagram Direct.
|
|
49
|
+
* Internally:
|
|
50
|
+
* - Uploads via rupload to get upload_id
|
|
51
|
+
* - Broadcasts the uploaded media to either a user (DM) or an existing thread
|
|
52
|
+
*
|
|
53
|
+
* @param {object} session - Authenticated session (with request.send)
|
|
54
|
+
* @param {SendFileOptions} opts - Options
|
|
55
|
+
* @returns {Promise<object>} Instagram response object
|
|
56
|
+
*/
|
|
57
|
+
async function sendFile(session, opts = {}) {
|
|
58
|
+
const {
|
|
59
|
+
fileBuffer,
|
|
60
|
+
mimeType = 'video/mp4',
|
|
61
|
+
fileName,
|
|
62
|
+
chunkSize,
|
|
63
|
+
isClipsMedia = false,
|
|
64
|
+
caption = '',
|
|
65
|
+
userId,
|
|
66
|
+
threadId,
|
|
67
|
+
mentions = [],
|
|
68
|
+
signal,
|
|
69
|
+
} = opts;
|
|
70
|
+
|
|
71
|
+
// Validate destination
|
|
72
|
+
if (!userId && !threadId) {
|
|
73
|
+
throw new Error('sendFile: You must provide either userId (DM) or threadId (existing thread).');
|
|
74
|
+
}
|
|
75
|
+
if (userId && threadId) {
|
|
76
|
+
throw new Error('sendFile: Provide only one destination — userId OR threadId, not both.');
|
|
77
|
+
}
|
|
78
|
+
// Validate buffer
|
|
79
|
+
if (!fileBuffer || !Buffer.isBuffer(fileBuffer) || fileBuffer.length === 0) {
|
|
80
|
+
throw new Error('sendFile: fileBuffer must be a non-empty Buffer.');
|
|
81
|
+
}
|
|
82
|
+
if (typeof mimeType !== 'string' || mimeType.length === 0) {
|
|
83
|
+
throw new Error('sendFile: mimeType must be a non-empty string (e.g., "video/mp4").');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 1) Upload file to get upload_id
|
|
87
|
+
const upload_id = await uploadFile(session, fileBuffer, {
|
|
88
|
+
mimeType,
|
|
89
|
+
fileName,
|
|
90
|
+
chunkSize,
|
|
91
|
+
isClipsMedia,
|
|
92
|
+
signal,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// 2) Build base form payload
|
|
96
|
+
const form = {
|
|
97
|
+
upload_id,
|
|
98
|
+
action: 'send_item',
|
|
99
|
+
caption,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// 3) Mentions (optional)
|
|
103
|
+
if (Array.isArray(mentions) && mentions.length > 0) {
|
|
104
|
+
form.entities = JSON.stringify(
|
|
105
|
+
mentions.map((uid) => ({
|
|
106
|
+
user_id: String(uid),
|
|
107
|
+
type: 'mention',
|
|
108
|
+
}))
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// 4) Destination-specific fields
|
|
113
|
+
// For video/audio/image via this flow, IG uses the "upload_video" broadcast endpoint.
|
|
114
|
+
// Images can also be sent via upload_photo (recommended via sendPhoto.js).
|
|
115
|
+
const url = '/direct_v2/threads/broadcast/upload_video/';
|
|
116
|
+
if (userId) {
|
|
117
|
+
form.recipient_users = JSON.stringify([[String(userId)]]);
|
|
118
|
+
} else {
|
|
119
|
+
form.thread_ids = JSON.stringify([String(threadId)]);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// 5) Send broadcast request
|
|
123
|
+
try {
|
|
124
|
+
const response = await session.request.send({
|
|
125
|
+
url,
|
|
126
|
+
method: 'POST',
|
|
127
|
+
form,
|
|
128
|
+
signal,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
if (!response) {
|
|
132
|
+
throw new Error('sendFile: Empty response from Instagram broadcast endpoint.');
|
|
133
|
+
}
|
|
134
|
+
return response;
|
|
135
|
+
} catch (err) {
|
|
136
|
+
throw new Error(`sendFile: Broadcast failed — ${normalizeError(err)}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Normalize error shapes to readable text.
|
|
142
|
+
*/
|
|
143
|
+
function normalizeError(err) {
|
|
144
|
+
if (!err) return 'Unknown error';
|
|
145
|
+
if (typeof err === 'string') return err;
|
|
146
|
+
if (err.message) return err.message;
|
|
147
|
+
try {
|
|
148
|
+
return JSON.stringify(err);
|
|
149
|
+
} catch {
|
|
150
|
+
return 'Unserializable error';
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
module.exports = sendFile;
|